diff --git a/content/events.js b/content/events.js index 991bf8a1..a256d46c 100644 --- a/content/events.js +++ b/content/events.js @@ -57,7 +57,7 @@ vimperator.Events = function() //{{{ vimperator.statusline.updateTabCount(); vimperator.buffer.updateBufferList(); vimperator.tabs.updateSelectionHistory(); - setTimeout(vimperator.focusContent, 10); // just make sure, that no widget has focus + setTimeout(function() { vimperator.focusContent(true); }, 10); // just make sure, that no widget has focus }, false); // this adds an event which is is called on each page load, even if the @@ -490,7 +490,8 @@ vimperator.Events = function() //{{{ switch (vimperator.mode) { case vimperator.modes.HINTS: - vimperator.modes.reset(); + case vimperator.modes.COMMAND_LINE: + vimperator.modes.reset(); break; case vimperator.modes.VISUAL: @@ -510,13 +511,12 @@ vimperator.Events = function() //{{{ if ((vimperator.modes.extended & vimperator.modes.TEXTAREA) && !vimperator.options["insertmode"]) vimperator.mode = vimperator.modes.TEXTAREA; else + { vimperator.modes.reset(); + vimperator.focusContent(true); + } break; - case vimperator.modes.COMMAND_LINE: - vimperator.commandline.close(); - vimperator.modes.reset(); - break; default: // clear any selection made @@ -527,6 +527,7 @@ vimperator.Events = function() //{{{ vimperator.commandline.clear(); vimperator.modes.reset(); + vimperator.focusContent(true); } } } @@ -614,18 +615,11 @@ vimperator.Events = function() //{{{ // FIXME: should be handled properly! if (key != "" && key != "") { -// // 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) { 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; } } diff --git a/content/find.js b/content/find.js index cf00092d..da30e914 100644 --- a/content/find.js +++ b/content/find.js @@ -208,15 +208,15 @@ vimperator.Search = function() //{{{ if (vimperator.options["hlsearch"]) this.highlight(search_string); - vimperator.modes.set(vimperator.modes.NORMAL, null, true); + vimperator.modes.reset(); } - // Called when the search is cancelled - for example if someone presses + // Called when the search is canceled - for example if someone presses // escape while typing a search this.searchCanceled = function() { - vimperator.modes.reset(); - //vimperator.focusContent(); + this.clear(); + // TODO: code to reposition the document to the place before search started } // this is not dependent on the value of 'hlsearch' diff --git a/content/hints.js b/content/hints.js index 75e64ca8..12056745 100644 --- a/content/hints.js +++ b/content/hints.js @@ -38,6 +38,8 @@ vimperator.Hints = function() //{{{ var canUpdate = true; var timeout = 200; // only update every 200ms when typing fast, not used yet + var wins = []; // keep track of the windows which we display the hints for + // this function 'click' an element, which also works // for javascript links function openHint(new_tab, new_window) @@ -146,6 +148,7 @@ vimperator.Hints = function() //{{{ win = window.content; var doc = win.document; + wins.push(doc); var baseNodeAbsolute = doc.createElementNS("http://www.w3.org/1999/xhtml", "span"); baseNodeAbsolute.style.backgroundColor = "red"; @@ -201,12 +204,8 @@ vimperator.Hints = function() //{{{ 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) @@ -239,25 +238,28 @@ outer: 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.indexOf(find_tokens[k]) < 0) { - //dump("NOT matching: " + text + "\n"); + // reset background color elem.style.backgroundColor = hints[i][3]; elem.style.color = hints[i][4]; span.style.display = "none"; continue outer; } } - //dump("MATCHING: " + text + "\n"); - elem.style.backgroundColor = "yellow"; - elem.style.color = "black"; + rect = elem.getClientRects()[0]; if (rect) { + if (hintnum == 1) + elem.style.backgroundColor = "#88FF00"; + else + elem.style.backgroundColor = "yellow"; + + elem.style.color = "black"; span.style.left = (rect.left + scrollX) + "px"; span.style.top = rect.top + scrollY + "px"; span.innerHTML = "" + (hintnum++); @@ -271,127 +273,94 @@ outer: return true; } - function hideHints(win) + function removeHints(doc, timeout) { - if (!win) - win = window.content; + if (!doc) + { + vimperator.log("Argument doc is required for internal removeHints() method", 9); + return; + } + var firstElem = valid_hints[0] || null; + var firstElemBgColor = ""; + var firstElemColor = ""; try { for (var i = 0; i < hints.length; i++) { // remove the span for the numeric display part - win.document.body.removeChild(hints[i][2]); + doc.body.removeChild(hints[i][2]); - // restore colors - var elem = hints[i][0]; - elem.style.backgroundColor = hints[i][3]; - elem.style.color = hints[i][4]; - } - } - catch(e) { vimperator.log("Error hiding hints, probably wrong window"); } - }; - - //////////////////////////////////////////////////////////////////////////////// - ////////////////////// PUBLIC SECTION ////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// - - // TODO: implement framesets - this.show = function(mode, minor) - { - if (mode == vimperator.modes.EXTENDED_HINT && !/^[afoOstTwWyY]$/.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 key = vimperator.events.toString(event); - var endAfterThisKey = false; - switch (key) - { - case "": - endAfterThisKey = true; - //if (valid_hints.length == 0) - //{ - // vimperator.beep(); - // vimperator.modes.reset(); - // return; - //} - //else - // valid_hints = [valid_hints[0]]; - break; - - case "": - linkNumString += " "; - break; - - case "": - if (linkNumString = "") + if (timeout && firstElem == hints[i][0]) { - vimperator.beep(); - return; + firstElemBgColor = hints[i][3]; + firstElemColor = hints[i][4]; } else - linkNumString = linkNumString.substr(0, linkNumString.length-1); - break; + { + // restore colors + var elem = hints[i][0]; + elem.style.backgroundColor = hints[i][3]; + elem.style.color = hints[i][4]; + } + } - default: - linkNumString += key; + // animate the disappearance of the first hint + if (timeout && firstElem) + { +// USE THIS FOR MAKING THE SELECTED ELEM RED +// firstElem.style.backgroundColor = "red"; +// firstElem.style.color = "white"; +// setTimeout(function() { +// firstElem.style.backgroundColor = firstElemBgColor; +// firstElem.style.color = firstElemColor; +// }, 200); +// OR USE THIS FOR BLINKING: +// var counter = 0; +// var id = setInterval(function() { +// firstElem.style.backgroundColor = "red"; +// if (counter % 2 == 0) +// firstElem.style.backgroundColor = "yellow"; +// else +// firstElem.style.backgroundColor = "#88FF00"; +// +// if (counter++ >= 2) +// { +// firstElem.style.backgroundColor = firstElemBgColor; +// firstElem.style.color = firstElemColor; +// clearTimeout(id); +// } +// }, 100); + setTimeout(function() { + firstElem.style.backgroundColor = firstElemBgColor; + firstElem.style.color = firstElemColor; + }, timeout); + } } + catch (e) { vimperator.log("Error hiding hints, probably wrong window"); } + }; - vimperator.statusline.updateInputBuffer(linkNumString); - showHints(null, linkNumString); - + function processHints(followFirst) + { if (valid_hints.length == 0) + { vimperator.beep(); + return false; + } else { - if (!endAfterThisKey) + if (!followFirst) { var first_href = valid_hints[0].getAttribute("href") || null; if (first_href) { if (valid_hints.some( function(e) { return e.getAttribute("href") != first_href; } )) - return; + return false; } else if (valid_hints.length > 1) - return; + return false; } - vimperator.echo(" "); - vimperator.statusline.updateInputBuffer(""); - if (vimperator.modes.extended & vimperator.modes.QUICK_HINT) openHint(false, false); else @@ -412,17 +381,117 @@ outer: case "y": yankHint(false); break; case "Y": yankHint(true); break; default: - vimperator.echoerr("INTERNAL ERROR: unknown submode: " + submode); + 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 - // XXX: currently closes SELECT fields, need have an own mode for that - setTimeout( function() { - if (vimperator.mode == vimperator.modes.HINTS) - vimperator.modes.reset(true); - }, endAfterThisKey ? 0 : 500); + // I KNOW, ugly but this. is not available in this context :( + vimperator.hints.hide(null, !followFirst); + } + return true; + }; + + //////////////////////////////////////////////////////////////////////////////// + ////////////////////// PUBLIC SECTION ////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + // TODO: implement framesets + this.show = function(mode, minor, filter) + { + if (mode == vimperator.modes.EXTENDED_HINT && !/^[afoOstTwWyY]$/.test(minor)) + { + vimperator.beep(); + return; + } + + vimperator.modes.set(vimperator.modes.HINTS, mode); + submode = minor; + linkNumString = filter || ""; + 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); + if (valid_hints.length == 0) + { + vimperator.beep(); + vimperator.modes.reset(); + return false; + } + else if (valid_hints.length == 1) + { + processHints(true); + return false; + } + else // still hints visible + return true; + }; + + this.hide = function(win, delayModeChange) + { + var timeout = delayModeChange ? 500 : 0; + doc = wins.pop(); + if(doc); + removeHints(doc, timeout); + + vimperator.echo(" "); + vimperator.statusline.updateInputBuffer(""); + + linkNumString = ""; + hints = []; + valid_hints = []; + canUpdate = false; + + // 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); + }, timeout); + }; + + this.onEvent = function(event) + { + var key = vimperator.events.toString(event); + var followFirst = false; + switch (key) + { + case "": + followFirst = true; + break; + + case "": + linkNumString += " "; + break; + + case "": + if (linkNumString == "") + { + vimperator.beep(); + return; + } + else + linkNumString = linkNumString.substr(0, linkNumString.length-1); + break; + + case "": + case "": + linkNumString = ""; + break; + + default: + linkNumString += key; + } + + vimperator.statusline.updateInputBuffer(linkNumString); + if (canUpdate) + { + showHints(null, linkNumString); + processHints(followFirst); } } @@ -442,13 +511,6 @@ outer: // else // doc = window.content.document; // } -// -// this.reshowHints = function() -// { -// onResize(null); -// }; -// -// } //}}} diff --git a/content/modes.js b/content/modes.js index 340f512d..d0ddb2ac 100644 --- a/content/modes.js +++ b/content/modes.js @@ -102,6 +102,10 @@ vimperator.modes = (function() case vimperator.modes.HINTS: vimperator.hints.hide(); break; + + case vimperator.modes.COMMAND_LINE: + vimperator.commandline.close(); + break; } if (newmode == vimperator.modes.NORMAL) @@ -112,8 +116,7 @@ vimperator.modes = (function() vimperator.options.setFirefoxPref("accessibility.browsewithcaret", false); vimperator.statusline.updateUrl(); - // XXX: auto-focusing breaks hints partly, find a good solution - vimperator.focusContent(); + vimperator.focusContent(false); } } diff --git a/content/ui.js b/content/ui.js index 0aceb571..578d85cd 100644 --- a/content/ui.js +++ b/content/ui.js @@ -284,7 +284,6 @@ vimperator.CommandLine = function() //{{{ { var res = vimperator.triggerCallback("cancel", cur_extended_mode); history.add(this.getCommand()); - //vimperator.modes.set(old_mode, old_extended_mode); vimperator.statusline.updateProgress(""); // we may have a "match x of y" visible this.clear(); } diff --git a/content/vimperator.js b/content/vimperator.js index eaa548bd..b71ba8a4 100644 --- a/content/vimperator.js +++ b/content/vimperator.js @@ -148,15 +148,16 @@ const vimperator = (function() //{{{ }, // after pressing Escape, put focus on a non-input field of the browser document - focusContent: function() + // if clearFocusedElement, also blur a focused link + focusContent: function(clearFocusedElement) { var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]. getService(Components.interfaces.nsIWindowWatcher); - if (window == ww.activeWindow && document.commandDispatcher.focusedElement) + if (window == ww.activeWindow && document.commandDispatcher.focusedElement && clearFocusedElement) document.commandDispatcher.focusedElement.blur(); - content.focus(); // FIXME: shouldn't be window.document.content? + content.focus(); }, // partial sixth level expression evaluation