diff --git a/content/buffers.js b/content/buffers.js index 5502bba5..7f892139 100644 --- a/content/buffers.js +++ b/content/buffers.js @@ -57,7 +57,7 @@ vimperator.Buffer = function() //{{{ // unsuccessfully attempt to reshow hints? i.e. isn't it just relying // on the recalculation side effect? -- djk // NOTE: we could really do with a zoom event... - vimperator.hints.reshowHints(); + // vimperator.hints.reshowHints(); } function bumpZoomLevel(steps, full_zoom) diff --git a/content/events.js b/content/events.js index fe633aa2..991bf8a1 100644 --- a/content/events.js +++ b/content/events.js @@ -489,6 +489,10 @@ vimperator.Events = function() //{{{ switch (vimperator.mode) { + case vimperator.modes.HINTS: + vimperator.modes.reset(); + break; + case vimperator.modes.VISUAL: if (vimperator.modes.extended & vimperator.modes.TEXTAREA) vimperator.mode = vimperator.modes.TEXTAREA; @@ -607,82 +611,25 @@ vimperator.Events = function() //{{{ // if Hit-a-hint mode is on, special handling of keys is required - // FIXME: total mess - if (vimperator.mode == vimperator.modes.HINTS) + // FIXME: should be handled properly! + if (key != "" && key != "") { - // never propagate this key to firefox, when hints are visible - //event.preventDefault(); - //event.stopPropagation(); - - var map = vimperator.mappings.get(vimperator.modes.HINTS, key); - if (map) +// // if the hint is all in UPPERCASE, open it in new tab +// vimperator.input.buffer += key; +// if (/[A-Za-z]/.test(vimperator.input.buffer) && vimperator.input.buffer.toUpperCase() == vimperator.input.buffer) +// vimperator.hints.openHints(true, false); +// else // open in current window +// vimperator.hints.openHints(false, false); + if (vimperator.mode == vimperator.modes.HINTS) { - if (map.always_active || vimperator.hints.currentState() == 1) - { - map.execute(null, vimperator.input.count); - if (map.cancel_mode) // stop processing this event - { - vimperator.hints.disableHahMode(); - vimperator.input.buffer = ""; - vimperator.statusline.updateInputBuffer(""); - return false; - } - else - { - // FIXME: make sure that YOU update the statusbar message yourself - // first in g_hint_mappings when in this mode! - vimperator.statusline.updateInputBuffer(vimperator.input.buffer); - return false; - } - } + vimperator.hints.onEvent(event); + event.preventDefault(); + event.stopPropagation(); + // if i do an alert("x") here, it doesn't crash on up/down, why? + return false; } - - // no mapping found, beep() - if (vimperator.hints.currentState() == 1) - { - vimperator.beep(); - vimperator.hints.disableHahMode(); - vimperator.input.buffer = ""; - vimperator.statusline.updateInputBuffer(vimperator.input.buffer); - return true; - } - - // if we came here, let hit-a-hint process the key as it is part - // of a partial link - var res = vimperator.hints.processEvent(event); - if (res < 0) // error occured processing this key - { - vimperator.beep(); - if (vimperator.modes.extended & vimperator.modes.QUICK_HINT) - vimperator.hints.disableHahMode(); - else // ALWAYS mode - vimperator.hints.resetHintedElements(); - vimperator.input.buffer = ""; - } - else if (res == 0 || vimperator.modes.extended & vimperator.modes.EXTENDED_HINT) // key processed, part of a larger hint - vimperator.input.buffer += key; - else // this key completed a quick hint - { - // if the hint is all in UPPERCASE, open it in new tab - vimperator.input.buffer += key; - if (/[A-Za-z]/.test(vimperator.input.buffer) && vimperator.input.buffer.toUpperCase() == vimperator.input.buffer) - vimperator.hints.openHints(true, false); - else // open in current window - vimperator.hints.openHints(false, false); - - if (vimperator.modes.extended & vimperator.modes.QUICK_HINT) - vimperator.hints.disableHahMode(); - else // ALWAYS mode - vimperator.hints.resetHintedElements(); - - vimperator.input.buffer = ""; - } - - vimperator.statusline.updateInputBuffer(vimperator.input.buffer); - return true; } - var count_str = vimperator.input.buffer.match(/^[0-9]*/)[0]; var candidate_command = (vimperator.input.buffer + key).replace(count_str, ''); var map; diff --git a/content/hints.js b/content/hints.js index d9822d10..49f8214e 100644 --- a/content/hints.js +++ b/content/hints.js @@ -1,897 +1,393 @@ /***** BEGIN LICENSE BLOCK ***** {{{ - * - * Mozilla Public License Notice - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "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 Original Code and Idea is the Hit-a-Hint Mozilla extension. - * The Initial Developer of the Original Code and the Idea is Pekka - * P. Sillanpaa. Portions created by Initial Developer are Copyright - * (C) 2004. All Rights Reserved. - * - * Contributor(s): Pekka Sillanpaa, Paul Stone - * adapted for Vimperator use by: Martin Stubenschrott - * +Version: MPL 1.1/GPL 2.0/LGPL 2.1 + +The contents of this file are subject to the Mozilla Public License Version +1.1 (the "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. + +(c) 2006-2007: Martin Stubenschrott + +Alternatively, the contents of this file may be used under the terms of +either the GNU General Public License Version 2 or later (the "GPL"), or +the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +in which case the provisions of the GPL or the LGPL are applicable instead +of those above. If you wish to allow use of your version of this file only +under the terms of either the GPL or the LGPL, and not to allow others to +use your version of this file under the terms of the MPL, indicate your +decision by deleting the provisions above and replace them with the notice +and other provisions required by the GPL or the LGPL. If you do not delete +the provisions above, a recipient may use your version of this file under +the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ vimperator.Hints = function() //{{{ { - const HINT_PREFIX = 'hah_hint_'; // prefix for the hint id - - this.hintedElements = function() { return hintedElems; }; - this.currentState = function() { return state;}; - this.setCurrentState = function(s) { state = s;}; - - var isHahModeEnabled = false; // is typing mode on - var hintedElems = []; var linkNumString = ""; // the typed link number is in this string - var linkCount = 0; - var state = 0; // 0: empty or processing, 1: a full hint was parsed - - var wins; // frame array - - // each hint element is a clone of this element - var hintElemSpan; - - //////////////////////////////////////////////////////////////////////////////// - // hint activating and loading related functions - //////////////////////////////////////////////////////////////////////////////// - - function startCoordLoader(doc) - { - win = doc.defaultView; - if (!win) - return; - - if (win.winId != null) - { - window.clearTimeout(win.coordLoaderId); - } - else - { - if (!wins) - wins = []; - - win.winId = wins.length; - wins.push(win); - } - // logMessage("winId:"+win.winId); - win.res = vimperator.buffer.evaluateXPath(vimperator.options["hinttags"], doc); - win.coordLoaderId = window.setTimeout("vimperator.hints.loadCoord(" + win.winId + ", 0);", 1); - } - - this.loadCoord = function(winId, i) - { - win = wins[winId]; - - // win.res is not ready when loading has not finished yet - if (!win.res) - return; - - var elem = win.res.snapshotItem(i); - - if (elem) - genElemCoords(elem); - - i++; - - if (i < win.res.snapshotLength && !isHahModeEnabled) - window.setTimeout("vimperator.hints.loadCoord(" + winId + ", "+ i +");", 1); - else - win.coordLoaderId = null; - }; - - function genElemCoords(elem) - { - // NOTE: experiment for making the function faster, report problems - var rect = elem.getClientRects()[0]; - if (rect) - { - if (!rect.left || !rect.top) - vimperator.log("HUI: no rect.left or top"); - elem.absoLeft = rect.left + window.content.scrollX; - elem.absoTop = rect.top + window.content.scrollY; - } - return; - } - - function createHints(win) - { - if (!win) - { - win = window.content; - linkCount = 0; - } - - var area = new Array(4); - area[0] = win.pageXOffset - 5; - area[1] = win.pageYOffset - 5; - area[2] = area[0] + win.innerWidth; - area[3] = area[1] + win.innerHeight; - - var doc = win.document; - var res = vimperator.buffer.evaluateXPath(vimperator.options["hinttags"], doc); - - var elem, i; - - hintElemSpan = doc.createElement('SPAN'); - hintElemSpan.style.cssText = vimperator.options["hintstyle"]; - hintElemSpan.setAttribute('name', 'hah_hint'); - - var hintContainer = doc.getElementById('hah_hints'); - if (hintContainer == null) - { - genHintContainer(doc); - hintContainer = doc.getElementById('hah_hints'); - if (!hintContainer) - return false; - } - hintContainer.valid_hint_count = 0; // none of these hints should be visible initially - - var hints = hintContainer.childNodes; - var maxhints = vimperator.options["maxhints"]; - //vimperator.log("snapshot length: " + res.snapshotLength); - for (i = 0; i < res.snapshotLength; i++) - { - // this saves from script timeouts on pages with some thousand links - if (linkCount >= maxhints) - break; - - elem = res.snapshotItem(i); - genElemCoords(elem); - - // for extended hint mode, show all - even currently hidden - hints - //if (vimperator.hasMode(vimperator.modes.QUICK_HINT) && (elem.absoTop < area[1] || elem.absoTop > area[3] || -// if ((elem.absoTop < area[1] || elem.absoTop > area[3] || -// elem.absoLeft > area[2] || elem.absoLeft < area[0])) -// continue; - - // if (elem.offsetWidth == 0 && elem.offsetHeight == 0) - // continue; - - var cs = doc.defaultView.getComputedStyle(elem, null); - - if (cs.getPropertyValue("visibility") == "hidden") - continue; - - if (linkCount < hints.length) - hintElem = hints[linkCount]; - else // need to attach this new hintElem to the hint container - { - hintElem = hintElemSpan.cloneNode(false); - hintContainer.appendChild(hintElem); - } - - hintElem.style.display = 'none'; - hintElem.style.top = elem.absoTop + "px"; - hintElem.style.left = elem.absoLeft + "px"; - hintElem.refElem = elem; - - hintContainer.valid_hint_count++; // one more visible hint in this frame - linkCount++; // and one more total hint - - // process firefox event to keep the UI snappy - // if (linkCount % 50 == 0) - // { - // Components.classes['@mozilla.org/thread-manager;1']. - // getService().mainThread.processNextEvent(false); - // //showHints(null, 0); - // } - } - - doc.coordsInvalidated = false; - - // recursively create hints - for (i = 0; i < win.frames.length; i++) - createHints(win.frames[i]); - } - - function showHints(win, off) - { - offset = off; // must be global without 'var' for recursion - - if (!win) - win = window.content; - - if (linkCount == 0 && !(vimperator.modes.extended & vimperator.modes.ALWAYS_HINT)) - { - vimperator.beep(); - vimperator.modes.reset(); - - // XXX: move to mode handling - isHahModeEnabled = false; - linkNumString = ''; - hintedElems = []; - - return; - } - - var doc = win.document; - var hintElem = null; - var hintContainer = doc.getElementById('hah_hints'); - var hints = hintContainer.childNodes; - var i, j; - - for (i = 0; i < hintContainer.valid_hint_count; i++) - { - hintText = formatHint(offset+i); - hintElem = hints[i]; - hintElem.style.display = 'inline'; - //hintElem.style.position = 'absolute'; - hintElem.innerHTML = hintText; - hintElem.id = HINT_PREFIX + hintText; - } - offset += hintContainer.valid_hint_count; - - // recursively show hints - for (j = 0; j < win.frames.length; j++) - showHints(win.frames[j], offset); - } - - /* removes all visible hints from doc - * or from current document, if win == null - */ - function removeHints(win) - { - if (!win) - win = window.content; - - var doc = win.document; - var res = vimperator.buffer.evaluateXPath("//HINTS/SPAN", doc) - var elem, i; - - for (i = 0; i < res.snapshotLength; i++) - { - elem = res.snapshotItem(i); - setHintStyle(elem, vimperator.options["hintstyle"]); - elem.style.display = 'none'; - } - - for (i = 0; i < win.frames.length; i++) - removeHints(win.frames[i]); - } - - function onResize(event) - { - if (event) - doc = event.originalTarget; - else - doc = window.content.document; - - invalidateCoords(doc); - startCoordLoader(doc); - } - - function invalidateCoords(doc) - { - if (!doc.coordsInvalidated) - { - // every element has .validCoord - // if it is the same as doc:s .validCoords, - // the coordinates have not been regenerated, otherwise they - // have. This way we can also use recursive generation - // so that the coordinates are generated for every - // element just once - doc.validCoords = !doc.validCoords; - // this is because window can be resized many times - // and the coords should be invalidated just once. - doc.coordsInvalidated = true; - // logMessage(doc.validCoords); - } - } - - function getHintById(id, win) - { - if (!win) - win = window.content; - - var doc = win.document; - var elem, i; - - //var hintId = parseInt(id, nums.length); - //elem = doc.getElementById(prefix + hintId); - elem = doc.getElementById(HINT_PREFIX + id); - - if (elem) - { - return elem; - } - else - { - for (i = 0; i < win.frames.length; i++) - { - elem = getHintById(id, win.frames[i]); - if (elem) - return elem; - } - } - return null; - } - - function formatHint(hintNum) - { - var hintCharacters = vimperator.options["hintchars"]; - var str = hintNum.toString(hintCharacters.length); // turn hintNum into a base(length) number - - // map the number onto the chars in the numbers string - var result = ''; - // make all links the same length - var hintLength = 1; - var tmp = linkCount; - while ((tmp /= hintCharacters.length) > 1.0) - hintLength++; - while (str.length < hintLength) - { - result += hintCharacters.charAt(0).toUpperCase(); - hintLength--; - } - - for (var i = 0; i < str.length; i++) - result += (hintCharacters.charAt(parseInt(str[i], hintCharacters.length))).toUpperCase(); - - return result; - } - - function setHintStyle(hintElem, styleString) - { - if (hintElem && hintElem.style) - { - xTemp = hintElem.style.left; - yTemp = hintElem.style.top; - hintElem.style.cssText = styleString; - hintElem.style.left = xTemp; - hintElem.style.top = yTemp; - } - } - - function changeHintFocus(linkNumString, oldLinkNumString) - { - var styleString = vimperator.options["hintstyle"]; - var styleStringFocus = vimperator.options["focusedhintstyle"]; - var hintElem; - - if (oldLinkNumString.length > 0) - { - hintElem = getHintById(oldLinkNumString); - setHintStyle(hintElem, styleString); - } - if (linkNumString.length > 0) - { - hintElem = getHintById(linkNumString); - setHintStyle(hintElem, styleStringFocus); - if (hintElem) - setMouseOverElement(hintElem.refElem); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // basic functionality - //////////////////////////////////////////////////////////////////////////////// - - /** - * Enables the HaH-mode by showing the hints and prepare to input the - * hint numbers - * - * @author Pekka Sillanpaa - * @param event that caused the mode to change - * @return -1 if already enabled - */ - // XXX: move to mode handling - this.enableHahMode = function(mode) - { - vimperator.modes.set(vimperator.modes.HINTS, mode); - state = 0; - linkCount = 0; - linkNumString = ''; - isHahModeEnabled = true; - - createHints(); - showHints(null, 0); - - return true; - }; - - /** - * Disables the HaH-mode by hiding the hints and disabling the input mode - * - * @author Pekka Sillanpaa - * @param event that caused the mode to change - * @param action = true if something is to be clicked - * false if cancel - * @return -1 if already disabled - */ - // XXX: move to mode handling - this.disableHahMode = function(win) - { - if (!isHahModeEnabled) - return; - - vimperator.modes.reset(); - - isHahModeEnabled = false; - linkNumString = ''; - hintedElems = []; - - removeHints(win); - return 0; - }; - - this.resetHintedElements = function() - { - linkNumString = ''; - state = 0; - - while (hintedElems.length > 0) - { - var elem = hintedElems.pop(); - if (!elem) - return 0; - // reset style attribute - setHintStyle(elem, vimperator.options["hintstyle"]); - } - }; - - this.reshowHints = function() - { - onResize(null); - - if (isHahModeEnabled) - { - removeHints(); - createHints(); - showHints(null, 0); - } - }; - - - // TODO: move these functions somewhere more general + var submode = ""; // used for extended mode, can be "o", "t", "y", etc. + + // hints[] = [elem, text, span, elem.style.backgroundColor, elem.style.color] + var hints = []; + var valid_hints = []; // store the indices of the "hints" array with valid elements + + var canUpdate = true; + var timeout = 200; // only update every 200ms when typing fast, not used yet // this function 'click' an element, which also works // for javascript links - this.openHints = function(new_tab, new_window) + function openHint(new_tab, new_window) { + if (valid_hints.length < 1) + return false; + var x = 0, y = 0; + var elem = valid_hints[0]; + var elemTagName = elem.tagName; + elem.focus(); - while (hintedElems.length > 0) - { - var elem = hintedElems.pop(); - if (!elem) - return 0; + if (elemTagName == 'FRAME' || elemTagName == 'IFRAME') + return 0; - setHintStyle(elem, vimperator.options["hintstyle"]); - elem = elem.refElem; - var elemTagName = elem.tagName; - elem.focus(); - - if (elemTagName == 'FRAME' || elemTagName == 'IFRAME') - return 0; - - // for imagemap - if (elemTagName == 'AREA') - { - var coords = elem.getAttribute("coords").split(","); - x = Number(coords[0]); - y = Number(coords[1]); - } - doc = window.content.document; - view = window.document.defaultView; - - var evt = doc.createEvent('MouseEvents'); - evt.initMouseEvent('mousedown', true, true, view, 1, x+1, y+1, 0, 0, /*ctrl*/ new_tab, /*event.altKey*/0, /*event.shiftKey*/ new_window, /*event.metaKey*/ new_tab, 0, null); - elem.dispatchEvent(evt); - - var evt = doc.createEvent('MouseEvents'); - evt.initMouseEvent('click', true, true, view, 1, x+1, y+1, 0, 0, /*ctrl*/ new_tab, /*event.altKey*/0, /*event.shiftKey*/ new_window, /*event.metaKey*/ new_tab, 0, null); - elem.dispatchEvent(evt); - - // for 'pure' open calls without a new tab or window it doesn't - // make sense to open more hints in the current tab, open new tabs - // for it - if (!new_tab && !new_window) - new_tab = true; - } - - return 0; - }; - - this.yankUrlHints = function() - { - var loc = ""; - var elems = this.hintedElements(); - var tmp = ""; - for (var i = 0; i < elems.length; i++) - { - tmp = elems[i].refElem.href; - if (typeof(tmp) != 'undefined' && tmp.length > 0) - { - if (i > 0) - loc += "\n"; - loc += tmp; - } - } - - // disable the hints before we can echo() an information - this.disableHahMode(null, true); - - vimperator.copyToClipboard(loc); - vimperator.echo("Yanked " + loc, vimperator.commandline.FORCE_SINGLELINE); - }; - - this.yankTextHints = function() - { - var loc = ""; - var elems = this.hintedElements(); - var tmp = ""; - for (var i = 0; i < elems.length; i++) - { - tmp = elems[i].refElem.textContent; - if (typeof(tmp) != 'undefined' && tmp.length > 0) - { - if (i > 0) - loc += "\n"; - loc += tmp; - } - } - - // disable the hints before we can echo() an information - this.disableHahMode(null, true); - - vimperator.copyToClipboard(loc); - vimperator.echo("Yanked " + loc, vimperator.commandline.FORCE_SINGLELINE); - }; - - this.saveHints = function(skip_prompt) - { - var elems = this.hintedElements(); - - for (var i = 0; i < elems.length; i++) - { - var doc = elems[i].ownerDocument; - var url = makeURLAbsolute(elems[i].refElem.baseURI, elems[i].refElem.href); - var text = elems[i].refElem.textContent; - - try - { - urlSecurityCheck(url, doc.nodePrincipal); - saveURL(url, text, null, true, skip_prompt, makeURI(url, doc.characterSet)); - } - catch (e) - { - vimperator.echoerr(e); - } - } - } - - function setMouseOverElement(elem) - { - var doc = window.document; - - if (elem.tagName == 'FRAME' || elem.tagName == 'IFRAME') - { - elem.contentWindow.focus(); - return; - } - //else - //{ - // elem.focus(); - //} - - var evt = doc.createEvent('MouseEvents'); - var x = 0; - var y = 0; // for imagemap - if (elem.tagName == 'AREA') + if (elemTagName == 'AREA') { var coords = elem.getAttribute("coords").split(","); x = Number(coords[0]); y = Number(coords[1]); } + doc = window.content.document; + view = window.document.defaultView; - evt.initMouseEvent('mouseover', true, true, doc.defaultView, 1, x, y, 0, 0, 0, 0, 0, 0, 0, null); + var evt = doc.createEvent('MouseEvents'); + evt.initMouseEvent('mousedown', true, true, view, 1, x+1, y+1, 0, 0, /*ctrl*/ new_tab, /*event.altKey*/0, /*event.shiftKey*/ new_window, /*event.metaKey*/ new_tab, 0, null); elem.dispatchEvent(evt); - } - //////////////////////////////////////////////////////////////////////////////// - // event handlers - //////////////////////////////////////////////////////////////////////////////// + var evt = doc.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, view, 1, x+1, y+1, 0, 0, /*ctrl*/ new_tab, /*event.altKey*/0, /*event.shiftKey*/ new_window, /*event.metaKey*/ new_tab, 0, null); + elem.dispatchEvent(evt); - // returns nr. of fully parsed links when a new hint has been found, - // otherwise 0 if current state is part of a hint, or -1 if an error occured - // (like we have typed keys which never can become a hint - this.processEvent = function(event) + return true; + }; + + function yankHint(text) { - if (!isHahModeEnabled) - return -1; + if (valid_hints.length < 1) + return false; - // reset state to show that we are in processing mode - state = 0; + if (text) + var loc = valid_hints[0].href; + else + var loc = valid_hints[0].textContent; - var num = String.fromCharCode(event.charCode).toUpperCase(); - var hintCharacters = vimperator.options["hintchars"]; - if (num != null && hintCharacters.toUpperCase().indexOf(num) > -1) + vimperator.copyToClipboard(loc); + vimperator.echo("Yanked " + loc, vimperator.commandline.FORCE_SINGLELINE); + }; + + function saveHint(skip_prompt) + { + if (valid_hints.length < 1) + return false; + + var elem = valid_hints[0]; + var doc = elem.ownerDocument; + var url = makeURLAbsolute(elem.baseURI, elem.href); + var text = elem.textContent; + + try { - var oldLinkNumString = linkNumString; - linkNumString += '' + num; - // update reference to currently selected node; - var elem = getHintById(linkNumString); - changeHintFocus(linkNumString, oldLinkNumString); - - // if we found the hint, fine just return it - if (elem) - { - hintedElems.push(elem); - linkNumString = ''; - state = 1; - return hintedElems.length; - } - - //calculate how many characters a hint must have - var hintLength = 1; - var tmp = linkCount; - while ((tmp /= hintCharacters.length) > 1.0) - hintLength++; - - if (linkNumString.length >= hintLength) - return -1; - else - return 0; + urlSecurityCheck(url, doc.nodePrincipal); + saveURL(url, text, null, true, skip_prompt, makeURI(url, doc.characterSet)); } - // an unparseable or wrong key - return -1; - } - - function genHintContainer(doc) - { - if (doc.getElementsByTagName('HINTS').length > 0) - return; - - hints = doc.createElement('HINTS'); - hints.id = "hah_hints"; - hints.valid_hint_count = 0; // initially 0 elements are usable as hints - - if (doc.body) - doc.body.appendChild(hints); - } - - function initDoc(event) - { - // vimperator.echoerr("Content loaded"); - - doc = event.originalTarget; - genHintContainer(doc); - isHahModeEnabled = false; - hintedElems = []; - - if (!doc.validCoords) - doc.validCoords = true; - else - doc.validCoords = false; - - // XXX: prepend a ! ? - if (doc.coordsInvalidated) - doc.coordsInvalidated = true; - else - doc.coordsInvalidated = false; - - startCoordLoader(doc); - - if (vimperator.modes.extended & vimperator.modes.ALWAYS_HINT) + catch (e) { - state = 0; - linkCount = 0; - linkNumString = ''; - isHahModeEnabled = true; - - setTimeout( function() { - createHints(); - showHints(null, 0); - }, 100); + vimperator.echoerr(e); } } - -// window.document.addEventListener("pageshow", function() { vimperator.log("pageshow"); }, null); - // FIXME: add resize support - //window.addEventListener("resize", onResize, null); - - getBrowser().addEventListener("DOMContentLoaded", function(event) { - if (vimperator.options["autohints"]) - vimperator.hints.show(event.target); - }, false); - this.show = function(doc, takenHints) + function generate(win) { - function getNextHintText(href) - { - var hintCharacters = "abcdefghijklmnopqrstuvwxyz123456789"; // no 0, as it looks too much like O - var len = hintCharacters.length; - var text = "aa"; - for (; nextHintFirstChar < len; nextHintFirstChar++) - { - for (; nextHintSecondChar < len; nextHintSecondChar++) - { - text = hintCharacters[nextHintFirstChar] + hintCharacters[nextHintSecondChar]; - if (typeof takenHints[text] === "undefined") - { - takenHints[text] = href; - return text.toUpperCase(); - } - } - nextHintSecondChar = 0; - } - vimperator.log("Too many hints on page"); - return null; - } + if (!win) + win = window.content; - if (!doc) - doc = window.content.document; - if (!takenHints) - takenHints = {}; + var doc = win.document; - var rel = 0, abs = 0, inl = 0, disc = 0; - var nextHintFirstChar = 0, nextHintSecondChar = 0; - - var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"] - .createInstance() - .QueryInterface(Components.interfaces.nsIFind); - finder.caseSensitive = false; - - var baseNodeInline = doc.createElementNS("http://www.w3.org/1999/xhtml", "span"); - baseNodeInline.style.backgroundColor = "#BCEE68"; - baseNodeInline.style.color = "black"; - baseNodeInline.style.display = "inline"; - baseNodeInline.style.fontSize = "inherit"; - baseNodeInline.style.padding = "0px"; - baseNodeInline.className = "vimperator-hint-inline"; var baseNodeAbsolute = doc.createElementNS("http://www.w3.org/1999/xhtml", "span"); - //baseNodeAbsolute.style.backgroundColor = "#BCEE68"; - baseNodeAbsolute.style.backgroundColor = "cyan"; - baseNodeAbsolute.style.color = "black"; + baseNodeAbsolute.style.backgroundColor = "red"; + baseNodeAbsolute.style.color = "white"; baseNodeAbsolute.style.position = "absolute"; baseNodeAbsolute.style.fontSize = "10px"; baseNodeAbsolute.style.fontWeight = "bold"; baseNodeAbsolute.style.lineHeight = "10px"; baseNodeAbsolute.style.padding = "0px 1px 0px 0px"; baseNodeAbsolute.style.zIndex = "5000"; - baseNodeAbsolute.className = "vimperator-hint-absolute"; + baseNodeAbsolute.className = "vimperator-hint"; - var scrollX = doc.defaultView.scrollX; - var scrollY = doc.defaultView.scrollY; - //var view = doc.defaultView; - - var retRange = null; - var searchRange = doc.createRange(); var res = vimperator.buffer.evaluateXPath(vimperator.options["hinttags"], doc, null, true); - var word, elem, tagname, count, href, text, lowertext; + var elem, tagname, text, span, rect; vimperator.log("Hinting " + res.snapshotLength + " items on " + doc.title); -outer: + + var height = window.content.innerHeight; + var width = window.content.innerWidth; + hints = []; + for (var i = 0; i < res.snapshotLength; i++) { - // the more often we check for firefox events, the slower it is - // best is checking between every 50-500 elements - if (i % 200 == 0) - { - Components.classes['@mozilla.org/thread-manager;1']. - getService().mainThread.processNextEvent(false); - - // update saved positions, as the user could have scrolled - scrollX = doc.defaultView.scrollX; - scrollY = doc.defaultView.scrollY; - vimperator.log(scrollY); - } - elem = res.snapshotItem(i); tagname = elem.tagName.toLowerCase(); + text = elem.textContent.toLowerCase(); + rect = elem.getBoundingClientRect(); + if (!rect || rect.bottom < 0 || rect.top > height || rect.right < 0 || rect.left > width) + continue; + rect = elem.getClientRects()[0]; + if (!rect) + continue; - //if (vimperator.buffer.evaluateXPath(".//*[@class='vimperator-hint-inline']", doc, elem).snapshotLength > 0 ) - // continue outer; - if (elem.getElementsByClassName("vimperator-hint-inline").length > 0) - continue outer; + span = baseNodeAbsolute.cloneNode(true); + span.innerHTML = ""; + span.style.display = "none"; + doc.body.appendChild(span); - count = elem.childNodes.length; - searchRange.setStart(elem, 0); - searchRange.setEnd(elem, count); - - // try to get a unique substring of the element - if (tagname == "input" || tagname == "textarea" || tagname == "select") - text = ""; - else - text = elem.textContent; // faster than searchRange.toString() + hints.push([elem, text, span, elem.style.backgroundColor, elem.style.color]); + } - href = elem.getAttribute("href"); - for (var j = 0; j < text.length - 1; j++) + return true; + } + + //this.show = function(doc, str, start_idx) + function showHints(win, str, start_idx) + { + if (!canUpdate) + return false; + + if (!win) + win = window.content; + if (!str) + str = ""; + + if (win.document.body.localName.toLowerCase() == "frameset") + { +// for (i = 0; i < win.frames.length; i++) +// removeHints(win.frames[i]); + vimperator.echo("hint support for frameset pages not fully implemented yet"); + } + + vimperator.log("Show hints matching: " + str, 7); + + var doc = win.document; + var scrollX = doc.defaultView.scrollX; + var scrollY = doc.defaultView.scrollY; + + var elem, tagname, text, rect, span; + var hintnum = start_idx > 0 ? start_idx : 1; + + var height = window.content.innerHeight; + var width = window.content.innerWidth; + var find_tokens = str.split(/ +/); + valid_hints = []; + +outer: + for (var i = 0; i < hints.length; i++) + { + elem = hints[i][0]; + text = hints[i][1]; + span = hints[i][2]; + //tagname = elem.tagName.toLowerCase(); + + for (var k = 0; k < find_tokens.length; k++) { - if (text.length < 2) - continue; - - word = text.substr(j, 2); - lowertext = word.toLowerCase(); - if (/[^a-z0-9]/.test(lowertext)) // 2x as fast as lowertext[0] > "a" etc. testing - continue; - - //dump(elem.tagname + " - " + text + ": " + word + "\n"); - - // hint not yet taken or taken and href the same - if (typeof(takenHints[lowertext]) === "undefined" || (href && takenHints[lowertext] == href)) - { - takenHints[lowertext] = href; - inl++; - - retRange = finder.Find(word, searchRange, searchRange, searchRange); - if (!retRange) - continue; - - var nodeSurround = baseNodeInline.cloneNode(true); - var startContainer = retRange.startContainer; - var startOffset = retRange.startOffset; - var docfrag = retRange.extractContents(); - var before = startContainer.splitText(startOffset); - var parent = before.parentNode; - nodeSurround.appendChild(docfrag); - parent.insertBefore(nodeSurround, before); + if (text.indexOf(find_tokens[k]) < 0) + { + //dump("NOT matching: " + text + "\n"); + elem.style.backgroundColor = hints[i][3]; + elem.style.color = hints[i][4]; + span.style.display = "none"; continue outer; } } - - // if we came here, there was no suitable inline hint, need - // to create an span relatively positioned to the element - if (tagname != "input" && tagname != "textarea" && tagname != "select") + //dump("MATCHING: " + text + "\n"); + elem.style.backgroundColor = "yellow"; + elem.style.color = "black"; + rect = elem.getClientRects()[0]; + if (rect) { - // heuristics to avoid duplicate relative hints for the same things: - // 1. a link with the same href in one of the next two elements - // this often is true for images which have a textlink right to it - // or a menu made up of a - if (i < res.snapshotLength-2) - { - if (href && href == res.snapshotItem(i+1).getAttribute("href") || - href == res.snapshotItem(i+2).getAttribute("href")) - { - disc++; - continue; - } - } - - elem.style.position = "relative"; - rel++; - var span = doc.createElement("span"); - span.setAttribute("style", "z-index: 5000; color:black; font-weight: bold; font-size: 10px; background-color:yellow; line-height: 10px; border: 0px; padding: 0px 1px 0px 0px; position: absolute; left: 0px; top: 0px"); - var hint = getNextHintText(href); - if (!hint) - return false; - span.innerHTML = hint; - //setTimeout(function() { elem.appendChild(span); }, 10); // 10ms delay to let firefox handle position=relative - elem.appendChild(span); + span.style.left = (rect.left + scrollX) + "px"; + span.style.top = rect.top + scrollY + "px"; + span.innerHTML = "" + (hintnum++); + span.style.display = "inline"; + valid_hints.push(elem); continue; } - else // absolute positioning - { - var rect = elem.getClientRects()[0]; - if (rect) - { - var span = baseNodeAbsolute.cloneNode(true); - var hint = getNextHintText(href); - if (!hint) - return false; - span.innerHTML = hint; - span.style.left = rect.left + scrollX + "px"; - span.style.top = rect.top + scrollY + "px"; - doc.body.appendChild(span); - abs++; - } - } } - vimperator.log("Hinted " + res.snapshotLength + " items on " + doc.title + " - inl: " + inl+ " rel: " + rel + " abs: " + abs + " discard: " + disc, 7); + + vimperator.log("Hinted " + valid_hints.length + " items of " + hints.length + " matching " + str, 7); return true; } - + + function hideHints(win) + { + if (!win) + win = window.content; + + for (var i = 0; i < hints.length; i++) + { + // remove the span for the numeric display part + win.document.body.removeChild(hints[i][2]); + + // restore colors + var elem = hints[i][0]; + elem.style.backgroundColor = hints[i][3]; + elem.style.color = hints[i][4]; + } + }; + + //////////////////////////////////////////////////////////////////////////////// + ////////////////////// PUBLIC SECTION ////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + // TODO: implement framesets + this.show = function(mode, minor) + { + if (mode == vimperator.modes.EXTENDED_HINT && !/^[aoOstTwWyY]$/.test(minor)) + { + vimperator.beep(); + return; + } + + vimperator.modes.set(vimperator.modes.HINTS, mode); + submode = minor; + linkNumString = ""; + canUpdate = false; + + generate(); + // get all keys from the input queue + var mt = Components.classes['@mozilla.org/thread-manager;1'].getService().mainThread; + while (mt.hasPendingEvents()) + mt.processNextEvent(true); + + canUpdate = true; + showHints(null, linkNumString); + return true; + }; + + // does not end the mode automatically + this.hide = function() + { + hideHints(); + + linkNumString = ""; + hints = []; + valid_hints = []; + canUpdate = false; + + return 0; + }; + + this.onEvent = function(event) + { + var num = String.fromCharCode(event.charCode).toLowerCase(); + linkNumString += "" + num; + //setTimeout( function() { canUpdate = true; }, timeout); + vimperator.statusline.updateInputBuffer(linkNumString); + showHints(null, linkNumString); + + if (valid_hints.length == 0) + vimperator.beep(); + else if (valid_hints.length >= 1) + { + var first_href = valid_hints[0].getAttribute("href"); + if (!first_href || valid_hints.some( function(e) { return e.getAttribute("href") != first_href; } )) + return; + + vimperator.echo(" "); + vimperator.statusline.updateInputBuffer(""); + + if (vimperator.modes.extended & vimperator.modes.QUICK_HINT) + openHint(false, false); + else + { + var loc = valid_hints.length > 0 ? valid_hints[0].href : ""; + switch (submode) + { + case "o": openHint(false, false); break; + case "O": vimperator.commandline.open(":", "open " + loc, vimperator.modes.EX); break; + case "t": openHint(true, false); break; + case "T": openHint(true, false); break; + case "T": vimperator.commandline.open(":", "tabopen " + loc, vimperator.modes.EX); break; + case "w": openHint(false, true); break; + case "W": vimperator.commandline.open(":", "winopen " + loc, vimperator.modes.EX); break; + case "a": saveHint(false); break; + case "s": saveHint(true); break; + case "y": yankHint(false); break; + case "Y": yankHint(true); break; + default: + vimperator.echoerr("INTERNAL ERROR: unknown submode: " + submode); + } + } + + this.hide(); + // only close this mode half a second later, so we don't trigger accidental actions so easily + setTimeout( function() { if (vimperator.mode == vimperator.modes.HINTS) vimperator.modes.reset(true); }, 500); + } + } + + + // FIXME: add resize support + //window.addEventListener("resize", onResize, null); + + // getBrowser().addEventListener("DOMContentLoaded", function(event) { + // if (vimperator.options["autohints"]) + // vimperator.hints.show(event.target); + // }, false); + +// function onResize(event) +// { +// if (event) +// doc = event.originalTarget; +// else +// doc = window.content.document; +// } +// +// this.reshowHints = function() +// { +// onResize(null); +// }; +// +// +// function setMouseOverElement(elem) +// { +// var doc = window.document; +// +// if (elem.tagName == 'FRAME' || elem.tagName == 'IFRAME') +// { +// elem.contentWindow.focus(); +// return; +// } +// //else +// //{ +// // elem.focus(); +// //} +// +// var evt = doc.createEvent('MouseEvents'); +// var x = 0; +// var y = 0; +// // for imagemap +// if (elem.tagName == 'AREA') +// { +// var coords = elem.getAttribute("coords").split(","); +// x = Number(coords[0]); +// y = Number(coords[1]); +// } +// +// evt.initMouseEvent('mouseover', true, true, doc.defaultView, 1, x, y, 0, 0, 0, 0, 0, 0, 0, null); +// elem.dispatchEvent(evt); +// } + } //}}} // vim: set fdm=marker sw=4 ts=4 et: diff --git a/content/mappings.js b/content/mappings.js index 4b6ff8db..d8151d06 100644 --- a/content/mappings.js +++ b/content/mappings.js @@ -1020,18 +1020,21 @@ vimperator.Mappings = function() //{{{ // hint managment addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], ["f"], - function() { vimperator.hints.enableHahMode(vimperator.modes.QUICK_HINT); }, + function() { vimperator.hints.show(vimperator.modes.QUICK_HINT); }, { short_help: "Start QuickHint mode", - help: "In QuickHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a label.
" + - "If you then press the keys for a label, it is followed as soon as it can be uniquely identified and this mode is stopped. Or press <Esc> to stop this mode.
" + - "If you write the hint in ALLCAPS, the hint is followed in a background tab." + usage: ["f{hint}"], + help: "In QuickHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a unique number (FIXME: numbers shown, but not usable yet).
" + + "You can now either type this number or type any part of the URL which you want to follow, and it is followed as soon as it can be uniquely identified. " + + //"If you write the hint in ALLCAPS, the hint is followed in a background tab.
" + + "Often it is can be useful to combine these techniques to narrow down results with some letters, and then typing a single digit to make the match unique.
" + + "<Esc> stops this mode at any time." } )); addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], ["F"], - function() { vimperator.hints.enableHahMode(vimperator.modes.ALWAYS_HINT); }, + function() { vimperator.echo("Always HINT mode not available anymore"); }, { - short_help: "Start AlwaysHint mode", + short_help: "Start AlwaysHint mode (CURRENTLY DISABLED)", help: "In AlwaysHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a label.
" + "If you then press the keys for a label, it is followed as soon as it can be uniquely identified. Labels stay active after following a hint in this mode, press <Esc> to stop this mode.
" + "This hint mode is especially useful for browsing large sites like Forums as hints are automatically regenerated when switching to a new document.
" + @@ -1039,26 +1042,28 @@ vimperator.Mappings = function() //{{{ } )); addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], [";"], - function() { vimperator.hints.enableHahMode(vimperator.modes.EXTENDED_HINT); }, + function(arg) { vimperator.hints.show(vimperator.modes.EXTENDED_HINT, arg); }, { short_help: "Start ExtendedHint mode", - help: "ExtendedHint mode is useful, since in this mode you can yank link locations, or open them in a new window.
" + - "E.g., if you want to yank the location of hint AB, press ; to start this hint mode.
" + - "Then press AB to select the hint. Now press y to yank its location.
" + - "Actions for selected hints in ExtendedHint mode are:
" + + usage: [";{mode}{hint}"], + help: "ExtendedHint mode is useful, since in this mode you can yank link locations, open them in a new window or save images.
" + + "If you want to yank the location of hint 24, press ;y to start this hint mode.
" + + "Then press 24 to copy the hint location.
" + + "{mode} can be either of:
" + "
    " + - "
  • y to yank its location
  • " + - "
  • Y to yank its text description
  • " + + "
  • a to save its destination (prompting for save location)
  • " + + "
  • s to save its destination
  • " + "
  • o to open its location in the current tab
  • " + "
  • t to open its location in a new tab
  • " + - "
  • O to open its location in an :open query (not implemented yet)
  • " + - "
  • T to open its location in an :tabopen query (not implemented yet)
  • " + - "
  • s to save its destination
  • " + - "
  • a to save its destination (prompting for save location)
  • " + - "
  • <C-w> to open its destination in a new window
  • " + + "
  • O to open its location in an :open query
  • " + + "
  • T to open its location in a :tabopen query
  • " + + "
  • y to yank its location
  • " + + "
  • Y to yank its text description
  • " + + "
  • w to open its destination in a new window
  • " + + "
  • W to open its location in a :winopen query
  • " + "
