AutoFocus

By samurai20000 Last update Dec 25, 2008 — Installed 1,973 times. Daily Installs: 0, 2, 3, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 2, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 2, 0

There are 2 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.5
// ==/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();
    log('focus!');
};

var launchAutoFocus = function(list) {
    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]);
	    }
	}
	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);
	}
    });
};

// 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);
	}
    }
}

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;
}

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

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