FDZ Title Keyword Hightlight

2010-10-04    基本架構完成
2010-10-05    使用GM API存取關鍵字
2010-10-06    使用GM_addStyle修正Inline stylesheet所引起的多次取代
2010-10-10    使用array.sort(compare function),自動排列關鍵字,字數較多者優先
2010-12-26    程式更名『FDZ Title Keyword Hightlight』
2011-03-05    文章描述加入搜尋
2011-03-09    加入開啟連結於新分頁和GUI

// ==UserScript==
// @name    FDZ Title Keyword Hightlight
// @description    自動高亮文章標題關鍵字
// @author    nightkid@FDZ
// @version    2011-03-09
// @include    http://forum.fdzone.org/forumdisplay.php?fid=*
// @include    http://forum.*.fdzone.org/forumdisplay.php?fid=*
// ==/UserScript==
GM_registerMenuCommand('FDZ Title Keyword Hightlight - Setting Keywords', settingKeywords);
GM_registerMenuCommand('FDZ Title Keyword Hightlight - Keywords List', listKeywords);
GM_registerMenuCommand('FDZ Title Keyword Hightlight - Open Link in New Tab', openNewTab);
//GM_registerMenuCommand('FDZ Title Find RegExp - DEL', DEL);
GM_addStyle('.GM_gotit {color:#000;background-color:#FBED73;-moz-border-radius:3px;padding:0 2px;}');    //Highlight Keyword Style
GM_addStyle('#GM_newtab {-moz-border-radius: 3px; color: #000000; cursor: pointer; font-size: 10px; height: 10px; position: fixed; right: 3px; top: 3px; width: 10px;} .GM_newtabOn {background-color: #00FF00} .GM_newtabOff {background-color: #FF0000}');    //NewTab State
/*function DEL() {GM_deleteValue("keywords");}*/

//setting Keywords
function settingKeywords() {
    var KWs = (decodeURI(GM_getValue("keywords")) == 'undefined') ? '' : decodeURI(GM_getValue("keywords"));
    var newKWs = prompt('Please Enter the Keywords.\n(use commas to separate)', KWs).split(',');
    newKWs.sort(descStrLen);
    GM_setValue("keywords", encodeURI(newKWs.join()));
    refreshPage();
}
//list Keywords
function listKeywords() {
    var listKWs = decodeURI(GM_getValue("keywords")).split(',');
    alert(listKWs.join('\n'));
}
//Open articles in new tab
function openNewTab() {
    GM_setValue("newtab", confirm("Open articles in new tab?"));
    refreshPage();
}
//sort function (by string length)
function descStrLen(a, b) {
    if (a.length < b.length) return 1;
}
//Message Refresh Page
function refreshPage() {
    alert('Please Refresh Page.');
}
function main() {
    var KWs = decodeURI(GM_getValue('keywords')).split(',');    //keywords array
    var titles = document.querySelectorAll('span[id^=thread_]');    //all articles' title
    var descs=document.querySelectorAll("[id^='desc_']");    //all articles' description
  
    //new tab state
    var tar=GM_getValue('newtab');
    var newtabState = document.createElement("div");
    newtabState.id="GM_newtab";
    newtabState.title="Open articles in newtab ?";
    newtabState.className=(tar)?"GM_newtabOn":"GM_newtabOff";
    document.getElementsByTagName("body")[0].appendChild(newtabState);
    document.getElementById('GM_newtab').addEventListener('click',function(){GM_setValue("newtab", 1-GM_getValue("newtab")); refreshPage(); },false);
  
    var i, j, k, r, titleStr, descStr;
    //先把KeyWord轉換成RegExp
    var rKWs = new Array(); //RegExp KeyWords
    for (k = 0; k < KWs.length; k++) {
        r = new RegExp('(' + KWs[k] + ')', 'ig');
        rKWs[k] = r;
    }
    for (i = 0; i < titles.length; i++) {
        //取出文章標題超連結的文字
        titleStr = titles[i].childNodes[0].innerHTML;
        //比對關鍵字
        for (j = 0; j < rKWs.length; j++) {
            if (rKWs[j].test(titleStr)) titleStr = titleStr.replace(rKWs[j], '<span class=\"GM_gotit\">$1</span>');
        }
        titles[i].childNodes[0].innerHTML = titleStr;
        titles[i].childNodes[0].target=(tar)?"_blank":"";
    }
    for (i = 0; i< descs.length; i++) {
        //取出文章描述的文字
        descStr = descs[i].innerHTML;
        //比對關鍵字
        for (j = 0; j < rKWs.length; j++) {
            if (rKWs[j].test(descStr)) descStr = descStr.replace(rKWs[j], '<span class=\"gotit\">$1</span>');
        }
        descs[i].innerHTML = descStr;
    }
}
main();

Note:
把字串陣列,轉換成RegExp陣列
var Strs = ['aa', 'bb', 'cc', 'dd', 'ee'];
var rStrs = new Array(); //用來存放轉換完的RegExp
for (i = 0; i < Strs.length; i++) {
    t = new RegExp('(' + Strs[i] + ')', 'i');
    rStrs[i] = t;
}

Greasemonkey Manual:API - GreaseSpot
修改 Textarea Backup 支援中文
GreaseMonkey的User Script Command怎麼使用?
Core Object - 正規表達式物件(RegExp Object) | JavaScript
MEMO-用Javascript RegExp將<x>置換成<span class="x"> - 黑暗執行緒
JavaScript join() Method
JavaScript split() Method