" + - "Multiple hints can be separated by commas where it makes sense. ;ab,ac,adt opens AB, AC and AD in a new tab.
" + - "Hintable elements for this mode can be set in the 'extendedhinttags' XPath string." + "Hintable elements for this mode can be set in the 'extendedhinttags' XPath string.", + flags: vimperator.Mappings.flags.ARGUMENT } )); @@ -1108,230 +1113,230 @@ vimperator.Mappings = function() //{{{ // Hints mode // {{{ - // action keys - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["o"], - function() { vimperator.hints.openHints(false, false); }, - { - cancel_mode: true, - always_active: false - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["t"], - function() { vimperator.hints.openHints(true, false); }, - { - cancel_mode: true, - always_active: false - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.hints.openHints(false, true ); }, - { - cancel_mode: true, - always_active: false - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["s"], - function() { vimperator.hints.saveHints(true); }, - { - cancel_mode: true, - always_active: false - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["a"], - function() { vimperator.hints.saveHints(false); }, - { - cancel_mode: true, - always_active: false - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["y"], - function() { vimperator.hints.yankUrlHints(); }, - { - cancel_mode: true, - always_active: false - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["Y"], - function() { vimperator.hints.yankTextHints(); }, - { - cancel_mode: true, - always_active: false - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [","], - function() { vimperator.input.buffer += ','; vimperator.hints.setCurrentState(0); }, - { - cancel_mode: false, - always_active: true - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [":"], - function() { vimperator.commandline.open(':', '', vimperator.modes.EX); }, - { - cancel_mode: false, - always_active: true - } - )); - - // movement keys - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function(count) { vimperator.buffer.scrollLines(count > 1 ? count : 1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function(count) { vimperator.buffer.scrollLines(-(count > 1 ? count : 1)); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.buffer.scrollTop(); }, - { - cancel_mode: false, - always_active: true - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.buffer.scrollBottom(); }, - { - cancel_mode: false, - always_active: true - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["", ""], - function(count) { vimperator.buffer.scrollPages(-(count > 1 ? count : 1)); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["", ""], - function(count) { vimperator.buffer.scrollPages(count > 1 ? count : 1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.buffer.scrollColumns(-(count > 1 ? count : 1)); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.buffer.scrollLines(count > 1 ? count : 1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.buffer.scrollLines(-(count > 1 ? count : 1)); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.buffer.scrollColumns(count > 1 ? count : 1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - - // tab management - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.tabs.select('+1', true); }, - { - cancel_mode: true, - always_active: true - } - )); // same as gt, but no count supported - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.tabs.select('-1', true); }, - { - cancel_mode: true, - always_active: true - } - )); - - // navigation - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function(count) { vimperator.history.stepTo(count > 0 ? -count : -1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function(count) { vimperator.history.stepTo(count > 1 ? count : 1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function(count) { vimperator.history.stepTo(count > 0 ? -count : -1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function(count) { vimperator.history.stepTo(count > 1 ? count : 1); }, - { - cancel_mode: false, - always_active: true, - flags: vimperator.Mappings.flags.COUNT - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { vimperator.tabs.remove(getBrowser().mCurrentTab, vimperator.input.count, false, 0); }, - { - cancel_mode: true, - always_active: true - } - )); - - // cancel_mode hint mode keys - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { ; }, - { - cancel_mode: true, - always_active: true - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { ; }, - { - cancel_mode: true, - always_active: true - } - )); - addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], - function() { ; }, - { - cancel_mode: true, - always_active: true - } - )); +// // action keys +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["o"], +// function() { vimperator.hints.openHints(false, false); }, +// { +// cancel_mode: true, +// always_active: false +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["t"], +// function() { vimperator.hints.openHints(true, false); }, +// { +// cancel_mode: true, +// always_active: false +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.hints.openHints(false, true ); }, +// { +// cancel_mode: true, +// always_active: false +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["s"], +// function() { vimperator.hints.saveHints(true); }, +// { +// cancel_mode: true, +// always_active: false +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["a"], +// function() { vimperator.hints.saveHints(false); }, +// { +// cancel_mode: true, +// always_active: false +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["y"], +// function() { vimperator.hints.yankUrlHints(); }, +// { +// cancel_mode: true, +// always_active: false +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["Y"], +// function() { vimperator.hints.yankTextHints(); }, +// { +// cancel_mode: true, +// always_active: false +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [","], +// function() { vimperator.input.buffer += ','; vimperator.hints.setCurrentState(0); }, +// { +// cancel_mode: false, +// always_active: true +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [":"], +// function() { vimperator.commandline.open(':', '', vimperator.modes.EX); }, +// { +// cancel_mode: false, +// always_active: true +// } +// )); +// +// // movement keys +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function(count) { vimperator.buffer.scrollLines(count > 1 ? count : 1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function(count) { vimperator.buffer.scrollLines(-(count > 1 ? count : 1)); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.buffer.scrollTop(); }, +// { +// cancel_mode: false, +// always_active: true +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.buffer.scrollBottom(); }, +// { +// cancel_mode: false, +// always_active: true +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["", ""], +// function(count) { vimperator.buffer.scrollPages(-(count > 1 ? count : 1)); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], ["", ""], +// function(count) { vimperator.buffer.scrollPages(count > 1 ? count : 1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.buffer.scrollColumns(-(count > 1 ? count : 1)); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.buffer.scrollLines(count > 1 ? count : 1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.buffer.scrollLines(-(count > 1 ? count : 1)); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.buffer.scrollColumns(count > 1 ? count : 1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// +// // tab management +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.tabs.select('+1', true); }, +// { +// cancel_mode: true, +// always_active: true +// } +// )); // same as gt, but no count supported +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.tabs.select('-1', true); }, +// { +// cancel_mode: true, +// always_active: true +// } +// )); +// +// // navigation +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function(count) { vimperator.history.stepTo(count > 0 ? -count : -1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function(count) { vimperator.history.stepTo(count > 1 ? count : 1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function(count) { vimperator.history.stepTo(count > 0 ? -count : -1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function(count) { vimperator.history.stepTo(count > 1 ? count : 1); }, +// { +// cancel_mode: false, +// always_active: true, +// flags: vimperator.Mappings.flags.COUNT +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { vimperator.tabs.remove(getBrowser().mCurrentTab, vimperator.input.count, false, 0); }, +// { +// cancel_mode: true, +// always_active: true +// } +// )); +// +// // cancel_mode hint mode keys +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { ; }, +// { +// cancel_mode: true, +// always_active: true +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { ; }, +// { +// cancel_mode: true, +// always_active: true +// } +// )); +// addDefaultMap(new vimperator.Map([vimperator.modes.HINTS], [""], +// function() { ; }, +// { +// cancel_mode: true, +// always_active: true +// } +// )); // }}} // Caret mode diff --git a/content/modes.js b/content/modes.js index 5d43ffa2..c0e9f3b3 100644 --- a/content/modes.js +++ b/content/modes.js @@ -71,6 +71,10 @@ vimperator.modes = (function() } } + // XXX: Pay attention that you don't run into endless loops + // Usually you should only indicate to leave a special mode linke HINTS + // by calling vimperator.modes.reset() and adding the stuff which is needed + // for its cleanup here function handleModeChange(oldmode, newmode) { vimperator.log("switching from mode " + oldmode + " to mode " + newmode, 7); @@ -96,13 +100,13 @@ vimperator.modes = (function() break; case vimperator.modes.HINTS: - // XXX: for now this does not work, but later it should be here - // vimperator.hints.disableHahMode(); + vimperator.hints.hide(); break; } if (newmode == vimperator.modes.NORMAL) { + // XXX: why this code? var value = vimperator.options.getFirefoxPref("accessibility.browsewithcaret", false); if (value) vimperator.options.setFirefoxPref("accessibility.browsewithcaret", false);