Created
February 16, 2011 16:34
-
-
Save alexeyr/829673 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********************************************************************************* | |
* The contents of this file are subject to the Mozilla Public License Version 1.1 | |
* ("License"); you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at http://www.mozilla.org/MPL/. | |
* | |
* Software distributed under the License is distributed on an "AS IS" basis, | |
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for | |
* the specific language governing rights and limitations under the License. | |
* | |
* The Initial Developer of the Original Code is Howie Wang. | |
* Contributor(s): Alexey Romanov, Jesse Weinstein. | |
* | |
* Alternatively, the contents of this file may be used under the terms | |
* of the GPL 2.0 license (http://www.gnu.org/licenses/gpl-2.0.html) or the | |
* LGPL 2.1 license (http://www.gnu.org/licenses/lgpl-2.1.html), in which case | |
* the provisions of this license are applicable instead of those above. | |
********************************************************************************/ | |
"use strict"; | |
window.addEventListener("load", function () { nextplease.init(); }, false); | |
window.addEventListener("popupshowing", function () { nextplease.showHideMenuItems(); }, false); | |
window.addEventListener("load", function (event) { nextplease.loadListener.onLoad(event); }, false); | |
nextplease.setUnicharPref = function (aPrefName, aPrefValue) { | |
// nextplease.logDetail("setting " + aPrefName + " to " + aPrefValue); | |
if (nextplease.prefs) { | |
try { | |
var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); | |
str.data = aPrefValue; | |
nextplease.prefs.setComplexValue(aPrefName, Components.interfaces.nsISupportsString, str); | |
} catch (e) { | |
nextplease.logError("Failed to set value of " + aPrefName + " to " + aPrefValue); | |
} | |
} else { | |
nextplease.logError("nextplease.prefs is not defined"); | |
} | |
}; | |
nextplease.getUnicharPref = function (aPrefName) { | |
// nextplease.logDetail("getting " + aPrefName); | |
if (nextplease.prefs) { | |
try { | |
return nextplease.prefs.getComplexValue(aPrefName, Components.interfaces.nsISupportsString).data; | |
} catch (e) { | |
nextplease.logError("Failed to get value for " + aPrefName); | |
} | |
} else { | |
nextplease.logError("nextplease.prefs is not defined"); | |
} | |
return ""; | |
}; | |
nextplease.gotHereUsingNextplease = false; | |
nextplease.MAX_LINK_NUM = 1000; | |
nextplease.MAX_GALLERY_GAP = 20; | |
nextplease.MAX_LINKS_TO_CHECK = 1000; | |
nextplease.SEARCH_FOR_SUBMIT = 1; | |
nextplease.directions = ["Next", "Prev", "First", "Last"]; | |
nextplease.imageURLsCache = {first: undefined, last: undefined, size: 0, MAX_SIZE: 500, map: {}}; | |
nextplease.SEARCH_TYPE = {Next: 1, Prev: 2, First: 3, Last: 4}; | |
nextplease.ResultType = {Link: 0, URL: 1, Input: 2, History: 3}; | |
nextplease.PREFETCH_ENUM = {No: 0, Yes: 1, Smart: 2}; | |
nextplease.highlighted_old_styles = {}; | |
// This code was stolen from brody on the mozillazine.org forums. | |
nextplease.loadListener = { | |
onLoad: function (event) { | |
getBrowser().addEventListener("DOMContentLoaded", function (event) { | |
nextplease.loadListener.onContentLoaded(event); | |
}, true); | |
}, | |
onContentLoaded: function (event) { | |
var doc = event.originalTarget; | |
// When this becomes true it means that | |
// all of the top level document's | |
// subframes have also finished loading | |
if (!this.isTopLevelDocument(doc)) { return; } | |
// Log/alert | |
if (nextplease.DEBUG_DETAILED) { | |
nextplease.logDetail("loadListener\n" + "DOMContentLoaded\n" + doc.title + "\n" + doc.documentURI); | |
} | |
nextplease.clearStatusBar(); | |
// no effect if nextplease.clearStatusBarTimer is invalid | |
clearTimeout(nextplease.clearStatusBarTimer); | |
nextplease.cacheImageLocations(); | |
nextplease.prefetched = {}; | |
nextplease.unhighlight(); | |
if (nextplease.prefetchPref === nextplease.PREFETCH_ENUM.Yes) { | |
nextplease.prefetch(); | |
} else if ((nextplease.prefetchPref === nextplease.PREFETCH_ENUM.Smart) && nextplease.gotHereUsingNextplease) { | |
nextplease.prefetch(); | |
nextplease.gotHereUsingNextplease = false; | |
} | |
}, | |
isTopLevelDocument: function (aDocument) { | |
return (aDocument === aDocument.defaultView.top.document); | |
} | |
}; | |
nextplease.prefObserver = { | |
QueryInterface: function QueryInterface(aIID) { | |
if (aIID.equals(Components.interfaces.nsIObserver) || | |
aIID.equals(Components.interfaces.nsISupportsWeakReference) || | |
aIID.equals(Components.interfaces.nsISupports)) { | |
return this; | |
} else { | |
throw Components.results.NS_NOINTERFACE; | |
} | |
}, | |
register: function () { | |
nextplease.prefs.addObserver("", this, true); | |
nextplease.accelKeyPrefs.addObserver("", this, true); | |
}, | |
observe: function (subject, topic, data) { | |
if (topic === "nsPref:changed") { | |
nextplease.readPreferences(); | |
} | |
} | |
}; | |
nextplease.prefObserver.register(); | |
nextplease.checkImageCache = function () { | |
var i, url, urlsCache = nextplease.imageURLsCache, cachedURLsNum = urlsCache.size; | |
var messageLines = ["size=" + cachedURLsNum + "; first=" + urlsCache.first + "; last=" + urlsCache.last], message; | |
if (cachedURLsNum > 0) { | |
url = urlsCache.first; | |
for (i = 0; i < cachedURLsNum; i++, url = urlsCache.map[url]) { | |
messageLines[messageLines.length] = "i=" + i + "; url=" + url + "; urlsCache.map[url]=" + urlsCache.map[url]; | |
if (!url) { | |
message = messageLines.join("\n\n"); | |
nextplease.logError(message); | |
alert(message); | |
return; | |
} | |
} | |
if (url !== urlsCache.last) { | |
message = messageLines.join("\n\n"); | |
nextplease.logError(message); | |
alert(message); | |
return; | |
} | |
} else if (urlsCache.first || urlsCache.last) { | |
message = messageLines[0]; | |
alert(message); | |
nextplease.logError(message); | |
} | |
}; | |
nextplease.addImageToCache = function (imgUrl) { | |
var urlToDelete, urlsCache = nextplease.imageURLsCache, incrSize = true; | |
if (imgUrl && !urlsCache.map[imgUrl]) { | |
// nextplease.logDetail("adding " + imgUrl + " to image cache"); | |
if (urlsCache.size === 0) { | |
urlsCache.first = imgUrl; | |
urlsCache.map[imgUrl] = imgUrl; | |
urlsCache.last = imgUrl; | |
urlsCache.size = 1; | |
} else { | |
if (urlsCache.size >= urlsCache.MAX_SIZE) { | |
urlToDelete = urlsCache.first; | |
urlsCache.first = urlsCache.map[urlToDelete]; | |
delete urlsCache.map[urlToDelete]; | |
incrSize = false; | |
} | |
urlsCache.map[urlsCache.last] = imgUrl; | |
urlsCache.map[imgUrl] = imgUrl; | |
urlsCache.last = imgUrl; | |
if (incrSize) { | |
urlsCache.size++; | |
} | |
} | |
} //else { | |
// nextplease.logDetail("" + imgUrl + " is already in image cache"); | |
//} | |
}; | |
nextplease.cacheImageLocations = function () { | |
var i, urlsCache = nextplease.imageURLsCache; | |
nextplease.logDetail("caching image location"); | |
nextplease.logDetail("there are currently " + urlsCache.size + " image URLs cached"); | |
var theDocument = window.content.document; | |
var start = new Date(); | |
var imgElems = theDocument.getElementsByTagName("img"), imgElemsNum = imgElems.length; | |
if (imgElems) { | |
var numberOfImagesToCheck = Math.min(nextplease.MAX_LINKS_TO_CHECK, imgElemsNum); | |
nextplease.logDetail("Checking " + numberOfImagesToCheck + " <img> elements out of " + imgElemsNum + " total."); | |
for (i = 0; i < numberOfImagesToCheck; i++) { | |
nextplease.addImageToCache(imgElems[i].src); | |
} | |
} | |
var links = theDocument.getElementsByTagName("a"), linksNum = links.length; | |
if (links) { | |
var numberOfLinksToCheck = Math.min(nextplease.MAX_LINKS_TO_CHECK, linksNum); | |
nextplease.logDetail("Checking " + numberOfLinksToCheck + " <a> elements out of " + linksNum + " total."); | |
for (i = 0; i < numberOfLinksToCheck; i++) { | |
var linkUrl = links[i].href; | |
if (!urlsCache.map[linkUrl]) { | |
// This is technically not correct, but performance sucks | |
// if we do a proper regex check. | |
if (linkUrl.length > 3) { | |
var suffix = linkUrl.slice(-3).toLowerCase(); | |
if ((suffix === 'jpg') || (suffix === 'gif') || (suffix === 'png') || (suffix === 'bmp')) { | |
nextplease.addImageToCache(linkUrl); | |
} | |
} | |
} //else { | |
// nextplease.logDetail("" + linkUrl + " is already in image cache"); | |
//} | |
} | |
} | |
var end = new Date(); | |
nextplease.logDetail("caching took " + (end.getTime() - start.getTime()) + " ms"); | |
if (nextplease.DEBUG_DETAILED) { | |
nextplease.logDetail("checking cache correctness again"); | |
nextplease.checkImageCache(); | |
} | |
nextplease.logDetail("there are currently " + urlsCache.size + " image URLs cached"); | |
// nextplease.logDetail(nextplease.imageLocationArray.toString()); | |
}; | |
nextplease.initKey = function (keyId, keyPrefName, modifierPrefName) { | |
var modString = nextplease.getModifierPref(modifierPrefName); | |
var keyOrCharCode = nextplease.prefs.getIntPref(keyPrefName); | |
if (keyOrCharCode === 0) { | |
nextplease.prefs.clearUserPref(keyPrefName); | |
keyOrCharCode = nextplease.prefs.getIntPref(keyPrefName); | |
} | |
var isKeyCodePrefName = "iskeycode." + keyPrefName; | |
var isKeyCode = nextplease.prefs.getBoolPref(isKeyCodePrefName); | |
var enablePrefName = "enable." + keyPrefName; | |
var enable = nextplease.prefs.getBoolPref(enablePrefName); | |
var keyString; | |
var keyElem = document.getElementById(keyId); | |
keyElem.setAttribute("modifiers", modString); | |
if (isKeyCode) { | |
keyString = nextplease.KeyCodeToNameMap[keyOrCharCode]; | |
keyElem.removeAttribute("key"); | |
keyElem.setAttribute("keycode", keyString); | |
} else { | |
keyString = String.fromCharCode(keyOrCharCode); | |
keyElem.setAttribute("key", keyString); | |
keyElem.removeAttribute("keycode"); | |
} | |
keyElem.setAttribute("disabled", !enable); | |
if (enable) { | |
nextplease.DisableKey(modString, keyString); | |
} | |
}; | |
nextplease.initNumberKeys = function () { | |
var modifier = nextplease.getModifierPref("numbermodifier"); | |
var numberKey, i; | |
for (i = 0; i < 10; i++) { | |
numberKey = document.getElementById("nextplease" + i + "key"); | |
numberKey.setAttribute("modifiers", modifier); | |
numberKey.setAttribute("disabled", !nextplease.useNumberShortcuts); | |
if (nextplease.useNumberShortcuts) { | |
nextplease.DisableKey(modifier, "" + i); | |
} | |
} | |
}; | |
nextplease.readPreferences = function () { | |
var i; | |
if (!nextplease.prefs) { | |
nextplease.logError("nextplease.prefs undefined. This shouldn't happen!"); | |
nextplease.prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("nextplease."); | |
} | |
try { | |
nextplease.DEBUG = nextplease.prefs.getBoolPref("log"); | |
nextplease.DEBUG_DETAILED = nextplease.DEBUG && nextplease.prefs.getBoolPref("log.detailed"); | |
// nextplease.logDetail("reading preferences"); | |
nextplease.initKey("nextpleasekey", "nextkey", "keymodifier"); | |
nextplease.initKey("nextpleaseprevkey", "prevkey", "prevkeymodifier"); | |
nextplease.initKey("nextpleasefirstkey", "firstkey", "firstkeymodifier"); | |
nextplease.initKey("nextpleaselastkey", "lastkey", "lastkeymodifier"); | |
// nextplease.logDetail("keys read"); | |
nextplease.useSubmit = nextplease.prefs.getBoolPref("allowsubmit"); | |
nextplease.useNumberShortcuts = nextplease.prefs.getBoolPref("allownumbershortcuts"); | |
nextplease.useContextMenu = nextplease.prefs.getBoolPref("allowcontextmenu"); | |
nextplease.useSmartNext = nextplease.prefs.getBoolPref("allowsmartnext"); | |
nextplease.prefetchPref = nextplease.prefs.getIntPref("prefetch"); | |
nextplease.useFrames = nextplease.prefs.getBoolPref("checkframes"); | |
// nextplease.logDetail("bools read"); | |
var nextRegExString = nextplease.getUnicharPref("nextregex"); | |
var prevRegExString = nextplease.getUnicharPref("prevregex"); | |
var firstRegExString = nextplease.getUnicharPref("firstregex"); | |
var lastRegExString = nextplease.getUnicharPref("lastregex"); | |
var galleryRegExString = nextplease.getUnicharPref("galleryregex"); | |
var galleryRegEx = new RegExp(galleryRegExString, "i"); | |
var matches = galleryRegEx.exec("http://nextplease.mozdev.org/test/test101.jpg"); | |
if (matches && (matches.length !== 4)) { | |
nextplease.logError("Gallery regex test failed!"); | |
nextplease.prefs.clearUserPref("galleryregex"); | |
galleryRegExString = nextplease.getUnicharPref("galleryregex"); | |
galleryRegEx = new RegExp(galleryRegExString, "i"); | |
} | |
nextplease.RegExes = {Next: new RegExp(nextRegExString, "i"), | |
Prev: new RegExp(prevRegExString, "i"), | |
First: new RegExp(firstRegExString, "i"), | |
Last: new RegExp(lastRegExString, "i"), | |
Gallery: galleryRegEx}; | |
// nextplease.logDetail("regexes read"); | |
// nextplease.logDetail("gallery regex read"); | |
nextplease.initNumberKeys(); | |
nextplease.ImageMap = {}; | |
nextplease.PhraseMap = {}; | |
// Read the phrases that specify a next link | |
// by reading the preferences or defaults, | |
// and put the phrases in a lookup table. | |
var addPrefsToMap = function (map, phraseOrImage, direction) { | |
var prefbranch = (direction + phraseOrImage).toLowerCase(); | |
var tempprefname = prefbranch + ".expr0"; | |
var prefValue = nextplease.getUnicharPref(tempprefname); | |
var values = prefValue.split("|"); | |
var i; | |
// nextplease.logDetail("initializing " + prefbranch); | |
for (i = 0; i < values.length; i++) { | |
var value = values[i].replace(/&pipe;/g, "|"); | |
if (value !== "") { | |
map[value] = direction; | |
// nextplease.logDetail("added "+value+" to "+direction+" "+phraseOrImage); | |
} | |
} | |
// nextplease.logDetail("finished initializing " + prefbranch); | |
}; | |
for (i = 0; i < nextplease.directions.length; i++) { | |
var direction = nextplease.directions[i]; | |
addPrefsToMap(nextplease.PhraseMap, "Phrase", direction); | |
addPrefsToMap(nextplease.ImageMap, "Image", direction); | |
} | |
nextplease.highlightColor = nextplease.prefs.getBoolPref("highlight") ? | |
nextplease.prefs.getCharPref("highlight.color") : | |
undefined; | |
nextplease.highlightPrefetchedColor = nextplease.prefs.getBoolPref("highlight.prefetched") ? | |
nextplease.prefs.getCharPref("highlight.prefetched.color") : | |
undefined; | |
nextplease.logDetail("preferences read"); | |
} catch (e) { | |
if (!nextplease.retryingToReadPreferences) { | |
// nextplease.prefs.resetBranch() isn't implemented according to MDC | |
var prefnames = nextplease.prefs.getChildList("", {}); | |
for (i = 0; i < prefnames.length; i++) { | |
nextplease.prefs.clearUserPref(prefnames[i]); | |
} | |
var errorMsg = nextplease.strings.GetStringFromName("readingPreferencesFailed"); | |
alert(errorMsg); | |
nextplease.retryingToReadPreferences = true; | |
nextplease.readPreferences(); | |
} | |
} | |
}; | |
nextplease.DisableKey = function (modifier, keyString) { | |
var conflictingKeys, conflictingKey, conflictingId, conflictingModifier, i; | |
if (keyString.indexOf("VK_") >= 0) { | |
// nextplease.logDetail("disabling keys conflicting with " + modifier + "+" + nextplease.KeyCodeToNameMap[keycode]); | |
conflictingKeys = document.getElementsByAttribute("keycode", keyString); | |
} else { | |
// nextplease.logDetail("disabling keys conflicting with " + modifier + "+" + key); | |
conflictingKeys = document.getElementsByAttribute("key", keyString.toLowerCase()); | |
} | |
var conflictingKeysLength = conflictingKeys.length; | |
// nextplease.logDetail(conflictingKeysLength + " keys conflicting with " + modifier + "+" keystring); | |
for (i = 0; i < conflictingKeysLength; i++) { | |
conflictingKey = conflictingKeys[i]; | |
conflictingId = conflictingKey.getAttribute("id"); | |
if (!(/nextplease/.test(conflictingId)) && conflictingKey.hasAttribute("modifiers")) { | |
conflictingModifier = conflictingKey.getAttribute("modifiers").replace(nextplease.accelKey, "accel"); | |
// nextplease.logDetail("potentially conflicting key: " + conflictingId); | |
if ((/alt/.test(modifier) === /alt/.test(conflictingModifier)) && | |
(/control/.test(modifier) === /control/.test(conflictingModifier)) && | |
(/meta/.test(modifier) === /meta/.test(conflictingModifier)) && | |
(/shift/.test(modifier) === /shift/.test(conflictingModifier)) && | |
(/accel/.test(modifier) === /accel/.test(conflictingModifier))) { | |
// conflictingKey.parentNode.removeChild(conflictingKey); | |
conflictingKey.setAttribute("disabled", true); | |
nextplease.log("Disabled conflicting key " + conflictingId); | |
} | |
} | |
} | |
}; | |
nextplease.init = function () { | |
nextplease.log("initializing"); | |
nextplease.retryingToReadPreferences = false; | |
nextplease.readPreferences(); | |
nextplease.statusBar = document.getElementById("nextplease_statusbar_panel"); | |
}; | |
nextplease.clearStatusBar = function () { | |
if (nextplease.statusBar) { | |
nextplease.statusBar.collapsed = true; | |
nextplease.statusBar.label = ""; | |
} | |
}; | |
nextplease.showInStatusBar = function (text) { | |
if (nextplease.statusBar) { | |
nextplease.statusBar.collapsed = false; | |
nextplease.statusBar.label = text; | |
} | |
}; | |
nextplease.notifyLinkNotFound = function () { | |
nextplease.showInStatusBar(nextplease.strings.GetStringFromName("linkNotFound")); | |
nextplease.clearStatusBarTimer = setTimeout(nextplease.clearStatusBar, 5000); | |
}; | |
nextplease.directionFromRel = function (link) { | |
// Look for rel attributes for next/prev/first/last | |
if (link.rel && link.href) { | |
var rel = link.rel.toLowerCase(); | |
if (rel === "next") { | |
nextplease.log('found rel="' + link.rel + '": ' + link.href); | |
return "Next"; | |
} else if ((rel === "prev") || (rel === "previous")) { | |
nextplease.log('found rel="' + link.rel + '": ' + link.href); | |
return "Prev"; | |
} else if ((rel === "start") || (rel === "first")) { | |
nextplease.log('found rel="' + link.rel + '": ' + link.href); | |
return "First"; | |
} else if ((rel === "end") || (rel === "last")) { | |
nextplease.log('found rel="' + link.rel + '": ' + link.href); | |
return "Last"; | |
} | |
} | |
return undefined; | |
}; | |
nextplease.directionFromText = function (text, direction, prefetching) { | |
var i; | |
if (text) { | |
var direction1 = nextplease.PhraseMap[text]; | |
if (direction1) { | |
nextplease.log('found text match for "' + text + '"'); | |
return direction1; | |
} else { | |
if (prefetching) { | |
for (i = 0; i < nextplease.directions.length; i++) { | |
var direction2 = nextplease.directions[i]; | |
if (!nextplease.prefetched[direction2] && nextplease.RegExes[direction2].test(text)) { | |
nextplease.log('found regex match for "' + text + '"'); | |
return direction2; | |
} | |
} | |
} else if (nextplease.RegExes[direction].test(text)) { | |
nextplease.log('found regex match for "' + text + '"'); | |
return direction; | |
} | |
} | |
} | |
return undefined; | |
}; | |
nextplease.directionFromImage = function (imageElem, direction, prefetching) { | |
var imgtext = imageElem.alt ? imageElem.alt : imageElem.title; | |
var direction1 = nextplease.ImageMap[imageElem.src]; | |
if (direction1) { | |
nextplease.log("found image match with URL " + imageElem.src); | |
if (!prefetching || !nextplease.prefetched[direction1]) { | |
return direction1; | |
} else { | |
return undefined; | |
} | |
} else { | |
return nextplease.directionFromText(imgtext, direction, prefetching); | |
} | |
}; | |
nextplease.ignoreRels = function (curWindow) { | |
var url = curWindow.location.href; | |
// viewtopic.php is used in PHPBB, index.php in SMF | |
// both (at least some versions) use <link> tags incorrectly | |
return url.match(/(viewtopic|index)\.php/); | |
}; | |
// Looks through all the links on the page | |
// and tries to look for one whose text matches | |
// one of the phrases or images. If so, it goes to/ | |
// the corresponding link. | |
// pages with frames. | |
nextplease.getLink = function (curWindow, direction) { | |
var doc = curWindow.document; | |
var i, j; | |
var prefetching = (direction === "Prefetch"); | |
var direction1; | |
var text; | |
var isInt = /^\s*\[?\s*(\d+)\s*,?\]?\s*$/; | |
var pageNumLinks = {Next: null, Prev: null, First: null, Last: null, Tmp: null}; | |
var firstPageNum; | |
var currentPageNum = 100000; // Init to arbitrarily large num | |
var tmpPageNum = 100000; // Init to arbitrarily large num | |
var greatestNum = 1; | |
var insideNumberBlock = false; | |
var link; | |
var temp; | |
if (prefetching) { | |
nextplease.logDetail("prefetching..."); | |
} else { | |
nextplease.logDetail("looking for a link..."); | |
} | |
var range = doc.createRange(); | |
var finishPrefetch = function () { | |
return prefetching && nextplease.prefetched.Next && nextplease.prefetched.Prev && | |
nextplease.prefetched.First && nextplease.prefetched.Last; | |
}; | |
if (nextplease.useSmartNext) { | |
if (getBrowser().canGoForward) { | |
nextplease.log("forward in history"); | |
link = [nextplease.ResultType.History, 1]; | |
if (direction === "Next") { | |
return link; | |
} else if (prefetching) { | |
nextplease.prefetched.Next = link; | |
} | |
} | |
if (getBrowser().canGoBack) { | |
nextplease.log("back in history"); | |
link = [nextplease.ResultType.History, -1]; | |
if (direction === "Prev") { | |
return link; | |
} else if (prefetching) { | |
nextplease.prefetched.Prev = link; | |
} | |
} | |
} | |
if (!nextplease.ignoreRels(curWindow)) { | |
// Look for <LINK> tags | |
nextplease.logDetail("checking <link> tags"); | |
var linktags = doc.getElementsByTagName("link"), linktagsNum = linktags.length; | |
for (i = 0; i < linktagsNum; i++) { | |
link = linktags[i]; | |
direction1 = nextplease.directionFromRel(link); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Link, link]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Link, link]; | |
continue; | |
} | |
} | |
} | |
if (finishPrefetch()) { return true; } | |
// Look for <A HREF="..."> tags | |
nextplease.logDetail("checking <a> tags"); | |
var alinks = doc.links, alinksNum = alinks.length; | |
var curWindowUrl = doc.location.href; | |
// Search through each link | |
for (i = 0; i < alinksNum; i++) { | |
link = alinks[i]; | |
if (link.href === curWindowUrl) { | |
continue; | |
} | |
direction1 = nextplease.directionFromRel(link); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Link, link]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Link, link]; | |
continue; | |
} | |
range.selectNode(link); | |
text = nextplease.Trim(range.toString()); | |
if (link.href.indexOf("/dictionary") < 0) { | |
direction1 = nextplease.directionFromText(text, direction, prefetching); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Link, link]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Link, link]; | |
continue; | |
} | |
} | |
direction1 = nextplease.directionFromText(link.title, direction, prefetching); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Link, link]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Link, link]; | |
continue; | |
} | |
// See if there's an image tag | |
var imgElems = link.getElementsByTagName("img"); | |
if (imgElems.length > 0) { | |
nextplease.logDetail("checking images inside <a>...</a>"); | |
// If the image matches, go to the URL. | |
//alert(imgElems[0].src); | |
direction1 = nextplease.directionFromImage(imgElems[0], direction, prefetching); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Link, link]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Link, link]; | |
continue; | |
} | |
} | |
if (finishPrefetch()) { return true; } | |
var intMatches = isInt.exec(text); | |
if (intMatches) { | |
var linkPageNum = parseInt(intMatches[1], 10); | |
// If the number is greater than nextplease.MAX_LINK_NUM | |
// it probably doesn't have anything to do with | |
// a next/prev link. | |
// alert(linkPageNum); | |
if (linkPageNum < nextplease.MAX_LINK_NUM) { | |
nextplease.logDetail("found link number " + linkPageNum + ", checking..."); | |
// Try to figure out what the current page and | |
// next/prev links are for pages that just have | |
// numbered links like 1 2 x 4 5. | |
// if (linkPageNum === 1) { | |
// We're seeing a number link that is smaller | |
// than a previous one so assume that we're | |
// starting a new set of number links, and | |
// count from the beginning. | |
if (linkPageNum <= tmpPageNum) { | |
insideNumberBlock = true; | |
// alert(linkPageNum); | |
// alert(currentPageNum); | |
pageNumLinks.First = link; | |
firstPageNum = linkPageNum; | |
greatestNum = linkPageNum; | |
pageNumLinks.Prev = null; | |
pageNumLinks.Next = null; | |
pageNumLinks.Last = null; | |
currentPageNum = linkPageNum; | |
pageNumLinks.First = link; | |
greatestNum = linkPageNum; | |
pageNumLinks.Last = null; | |
//} else if (currentPageNum === linkPageNum) { | |
// currentPageNum++; | |
// pageNumLinks.Prev = link; | |
} else if (tmpPageNum + 1 === linkPageNum) { | |
pageNumLinks.Last = link; | |
} else if (tmpPageNum + 2 === linkPageNum) { | |
pageNumLinks.Prev = pageNumLinks.Tmp; | |
pageNumLinks.Next = link; | |
pageNumLinks.Last = link; | |
} else if (insideNumberBlock) { | |
pageNumLinks.Last = link; | |
} | |
tmpPageNum = linkPageNum; | |
pageNumLinks.Tmp = link; | |
} | |
} else { | |
insideNumberBlock = false; | |
} | |
} | |
// next and prev are null so that means | |
// we have a solid block of numbers, e.g. 3,4,5,6,... | |
if ((pageNumLinks.Next === null) && (pageNumLinks.Prev === null)) { | |
// If we start with 1, we're probably on last page. | |
// Set prev to be lastPage | |
if (firstPageNum === 1) { | |
pageNumLinks.Prev = pageNumLinks.Last; | |
pageNumLinks.Last = null; | |
} | |
// If we start with 2, we're probably on first page. | |
// Set next to be first page | |
if (firstPageNum === 2) { | |
pageNumLinks.Next = pageNumLinks.First; | |
pageNumLinks.First = null; | |
} | |
if (firstPageNum > 2) { | |
pageNumLinks.Next = pageNumLinks.First; | |
pageNumLinks.Prev = pageNumLinks.Last; | |
} | |
} | |
if (pageNumLinks.First && pageNumLinks.Last && (pageNumLinks.First.text === pageNumLinks.Last.text)) { | |
pageNumLinks.First = null; | |
} | |
nextplease.logDetail("first page seems to be " + pageNumLinks.First); | |
nextplease.logDetail("previous page seems to be " + pageNumLinks.Prev); | |
nextplease.logDetail("next page seems to be " + pageNumLinks.Next); | |
nextplease.logDetail("last page seems to be " + pageNumLinks.Last); | |
// Try to find a match using our number algorithm | |
if (prefetching) { | |
for (i = 0; i < nextplease.directions.length; i++) { | |
direction1 = nextplease.directions[i]; | |
if (!nextplease.prefetched[direction1] && pageNumLinks[direction1]) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Link, pageNumLinks[direction1]]; | |
} | |
} | |
if (finishPrefetch()) { return true; } | |
} else if (pageNumLinks[direction]) { return [nextplease.ResultType.Link, pageNumLinks[direction]]; } | |
// Otherwise try looking for next/prev submit buttons | |
// if the user allows it. | |
if (nextplease.useSubmit) { | |
temp = nextplease.getForm(direction, prefetching); | |
if (temp) { return temp; } | |
} | |
// See if we can increment the URL to get to next/prev/first | |
var galleryURL = nextplease.getGalleryNumberURL(curWindow, direction); | |
// alert(galleryURL); | |
// alert(nextplease.imageLocationArray.length); | |
// if (galleryURL) {curWindow.open(galleryURL, "_self", "");} | |
if (galleryURL && !prefetching) { return [nextplease.ResultType.URL, galleryURL]; } | |
// None of it worked, so make a recursive call to | |
// nextplease.getLink on the frame windows. | |
if (nextplease.useFrames) { | |
var frames = curWindow.frames, framesNum = frames.length; | |
for (j = 0; j < framesNum; j++) { | |
temp = nextplease.getLink(frames[j], direction); | |
if (temp) { return temp; } | |
} | |
} | |
return finishPrefetch(); | |
}; | |
nextplease.getGalleryNumberURL = function (curWindow, direction) { | |
nextplease.logDetail("trying to change the URL by a suitable number"); | |
var i; | |
// alert(nextplease.imageLocationArray); | |
var matches = nextplease.RegExes.Gallery.exec(decodeURI(curWindow.location.href)); | |
var prefixUrl, suffixUrl, numberUrlPartLength, curNumber, urlNumber, padStr, linkUrl; | |
var urlsCache = nextplease.imageURLsCache; | |
if (matches && (matches.length === 4)) { | |
prefixUrl = matches[1]; | |
numberUrlPartLength = matches[2].length; | |
suffixUrl = matches[3]; | |
nextplease.logDetail("URL prefix is " + prefixUrl + ", URL suffix is " + suffixUrl); | |
if (direction === "Next") { | |
curNumber = parseInt(matches[2], 10); | |
for (i = 1; i < nextplease.MAX_GALLERY_GAP; i++) { | |
urlNumber = curNumber + i; | |
padStr = nextplease.padNumber(numberUrlPartLength, urlNumber); | |
linkUrl = prefixUrl + padStr + suffixUrl; | |
if (urlsCache.map[linkUrl]) { | |
nextplease.log("gallery URL found: " + linkUrl); | |
return linkUrl; | |
} | |
} | |
urlNumber = curNumber + 1; | |
padStr = nextplease.padNumber(numberUrlPartLength, urlNumber); | |
linkUrl = prefixUrl + padStr + suffixUrl; | |
return linkUrl; | |
} else if (direction === "Prev") { | |
curNumber = parseInt(matches[2], 10); | |
var maxToSubtract = Math.min(curNumber, nextplease.MAX_GALLERY_GAP); | |
for (i = 1; i <= maxToSubtract; i++) { | |
urlNumber = curNumber - i; | |
padStr = nextplease.padNumber(numberUrlPartLength, urlNumber); | |
linkUrl = prefixUrl + padStr + suffixUrl; | |
if (urlsCache.map[linkUrl]) { | |
nextplease.log("gallery URL found: " + linkUrl); | |
return linkUrl; | |
} | |
} | |
urlNumber = curNumber - 1; | |
if (urlNumber >= 0) { | |
padStr = nextplease.padNumber(numberUrlPartLength, urlNumber); | |
linkUrl = prefixUrl + padStr + suffixUrl; | |
nextplease.log("gallery URL found: " + linkUrl); | |
return linkUrl; | |
} | |
} else if (direction === "First") { | |
urlNumber = 1; | |
padStr = nextplease.padNumber(numberUrlPartLength, urlNumber); | |
linkUrl = prefixUrl + padStr + suffixUrl; | |
nextplease.log("gallery URL found: " + linkUrl); | |
return linkUrl; | |
} | |
} | |
return undefined; | |
}; | |
nextplease.padNumber = function (length, newNum) { | |
var padStr = "" + newNum; | |
var padLen = length - padStr.length; | |
var i; | |
for (i = 0; i < padLen; i++) { | |
padStr = "0" + padStr; | |
} | |
return padStr; | |
}; | |
// Look through all the HTML inputs for submit buttons | |
// that have a value that matches our phrases. If it | |
// finds a match, it calls input.click() | |
nextplease.getForm = function (direction, prefetching) { | |
var finishPrefetch = function () { | |
return prefetching && nextplease.prefetched.Next && nextplease.prefetched.Prev && | |
nextplease.prefetched.First && nextplease.prefetched.Last; | |
}; | |
var i, text, direction1; | |
nextplease.logDetail("looking for submit buttons"); | |
// Probably would be a little faster to | |
// only check forms, but I'm getting problems | |
// with them. I'm not sure if it's only on | |
// malformed HTML pages, or if it's a Firefox bug. | |
var inputs = window.content.document.getElementsByTagName("input"), inputsNum = inputs.length; | |
for (i = 0; i < inputsNum; i++) { | |
var input = inputs[i]; | |
text = nextplease.Trim(input.value); | |
direction1 = nextplease.directionFromText(text, direction, prefetching); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Input, input]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Input, input]; | |
} | |
} | |
var buttons = window.content.document.getElementsByTagName("button"), buttonsNum = buttons.length; | |
var range = document.createRange(); | |
for (i = 0; i < buttonsNum; i++) { | |
var button = buttons[i]; | |
range.selectNode(button); | |
text = nextplease.Trim(range.toString()); | |
direction1 = nextplease.directionFromText(text, direction, prefetching); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Input, button]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Input, button]; | |
} | |
var imgElems = buttons[i].getElementsByTagName("img"); | |
if (imgElems.length > 0) { | |
nextplease.logDetail("checking images inside <a>...</a>"); | |
// If the image matches, go to the URL. | |
//alert(imgElems[0].src); | |
direction1 = nextplease.directionFromImage(imgElems[0], direction, prefetching); | |
if (direction === direction1) { | |
return [nextplease.ResultType.Input, button]; | |
} else if (direction1 && prefetching) { | |
nextplease.prefetched[direction1] = [nextplease.ResultType.Input, button]; | |
continue; | |
} | |
} | |
} | |
return finishPrefetch(); | |
}; | |
nextplease.openResult = function (curWindow, result) { | |
if (nextplease.highlightColor) { | |
nextplease.highlight(result, nextplease.highlightColor); | |
} | |
switch (result[0]) { | |
case nextplease.ResultType.URL: | |
var url = result[1]; | |
curWindow.open(url, "_self", ""); | |
return true; | |
case nextplease.ResultType.Link: | |
var linkNode = result[1]; | |
if (!linkNode) { | |
nextplease.logError("Tried to open undefined link, this should never happen!"); | |
return false; | |
} | |
// If it's got an onclick attr, then try to | |
// simulate a mouse click to activate link. | |
if (linkNode.hasAttribute("onclick")) { | |
// alert(linkNode.getAttribute("onclick")); | |
var e = document.createEvent("MouseEvents"); | |
// e.initMouseEvent("click", 1, 1, window, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, linkNode); | |
// From https://developer.mozilla.org/en/DOM/event.initMouseEvent | |
e.initMouseEvent("click", true, true, window, | |
0, 0, 0, 0, 0, false, false, false, false, 0, null); | |
linkNode.dispatchEvent(e); | |
} else { | |
curWindow.open(linkNode.href, "_self", ""); | |
} | |
nextplease.gotHereUsingNextplease = true; | |
return true; | |
case nextplease.ResultType.Input: | |
var input = result[1]; | |
input.click(); | |
return true; | |
case nextplease.ResultType.History: | |
var num = result[1]; | |
curWindow.history.go(num); | |
return true; | |
} | |
}; | |
// Looks through all the links and finds the link | |
// that matches the linkNum (an integer between | |
// 1 and 9). If it finds a match, it will go to | |
// that link. | |
nextplease.openNumberedLink = function (curWindow, linkNum) { | |
var text; | |
var isInt = /^\s*\[?\s*(\d+)\s*\]?\s*$/; | |
var i, j; | |
nextplease.logDetail("looking for a link numbered " + linkNum); | |
var alinks = curWindow.document.links; | |
// Search through each link | |
for (i = alinks.length - 1; i >= 0; i--) { | |
var link = alinks[i]; | |
text = nextplease.Trim(link.text); | |
var intMatches = isInt.exec(text); | |
if (intMatches) { | |
var linkPageNum = parseInt(intMatches[1], 10); | |
if (linkPageNum === linkNum) { | |
return nextplease.openResult(curWindow, [nextplease.ResultType.Link, link]); | |
//curWindow.open(link.href, "_self", ""); | |
//return true; | |
} | |
} | |
} | |
if (nextplease.useFrames) { | |
var frames = curWindow.frames; | |
for (j = 0; j < frames.length; j++) { | |
if (nextplease.openNumberedLink(frames[j], linkNum)) { return true; } | |
} | |
} | |
nextplease.notifyLinkNotFound(); | |
return false; | |
}; | |
nextplease.openDirection = function (direction) { | |
var result = nextplease.prefetched[direction] || nextplease.getLink(window.content, direction); | |
if (result) { | |
return nextplease.openResult(window.content, result); | |
} else { | |
nextplease.notifyLinkNotFound(); | |
return false; | |
} | |
}; | |
nextplease.openNextLink = function () { | |
nextplease.logDetail("Looking for next link"); | |
return nextplease.openDirection("Next"); | |
}; | |
nextplease.openPrevLink = function () { | |
nextplease.logDetail("Looking for prev link"); | |
return nextplease.openDirection("Prev"); | |
}; | |
nextplease.openFirstLink = function () { | |
nextplease.logDetail("Looking for first link"); | |
return nextplease.openDirection("First"); | |
}; | |
nextplease.openLastLink = function () { | |
nextplease.logDetail("Looking for last link"); | |
return nextplease.openDirection("Last"); | |
}; | |
nextplease.prefetch = function () { | |
nextplease.getLink(window.content, "Prefetch"); | |
if (nextplease.highlightPrefetchedColor) { | |
nextplease.highlight(nextplease.prefetched.Next, nextplease.highlightPrefetchedColor); | |
nextplease.highlight(nextplease.prefetched.Prev, nextplease.highlightPrefetchedColor); | |
nextplease.highlight(nextplease.prefetched.First, nextplease.highlightPrefetchedColor); | |
nextplease.highlight(nextplease.prefetched.Last, nextplease.highlightPrefetchedColor); | |
} | |
}; | |
// old names retained because of http://www.mousegestures.org/exchange/details.php?mappingID=295 | |
nextplease.getNextLink = nextplease.openNextLink; | |
nextplease.getPrevLink = nextplease.openPrevLink; | |
nextplease.getFirstLink = nextplease.openFirstLink; | |
nextplease.getLastLink = nextplease.openLastLink; | |
nextplease.highlight = function (result, color) { | |
if (result) { | |
var element; | |
switch (result[0]) { | |
case nextplease.ResultType.URL: | |
break; | |
case nextplease.ResultType.Link: | |
case nextplease.ResultType.Input: | |
element = result[1]; | |
break; | |
// case nextplease.ResultType.History: | |
// TODO The forward button doesn't get unhighlighted correctly | |
// when it becomes disabled. | |
// switch (result[1]) { | |
// case 1: element = document.getElementById("forward-button"); break; | |
// case -1: element = document.getElementById("back-button"); break; | |
// } | |
} | |
if (element) { | |
if (!nextplease.highlighted_old_styles[element]) { | |
nextplease.highlighted_old_styles[element] = element.style; | |
} | |
element.style.background = color; | |
} | |
} | |
}; | |
nextplease.unhighlight = function () { | |
var element; | |
for (element in nextplease.highlighted_old_styles) { | |
element.style = nextplease.highlighted_old_styles[element]; | |
delete nextplease.highlighted_old_styles[element]; | |
} | |
}; | |
nextplease.showHideMenuItems = function () { | |
var i, elem; | |
var direction, numDirections = nextplease.directions.length; | |
var propertyKey; | |
var getCMItemByDir = function (direction) { | |
var elemId = "nextPleaseAddRemove" + direction; | |
return document.getElementById(elemId); | |
}; | |
if (gContextMenu) { | |
gContextMenu.showItem("nextplease.topMenu", nextplease.useContextMenu); | |
if (nextplease.useContextMenu) { | |
if (!gContextMenu.onLink && !gContextMenu.onImage) { | |
gContextMenu.showItem("nextplease-separator", false); | |
gContextMenu.showItem("nextpleaseTextOrURL", false); | |
gContextMenu.showItem("nextPleaseAddRemoveNext", false); | |
gContextMenu.showItem("nextPleaseAddRemovePrev", false); | |
gContextMenu.showItem("nextPleaseAddRemoveFirst", false); | |
gContextMenu.showItem("nextPleaseAddRemoveLast", false); | |
} else { | |
var textOrUrl = nextplease.getTextOrUrlUnderPopup(); | |
var phraseOrImage = gContextMenu.onImage ? "Image" : "Phrase"; | |
document.getElementById("nextpleaseTextOrURL").label = gContextMenu.onImage ? textOrUrl : '"' + textOrUrl + '"'; | |
var directionForItem = nextplease[phraseOrImage + "Map"][textOrUrl]; | |
for (i = 0; i < numDirections; i++) { | |
direction = nextplease.directions[i]; | |
elem = getCMItemByDir(direction); | |
propertyKey = (direction === directionForItem ? "remove" : "add") + phraseOrImage + "ContextMenu"; | |
// alert("str = " + nextplease.strings.GetStringFromName(propertyKey) + "; param = " + nextplease.getDirectionString(direction)); | |
elem.label = nextplease.strings.formatStringFromName(propertyKey, [nextplease.getDirectionString(direction)], 1); | |
} | |
gContextMenu.showItem("nextplease-separator", true); | |
gContextMenu.showItem("nextpleaseTextOrURL", true); | |
gContextMenu.showItem("nextPleaseAddRemoveNext", true); | |
gContextMenu.showItem("nextPleaseAddRemovePrev", true); | |
gContextMenu.showItem("nextPleaseAddRemoveFirst", true); | |
gContextMenu.showItem("nextPleaseAddRemoveLast", true); | |
} | |
} | |
} | |
}; | |
nextplease.addRemoveCM = function (direction) { | |
var phraseOrImage = gContextMenu.onImage ? "Image" : "Phrase"; | |
var textOrUrl = nextplease.getTextOrUrlUnderPopup(); | |
var currentDirection = nextplease[phraseOrImage + "Map"][textOrUrl]; | |
if (currentDirection === direction) { // removing | |
if (nextplease.confirmRemove(phraseOrImage, textOrUrl, currentDirection)) { | |
nextplease.addOrRemovePhraseOrImage(currentDirection, textOrUrl, phraseOrImage, "Remove"); | |
} | |
} else if (currentDirection) { // replacing | |
if (nextplease.confirmReplace(phraseOrImage, textOrUrl, currentDirection, direction)) { | |
nextplease.addOrRemovePhraseOrImage(currentDirection, textOrUrl, phraseOrImage, "Remove"); | |
nextplease.addOrRemovePhraseOrImage(direction, textOrUrl, phraseOrImage, "Add"); | |
} | |
} else { | |
nextplease.addOrRemovePhraseOrImage(direction, textOrUrl, phraseOrImage, "Add"); | |
} | |
}; | |
nextplease.addOrRemovePhraseOrImage = function (direction, textOrUrl, whichPhraseOrImage, whichAddOrRemove) { | |
var prefname, map, logMessage; | |
if (whichPhraseOrImage === "Phrase") { | |
prefname = direction.toLowerCase() + "phrase"; | |
map = nextplease.PhraseMap; | |
logMessage = (whichAddOrRemove === "Add") ? | |
"adding phrase '" + textOrUrl + "' to " + prefname : | |
"removing phrase '" + textOrUrl + "' from " + prefname; | |
nextplease.logDetail(logMessage); | |
} else { | |
prefname = direction.toLowerCase() + "image"; | |
map = nextplease.ImageMap; | |
logMessage = (whichAddOrRemove === "Add") ? | |
"adding image URL " + textOrUrl + " to " + prefname : | |
"removing image URL " + textOrUrl + " from " + prefname; | |
nextplease.logDetail(logMessage); | |
} | |
if (whichAddOrRemove === "Add") { | |
if (map[textOrUrl] !== direction) { | |
map[textOrUrl] = direction; | |
nextplease.addToPrefs(prefname, textOrUrl); | |
} else { | |
nextplease.log("error: already present in the list!"); | |
} | |
} else { | |
if (map[textOrUrl] === direction) { | |
delete map[textOrUrl]; | |
nextplease.removeFromPrefs(prefname, textOrUrl); | |
} else { | |
nextplease.log("error: not present in the list!"); | |
} | |
} | |
}; | |
nextplease.getTextOrUrlUnderPopup = function () { | |
if (gContextMenu && gContextMenu.onLink) { | |
if (gContextMenu.onImage) { | |
return document.popupNode.src; | |
} else { | |
var range = document.createRange(); | |
range.selectNode(document.popupNode); | |
return nextplease.Trim(range.toString()); | |
} | |
} else { | |
return undefined; | |
} | |
}; | |
nextplease.addToPrefs = function (prefbranch, text) { | |
nextplease.logDetail("adding " + text + " to " + prefbranch); | |
var tempprefname = prefbranch + '.expr0'; | |
var prefvalue = nextplease.getUnicharPref(tempprefname); | |
var resultprefvalue = prefvalue + "|" + text.replace(/\|/g, "&pipe;"); | |
nextplease.setUnicharPref(tempprefname, resultprefvalue); | |
}; | |
nextplease.removeFromPrefs = function (prefbranch, text) { | |
nextplease.logDetail("removing " + text + " from " + prefbranch); | |
var tempprefname = prefbranch + '.expr0'; | |
var prefvalue = nextplease.getUnicharPref(tempprefname); | |
var text1 = new RegExp("\\|" + text.replace(/\|/g, "&pipe;") + "(?=\\||$)", "g"); | |
var resultprefvalue = prefvalue.replace(text1, ""); | |
nextplease.setUnicharPref(tempprefname, resultprefvalue); | |
}; | |
nextplease.linkNumber = 0; | |
nextplease.handleNumberShortcut = function (digit) { | |
// no effect if nextplease.NumberShortcutTimer is invalid | |
clearTimeout(nextplease.NumberShortcutTimer); | |
nextplease.linkNumber = nextplease.linkNumber * 10 + digit; | |
nextplease.showInStatusBar( | |
nextplease.strings.formatStringFromName("lookingForNumberedLink", [nextplease.linkNumber], 1)); | |
nextplease.NumberShortcutTimer = setTimeout(nextplease.finishNumberShortcut, 500); | |
}; | |
nextplease.finishNumberShortcut = function () { | |
nextplease.openNumberedLink(window.content, nextplease.linkNumber); | |
nextplease.linkNumber = 0; | |
clearTimeout(nextplease.NumberShortcutTimer); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment