// ==UserScript==
// @name Enhanced word highlight
// @name:en Enhanced word highlight
// @namespace http://userscripts.org/users/86496
// @description 在搜索引擎和任意网页获得增强的高亮!
// @description:en Enhanced keywords highlight for Search Engines and All !
// @match *://*/*
// @exclude http://maps.google.com/*
// @exclude https://maps.google.com/*
// @grant GM_log
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_openInTab
// @grant GM_registerMenuCommand
// @license GNU GPLv3
// @version 1.7.3
// @downloadURL none
// ==/UserScript==
// great credit for original script wright os0x [http://userscripts.org/scripts/show/43419]
// hzhbest modded | detail in http://userscripts.org/scripts/show/64877
// 173: fix charset recognition, update look
//console.time("highlight");
function l() { //debug
var args = Array.prototype.slice.call(arguments);
console.log.apply(console, args);
}
(function word_hightlight(loaded){
//if (window.top != window.self) return; //don't run on frames or iframes
// check browser
if (!loaded && window.opera && document.readyState == 'interactive') {
document.addEventListener('DOMContentLoaded', function(){
loaded = true;
word_hightlight(true);
}, false);
window.addEventListener('load', function(){
if (!loaded) {
word_hightlight(true);
}
}, false);
return;
}
if (document.contentType && !/html/i.test(document.contentType)) return;
// check api
var getv, setv
if (typeof GM_getValue == "function") {
getv = GM_getValue;
setv = GM_setValue;
} else { // workaround functions, creadit to ww_start_t
setv = function(cookieName, cookieValue, lifeTime){
if (!cookieName) {return;}
if (lifeTime == "delete") {lifeTime = -10;} else {lifeTime = 31536000;}
document.cookie = escape(cookieName)+ "=" + escape(getRecoverableString(cookieValue))+
";expires=" + (new Date((new Date()).getTime() + (1000 * lifeTime))).toGMTString() + ";path=/";
};
getv = function(cookieName, oDefault){
var cookieJar = document.cookie.split("; ");
for (var x = 0; x < cookieJar.length; x++ ) {
var oneCookie = cookieJar[x].split("=");
if (oneCookie[0] == escape(cookieName)) {
try {
eval('var footm = '+unescape(oneCookie[1]));
} catch (e) {return oDefault;}
return footm;
}
}
return oDefault;
};
}
//{ values >
var isOpera = !!this.opera,
isFirefox = !!this.Components,
isChromium = !!this.chromium,
isSafari = this.getMatchedCSSRules && !isChromium;
var STYLE_COLOR = ['#FFFF80','#99ccff','#ff99cc','#66cc66','#cc99ff','#ffcc66','#66aaaa','#dd9966','#aaaaaa','#dd6699'];
var BORDER_COLOR = ['#aaaa20','#4477aa','#aa4477','#117711','#7744aa','#aa7711','#115555','#884411','#555555','#881144'];
//浅一点的一套配色
var STYLE_COLOR_2 = ['#FFFFa0','#bbeeff','#ffbbcc','#88ee88','#ccbbff','#ffee88','#88cccc','#ffbb88','#cccccc','#ffaabb'];
var BORDER_COLOR_2 = ['#aaaa40','#6699aa','#aa6699','#339933','#9966aa','#aa9933','#337777','#aa6633','#777777','#aa3366'];
// button color: normal bg / active bg / disabled bg / border color.
var but_c = '#cce5cc', but_ca = '#FFD000', but_cd = '#999999', but_cb = '#669966';
// lexicon 词汇表
// highlighted word:高亮词:已用于被高亮的单个【字符串】
// highlight(s):高亮:在页面中针对高亮词形成的带高亮效果【节点】
// navigate:寻觅:在页面中对寻找某高亮词或不指定高亮词的高亮的位置的【动作】
// keyword:关键词:通过自动高亮功能识别到的高亮词候选的单个【字符串】
// word:词:任何输入到Ewh的单个【字符串】
// map:分布图:显示各高亮在页面分布相对位置的【画布节点】
// viewport:指示窗:显示当前窗口可见区域在页面相对位置的【画布节点】
// panel:高亮面板:Ewh主要功能【节点】,上面有控制按钮和高亮按钮
// highlight button:高亮按钮:在高亮面板上代表并可用于寻觅各高亮词的高亮的【节点】
// turn off:停用:保留高亮面板但不显示各高亮的【动作】,可重新turn on
// disable:禁用:不保留高亮功能在当前窗口不显示并不再显示高亮的【动作】,可重新添加词来重启高亮
// window:窗口:显示网页的浏览器【组件】;不同于浏览器窗口,一个浏览器窗口包含了其功能按钮和窗口,甚至通过多标签页包含多个窗口
// Initialize value
var PRE = 'wordhighlight', ID_PRE = PRE + '_id', ST_PRE = PRE + '_store', PO_PRE = PRE + '_position', CO_PRE = PRE + '_config';
var STYLE_CLASS = '0123456789'.split('').map(function(a,i){return PRE + '_word'+i;});
var setuped = false; //初始启动状态:否
var highlight_off = false; //初始停用状态:否
var addKeyword = true; //初始添加状态:是(关键词输入框为“Add”而非“New”)
var keyword = ''; //关键词文本
var words = []; //关键词数组
var word_lists = []; //放在word_inputs_list内的含单个关键词的li元素的数组
var word_inputs_list; //容纳word_lists的ul元素,位于panel内
var layers; //高亮元素span的数组
var positions = []; //高亮元素的指针位置,[#0:不指定高亮,#1:第一个词,#2:第二个词,……]
var words_off = []; //略过不高亮状态数组,其顺序对应words,略过时为“1”
var xp_all = new $XE('descendant::span[starts-with(@name,"' + PRE + '_word")]', document.body);
//body中所有name属性为高亮标识开头的span元素进行xpath检索的检索体对象,其get方法输出span元素数组
//其使用get方法的目的是,每次调用时就是重新获取所有span元素生成数组,而不是固定数组
var keyCodeStr = { //key press 事件返回的which代码对应按键键名对应表对象
8: 'BAC',
9: 'TAB',
10: 'RET',
13: 'RET',
27: 'ESC',
33: 'PageUp',
34: 'PageDown',
35: 'End',
36: 'Home',
37: 'Left',
38: 'Up',
39: 'Right',
40: 'Down',
45: 'Insert',
46: 'Delete',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12'
};
var whichStr = {
32: 'SPC'
};
var htmlDoc = isChromium ? document.implementation.createHTMLDocument('hogehoge') : document; //文档根节点
var highlight_reset = function(){}; //重置高亮的预定义函数
var canvas; //分布图底板canvas
var cw; //分布图位置指示canvas
var c2context; //分布图指示标canvas 2D图形
var nav; //分布图容器
var root = /BackCompat/i.test(document.compatMode) ? document.body : document.documentElement; //页面根节点
const CanvasWidth = 150; //分布图基础宽度
var ratio = 1; //分布图位置指示与实际比例
var aside, section, td0, lock, edit, off, text_input, posi_tip, posi_tip_timer, inputBOX; // panel elements
var sheet, main_sheet, move_sheet, inst_sheet, config_sheet; // style sheets
var pausetimer, onpause;
//language detection
const lang = (navigator.appName=="Netscape")? navigator.language : navigator.userLanguage;
var _L;
if (lang.indexOf('zh-') == -1) {
_L = 0;
} else _L = 1;
// string arrays
var _ti = { // en/zh locale string for tooltip.
edit: ['Edit current keywords','编辑现有关键词'],
edit_a: ['Confirm editing keywords','确认编辑关键词'],
off: ['Toggle all keywords\' highlight','切换全部关键词的高亮'],
td0: ['Double-click to minimize the panel','双击最小化面板'],
td0_a: ['Double-click to restore Ewh panel','双击恢复 Ewh 面板'],
lock: ['Lock current set of keywords','锁定当前的关键词组'],
lock_a: ['Current locked keyword(s):','当前锁定的关键词组:'],
lock_u: ['Function not supported by this browser','此浏览器不支持该功能'],
close: ['Close Enhanced word highlight','关闭关键词高亮'],
kwL: ['Left click to the next; Right click to the previous','左击跳到下一个;右击跳到上一个'],
check: [['Toggle highlight of "','"'],['切换“','”的高亮']],
mapl:['Toggle highlight map locking status','切换高亮分布图的锁定状态'],
ad_nw: ['Toggle add/new keywords for highlight','切换添加/取代关键词的高亮'],
subm: ['Submit keywords','提交关键词'],
clos: ['Close input box','关闭输入框']
};
var _di = { // en/zh locale string for dialog.
confT: ['Enhanced word highlight Advanced Config','Enhanced word highlight 高级设置'],
ap_option: ['What auto-pager tool do you mostly use?','你主要用那种自动翻页工具?'],
ap_option1: ['Autopagerize GM script','Autopagerize GM 脚本'],
ap_option2: ['Autopager extension','Autopager 扩展'],
ap_option3: ['Other (can handle all auto-paging tools','其他(能应付任何自动翻页工具)'],
off_short_words: ['Skip highlighting of short words?','是否忽略短词的高亮?'],
off_short_words1: ['Don\'t skip','否'],
off_short_words2: ['One-letter/digit word','忽略单个字母/数字的词'],
off_short_words3: ['One- and two-letter/digit word','忽略一至两个字母/数字的词'],
skip_word_list: ['Skip highlighting of words below: (separate words with a space in between)','忽略以下词的高亮:(使用空格分隔各词)'],
no_auto_hili: ['Disable auto-highlight (auto-capture keywords for highlight) ?','是否禁用自动高亮(自动抓取关键词来高亮)?'],
no_auto_hili1: ['Enable','不禁用'],
no_auto_hili2: ['Completely disable','完全禁用'],
no_auto_hili3: ['Disable only on pages from search result links','仅在搜索结果链接打开的页面上禁用'],
no_auto_hili4: ['Disable only on search result pages','仅在搜索结果页面上禁用'],
sort_keywords: ['Sort words so that longer word will be highlighted earlier. Recommended, except for highlighting regular expression.', '从长到短排序目标词然后依此进行高亮,推荐选择,需要高亮正则表达式的除外。'],
sort_keywords1: ['Sort words before highlight','高亮前先排序目标词'],
save_panel_pos: ['If you have your own favorite panel position, check this.', '如果你希望面板默认在你喜欢的位置显示,就开启这功能。'],
save_panel_pos1: ['Save panel position','保存面板位置'],
show_indc_bar: ['Check this and a transparent indicator bar will appear when navigating through highlights, telling which row the current highlight is.', '若该功能开启,在查找高亮时会显示半透明指示条以标示当前高亮所在的行。'],
show_indc_bar1: ['Show indicator bar when navigating','查找关键词时显示指示条'],
button_yes: ['OK', '确定'],
button_no: ['Cancel', '取消'],
};
//}
//{ Config I >
// #### Config I #### --------------------------{{
// List of url patterns; Array('NAME', 'KEYWORD_PREFIX', 'URL_PATTERN')搜索引擎信息数组
var urlArr = [
['Google', 'q', '.google.'],
['Yahoo', 'p', 'search.yahoo.'],
['Baidu', 'wd', '.baidu.com'],
['Baidu', 'word', '.baidu.com'],
['Ask', 'q', 'www.ask.com'],
['Bing', 'q', '.bing.com'],
['Youdao', 'q', 'www.youdao.com'],
['cnki', 'keyValue', 'kns.cnki.net'],
['sogou', 'query', 'www.sogou.com'],
['weibo', 'q', 's.weibo.com'],
['duckduckgo', 'q', 'duckduckgo.com'], //https://duckduckgo.com/?q=DDG&t=h_&ia=web
['greasyfork', 'q', 'greasyfork.org'], //https://greasyfork.org/zh-CN/scripts?q=%E9%AB%98%E4%BA%AE
['ecosia', 'q', 'www.ecosia.org'] //https://www.ecosia.org/search?q=%E7%9C%BC%E7%90%83%E8%B7%9F%E8%B8%AA
];
// List of IDs of query input boxes; Array('#SEARCHBOX_ID#', 'SEARCHPAGE SPEC_URL')
var queryArr = [
['query', '/search'], // most common
['search', ''], // most common
['script_q', 'userscripts.org/scripts/search'], // userscripts.org
['search-q', '/search'] // addons.mozilla.org
];
// keybinds
var KEY_NEXT = 'n'; // "n" Next occurrence
var KEY_PREV = 'N'; // "Shift-n" Previous occurrence
var KEY_SEARCH = 'M-/'; // "Alt-/" Add keywords
var KEY_OFF = 'M-,'; // "Alt-," Suspend highlight
var KEY_CLOSE = 'C-M-/'; // "Ctrl-Alt-/" Disable highlight
var KEY_EDIT = 'M-.'; // "Alt-." Edit highlight
var KEY_REFRESH = 'r'; // "r" Refresh highlight
// delay of highlighting (ms)
var delay = 500;
// instant highlight selected keywords
var instant = true;
// restore focus and scroll position after closing keyword input box with shortcut key?
// mainly useful for keyboard navigation, not recommend for mouse navigation.
var refocus = false;
// minimize the panel initially?
var panel_hide = false;
// #### Config I #### --------------------------}}
//}
if (window.top.document.location.href != window.self.document.location.href) panel_hide = true; //hide panel in iframes
//l(window.top.document.location.href != window.self.document.location.href);
// #### Config II #### --------------------------{{
var CFG = {
ap_option: 2,
// What's your main auto-pager tool?
// 0 - Autopagerize (GM script, obsolete)
// 1 - AuroPager (Firefox extension, obsolete)
// 2 - Other (Other auto-paging scripts or extensions)
off_short_words: 1,
// turn off short keywords (one or two letters or number) by default?
// 0-no, 1-one letter, 2-one or two letters
skip_word_list: "the to in on among between and a an of by with",
// skip highlighting word list
no_auto_hili: 0,
// Stop auto-highlight on supported pages?
// 0-no, 1-yes, 2-only those from search results, 3-only search results
sort_keywords: 1,
// sort keywords? 0-no, 1-yes
// Setting this to "yes" will produce better highlight result,
// while "no" will perform faster and support ReExp input better.
save_panel_pos: 0,
// save panel position? 0-no, 1-yes
show_indc_bar: 1,
// show indicator bar when navigating? 0-no, 1-yes
};//l(JSON.stringify(CFG));
// #### Config II #### --------------------------}}
// GM APIs available?
if (typeof GM_getValue == "function") var gm_ok = true;
var panel_pos_arr = ['right:-1px;','bottom:-1px;'];
if (gm_ok) {
// Configs
var confstr = GM_getValue(CO_PRE); //提取GM储存的设置
if (!!confstr && confstr.slice(0,1) === "{") { //如果设置是对象文本(JSON)
CFG = JSON.parse(confstr); //则载入
} else { //否则将默认设置写入储存
GM_setValue(CO_PRE, JSON.stringify(CFG));
}
// Locked keywords
var keyword_locked = GM_getValue(ST_PRE);
// Saved position
if (CFG.save_panel_pos) panel_pos_arr = GM_getValue(PO_PRE, panel_pos_arr.join('|')).split('|');
// Configs menu
window.addEventListener('load', function(){GM_registerMenuCommand(_di.confT[_L], config_box);}, false);
unsafeWindow.EWH_iSearch = function() {instant_search(false, null);};
unsafeWindow.EWH_cClose = function() {command_close();};
}
// main process
init_keyboard();
if (load_keyword() !== false || init_keyword() !== false) {
//window.addEventListener('load', setup, false);
setTimeout(setup, delay);
}
// var oldurl = window.location.href;
// window.addEventListener('DOMNodeInserted', function(e){ l(window.location.href);
// if (window.location.href !== oldurl) {
// if (load_keyword() !== false || init_keyword() !== false) {
// setTimeout(setup, delay*2);
// }
// }
// }, false);
// Functions
// 对目标文档(元素)对指定关键词数组进行高亮 ##
function highlight(doc, ext_word) {
var _words = words.filter(function(w,i){return !words_off[i];});
if (_words.length <= 0) {
return;
}
var _index;
if (ext_word && ext_word.words) {
_words = ext_word.words;
_index = ext_word.index;
}
var exd_words, xw;
if (_words.length === 1 && _words[0].exp) {
exd_words = _words.map(function(e){return e.exp;});
xw = '';
} else {
exd_words = _words.map(function(w){return w.test ? w : new RegExp('(' + w.replace(/\W/g,'\\$&') + ')(?!##)', 'ig');});
xw = ' and (' + _words.map(function(w){return ' contains(translate(self::text(),"abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ"),'+escapeXPathExpr(w.toUpperCase())+') ';}).join(' or ') + ') ';
}
$X('descendant::text()[string-length(normalize-space(self::text())) > 0 ' + xw +' and not(ancestor::textarea or ancestor::script or ancestor::style or ancestor::aside)]', doc).forEach(function(text_node) {
var df, text = text_node.nodeValue, id_index = 0,
parent = text_node.parentNode, range = document.createRange(), replace_strings = [],
new_text = reduce(exd_words, function(text,ew,i) {
var _i = _index || i;
return text.replace(ew,function($0,$1) {
replace_strings[id_index] = '' + $1 + '';
return '##'+(id_index++)+'##';
});
}, text).
replace(/&/g, '&').replace(//g, '>').
replace(/##(\d+)##/g, function($0,$1) {
return replace_strings[$1] || '';
});
if (replace_strings.length) {
try {
if (isChromium) {
range.selectNodeContents(htmlDoc.documentElement);
} else {
range.selectNode(text_node);
}
df = range.createContextualFragment(new_text);
if (df.firstChild) parent.replaceChild(df, text_node);
range.detach();
} catch (e) {
error(e);
}
}
});
}
// 生成主css样式表
function addsheet() {
if (!main_sheet) {
var hilistyles = STYLE_COLOR.map(function(rgb,i){
return 'span.' + PRE + '_word'+i+',.' + PRE + '_item'+i+'{background:'+rgb+'!important;}';
});
var borderstyles = BORDER_COLOR.map(function(rgb,i){
return 'li.' + PRE + '_item'+i+'{outline:1px solid '+rgb+'!important;}';
});
sheet = addCSS([
//Additional Style
'span[class^="' + PRE + '_word"]{color:black!important;font:inherit!important;display:inline!important;margin:0!important;padding:0!important;text-align:inherit!important;float:none!important;position:static!important;}', //vertical-align:inherit !important;
'#' + PRE + '_words, #' + PRE + '_words *{font-family: Arial ;}',
'#' + PRE + '_words{line-height:1;position:fixed;z-index:60000;opacity:0.8;list-style-type:none;margin:0;padding:0;width:auto;max-width:100%;' + panel_pos_arr[0] + panel_pos_arr[1] +'}',
'#' + PRE + '_words > section{clear:right;line-height:1;border:1px solid #d6d6d6;background:#fff;display:block;position:relative;}',
'#' + PRE + '_words * {margin:0;padding:0;width:auto;height:auto;}',
'#' + PRE + '_words:hover{opacity:1;}',
'#' + PRE + '_words:hover > section{opacity:1;border-color:#333;}',
'#' + PRE + '_words #_ewh_handle{background:#666;width:10px;cursor:move;}',
'#' + PRE + '_words:hover #_ewh_handle{background:#333;}',
'#' + PRE + '_words.ewh_hide #_ewh_handle{cursor:pointer;}',
'#' + PRE + '_words > nav{display:none;width:100%;padding:3px;position:relative;}',
'#' + PRE + '_words > nav > canvas.backport{background:rgba(0,0,0,0.5);cursor:pointer;position:absolute;right:6px;z-index:3;}',
'#' + PRE + '_words > nav > canvas.viewport{background:rgba(79,168,255,0.7);cursor:default;position:absolute;bottom:0px;}',//outline:6px solid rgba(79,168,255,0.7);
'#' + PRE + '_words:hover > nav{display:block;}',
'#' + PRE + '_words > nav._locked{display:block;}',
'#' + PRE + '_words:hover > nav > canvas.backport{bottom:0px;}',
'#' + PRE + '_words > nav._locked > canvas.backport{bottom:0px;}',
'#' + PRE + '_words.ewh_edit{opacity:1;}',
'#' + PRE + '_words.ewh_edit #' + PRE + '_word_inputs_list{display:none;}',
'#' + PRE + '_words form.' + PRE + '_editor{display:none;}',
'#' + PRE + '_words.ewh_edit form.' + PRE + '_editor{display:inline-block;}',
'#' + PRE + '_words.ewh_edit form.' + PRE + '_editor input{min-width:80px;}',
'#' + PRE + '_words li{display:inline-block;margin:0.1em 0.2em;line-height:1.3em;font-size:12pt !important;}',
'#' + PRE + '_words > section > table {border:0;margin:0;padding:0;border-spacing:2px;border-collapse:separate!important;}',
'#' + PRE + '_words > section > * {vertical-align:middle;}',
'#' + PRE + '_words > section td {border:none;}',
'#' + PRE + '_words > section form.' + PRE + '_ctrl{max-width: 0; max-height: 0; overflow: hidden; transition: all 0.3s ease-in-out 5s;}',
'#' + PRE + '_words:hover > section form.' + PRE + '_ctrl{display:inline-block !important;max-width: 200px; max-height: 1.3em; transition: all 0.1s ease-in-out 0s;}',
'#' + PRE + '_words > section form.' + PRE + '_ctrl > input{display:inline;width:1.3em;height:1.6em;margin-right:1px;background:'+ but_c +';border:0px solid '+ but_cb +';cursor:pointer;font-size:10pt !important;color:black;}',
'#' + PRE + '_words > section form.' + PRE + '_ctrl > input._active{background:'+ but_ca +';}',
'#' + PRE + '_words > section form.' + PRE + '_ctrl > input._disable{background:'+ but_cd +' !important;cursor:default;}',
'#' + PRE + '_words > section form.' + PRE + '_ctrl > input:hover{outline:1px solid '+ but_cb +'!important;}',
'#' + PRE + '_word_inputs_list {padding:0!important;margin:0.2em!important;display:inline-block;border:none!important;}',
'#' + PRE + '_word_inputs_list > li{position:relative;padding:0 4px;user-select: none;}',
'#' + PRE + '_word_inputs_list > li.ewh_disable{background:white!important;outline:1px solid #999!important;}',
'#' + PRE + '_word_inputs_list > li > label{cursor:pointer;color:black!important;}',
'#' + PRE + '_word_inputs_list > li > input{cursor:pointer;}',
'#' + PRE + '_word_inputs_list > li > input[type=checkbox]{display:none;position:absolute;right:0px;top:0px;opacity:0.7;}',
'#' + PRE + '_word_inputs_list > li:hover{outline-width:2px!important;}',
'#' + PRE + '_word_inputs_list > li:hover > input[type=checkbox]{display:block;}',
'#' + PRE + '_word_inputs_list > li > input[type=checkbox]:hover{opacity:1;}',
'#' + PRE + '_words > section td#_ewh_maplock > input {display:inline;width:1.3em;margin:0.1em 0.1em;background:#FAFAFA;border:none;cursor:pointer;font-size:10pt;color:#4d4d4d;}',
'@keyframes fadeit {from {opacity:1;} to {opacity:0;}}',
'#' + PRE + '_words > section td#_ewh_maplock > input:hover {background:'+ but_c +';}',
'#' + PRE + '_words > section td#_ewh_maplock > input._active {background:'+ but_ca +';}',
].concat(hilistyles, borderstyles).join('\n'));
main_sheet = true;
}
if (!move_sheet) addmovesheet()
}
// 生成突出高亮样式表
function addmovesheet() {
addCSS('.wordhighlight_em{outline:4px solid #FF7B00;-webkit-outline:4px solid #FF7B00;text-decoration:blink;}');
move_sheet = true;
}
// 启动:生成面板,形成面板互动机制,生成分布图和分布图互动机制,可拖动绑定,自动翻页响应,开始高亮全文档 ##
function setup(init) { //输入:若init=true,则无视panel_hide的状态,不隐藏面板
setuped = true;
addsheet();
// build ui
aside = creaElemIn('aside', document.body); //基底容器
aside.id = PRE + '_words';
section = creaElemIn('section', aside); //主容器
var table_COL = creaElemIn('table', section); //排版容器
table_COL.setAttribute('cellspacing', '0');
table_COL.setAttribute('cellpadding', '0');
var tbdy_COL = creaElemIn('tbody', table_COL); //表主体
var tr_COL = creaElemIn('tr', tbdy_COL); //表行体
td0 = creaElemIn('td', tr_COL); //拖动手柄
td0.id = '_ewh_handle';
td0.title = _ti.td0[_L];
var td1 = creaElemIn('td', tr_COL); //功能按钮区
var td2 = creaElemIn('td', tr_COL); //高亮按钮区
var td3 = creaElemIn('td', tr_COL); //分布图按钮区
td3.id = '_ewh_maplock';
var editor = creaElemIn('form', td2); //关键词编辑表单
editor.className = PRE + '_editor';
text_input = creaElemIn('input', editor); //关键期编辑输入框
text_input.type = 'text';
var ctrl = creaElemIn('form', td1); //控制按钮表单
ctrl.className = PRE + '_ctrl';
var close_button = creaElemIn('input', ctrl); //关闭按钮
close_button.type = 'button';
close_button.className = 'c_b';
close_button.value = 'X';
close_button.title = _ti.close[_L];
off = creaElemIn('input', ctrl); //停用按钮
off.type = 'button';
off.value = 'O';
off.title = _ti.off[_L];
lock = creaElemIn('input', ctrl); //锁定按钮
lock.type = 'button';
lock.value = 'L';
edit = creaElemIn('input', ctrl); //编辑按钮
edit.type = 'button';
edit.value = 'E';
edit.title = _ti.edit[_L];
word_inputs_list = creaElemIn('ul', td2); //高亮按钮列表容器
word_inputs_list.id = PRE + '_word_inputs_list';
word_inputs_list.className = PRE + '_inputs';
var maplock = creaElemIn('input', td3); //分布图按钮
maplock.type = 'button';
maplock.value = '▲';
maplock.title = _ti.mapl[_L];
// add interactivity
edit.addEventListener('click',command_edit,false);
off.addEventListener('click',command_off,false);
close_button.addEventListener('click',command_close,false);
editor.addEventListener('submit',function(e){
command_edit();
e.preventDefault();
e.stopPropagation();
},false);
if (gm_ok) {
lock.title = _ti.lock[_L];
lock.className = (keyword_locked)? '_active' : '';
lock.addEventListener('click',function(){
if (aside.className == 'ewh_edit') return;
if (keyword_locked) {
lock.className = '';
lock.title = _ti.lock[_L];
GM_setValue(ST_PRE, '');
keyword_locked = '';
// lock.value = 'Lock: Off';
} else {
lock.className = '_active';
lock.title = _ti.lock_a[_L] + ' ' + keyword;
GM_setValue(ST_PRE, keyword);
keyword_locked = keyword;
// lock.value = 'Lock: On';
}
},false);
} else {
lock.title = _ti.lock_u[_L];
lock.className = '_disable';
}
td0.addEventListener('dblclick',function(evt){//l(panel_hide,window.innerWidth - aside.offsetLeft,1);
if (panel_hide) {//l('O');
aside.style.right = '0px';
aside.className = '';
panel_hide = false;
this.title = _ti.td0[_L];
}else{//l(panel_hide);
aside.style.right = (14 - aside.offsetWidth) +'px';
aside.className = 'ewh_hide';
panel_hide = true;//l(panel_hide,3);
this.title = _ti.td0_a[_L];
}
}, false);
maplock.addEventListener('click',function(){
if(!nav.className) {
nav.className = '_locked';
this.value = '▼';
this.className = '_active';
}
else {
nav.className = '';
this.value = '▲';
this.className = '';
}
},false);
// enable drag
var drag = endrag(aside,{x:'right',y:'bottom'}); // 对aside面板的right和bottom属性进行拖动联动(实现可拖动功能)
drag.hook('__drag_begin', function(e){ // 对drag对象的hook方法进行输入:如果面板是编辑或隐藏状态,则不允许拖动
if (this.element && ((this.element.className === 'ewh_edit') || (this.element.className === 'ewh_hide'))) {// || /^canvas$/i.test(e.target.localName) || /^lable$/i.test(e.target.localName))
return false;
}
});
// build map
nav = document.createElement('nav');
aside.insertBefore(nav,aside.firstChild);
canvas = creaElemIn('canvas', nav);
canvas.className='backport';
cw = creaElemIn('canvas', nav);
cw.className='viewport';
var c2 = c2context = canvas.getContext('2d');
// /+drag codes by grea
// scrolling per events
var perf = 2, perfic = 0;
var moveTo = function(evt){
if (perfic++ % perf || !window.drgg) return;
var x = (evt.offsetX || evt.layerX)/ratio - root.clientWidth/2;
var y = (evt.offsetY || evt.layerY)/ratio - root.clientHeight/2;
window.scrollTo(x, y);
}
canvas.addEventListener('mousedown', function(e){ window.drgg = true; moveTo(e); },false);
canvas.addEventListener('mousemove', function(e){ moveTo(e); },false);
canvas.addEventListener('mouseup', function(e){ window.drgg = false; moveTo(e); },false);
canvas.addEventListener('mouseout', function(e){ window.drgg = false; moveTo(e); },false);
// +/codes end
// add AutoPager page change detector
if (CFG.ap_option) {
var pagef = 5, pagefic = 0;
var docHeight = document.body.scrollHeight, pageChanged;
var checkpage = function(){
if ((pagefic++ % pagef == 0) && (document.body.scrollHeight > docHeight)) {
switch (CFG.ap_option) {
case 1:
after_load();
break;
case 2:
resetup();
break;
}
docHeight = document.body.scrollHeight;
}
}
}
// sync with map & check page
window.addEventListener('scroll',function(){
var x = window.pageXOffset * ratio;
var y = window.pageYOffset * ratio;
cw.style.bottom = (canvas.height - cw.height - y) + 'px';
cw.style.right = (canvas.width - cw.width - x + 6) + 'px'; //l("s:" + onpause);
if (CFG.ap_option && (window.name != PRE + '::CLOSED::') && !onpause) checkpage();
},false);
// go to highlight
highlight(document.body);
word_lists = create_inputlist(words);
layers = xp_all.get();
draw_wordmap();
if (!CFG.ap_option) init_autopager();
if (panel_hide && !init){
aside.style.right = (14 - aside.offsetWidth) +'px';
aside.className = 'ewh_hide';
td0.title = _ti.td0_a[_L];
}
}
// function restore_words(layer_s) { // 针对必应国际版,由于其鼠标取词功能会和新高亮清除算法冲突,只能用旧算法
// if (location.host == 'cn.bing.com' && (getUriParam(location.href, 'ensearch') == '1' || parseCookie(document.cookie)["ensearch"][1] == 1)) {
// old_restore_words(layer_s);
// } else {
// new_restore_words(layer_s);
// }
// }
// // 去除高亮:新算法,重组高亮元素所在的文本节点(无则新增)再去除高亮元素,使文本节点不再“断裂”,从而避免去掉短词高亮无法实现长词高亮问题。
// function new_restore_words(layer_s) {
// // 如果指定layer_s高亮元素,则用,否则用xp_all.get()来获取全部高亮元素;对获取的高亮元素遍历
// var ls = (layer_s||xp_all.get());
// for (let i = ls.length - 1; i >= 0; i--) { // 为避免移除靠前元素致靠后元素定位失败,从末尾开始遍历
// var _t = ls[i].innerHTML; // 提取高亮元素的文本内容
// var _par = ls[i].parentNode;//l(_par); // 提取高亮元素父元素(避免一会移除高亮元素后无法追踪)
// var _nt = '', _pt = ''; // 后一节点和前一节点的文本内容,默认为空
// var _n = ls[i].nextSibling; // 提取高亮元素后一节点
// if (!!_n && _n.nodeName == "#text") { // 如果后一节点存在且为文本节点,则使用其文本内容(非文本节点则不处理)
// _nt = _n.nodeValue;
// }
// var _p = ls[i].previousSibling; // 同上处理后一节点内容
// if (!!_p && _p.nodeName == "#text") {
// _pt = _p.nodeValue;
// }
// _par.removeChild(ls[i]); // 移除高亮元素
// if (!!_pt) { // 如果前一节点文本非空,则移除存在的后一节点,在前一节点内容后添加高亮元素和后一节点的内容
// if (!!_nt) _n.parentNode.removeChild(_n);
// _p.nodeValue = _pt + _t + _nt;
// } else if (!!_nt) { // 如果无前一节点内容有后一节点内容,则在后一节点内容前添加高亮元素内容
// _n.nodeValue = _t + _nt;
// } else { // 如果既无前又无后,则在父元素中新建文本节点承载高亮元素内容
// _par.appendChild(document.createTextNode(_t));
// }
// }
// }
// 去除高亮:旧算法
// function old_restore_words(layer_s) {
function restore_words(layer_s) {
(layer_s||xp_all.get()).forEach(function(layer,i){
var parent = layer.parentNode;
while (layer.firstChild){
parent.insertBefore(layer.firstChild, layer);
}
parent.removeChild(layer);
parent.normalize(); //文本节点整合
});
}
// 绘制分布图
function draw_wordmap() {
var c2 = c2context;
var _height = root.clientHeight * 0.95;
if (_height > CanvasWidth * (root.scrollHeight / root.scrollWidth)) {
canvas.width = CanvasWidth;
canvas.height = CanvasWidth * (root.scrollHeight / root.scrollWidth);
ratio = CanvasWidth / root.scrollWidth;
} else {
canvas.height = _height;
canvas.width = _height * (root.scrollWidth / root.scrollHeight);
ratio = _height / root.scrollHeight;
}
cw.width = root.clientWidth * ratio;
cw.height = root.clientHeight * ratio;
cw.style.bottom = (canvas.height - cw.height - window.pageYOffset * ratio) + 'px';
cw.style.right = (canvas.width - cw.width + 6) + 'px';
c2.clearRect(0, 0, window.innerWidth, window.innerHeight);
c2.beginPath();
word_lists.forEach(function(item, i){
if(!words_off[i]) {
c2.fillStyle = STYLE_COLOR[i%10];
item.get_w().forEach(function(ly, j){
var recs = ly.getClientRects();
for (var i = 0, l = recs.length; i < l; ++i){
var rec = recs[i];
var x = Math.max(ratio * (root.scrollLeft + rec.left), 2);
var y = Math.max(ratio * (root.scrollTop + rec.top), 2);
var width = Math.max(ratio * (rec.width || (rec.right-rec.left)), 2);
var height = Math.max(ratio * (rec.height || (rec.bottom-rec.top)), 2);
c2.fillRect(x, y, width, height);
}
});
}
});
c2.fill();
}
// 添加新的关键词高亮及相关
function add_word(word) {
var word_tmp = init_words(word);
var word_tmp_len = word_tmp.length, words_len = words.length; // 前者:要添加的新词数组长度;后者:已有的旧词数组长度
for (var m=0; m w 代表单个词
var _i = i + (start||0); //当前词的高亮编号;如果无 start ,则为零否则加上已有高亮词数量; _i+1 为高亮指针位置专用高亮编号
var li = creaElemIn('li', word_inputs_list);
li.className = PRE + '_item' + _i%10; //根据位置定颜色(最多十种,所以求余)
var label = creaElemIn('div', li); //高亮按钮主体
(!CFG.sort_keywords && positions[_i+1]) || (positions[_i+1] = -1); //如果不排序且当前高亮编号已有则略过;否则当前高亮编号指针位置“归零”
var xp = new $XE('descendant::span[@name="' + PRE + '_word' + _i +'"]', document.body); //提取当前高亮编号的所有高亮的函数
var xp_count = new $XE('count(descendant::span[@name="' + PRE + '_word' + _i +'"])', document.body); //对当前高亮编号的所有高亮计数的函数
var wheelfunction = (evt) => { //l(evt); //响应鼠标滚轮事件
if (words_off[_i]) return;
evt.stopPropagation();
evt.preventDefault();
onpause = true;
clearTimeout(pausetimer);
pausetimer = setTimeout(() => {
onpause = false;
}, 1000); //l("p:" + onpause);
var layers = xp.get();
var ct = (-evt.deltaY || -evt.detail);
ct < 0 ? next(_i+1,layers) : prev(_i+1,layers);
//return false;
};
label.addEventListener('click',function(){ //左键点击高亮按钮
if (words_off[_i]) return; //如果是略过词,则忽略
var layers = xp.get(); //获取全部高亮
next(_i+1,layers); //跳到当前词的下一个高亮
},false);
label.addEventListener('contextmenu',function(evt){ //右键点击高亮按钮(其余同上)
if (words_off[_i]) return;
evt.preventDefault(); //prevent activating context menu
evt.stopPropagation();
var layers = xp.get();
prev(_i+1,layers);
},false);
// https://stackoverflow.com/a/32215631/2755602
var wheelEvt = "onwheel" in document.createElement("div") ? "wheel" : (document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll"); //compatibility fix for Chrome-core browsers
label.addEventListener(wheelEvt, wheelfunction, false); //在高亮按钮上滚动滚轮
label.className = PRE + '_label' + _i % 10;
label.title = _ti.kwL[_L];
label.textContent = w + ' (' + xp_count.get({result_type:XPathResult.NUMBER_TYPE}).numberValue + ')';
var check = creaElemIn('input', li);
check.type = 'checkbox';
if (words_off[_i]) {
check.checked = false;
li.className += ' ewh_disable';
}
else check.checked = true;
check.title = _ti.check[_L][0] + w + _ti.check[_L][1];
var _id = check.id = ID_PRE + '_check' + _i;
var list = {item:li,word:w,label:label,check:check,get_count:xp_count.get,get_w:xp.get};
check.addEventListener('change', function(){
if (check.checked) {
words_off[_i] = false;
highlight(document.body,{words:[w],index:_i});
after_load(null, _i);
this.parentNode.className = this.parentNode.className.replace(' ewh_disable', '');
} else {
words_off[_i] = true;
restore_words(xp.get());
draw_wordmap();
this.parentNode.className += ' ewh_disable';
}
},false);
return list;
});
}
// 对element添加可拖动的功能
function endrag(element,opt) { // 输入:目标元素element,拖动位置参考系opt(对象{参考left或right,参考top或bottom})
var p_x, p_y, isDragging
endrag = function(element,opt){
return new endrag.proto(element,opt||{});
}
endrag.proto = function(elem,opt){
var self = this;
this.element = elem;
this.style = elem.style;
var _x = opt.x !== 'right';
var _y = opt.y !== 'bottom';
this.x = _x ? 'left' : 'right';
this.y = _y ? 'top' : 'bottom';
p_x = this.x;
p_y = this.y;
this.xd = _x ? -1 : 1;
this.yd = _y ? -1 : 1;
this.computed_style = document.defaultView.getComputedStyle(elem, '');
this.drag_begin = function(e){self.__drag_begin(e);};
td0.addEventListener('mousedown', this.drag_begin, false); //only drag on handler
this.dragging = function(e){self.__dragging(e);};
document.addEventListener('mousemove', this.dragging, false);
this.drag_end = function(e){
if (CFG.save_panel_pos && isDragging && elem.style[p_x] && gm_ok) {
var h_pos = p_x + ':' + elem.style[p_x] + ';';
var v_pos = p_y + ':' + elem.style[p_y] + ';';
GM_setValue(PO_PRE, h_pos + '|' + v_pos);
}
// if (panel_hide && isDragging && ((window.innerWidth - aside.offsetLeft) > 14)){
// section.className = '';
// panel_hide = false;
// }
self.__drag_end(e);
};
document.addEventListener('mouseup', this.drag_end, false);
};
endrag.proto.prototype = {
__drag_begin:function(e){
if (e.button == 0) {
var _c = this.computed_style;
this.isDragging = isDragging = true;
this.position = {
_x:parseFloat(_c[this.x]),
_y:parseFloat(_c[this.y]),
x:e.pageX,
y:e.pageY
};
e.preventDefault();
}
},
__dragging:function(e){
if (!this.isDragging) return;
var x = Math.floor(e.pageX), y = Math.floor(e.pageY), p = this.position;
// prevent moving out of window
var x_border = window.innerWidth - 40, y_border = window.innerHeight - 20;
if (x - window.pageXOffset > x_border) x = window.pageXOffset + x_border;
if (y - window.pageYOffset > y_border) y = window.pageYOffset + y_border;
p._x = p._x + (p.x - x) * this.xd;
p._y = p._y + (p.y - y) * this.yd;
this.style[this.x] = p._x + 'px';
this.style[this.y] = p._y + 'px';
p.x = x;
p.y = y;
},
__drag_end:function(e){
if (e.button == 0) {
if (this.isDragging) {
this.isDragging = isDragging = false;
}
}
},
hook:function(method,func){
if (typeof this[method] === 'function') {
var o = this[method];
this[method] = function(){
if (func.apply(this,arguments) === false) {
return;
}
o.apply(this,arguments);
};
}
}
};
return endrag(element,opt);
}
// 从设置中加载锁定关键词
function load_keyword() {
if (keyword_locked) {
keyword = keyword_locked;
prep_keyword();
return true;
}else {
return false;
}
}
// 获取自动高亮的关键词:通过各获取过程得到keyword文本,转递给prep_keyword()生成words关键词列表
function init_keyword() {
if (CFG.no_auto_hili == 1) return false; // 如果不自动高亮,直接退出
var name = window.name;
if (CFG.no_auto_hili == 2 || name == (PRE + '::CLOSED::')) var _no_refer = true; // 如果不继承高亮或本窗口已清理高亮,则不再继承高亮
if (CFG.no_auto_hili != 3) init_KW_SR(); //l(101,keyword); // 如果允许搜索网站高亮,从搜索网站获取
if (!keyword) init_KW_IH(); //l(102,keyword); // 如果上一步找不到,则进行继承高亮
if (!_no_refer && !keyword) init_KW_RF(); //l(103,keyword); // 如果继承高亮了还找不到,则从页面来源获取
if (CFG.no_auto_hili != 3 && !keyword) init_KW_SRo(); //l(104,keyword); // 如果允许搜索网站高亮且还是找不到,则从搜索框获取
keyword = trim(keyword); // 清除前后杂物
if (keyword) {
window.name = PRE + '::' + encodeURIComponent(keyword); // 在窗口内名中加入关键词,用于继承高亮
prep_keyword();//l(104,keyword); // 生成words列表
return true;
} else {//l(105,'false');
return false;
}
}
// 从已知特征的搜索网站网址中获取关键词(一般搜索结果页面内高亮)
function init_KW_SR() { //for Search Results
var host = location.host, h = document.location.href, e = -1;
for (let i = 0; i < urlArr.length; i++) {
if (host.indexOf(urlArr[i][2]) != -1 && h.indexOf(urlArr[i][1]) != -1) e = i;//l(e);
}
if (e >= 0) {
keyword = get_KW_from_URL(h, urlArr[e]);//l(keyword);
}
}
// 从已知id的搜索输入框中获取关键词(其他搜索结果页面内高亮)
function init_KW_SRo() { //for other search result pages
var locationhref = escape(document.location.href);
for (var z = 0; z < queryArr.length; z++) {
var input_query = document.getElementById(queryArr[z][0]);
if (!input_query || locationhref.indexOf(queryArr[z][1]) == -1) continue;
if (input_query.tagName.toLowerCase() == "input") keyword = clean(input_query.value);
if (keyword) break;
}
}
// 从referer(页面打开来源,通常是点开的链接所在的页面url;但若页面有防跟踪机制不给出正确referer的话这功能无法正常运作)获取关键词(搜索结果跳转高亮):输出keyword文本
function init_KW_RF() { //for Pages from Results
var host = location.host, ref = document.referrer, e = -1;
for (let i = 0; i < urlArr.length; i++) {
if (CFG.no_auto_hili == 3 && host.indexOf(urlArr[i][2]) != -1) return;
if (ref.indexOf(urlArr[i][2]) != -1 && ref.indexOf(urlArr[i][1]) != -1) e = i;//l(e);
}
if (e >= 0) {
keyword = get_KW_from_URL(ref, urlArr[e]);//l(keyword);
}
}
// 从窗口(标签页)内名(window.name)中获取关键词(继承高亮):输出keyword文本
function init_KW_IH() { //look for keywords in name
if (window.name.indexOf(PRE) == 0 && window.name != (PRE + '::CLOSED::')) {
keyword = (new RegExp(PRE + '\\d*::(.+)').exec(decodeURIComponent(window.name))[1]) || '';//l(102.1,keyword);
}//l(102.2,keyword);
}
// 从url中提取搜索关键词(针对Google、百度作专门处理),输入url和对应搜索引擎信息数组,输出关键词文本
function get_KW_from_URL(sUrl, sArr) {
if (sArr[0] =='Google' && !!getUriParam(sUrl, 'url')) sUrl = sUrl.replace(/%25/g,'%'); // if it is from Google's redirect link
var kwtmp, KW;
KW = getUriParam(sUrl, sArr[1]); //l(Arr[1] + ", " + KW);
if (!!KW) KW = KW.replace(/\+/g,' ');//l('gku:',KW);
if (sArr[0] =='Baidu' && document.characterSet !== "UTF-8") {
kwtmp = urlDecode(KW); // 如果是百度且非utf-8 //2017-5-27百度似乎已经主用utf-8 //20170922 helloBibo 增加了“&& urlsearch.indexOf('ie=UTF-8') == -1” //20230505百度真的默认utf-8,修改识别方式
} else {
kwtmp = decodeURIComponent(KW);
}
return clean(kwtmp);
}
// 从url中提取名为【param】的参数的值;提取不到返回空字符
function getUriParam(surl, param) {
var result = surl.match(new RegExp("(\\?|&)" + param +"(\\[\\])?=([^&]*)"));
return result ? result[3] : '';
}
// 将给定关键词文本整理成关键词列表(数组)
function prep_keyword() {
words = init_words(keyword);
}
// 去除回行、前后空格、【句点加号】组合
function trim(str) {
return str.replace(/[\n\r]+/g,' ').replace(/^\s+|\s+$/g,'').replace(/\.+\s|\.+$/g,'');
}
// 清除搜索关键词中的修饰功能部分,例如站内、标题搜索,逻辑运算词等
function clean(str) {
return str.replace(/(?:(?:\s?(?:site|(?:all)?in(?:url|title|anchor|text)):|(?:\s|^)-)\S*|(\s)(?:OR|AND)\s|[()])/g,'$1');
}
// 输出不重复元素的数组
function uniq(arr) {
return arr.reduce((output, current) => {
return output.includes(current) ? output : output.concat(current);
}, []);
}
// arr.sort 使用,比较前后两字符串的长度,输出差值
function word_length_Comp(a,b) {
return (b.length - a.length);
}
// 将自动获取的关键词转化为关键词列表(数组)
function init_words(word) {
var erg = word.match(new RegExp("^ ?/(.+)/([gim]+)?$")); // 判别是否正则表达式
var word_s; // 输出关键词列表
if (erg) {
var ew = erg[1], flag = erg[2] || ''; // 提取出正则表达式的表达式部分和标记部分
word_s = [{exp:new RegExp('(' + ew + ')(?!##)', flag), text:ew, toString:function(){return ew;}}]; //输出单元素数组:正则对象
} else if (word) { // 如果非正则且有内容
var ret=[]; // 限定词数组
var eword = word.replace(/"([^"]+)"/g,function($0,$1){$1 && ret.push($1);return '';}); // 提取限定词(用半角双引号括起来的部分)并从word中去除,单独加入限定词数组
word_s = eword.split(/[\+\s:\|#]/).filter(function(w){return !!w;}).concat(ret); // 切分关键词,去除非内容切分形成数组,并在数组后加上限定词数组
word_s = (CFG.sort_keywords)? uniq(word_s).sort(word_length_Comp) : uniq(word_s); // ###如果启用了关键词排序,则按长度排序;关键词列表去重
if (CFG.off_short_words) { // 如果启用了不高亮短词
for (var i in word_s) { // 对关键词列表中短词设置对应不高亮标记
if (/^[a-z0-9]$/i.test(word_s[i]) || (CFG.off_short_words == 2 && /^[a-z0-9]{2}$/i.test(word_s[i]))) {
words_off[i] = true;
} else {
words_off[i] = false;
}
}
}
if (CFG.skip_word_list.length) { // 如果有不高亮词表
var swl = CFG.skip_word_list.split(' ');
for (i in word_s) {
for (var j in swl) { // 对匹配不高亮词表的设置对应不高亮标记
if (word_s[i].toLowerCase() == swl[j]) words_off[i] = true;
}
}
}
}//l(word_s[0].exp);
return word_s;
}
// 移动到下一个高亮的位置并提示
function next(index,_layers) { // 输入:当前关键词index(序号),当前关键词layers(高亮元素)
_layers || (_layers = (layers || (layers = xp_all.get()) )); // 如果有输入则使用,否则以当前全局layers或者即时获取来使用
index || (index = 0); // 如果有输入则使用,否则为不指定关键词
move(_layers[++positions[index]] || (positions[index] = 0, _layers[positions[index]])); // 移动到layers下一个高亮位置;如果没有下一个位置则重置为零并移动过去
position_box(index); // 显示指针位置提示
}
// 移动到上一个高亮的位置并提示
function prev(index,_layers) {
_layers || (_layers = (layers || (layers = xp_all.get()) ));
index || (index = 0);
move(_layers[--positions[index]] || (positions[index] = _layers.length - 1, _layers[positions[index]]));
position_box(index);
}
// 当前高亮指针位置提示:在面板或当前正在查找的高亮关键词按钮上方,显示当前查找到的高亮的指针位置
function position_box(index) {
if (!posi_tip) { // 如果提示框不存在则新建
posi_tip = creaElemIn('div', section);
posi_tip.setAttribute('style', 'background:white;color:black;border:1px solid black;text-align:center;position:absolute;left:30px;z-index:1025;font-size:16px;height:20px;top:-20px;width:40px;box-shadow:0 2px 4px #444444;');
}
clearTimeout(posi_tip_timer); // 提示框计时重置
posi_tip.style.display = 'block'; // 显示
posi_tip.innerHTML = positions[index]+1; // 提示框内容为指针位置(index为关键词(按钮)序号,index=0即不指定关键词)
if (index == 0) {
posi_tip.style.left = '30px';
} else {
posi_tip.style.left = (word_lists[index-1].item.offsetLeft + (word_lists[index-1].item.clientWidth - 40)/2) + 'px';
}
posi_tip_timer = setTimeout(function(){posi_tip.style.display = 'none';},3000); // 三秒后隐藏提示框
}
// 决定击键处理方式:如果有Minibuffer则调用,否则直接由keydown触发按键识别
function init_keyboard() {
if (isOpera) {
} else if (window.Minibuffer) {
init_minibuffer();
return;
} else {
window.addEventListener('GM_MinibufferLoaded', init_minibuffer, false);
}
if (!window.chromium && false) { //实际上不执行第一条,只执行keydown
document.addEventListener('keypress', keyhandler, false);
} else {
document.addEventListener('keydown', keyhandler, false);
}
}
// minibuffer处理:跟keyhandler一样
function init_minibuffer() {
if (window.Minibuffer) {
document.removeEventListener('keypress', keyhandler, false);
}
var mini = window.Minibuffer;
mini.addCommand({
name: 'keyword-search',
command: function(stdin){
keyword += ' ' + this.args.join(' ');
keyword = trim(keyword);
prep_keyword();
if (setuped) resetup();
else setup();
return stdin;
}
});
mini.addShortcutkey({
key:KEY_NEXT,
command:next,
description: 'emphasis next keyword'
});
mini.addShortcutkey({
key:KEY_PREV,
command:prev,
description: 'emphasis prev keyword'
});
mini.addShortcutkey({
key:KEY_SEARCH,
command:function(e){
instant_search();
},
description: 'emphasis prev keyword'
});
}
// 按键evt.which转换为键名
function get_key(evt) {
var key = String.fromCharCode(evt.which),
ctrl = evt.ctrlKey ? 'C-' : '',
meta = (evt.metaKey || evt.altKey) ? 'M-' : '';
if (!evt.shiftKey){
key = key.toLowerCase();
}
if (evt.ctrlKey && evt.which >= 186 && evt.which < 192) {
key = String.fromCharCode(evt.which - 144);
}
if (evt.key && evt.key !== 'Enter' && !/^U\+/.test(evt.key) ) {
key = evt.key;
} else if ( evt.which !== evt.keyCode ) {
key = keyCodeStr[evt.keyCode] || whichStr[evt.which] || key;
} else if (evt.which <= 32) {
key = keyCodeStr[evt.keyCode] || whichStr[evt.which];
}
return ctrl+meta+key;
}
// 按键识别:根据键名调用相应过程
function keyhandler(evt) {
//console.log(evt);
var fullkey = get_key(evt);
//console.log(fullkey);
if (fullkey == KEY_SEARCH) {
evt.preventDefault();
evt.stopPropagation();
instant_search((evt.target.id == PRE + '_textinput') ? true : false, evt.target);
} else if (/^(?:input|textarea)$/i.test(evt.target.localName)) {
return;
} else if (setuped){
switch (fullkey) {
case KEY_NEXT:
next();
break;
case KEY_PREV:
prev();
break;
case KEY_OFF:
command_off();
break;
case KEY_CLOSE:
command_close();
break;
case KEY_EDIT:
command_edit();
break;
case KEY_REFRESH:
resetup();
break;
}
}
}
// X按钮:清理高亮并关闭面板
function command_close() {
document.body.removeChild(aside);
if (document.getElementById(PRE + '_textinputbox')) document.body.removeChild(inputBOX);
instant_search.input = null;
restore_words();
// sheet.disable = true;
if (addCSS.__style.parentNode) addCSS.__root.removeChild(addCSS.__style);
window.name = PRE + '::CLOSED::';
word_lists = [];
// _words = [];
setuped = false;
highlight_reset();
}
// O按钮:切换全部高亮状态
function command_off() {
if (aside.className == 'ewh_edit') return;
if (!highlight_off) {
restore_words();
for (var i in word_lists) {
word_lists[i].check.checked = false;
word_lists[i].item.className += ' ewh_disable'
}
off.className = '_active'
highlight_off = true;
} else {
word_lists = [];
word_inputs_list.innerHTML = '';
resetup();
for (i in word_lists) {
word_lists[i].check.checked = true;
word_lists[i].item.className = word_lists[i].item.className.replace(' ewh_disable', '');
}
off.className = '';
highlight_off = false;
}
draw_wordmap();
}
// E按钮:切换编辑状态(显隐关键词编辑框/关键词列表)
function command_edit() {
if (aside.className == 'ewh_edit') {
// aside.style.width = 'auto';
// edit.value = 'Edit';
edit.className = '';
edit.title = _ti.edit[_L];
if (gm_ok) lock.className = lock.className.replace(' _disable','');
off.className = '';
highlight_off = false;
aside.className = '';
keyword = trim(text_input.value);
prep_keyword();
window.name = PRE + '::' + encodeURIComponent(keyword);
resetup();
} else {
var _aside_w = aside.offsetWidth;
// edit.value = 'Set';
edit.className = '_active';
edit.title = _ti.edit_a[_L];
if (gm_ok) lock.className += ' _disable';
off.className += ' _disable';
aside.className = 'ewh_edit';
text_input.value = keyword;
text_input.focus();
var t_width = (Math.max(320,_aside_w) - 135) +'px';
text_input.style = 'width:' + t_width + ';height:22px;margin:2px 0;font-size:15px;';
// aside.style.width = Math.max(320,_aside_w) +'px';
}
}
// 激活关键词输入框,并进行即时查找当前输入的单个关键词
function instant_search(_r, e_target) {
var input_cancel = function(){
if (refocus) {
var top = document.body.scrollTop || document.documentElement.scrollTop;
var left = document.body.scrollLeft || document.documentElement.scrollLeft;
}
document.body.removeChild(inputBOX);
instant_search.input = null;
if (refocus && e_target) {
e_target.focus();
document.body.scrollTop = document.documentElement.scrollTop = top;
document.body.scrollLeft = document.documentElement.scrollLeft = left;
}
};
var input_position = function(){
inputBOX.style.bottom = '30px' ;//window.innerHeight - aside.offsetTop + 4 + 'px';
}
var input_comfirm = function(text, bAdd){
if (!text && setuped) return;
if (bAdd) {
keyword = trim(((setuped)?keyword:'') + ' ' + text);
prep_keyword();
if (setuped) {
if (CFG.sort_keywords) resetup();
else add_word(text);
}
else setup(true);
} else {
keyword = trim(text);
prep_keyword();
if (setuped) {
resetup();
}
else setup(true);
}
window.name = PRE + '::' + encodeURIComponent(keyword);
if (instant_search.input) {input_position(); instant_search.input.select();}
};
if (_r) {input_cancel(); return;}
var selectedText;
if (/^(?:input)$/i.test(e_target.localName)) {
selectedText = e_target.value;
} else {
selectedText= getSelection();
}
if (instant && selectedText.toString()) {
input_comfirm(selectedText.toString(), true);
return;
}
if (instant_search.input) {
(instant_search.input.value = selectedText) && instant_search.input.select();
// instant_search.input.focus();
return;
}
if (!inst_sheet) {
addCSS([
'#' + PRE + '_textinputbox input[type=button]{padding:0;display:inline;margin:0.1em 0.2em;width:1.4em;height:1.4em;background:'+ but_c +';border:1px solid #996666;cursor:pointer;font-size:12pt;color:black;}',
'#' + PRE + '_textinputbox label{padding:0;display:inline;}',
'#' + PRE + '_textinputbox{border:1px solid #333;margin:0px;padding:0px;position:fixed;bottom:34px;left:5%;z-index:1023;background:#fff;box-shadow: #333 3px 3px 2px;color:#000;color:#000;font-weight:bold;max-width:70%;font-size:16pt;height:auto;opacity:0.95;}',
'#' + PRE + '_textinputbox,#' + PRE + '_textinputbox *{font-family: Arial;}',
'#' + PRE + '_textinput{border:none;margin:0 0 0 5px;padding:0px;max-width:80%;height:100%;background:#fff;color:#000;font-weight:bold;font-size:inherit;}'
].join('\n'));
inst_sheet = true;
}
if (!move_sheet) addmovesheet();
inputBOX = creaElemIn('div', document.body);
inputBOX.id = PRE + '_textinputbox';
inputBOX.setAttribute('class', PRE + '_inbox');
if (setuped) {
input_position();
}
var inputCHECK = creaElemIn('input', inputBOX);
inputCHECK.type = 'checkbox';
inputCHECK.checked = addKeyword;
inputCHECK.title = _ti.ad_nw[_L];
var inputCHECKlabel = creaElemIn('label', inputBOX);
inputCHECKlabel.textContent = (addKeyword) ? 'Add':'New';
inputCHECKlabel.title = inputCHECK.title;
var i_C_id = inputCHECK.id = 'Add_Check';
inputCHECKlabel.htmlFor = i_C_id;
var input = instant_search.input = creaElemIn('input', inputBOX);
input.id = PRE + '_textinput';
var go_button = creaElemIn('input', inputBOX);
go_button.type = 'button';
go_button.value = '\u2192';
go_button.title = _ti.subm[_L];
var close_button = creaElemIn('input', inputBOX);
close_button.type = 'button';
close_button.value = 'X';
close_button.title = _ti.clos[_L];
inputCHECK.addEventListener('change', function(){
inputCHECKlabel.textContent = (this.checked) ? 'Add':'New';
addKeyword = this.checked;
input.focus();
},false);
go_button.addEventListener('click', function(){input_comfirm(input.value, addKeyword);}, false);
close_button.addEventListener('click', input_cancel, false);
input.addEventListener('keypress',function(evt){
var fullkey = get_key(evt);
switch (fullkey) {
case 'RET':
evt.preventDefault();
evt.stopPropagation();
input_comfirm(this.value, addKeyword);
break;
case 'ESC':
input_cancel();
}
},false);
input.addEventListener('input',function(e) {
var text = input.value.toUpperCase();
if (!/\S/.test(text) || text.length <2) return;
var x = 'descendant::text()[contains(translate(self::text(),"abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ"),'+escapeXPathExpr(text)+') and not(ancestor::textarea) and not(ancestor::script) and not(ancestor::style)]/parent::*';
var node = document.evaluate(x, document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (node) move(node);
},false);
if (selectedText.toString()) {
input.value = selectedText.toString();
input.select();
} else if (keyword && !setuped) {
input.value = keyword;
input.select();
} else input.focus();
}
// 构建设置对话框并且建立存取设置机制
function config_box() {
var dbox = { //设置项构造器
addsetting: function(setting, basenode, config){
var setbox = creaElemIn('div', basenode);
setbox.className = '_setbox';
creaElemIn('br',setbox);
var titlebox = this.addtextnode(setting.title, setbox);
titlebox.className = '_titlebox';
var i;
switch(setting.type) {
case 'fill': //填空
var inputbox = creaElemIn('input', setbox);
inputbox.type = 'text';
inputbox.style = 'width: 90%; height: 2em;';
inputbox.id = PRE + setting.id;
inputbox.value = config[setting.id];
inputbox.addEventListener('blur', () => {
config[this.id.replace(PRE, '')] = this.value;
});
break;
case 'check':
if (setting.choices.length == 1) { //复选
var checknode = this.addcheckbox(PRE + setting.id, setting.choices[0], setbox);
checknode.name = PRE + setting.id;
checknode.checked = !!(config[setting.id] == 1);
checknode.addEventListener('change', (event) => {
config[event.target.id.replace(PRE, '')] = (event.target.checked)? 1 : 0;
});
} else if (setting.choices.length > 1) { //单选
var radionodes = [];
for (i in setting.choices) {
radionodes[i] = this.addradiobox(PRE + setting.id + i, setting.choices[i], setbox);
radionodes[i].name = PRE + setting.id;
radionodes[i].checked = (i == config[setting.id]);
radionodes[i].addEventListener('change', (event) => {
config[event.target.name.replace(PRE, '')] = Number(event.target.id.replace(event.target.name, ''))//;l(CFG);
});
}
}
break;
case 'text': //纯文本/描述
for (i in setting.choices) {
this.addtextnode(setting.choices[i], setbox);
}
}
},
addtextnode: function(text, basenode){
var textnode = creaElemIn('p', basenode);
textnode.innerHTML = text;
return textnode;
},
addcheckbox: function(id, text, basenode){
var checknode = creaElemIn('input', basenode);
checknode.id = id;
checknode.type = 'checkbox';
var checklabel = creaElemIn('label',basenode);
checklabel.innerHTML = text;
checklabel.htmlFor = checknode.id;
creaElemIn('br',basenode);
return checknode;
},
addradiobox: function(id, text, basenode){
var radionode = creaElemIn('input', basenode);
radionode.id = id;
radionode.type = 'radio';
var radiolabel = creaElemIn('label',basenode);
radiolabel.innerHTML = text;
radiolabel.htmlFor = radionode.id;
creaElemIn('br',basenode);
return radionode;
},
};
var cancconfig = function(){
document.body.removeChild(confBOXBack);
CFG = JSON.parse(GM_getValue(CO_PRE)); //从GM储存中恢复原有设置(放弃更改)
}
var saveconfig = function(){
document.body.removeChild(confBOXBack);
GM_setValue(CO_PRE, JSON.stringify(CFG)); //将设置存入GM储存
location.reload();
};
// 设置对话框规范题目设置
var config_setting = [
{
id: "ap_option",
title: _di.ap_option[_L],
type: "check", //text:文本描述,fill:填空,check: 复选框(choices=1)或单选(choices>1)
choices: [_di.ap_option1[_L], _di.ap_option2[_L], _di.ap_option3[_L]]
},
{
id: "off_short_words",
title: _di.off_short_words[_L],
type: "check",
choices: [_di.off_short_words1[_L], _di.off_short_words2[_L], _di.off_short_words3[_L]]
},
{
id: "skip_word_list",
title: _di.skip_word_list[_L],
type: "fill",
choices: []
},
{
id: "no_auto_hili",
title: _di.no_auto_hili[_L],
type: "check",
choices: [_di.no_auto_hili1[_L], _di.no_auto_hili2[_L], _di.no_auto_hili3[_L], _di.no_auto_hili4[_L]]
},
{
id: "sort_keywords",
title: _di.sort_keywords[_L],
type: "check",
choices: [_di.sort_keywords1[_L]]
},
{
id: "save_panel_pos",
title: _di.save_panel_pos[_L],
type: "check",
choices: [_di.save_panel_pos1[_L]]
},
{
id: "show_indc_bar",
title: _di.show_indc_bar[_L],
type: "check",
choices: [_di.show_indc_bar1[_L]]
},
];
// 设置对话框构建
var confBOXBack = creaElemIn('div', document.body); //半透明白色背景
confBOXBack.className = PRE + '_cb';
var confBOX = creaElemIn('div', confBOXBack); //设置对话框主框
confBOX.className = PRE + '_cbox';
var confTOP = creaElemIn('div', confBOX); //设置对话框标题头
var confTitle = creaElemIn('h3', confTOP); //设置对话框标题
confTitle.innerHTML = _di.confT[_L];
var confBk = creaElemIn('div', confTOP); //按钮框
confBk.className = PRE + '_bbox';
var confBy = creaElemIn('input', confBk); //确定按钮
confBy.type = 'button';
confBy.value = _di.button_yes[_L];
confBy.addEventListener('click', saveconfig, false);
var confBn = creaElemIn('input', confBk); //取消按钮
confBn.type = 'button';
confBn.value = _di.button_no[_L];
confBn.addEventListener('click', cancconfig, false);
var confSk = creaElemIn('div', confBOX); //选项框
confSk.className = PRE + '_cobox';
config_setting.forEach((item, index) => {
dbox.addsetting(item, confSk, CFG);
});
if (!config_sheet) {
addCSS([
'.' + PRE + '_cb{background:#ffffffaa;position:fixed;top:0;left:0;width:100%;height:100%;text-align:center;z-index:30000;}',
'.' + PRE + '_cbox{line-height:1.2;border:1px solid #333;border-left-width:10px;width:600px;height:90%;margin:30px auto auto auto;padding:5px;color: black !important;background: white; box-shadow: 0 0 15px 2px #b5b5b5;text-align:left;position: relative;}',
'.' + PRE + '_cbox h3{font-weight:800;border-bottom:1px solid black;width:100%;margin:15px auto 10px auto;font-size: 15pt !important;}',
'.' + PRE + '_bbox{width: 150px; text-align: center; position: absolute; top: 20px; right: 20px;}',
'.' + PRE + '_bbox input{width: 56px;margin: 0 6px;}',
'.' + PRE + '_cobox{height: 92%; overflow-y:scroll;}',
'.' + PRE + '_cobox ._setbox{display: block; padding: 3px 0;}',
'.' + PRE + '_cobox ._titlebox{background: #e0f5ff; padding: 3px 0;}',
'.' + PRE + '_cobox input{color: black !important;}',
'.' + PRE + '_cobox label{min-width: 80%;color: black !important;display:inline-block;}',
'.' + PRE + '_cobox label:hover{background: #eeeeff;}'
].join('\n'));
config_sheet = true;
}
}
// 在高亮(关键词或页面)改变后,延时重新计数高亮数和重绘分布图
function after_load(e, _ind) {
var cmd = function(_ind){
if (!_ind) {
word_lists.forEach(function(item){
item.label.textContent = item.word + ' (' + item.get_count({result_type:XPathResult.NUMBER_TYPE}).numberValue + ')';
});
} else {
word_lists[_ind].label.textContent = word_lists[_ind].word + ' (' + word_lists[_ind].get_count({result_type:XPathResult.NUMBER_TYPE}).numberValue + ')';
}
layers = xp_all.get();
draw_wordmap();
if (panel_hide){aside.style.right = (14 - aside.offsetWidth) +'px';}
}
setTimeout(cmd, delay+100, _ind);
}
// add event listener to insert / renew highlights when autopager add pages
function init_autopager(e) {
var page = 0, disabled = false;
var inserted_highlight = function(e){
setTimeout(highlight, delay, e.target);
};
window.addEventListener('AutoPatchWork.DOMNodeInserted', inserted_highlight,false);
window.addEventListener('AutoPatchWork.pageloaded', after_load,false);
window.addEventListener('AutoPagerize_DOMNodeInserted', inserted_highlight,false);
window.addEventListener('GM_AutoPagerizeNextPageLoaded', after_load,false);
window.addEventListener('Super_preloaderPageLoaded', resetup ,false);
highlight_reset = function(){
window.removeEventListener('AutoPatchWork.DOMNodeInserted', inserted_highlight,false);
window.removeEventListener('AutoPatchWork.pageloaded', after_load,false);
window.removeEventListener('AutoPagerize_DOMNodeInserted', inserted_highlight,false);
window.removeEventListener('GM_AutoPagerizeNextPageLoaded', after_load,false);
window.removeEventListener('Super_preloaderPageLoaded', resetup ,false);
}
}
// get an element by css selector
function qElem(cssselector) {
return document.querySelector(cssselector);
}
// get all elements by css selector
function qaElem(cssselector) {
return document.querySelectorAll(cssselector);
}
// get elements as an arry from xpath, detail ver
function $X(exp, context, resolver, result_type) {
context || (context = document);
var Doc = context.ownerDocument || context;
var result = Doc.evaluate(exp, context, resolver, result_type || XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (result_type) return result;
for (var i = 0, len = result.snapshotLength, res = new Array(len); i < len; i++) {
res[i] = result.snapshotItem(i);
}
return res;
}
// get elements as an arry from xpath, simple ver
function $XE(exp, context) {
var xe = new XPathEvaluator();
var resolver = xe.createNSResolver(document.documentElement);
//var defaultNS = document.lookupNamespaceURI(window.opera ? '' : null);
var defaultNS = (document.documentElement.nodeName !== 'HTML') ? context.namespaceURI : null;
if (defaultNS) {
var defaultPrefix = '__default__';
if (!isChromium) {
exp = addDefaultPrefix(exp, defaultPrefix);
}
var defaultResolver = resolver;
resolver = function (prefix) {
return (prefix == defaultPrefix) ? defaultNS : defaultResolver.lookupNamespaceURI(prefix);
};
}
var ex = xe.createExpression(exp, resolver);
this.get = function(param) {
param || (param={});
var result = this.result =
ex.evaluate(param.context||context, param.result_type||XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,this.result);
if (param.result_type) return result;
for (var i = 0, len = result.snapshotLength, res = new Array(len); i < len; i++) {
res[i] = result.snapshotItem(i);
}
return res;
};
}
// via AutoPagerize Thx! nanto_vi
function addDefaultPrefix(xpath, prefix) {
var tokenPattern = /([A-Za-z_\u00c0-\ufffd][\w\-.\u00b7-\ufffd]*|\*)\s*(::?|\()?|(".*?"|'.*?'|\d+(?:\.\d*)?|\.(?:\.|\d+)?|[\)\]])|(\/\/?|!=|[<>]=?|[\(\[|,=+-])|([@$])/g;
var TERM = 1, OPERATOR = 2, MODIFIER = 3;
var tokenType = OPERATOR;
prefix += ':';
function replacer(token, identifier, suffix, term, operator, modifier) {
if (suffix) {
tokenType =
(suffix == ':' || (suffix == '::' && (identifier == 'attribute' || identifier == 'namespace')))
? MODIFIER : OPERATOR;
} else if (identifier) {
if (tokenType == OPERATOR && identifier != '*') {
token = prefix + token;
}
tokenType = (tokenType == TERM) ? OPERATOR : TERM;
} else {
tokenType = term ? TERM : operator ? OPERATOR : MODIFIER;
}
return token;
}
return xpath.replace(tokenPattern, replacer);
}
// http://d.hatena.ne.jp/amachang/20090917/1253179486
function escapeXPathExpr(text) {
var matches = text.match(/[^"]+|"/g);
function esc(t) {
return t == '"' ? ('\'' + t + '\'') : ('"' + t + '"');
}
if (matches) {
if (matches.length == 1) {
return esc(matches[0]);
} else {
var results = [];
for (var i = 0, len = matches.length; i < len; i ++) {
results.push(esc(matches[i]));
}
return 'concat(' + results.join(', ') + ')';
}
} else {
return '""';
}
}
// reduce https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce#Compatibility
function reduce(arr, fun) {
var len = arr.length, i = 0, rv;
if (arguments.length >= 3) rv = arguments[2];
else {do {
if (i in arr) {
rv = arr[i++];break;
}
if (++i >= len) throw new TypeError();
} while (true)};
for (; i < len; i++) {if (i in arr) rv = fun.call(null, rv, arr[i], i, arr);}
return rv;
}
function error(e) {
if (isOpera) {
opera.postError(e);
} else if (window.console) {
console.error(e);
}
}
// add style sheet to the document
function addCSS(css) {
var sheet, self = arguments.callee;
if (document.createStyleSheet) { // for IE
sheet = document.createStyleSheet();
sheet.cssText = css;
return sheet;
} else if (!self.__style || !self.__root) {
sheet = document.createElement('style');
sheet.type = 'text/css';
self.__style = sheet;
self.__root = document.getElementsByTagName('head')[0] || document.documentElement;
}
sheet = self.__style.cloneNode(false);
sheet.textContent = css;
return self.__root.appendChild(sheet).sheet;
}
// get the accumulative offsetTop of target element
function getY(oElement) {
var iReturnValue = 0;
while (oElement != null) {
iReturnValue += oElement.offsetTop;
oElement = oElement.offsetParent;
}
return iReturnValue;
}
// create some element and append to the destination
function creaElemIn(tagname, destin) {
var theElem = destin.appendChild(document.createElement(tagname));
return theElem;
}
/** Get elements by className
* @function getElementsByClassName
* @param string className
* @param optional string tag restrict to specified tag
* @param optional node restrict to childNodes of specified node
* @return Array of nodes
* @author Jonathan Snook, http://www.snook.ca/jonathan
* @author Robert Nyman, http://www.robertnyman.com
*/
function getElementsByClassName(className, tag, elm) {
var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
tag = tag || "*";
elm = elm || document;
var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
var returnElements = [];
var current;
var length = elements.length;
for(var i=0; i 0x7f) {
ret += asc2str(parseInt("0x" + asc+str.substring(i+4, i+6)));
i += 5;
} else {
ret += asc2str(parseInt("0x"+asc));
i += 2;
}
} else {
ret += chr;
}
}
return ret;
}
function parseCookie(cookie) {
var cookies = {};
if(!cookie){
return cookies;
}
var list = cookie.split(';');
for (var i=0; i