// ==UserScript== // @name View image links // @namespace http://gaia.freera.net/~horance/userscripts/ // @description generate album view for image links. all button has access key (the first letter). // @include http://www.wretch.cc/album/album.php* // @include http://*diggirl.net/*detail.jsp* // @include http://photo.xuite.net/*/* // @include http://www.pixnet.net/album/* // @include http://album.blog.yam.com/*&folder=* // ==/UserScript== // $Author$ (function(){ const MY_NAME = 'View image links'; const MY_NAMESPACE = 'http://gaia.freera.net/~horance/userscripts/'; const UPDATE_URL = 'https://opensvn.csie.org/MirrorScripts/userscripts/view.image.links.user.js'; const FILTER_URL = 'https://opensvn.csie.org/MirrorScripts/userscripts/view.image.links.filter.js'; checkUpdate(); /* * see https://opensvn.csie.org/traccgi/MirrorScripts/trac.cgi/log/userscripts/view.image.links.user.js for change logs. */ var EMPTY_FEED_XML = ''; // PicLens API URL //var PICLENS_API_URL = 'http://fundnav.googlepages.com/piclens.js'; var PICLENS_API_URL = 'http://lite.piclens.com/current/piclens.js'; loadPicLensAPI(); // filter map var filterMap = {}; // current matched url regex var currentMatch = ''; // filter var filter = defaultFilter; //filtering links var urls = new Array(); //preload 5 images by default. if i == 0, this will load 0,1,2 elements in urls array. //if i == 2, then 0,1,2,3,4 will be pre-loaded var preload = 5; //refresh url urls = refreshURLs(); var piclensfeeddata = generateFeedDataForPicLens(urls); //current edit var curEdit = 1; //initialize cache if(preload % i == 0){ preload ++; } //current image index var i = 0; var c_url = ''; var c_desc = ''; var c_link = ''; if(urls[i]){ c_url = urls[i].src; c_desc = urls[i].desc; c_link = urls[i].link?urls[i].link:urls[i].src; } // HTML injection ;) var div = document.createElement('div'); div.innerHTML = '
' + ' ' + ' ' + ' ' + '
' + ''+ '
'; document.body.insertBefore(div, document.body.firstChild); // get object references var img = _gel('vil_img'); var btn_prev = _gel('vil_prev'); var btn_next = _gel('vil_next'); var btn_top = _gel('vil_top'); var btn_end = _gel('vil_end'); var btn_jump = _gel('vil_jump'); var btn_del = _gel('vil_del'); var vil_fit = _gel('vil_fit'); var ctrl = _gel('vil_control'); var disp = _gel('vil_display'); var conf = _gel('vil_config'); var text_input = _gel('vil_input'); var text_width = _gel('vil_width'); var text_fg = _gel('vil_fg'); var text_bg = _gel('vil_bg'); var text_regex = _gel('vil_regex'); var text_filter = _gel('vil_filter'); var vil_list = _gel('vil_list'); var vil_style = _gel('vil_style'); var link_href = _gel('vil_url'); var radio_filter = _gel('radio_filter'); var radio_style = _gel('radio_style'); var disp_image = _gel('vil_image'); // main function to refresh config and URLs function refreshURLs(){ //load filters filterMap = loadFilterMap(); //get filter filter = getFilter(); //execute filter return getURLs(); } //function to load filter map by GM_getValue function loadFilterMap(){ var filterSrc = GM_getValue('filters', 'no filter defined'); if(filterSrc != 'no filter defined'){ try { eval( 'var tmpMap = ' + filterSrc ); return tmpMap; } catch (err){ GM_log(filterSrc); alert('error parsing filter config! ' + err); // return empty map return {}; } } else { return {}; } } //get current filter by matching current window.location.href function getFilter(){ //filter loaded, matching document.location var loc = window.location.href; for( key in filterMap ){ var regex = new RegExp(key, 'ig'); if(regex && loc.match(regex)){ filter = filterMap[key]; currentMatch = key; return filter; } } } //exec filter to get URLS function getURLs(){ //get urls if(filter){ urls = filter(); //invalid return if(!urls || 'object' != typeof urls){ alert('invalid return from filter function:' + urls); //fallback to default urls = defaultFilter(); } } else { urls = defaultFilter(); } if('string' == typeof urls[0]){ for(var i=0;i img.height){ if(img.width > w){ img.height = Math.round(w/img.width*img.height); img.width = w; } } } if(f == 'h' || f == 'b'){ if(f != 'b' || img.height > img.width){ if(img.height > w){ img.width = Math.round(w/img.height*img.width); img.height = w; } } } if(f == 'n'){ //reset inmage size img.removeAttribute('width'); img.removeAttribute('height'); } }else{ alert('invalid width: '+text_width); } preloadImage(); setButtons(); } function MM_preload() { //v2.1 (OSL) if (document.images) { var imgFiles = MM_preload.arguments; if (document.preloadArray==null) document.preloadArray = new Array(); document.preloadArray.length = imgFiles.length; var i = document.preloadArray.length; with (document) for (var j=0; j0?(i-size):0; var end = (i+size > urls.length)?urls.length:i+size; var str = ''; for(var j = start;j= urls.length){ alert('Invalid input: no such image'); }else{ i = idx; showImage(); } } //prev image function prev(){ i--; if(i<0){ alert('This is the first picture!'); }else{ showImage(); } } //next image function next(){ i++; if(i >= urls.length){ alert('This is the last picture!'); }else{ showImage(); } } // first image function top(){ i=0; showImage(); } // last image function end(){ i=urls.length-1; showImage(); } // show display panel function show(){ if(urls.length==0){ alert('no image links!'); return; } ctrl.style.display = 'none'; disp.style.display = 'block'; } // hide display panel function hide(){ ctrl.style.display = 'block'; disp.style.display = 'none'; } // toggle config panel function toggle(tid, flag){ var obj = _gel(tid); if(obj){ if(flag){ obj.style.display = flag; }else{ if(obj.style.display != 'none'){ obj.style.display = 'none'; }else{ obj.style.display = ''; } } } } //show image! function showImage(){ if(urls[i]){ c_url = urls[i].src; c_desc = urls[i].desc; link_href.href=c_url; link_href.innerHTML=loadingimg+'  loading......'; //reset image size img.removeAttribute('width'); img.removeAttribute('height'); //load image img.src=c_url; img.alt=c_desc; } } // set navigation button state function setButtons(){ text_input.value=i; btn_top.disabled = false; btn_prev.disabled = false; btn_next.disabled = false; btn_end.disabled = false; if(i<=0){ btn_top.disabled = true; btn_prev.disabled = true; } if(i>=urls.length-1){ btn_next.disabled = true; btn_end.disabled = true; } } // prepare config list function prepareConfigList(){ var label1 = 'URL Regex: '; var label2 = 'Filter function:'; var label3 = 'New Filter'; var selectedValue = currentMatch; var dataMap = filterMap; if(curEdit == 2){ label1 = 'CSS Name : '; label2 = 'CSS Style:'; label3 = 'New Style'; selectedValue = cssName; dataMap = cssMap; } text_regex.previousSibling.nodeValue = label1; text_filter.previousSibling.previousSibling.nodeValue = label2; var tmpstr = ''; for(key in dataMap){ tmpstr += ''; } vil_list.innerHTML = tmpstr; listChange(); var ac = GM_getValue('checkInterval','1'); var isac = (parseInt(ac) > 0); _gel('vil_autocheck').checked = isac; _gel('vil_ac_int').value = (isac?ac:'1'); toggle('vil_ac_config', (isac?'block':'none')); } // update UI, call by event listener function listChange(){ var isFilter = (curEdit == 1); var dataMap = (isFilter)?filterMap:cssMap; var def_value = (isFilter)?defaultFilter.toString():defaultStyle; var key = vil_list.value; if(key == '--'){ btn_del.disabled = true; key = (isFilter?'^.*foo\\.bar\\.com.*$':'default'); }else{ btn_del.disabled = false; } text_regex.value = key; text_filter.value = (dataMap[key])?dataMap[key].toString():def_value; if(!isFilter){ changeStyle(key); } } //save CSS or filter config function saveData(){ //check auto-update setting var ac = _gel('vil_autocheck').checked; if(ac){ var days = parseInt(_gel('vil_ac_int').value); if(isNaN(days) || days < 1){ alert('invalid check interval! (must be an integer and > 0)'); _gel('vil_ac_int').focus(); return; }else{ GM_setValue('checkInterval',''+days); } }else{ GM_setValue('checkInterval','-1'); } var dataMap = filterMap; var dataValue = null; var saveTag = 'filters'; var refreshFunction = refreshURLs; if(curEdit == 1){ // filter try { //test URL Regexp new RegExp(text_regex.value); //test filter code eval('var f = ' + text_filter.value); if( 'function' != typeof f ){ throw 'invalid filter function'; } else { //check return var us = f(); if( 'object' != typeof us ){ throw 'invalid return from filter: '+us; } } dataValue = f; }catch(ex){ alert('error parsing URL Pattern or filter: ' + ex); return false; } }else if(curEdit == 2){ saveTag = 'styleMap'; dataMap = cssMap; dataValue = text_filter.value; refreshFunction = reloadStyle; } //all passed, store filter dataMap[text_regex.value] = dataValue; //save filterMap GM_setValue(saveTag, serializeMap(dataMap)); //reload refreshFunction(); //tell user we've done alert('data saved!'); //reset config list prepareConfigList(); } //delete CSS or filter function deleteData(){ var dataMap = filterMap; var saveTag = 'filters'; var refreshFunction = refreshURLs; var confirmStr = 'Delete filter for '; if(curEdit == 2){ saveTag = 'styleMap'; dataMap = cssMap; refreshFunction = reloadStyle; confirmStr = 'Delete style: '; } if(confirm(confirmStr + text_regex.value + ' ?')){ //there no way to remove value from map, instead we set it to null, // and skip it in function serializeMap() dataMap[text_regex.value] = null; //save GM_setValue(saveTag, serializeMap(dataMap)); //reload refreshFunction(); //reset config list prepareConfigList(); } } //convert filter config to String function serializeMap(map){ var res = '{'; for(key in map){ if(map[key]){ var mapValue = map[key]; if(curEdit == 2){ mapValue = '"' + map[key].replace(/\n/mg,'\\n').replace(/\r/mg,'\\r') + '"'; } res+=('"' + key + '" : ' + mapValue + ','); } } res += '}'; return res; } //change panel color function changeColor(){ disp.style.color = text_fg.value; disp.style.backgroundColor = text_bg.value; } //addGlobalStyle -- derived from http://diveintogreasemonkey.org/patterns/add-css.html function addGlobalStyle(css) { var head, style; head = document.getElementsByTagName('head')[0]; if (!head) { return; } style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css; head.appendChild(style); return style; } //register event listener for click document.addEventListener('click', function(event) { if(event.target.name && event.target.name.match(/^vil/)){ if(event.target.name == 'vil_next'){ next(); }else if(event.target.name == 'vil_prev'){ prev(); }else if(event.target.name == 'vil_show'){ show(); }else if(event.target.name == 'vil_piclens'){ startPicLensLite(); }else if(event.target.name == 'vil_hide'){ hide(); }else if(event.target.name == 'vil_top'){ top(); }else if(event.target.name == 'vil_end'){ end(); }else if(event.target.name == 'vil_jump'){ jumpto(); }else if(event.target.name == 'vil_color'){ changeColor(); }else if(event.target.name == 'vil_conf'){ toggle('vil_download_panel','none'); prepareConfigList(); toggle('vil_config'); }else if(event.target.name == 'vil_save'){ saveData(); }else if(event.target.name == 'vil_del'){ deleteData(); }else if(event.target.name == 'vil_download'){ toggle('vil_config','none'); prepareFileList(); toggle('vil_download_panel'); }else if(event.target.name == 'vil_browse'){ browseOutputFolder(); }else if(event.target.name == 'vil_start'){ startDownload(); }else if(event.target.name == 'vil_autocheck'){ var ac = _gel('vil_autocheck').checked; toggle('vil_ac_config', (ac?'block':'none')); }else if(event.target.name == 'vil_checknow'){ var ac = _gel('vil_checknow').checked; checkUpdate(true); } } }, true); function handleError(event, imgobj, idx){ GM_log('error loading img:'+imgobj.src + "current idx: "+idx); } //register event listener for img.onload img.addEventListener('load', function(event){ resize(); }, true); img.addEventListener('error', function(event){ handleError(event, this, i); }, true); //register event listener for select.onchange vil_list.addEventListener('change', function(event){ listChange(); }, true); //register event listener for select.onchange vil_style.addEventListener('change', function(event){ changeStyle(vil_style.value); }, true); //register event listener for select.onchange vil_fit.addEventListener('change', function(event){ resize(); }, true); //register event listener for radio.onchange radio_filter.addEventListener('click', function(event){ curEdit = 1; prepareConfigList(); }, true); //register event listener for radio.onchange radio_style.addEventListener('click', function(event){ curEdit = 2; prepareConfigList(); }, true); //loading animation icon const loadingimg = 'loading'; const defaultStyle = '#vil_control {\n' + ' position: absolute;\n' + ' right: 0px;\n' + ' top: 0px;\n' + '}\n' + 'div.vil {\n' + ' margin: 5px;\n' + ' padding: 10px;\n' + ' z-index: 999;\n' + ' background-color: #E5ECF9;\n' + '}\n' + '.vil, div.vil > input, div.vil > p > textarea , div.vil > p > select, div.vil > p > input {\n' + ' color: black;\n' + ' font-style: normal;\n' + ' font-weight: 400;\n' + ' font-size: 13px;\n' + ' font-family: arial;\n' + '}\n' + 'div.vil > p > textarea, #vil_flist {\n' + ' width: 285px;\n' + '}\n' + '#vil_style {\n' + ' width: 50px;\n' + '}\n' + 'div.vil > p > select {\n' + ' width: 225px;\n' + '}\n' + '#vil_del {\n' + ' color: red;\n' + ' margin-left: 5px;\n' + ' width: 50px;\n' + '}\n' + '#vil_regex {\n' + ' margin: 5 0 5 0;\n' + ' vertical-align: middle;\n' + ' width: 210px;\n' + '}\n' + '#vil_save, #vil_start {\n' + ' position: absolute;\n' + ' right: 15px;\n' + '}\n' + '#vil_url > img {\n' + ' margin-right: 5px;\n' + ' border: 0px;\n' + ' vertical-align: middle;\n' + '}\n' + '#vil_img {\n' + ' margin-top: 5px;\n' + '}\n'; //setting up style function reloadStyle(){ cssMap = loadStyleMap(); cssName = GM_getValue('style', 'default'); var cssStyleStr = defaultStyle; if(cssMap[cssName]){ cssStyleStr = cssMap[cssName]; } setStyle(cssStyleStr); //reset style list var tmpStr = ''; for(key in cssMap){ tmpStr += ''; } vil_style.innerHTML = tmpStr; } // set current style function setStyle(cssStyleStr){ if(cssStyleElement){ cssStyleElement.innerHTML = cssStyleStr; }else{ cssStyleElement = addGlobalStyle(cssStyleStr); } } //load style map with GM_getValue(); function loadStyleMap(){ var styleSrc = GM_getValue('styleMap', 'no style defined'); if(styleSrc != 'no style defined'){ try { eval( 'var tmpCSSMap = ' + styleSrc ); return tmpCSSMap; } catch (err){ GM_log(styleSrc); alert('error parsing CSS config! ' + err); // return empty map return {}; } } else { return {}; } } //change style - called by event listener function changeStyle(key){ if(cssMap[key]){ cssName = key; setStyle(cssMap[cssName]); GM_setValue('style', cssName); } } //add for PicLens support function parseXMLtoDOM(xmlstring){ var parser = new DOMParser(); try{ return parser.parseFromString(xmlstring, 'application/xml'); }catch(err){ GM_log('error parsing xml, reason:'+err); } } /** * using current imgage url object, attributes are: * src: image url (required) * desc: description text of the image (optional, using image url if empty), * thumburl: thumbnail image url (optional, using image url if empty), * link: link url (optional, using image url if empty) **/ function generateFeedDataForPicLens(turls){ if(!turls || turls.length == 0){ return false; } var feedxml = parseXMLtoDOM(EMPTY_FEED_XML); var channelNode = feedxml.documentElement.firstChild; for(i=0;i tag ...'); var head = document.getElementsByTagName('head')[0]; if(!head){ // head element not found ?! head = document.createElement('head'); document.documentElement.insertBefore(head,document.body); } var stag = document.createElement('script'); stag.setAttribute('type', 'text/javascript'); stag.setAttribute('src', PICLENS_API_URL); head.appendChild(stag); } } // start! function startPicLensLite(){ if (typeof unsafeWindow.PicLensLite == 'undefined'){ GM_log('PicLensLite object not found, waiting ...'); window.setTimeout(startPicLensLite, 1000); }else{ var hasClient = unsafeWindow.PicLensLite.hasClient(); GM_log('PicLensLite.hasPicLensClient() = '+hasClient); var temprss = false; if(!piclensfeeddata && urls.length > 0){ //regenerate feed data piclensfeeddata = generateFeedDataForPicLens(urls); } if(hasClient && (temprss = writeTempFeedFile(piclensfeeddata)) ){ unsafeWindow.PicLensLite.start({feedUrl:temprss}); }else{ var feedtext = serializeXMLtoString(piclensfeeddata); unsafeWindow.PicLensLite.start({feedData:feedtext}); } } } //serialize XML to String function serializeXMLtoString(xmldoc){ var se = new XMLSerializer(); return se.serializeToString(xmldoc); } //thanks to tiddly wiki source..:p function writeTempFeedFile(feeddata){ var filePath; try{ unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); filePath = writeToFile(manualConvertUnicodeToUTF8(serializeXMLtoString(feeddata)), null, 'gm_vil_temp_rss.xml'); }catch(ex){ alert("Oops! I can't create temp feed file for PicLens extension,\n"+ "I will use Lite version instead...\n"+ "you can set \"signed.applets.codebase_principal_support\" = true in \"about:config\"" +"to avoid this problem."); GM_log("error creating file:"+filePath+", reason:"+ex); } return filePath; } function writeToFile(content, outputPath, fname){ var filePath; if(Components) { // ask user permission //unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var fileObj; if(!outputPath){ // get home directory fileObj= Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("Home", Components.interfaces.nsILocalFile); }else{ fileObj = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); fileObj.initWithPath(outputPath); } // append file name fileObj.append(fname); // file is nsIFile var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var fileHandler = ios.getProtocolHandler("file") .QueryInterface(Components.interfaces.nsIFileProtocolHandler); filePath = fileHandler.getURLSpecFromFile(fileObj); // get file:// URL GM_log("filePath:"+filePath); if(!fileObj.exists()) //0 for File, 0600 is permission fileObj.create(0,0600); //prepare output stream var out = Components.classes["@mozilla.org/network/file-output-stream;1"] .createInstance(Components.interfaces.nsIFileOutputStream); out.init(fileObj,0x20|0x02,00004,null); //it's very strange that the PicLens extension refuse to load feed which contains UTF-8 chinese character, //manualConvertUnicodeToUTF8 will convert unicode character to &#nnnn notation. out.write(content,content.length); out.flush(); out.close(); return filePath; } return false; } //using XPCOM converter service function mozConvertUnicodeToUTF8(s) { //unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); try { var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; } catch(ex) { GM_log("error convert from mozConvertUnicodeToUTF8:"+ex); return manualConvertUnicodeToUTF8(s); } // fallback var u = converter.ConvertFromUnicode(s); var fin = converter.Finish(); return fin.length > 0 ? u + fin : u; } //convert unicode to &#nnnnn; function manualConvertUnicodeToUTF8(s) { var re = /[^\u0000-\u007F]/g ; return s.replace(re,function($0) {return "&#" + $0.charCodeAt(0).toString() + ";";}); } // function downloadFile(httpLoc, outputFolder, localfile, listener, flag) { try { //new obj_URI object var obj_URI = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(httpLoc, null, null); //new file object var obj_TargetFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); //set file with path obj_TargetFile.initWithPath(outputFolder); obj_TargetFile.append(localfile); //if file doesn't exist, create if(!obj_TargetFile.exists()) { obj_TargetFile.create(0x00,0644); } //new persitence object var obj_Persist = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist); obj_Persist.persistFlags = Components.interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; obj_Persist.persistFlags |= Components.interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; if(flag){ obj_Persist.persistFlags |= flag; } //save file to target obj_Persist.progressListener = (listener?listener:defaultProgressListener); obj_Persist.saveURI(obj_URI,null,null,null,null,obj_TargetFile); } catch (e) { alert(e); } } function prepareFileList(){ var obj = _gel('vil_flist'); var opts = obj.options; for(var j=0;j' + urls[j].desc + '\n'; } idxdata += ''; //GM_log(mozConvertUnicodeToUTF8(idxdata)); return mozConvertUnicodeToUTF8(idxdata); } function _gel(tid){ return document.getElementById(tid); } function checkUpdate(forcechk){ //last check time as long var lastcheck = parseInt(GM_getValue('last_check','0')); GM_log('last check is '+lastcheck); var filterlastcheck = parseInt(GM_getValue('filter_last_check','0')); GM_log('filter last check is '+filterlastcheck); //days var checkInterval = forcechk?0:parseInt(GM_getValue('check_interval','1')); var nowtime = (new Date()).getTime(); //start check if over interval if(checkInterval >= 0 && (nowtime - lastcheck)>(checkInterval * 86400000)){ GM_log('start checking from '+UPDATE_URL); sendHTTPRequest(UPDATE_URL,'HEAD', {'If-None-Match': 'never match'},function(rspDtls){ var checked = onCheckRevSuccess(rspDtls,'revision',startUpdateProcess, forcechk); if(checked){ GM_setValue('last_check', ''+nowtime); } }); } if(checkInterval >= 0 && (nowtime - filterlastcheck)>(checkInterval * 86400000)){ GM_log('start checking from '+FILTER_URL); sendHTTPRequest(FILTER_URL,'GET', {'If-None-Match': 'never match'},function(rspDtls){ var checked = onCheckRevSuccess(rspDtls,'filter.revision',startFilterUpdateProcess,forcechk); if(checked){ GM_setValue('filter_last_check', ''+nowtime); } }); } } function onCheckRevSuccess(rspDtls, revtag, updateFunction, showOptMessage) { if('200' != rspDtls.status){ GM_log('check failed, response HTTP status: '+rspDtls.status); return; }else{ var myrev = parseInt(GM_getValue(revtag,'0')); var remoterev = parseInt(rspDtls.responseHeaders.match(/Etag:\s+"([0-9]+).*"/)[1]); GM_log('remote rev is ' + remoterev + ', current rev is ' + myrev); if(myrev < remoterev){ return updateFunction(rspDtls, remoterev); }else{ if(showOptMessage){ alert('remote rev is ' + remoterev + ', my rev is ' + myrev + ', no need to update.'); } return true; } } } function sendHTTPRequest(targeturl, reqMethod, headerMap, onSuccess){ GM_xmlhttpRequest({ method: reqMethod, url: targeturl, headers: headerMap, onload: onSuccess }); } function startFilterUpdateProcess(responseDetail, remoterev){ if(!confirm('new filter configs found (rev: ' + remoterev + ' )\nUpdate now?')){ GM_setValue('filter_last_check',''+(new Date()).getTime()); return true; } try { //looking up gm_script dir eval('var remoteFilters = ' + responseDetail.responseText); if(filterMap.length == 0){ filterMap = loadFilterMap(); } //GM_log('got filters :'+responseDetail.responseText); for(var key in remoteFilters){ var remote = remoteFilters[key]; //GM_log('remote filter key:'+key + 'filter: '+remote.filter.toString()); if(filterMap[key]){ if(filterMap[key].toString() != remote.filter.toString()){ //exists if(confirm('filter for '+key+' is exist, overwrite? (new filter will be logged to console if choose cancel)')){ filterMap[key] = remote.filter; }else{ GM_log('new filter for '+key+' is \n'+remote.filter.toString()); } } }else{ alert('got new filter for '+key+', please add "'+remote.include+'" to "included pages" of greasemonkey'); GM_log('got new filter for '+key+', please add "'+remote.include+'" to "included pages" of greasemonkey'); filterMap[key] = remote.filter; } } GM_setValue('filters', serializeMap(filterMap)); GM_setValue('filter.revision',remoterev); alert('filter updated successful! reload page to see changes!'); return true; }catch(ex){ alert('update filter failed! reason:' + ex); } return false; } function startUpdateProcess(responseDetail, remoterev){ if(!confirm('new revision found (rev: ' + remoterev + ' )\nUpdate now?')){ GM_setValue('last_check',''+(new Date()).getTime()); return true; } alert('Please Allow Privilege request to start update process.\nDO NOT check "remember my decision" on next confirm dialog unless you know how to remove them.'); try { unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); //looking up gm_script dir var fname = getInstalledFileName(); var updateProgressListener = { onStateChange: function(awsp, areq, aStateflag, astatus){ if(aStateflag & Components.interfaces.nsIWebProgressListener.STATE_STOP){ //finished GM_setValue('last_check',''+(new Date()).getTime()); GM_setValue('revision',remoterev); alert('script updated, reload to see change!'); } }, onProgressChange: function(){}, //do nothing onStatusChange: function(){}, //do nothing onLocationChange: function(){}, //do nothing onSecurityChange: function(){} //do nothing } //download and bypass cache downloadFile(UPDATE_URL, getScriptDir().path, fname, updateProgressListener, 2); return true; }catch(ex){ alert('update failed! reason:' + ex); } return false; } function getInstalledFileName(){ var installedFilename = ''; var configContents = getContents(getScriptFileURI("config.xml")); var domParser = new DOMParser(); var doc = domParser.parseFromString(configContents, "text/xml"); var nodes = doc.evaluate("/UserScriptConfig/Script", doc, null, 0, null); for (var node = null; (node = nodes.iterateNext()); ) { var fname = node.getAttribute("filename"); var name = node.getAttribute("name"); var namespace = node.getAttribute("namespace"); if(name == MY_NAME && namespace == MY_NAMESPACE){ installedFilename = fname; break; } } return installedFilename; } function getContents(aURL, charset){ if( !charset ) { charset = "UTF-8" } var ioService=Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var scriptableStream=Components .classes["@mozilla.org/scriptableinputstream;1"] .getService(Components.interfaces.nsIScriptableInputStream); // http://lxr.mozilla.org/mozilla/source/intl/uconv/idl/nsIScriptableUConv.idl var unicodeConverter = Components .classes["@mozilla.org/intl/scriptableunicodeconverter"] .createInstance(Components.interfaces.nsIScriptableUnicodeConverter); unicodeConverter.charset = charset; var channel=ioService.newChannelFromURI(aURL); var input=channel.open(); scriptableStream.init(input); var str=scriptableStream.read(input.available()); scriptableStream.close(); input.close(); try { return unicodeConverter.ConvertToUnicode(str); } catch( e ) { return str; } } function getScriptFileURI(fileName) { return Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService) .newFileURI(getScriptFile(fileName)); } function getScriptFile(fileName) { var file = getScriptDir(); file.append(fileName); return file; } function getScriptDir() { var dir = getNewScriptDir(); if (dir.exists()) { return dir; } else { var oldDir = getOldScriptDir(); if (oldDir.exists()) { return oldDir; } else { // if we called this function, we want a script dir. // but, at this branch, neither the old nor new exists, so create one return GM_createScriptsDir(dir); } } } function getNewScriptDir() { var file = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("ProfD", Components.interfaces.nsILocalFile); file.append("gm_scripts"); return file; } function getOldScriptDir() { var file = getContentDir(); file.append("scripts"); return file; } function getContentDir() { var reg = Components.classes["@mozilla.org/chrome/chrome-registry;1"] .getService(Components.interfaces.nsIChromeRegistry); var ioSvc = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var proto = Components.classes["@mozilla.org/network/protocol;1?name=file"] .getService(Components.interfaces.nsIFileProtocolHandler); var chromeURL = ioSvc.newURI("chrome://greasemonkey/content", null, null); var fileURL = reg.convertChromeURL(chromeURL); var file = proto.getFileFromURLSpec(fileURL.spec).parent; return file } // load CSS style map and last-used theme var cssMap = {}; var cssName = 'default'; //add style to var cssStyleElement = null; reloadStyle(); })();//end mark for userscript