AutoFocus

By samurai20000 Last update Dec 12, 2009 — Installed 3,615 times.

There are 4 previous versions of this script.

// ==UserScript==
// @name          AutoFocus
// @namespace     http://d.hatena.ne.jp/samurai20000/
// @description	  auto focus on where you wish
// @include       http://*
// @include	  https://*
// @version       0.0.7
// ==/UserScript==
//
// this script based on autopagerize.user.js
// thanks to id:swdyh
//

const CACHE_EXPIRE = 24 * 60 * 60 * 1000;
const SITEINFO_URLS = ['http://wedata.net/databases/AutoFocus/items.json'];
const XHR_TIMEOUT = 30 * 1000;
const SITEINFO = [
    /* sample
    {
	url:   'http://reader\\.livedoor\\.com/',
	focus: '//div[@id="login"]/h3/a'
    }
    */
    /* templete
    {
	url:   '',
	focus: ''
    }
    */
];

var AutoFocus = function(info) {
    var focus_element = getFocusElementByXpath(info.focus);
    focus_element.focus();
};

var launchAutoFocus = function(list) {
    add_focus_style();
    if (!reloaded()) {
        for (var i = 0; i < list.length; i++) {
            try {
	        if (!af && location.href.match(list[i].url) &&
	            getFocusElementByXpath(list[i].focus)) {
		        af = new AutoFocus(list[i]);
	        }
                window.name = window.location.href;
	    } catch(e) {
	        log(e);
	        continue;
	    }
        }
    }
};


var getsiteinfo = function(urls) {
    var xhrStates = {};
    cacheInfo = getCache();
    urls.forEach(function(i) {
	if(!cacheInfo[i] || cacheInfo[i].expire < new Date()) {
	    var opt = {
		method  : 'get',
		url     : i,
		onload  : function(res) {
                    xhrStates[i] = 'loaded';
                    getCacheCallback(res, i);
                },
		onerror : function(res) {
                    xhrStates[i] = 'error';
                    getCacheErrorCallback(i);
                }
	    };
            xhrStates[i] = 'start';
	    GM_xmlhttpRequest(opt);
            setTimeout(function() { if (xhrStates[i] == 'start') { getCacheErrorCallback(i); }} , XHR_TIMEOUT);
	}
	else {
	    launchAutoFocus(cacheInfo[i].info);
	}
    });
};

var add_focus_style = function() {
    // based on http://userstyles.org/styles/305
    var css = 'a:hover:active {color: #10bae0;}' +
              'a:not(:hover):active {  color: #0000ff;}' +
              '*:focus {-moz-outline: 4px solid -moz-rgba(16,186,224,0.3) !important;-moz-outline-offset: 1px !important;-moz-outline-radius: 3px !important;}' +
              'button:focus,input[type="reset"]:focus,input[type="button"]:focus,input[type="submit"]:focus,input[type="file"] > input[type="button"]:focus {-moz-outline-radius: 5px !important;}' +
              'button:focus::-moz-focus-inner {border-color: transparent !important;}' +
              'button::-moz-focus-inner,input[type="reset"]::-moz-focus-inner,input[type="button"]::-moz-focus-inner,input[type="submit"]::-moz-focus-inner,input[type="file"] > input[type="button"]::-moz-focus-inner {border: 1px dotted transparent !important;}' +
              'textarea:focus, button:focus, select:focus, input:focus {-moz-outline-offset: -1px !important;}' +
              'input[type="radio"]:focus {-moz-outline-radius: 12px;-moz-outline-offset: 0px !important;}' +
              'a:focus {-moz-outline-offset: 0px !important;}';

    addstyle(css);
};


// utility SITE_INFO
function parseInfo(str) {
    var lines = str.split(/\r?\n|\r/);
    var strip = str.replace(/^\s+|\s+$/g, '');
    var re = /^([^:]+?):(.*)$/;
    var info = {};
    lines.forEach(function(line) {
	if (re.test(line)) {
	    info[RegExp.$1] = RegExp.$2.replace(/^\s+/, '');
	}
    });

    var isValid = function(info) {
	return !['url', 'focus'].some(function(property) {
	    return !info.hasOwnProperty(property);
	});
    };

    return isValid(info) ? info : null;
}

function clearCache() {
    GM_setValue('cacheInfo', '');
}

function getCache() {
    return eval(GM_getValue('cacheInfo')) || {};
}

function getCacheCallback(res, url) {
    if (res.status != 200) {
	return getCacheErrorCallback(url);
    }
    
    var info
    try {
        info = eval(res.responseText).map(function(i) { return i.data })
    } catch(e) {
        var info      = [];
        var matched   = false;
        var hdoc      = createHTMLDocumentByString(res.responseText);
        var textareas = getElementsByXPath('//*[@class="autofocus_data"]', hdoc) || [];

        textareas.forEach(function(textareass) {
	    var d = parseInfo(textareas.innerHTML);
	    if (!d) return;
	    info.push(d);
	    if (!matched && location.href.match(d.url)) {
	        matched = d;
	    }
        });
    }

    if (info.length > 0) {
	cacheInfo[url] = {
	    urls   : url,
	    expire : new Date(new Date().getTime() + CACHE_EXPIRE),
	    info   : info
	};
	GM_setValue('cacheInfo', cacheInfo.toSource());
        log('cache!');

	if (!af && !!matched) {
	    af = new AutoFocus(matched);
            window.name = window.location.href;
	}
    }
}

function getCacheErrorCallback(url) {
    if (cacheInfo[url]) {
	cacheInfo[url].expire = new Date(new Date().getTime() + CACHE_EXPIRE);
	GM_setValue('cacheInfo', cacheInfo.toSource());
	launchAutoFocus(cacheInfo[url].info);
    }
}

function createHTMLDocumentByString(str) {
    var html     = str.replace(/<!DOCTYPE[ \t\r\n][^>]*>|<html(?:(?=<)|[ \t\r\n]*>|[ \t\r\n][^<>]*(?:>|(?=<)))|<\/html(?:[ \t\r\n>].*)?$/ig, '');
    var htmlDoc  = document.implementation.createDocument(null, 'html', null);
    var fragment = createDocumentFragmentByString(html);
    try {
        fragment = htmlDoc.adoptNode(fragment);
    } catch(e) {
        fragment = htmlDoc.importNode(fragment, true);
    };
    htmlDoc.documentElement.appendChild(fragment);
    return htmlDoc;
}

function createDocumentFragmentByString(str) {
    var range = document.createRange();
    range.setStartAfter(document.body);
    return range.createContextualFragment(str);
}

function getFocusElementByXpath(xpath) {
    var result = document.evaluate(xpath, document, null,
                                   XPathResult.FIRST_ORDERED_NODE_TYPE, null);
    return result.singleNodeValue ? result.singleNodeValue: null;
}

function getElementsByXPath(xpath, node) {
    var node = node || document;
    var nodesSnapshot = document.evaluate(xpath, node, null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    var data = [];
    for (var i = 0; i < nodesSnapshot.snapshotLength; i++) {
	data.push(nodesSnapshot.snapshotItem(i));
    }
    return (data.length >= 1) ? data : null;
}

//this code based ldrize.user.js
function addstyle(css) { 
    var link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = 'data:text/css,' + escape(css);
    document.documentElement.childNodes[0].appendChild(link);
}

function reloaded() {
    return window.name == window.location.href ? true : false;
}

function log(message) {
    GM_log(message);
}

//main
GM_registerMenuCommand('AutoFocus - clear cache', clearCache)
var af = null;
launchAutoFocus(SITEINFO);
getsiteinfo(SITEINFO_URLS);