diff --git a/.hgignore b/.hgignore index 40d211a3..93349ece 100644 --- a/.hgignore +++ b/.hgignore @@ -11,6 +11,8 @@ syntax: glob */locale/*/*.html */chrome */contrib/vim/*.vba +*/bak/* +downloads/* ## Editor backup and swap files *~ diff --git a/common/content/autocommands.js b/common/content/autocommands.js index 36750b75..a273b16b 100644 --- a/common/content/autocommands.js +++ b/common/content/autocommands.js @@ -271,9 +271,9 @@ const AutoCommands = Module("autocommands", { completer: function () config.autocommands.concat([["all", "All events"]]) }); - options.add(["focuscontent", "fc"], - "Try to stay in normal mode after loading a web page", - "boolean", false); + options.add(["strictfocus", "sf"], + "Prevent scripts from focusing input elements without user intervention", + "boolean", true); } }); diff --git a/common/content/buffer.js b/common/content/buffer.js index a656ff6f..be2362bf 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -200,19 +200,7 @@ const Buffer = Module("buffer", { // any buffer, even in a background tab doc.pageIsFullyLoaded = 1; - // code which is only relevant if the page load is the current tab goes here: - if (doc == config.browser.contentDocument) { - // we want to stay in command mode after a page has loaded - // TODO: move somewhere else, as focusing can already happen earlier than on "load" - if (options["focuscontent"]) { - setTimeout(function () { - let focused = liberator.focus; - if (focused && (focused.value != null) && focused.value.length == 0) - focused.blur(); - }, 0); - } - } - else // background tab + if (doc != config.browser.contentDocument) liberator.echomsg("Background tab loaded: " + doc.title || doc.location.href, 3); this._triggerLoadAutocmd("PageLoad", doc); @@ -474,6 +462,18 @@ const Buffer = Module("buffer", { return String(selection); }, + /** + * Returns true if a scripts are allowed to focus the given input + * element or input elements in the given window. + * + * @param {Node|Window} + * @returns {boolean} + */ + focusAllowed: function (elem) { + let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem; + return !options["strictfocus"] || elem.liberatorFocusAllowed; + }, + /** * Focuses the given element. In contrast to a simple * elem.focus() call, this function works for iframes and @@ -483,7 +483,10 @@ const Buffer = Module("buffer", { */ focusElement: function (elem) { let doc = window.content.document; - if (elem instanceof HTMLFrameElement || elem instanceof HTMLIFrameElement) + let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem; + win.liberatorFocusAllowed = true; + + if (isinstance(elem, [HTMLFrameElement, HTMLIFrameElement])) elem.contentWindow.focus(); else if (elem instanceof HTMLInputElement && elem.type == "file") { Buffer.openUploadPrompt(elem); diff --git a/common/content/events.js b/common/content/events.js index a22785eb..4ec214d2 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -103,32 +103,16 @@ const Events = Module("events", { } }, 100); - function wrapListener(method) { - return function (event) { - try { - self[method](event); - } - catch (e) { - if (e.message == "Interrupted") - liberator.echoerr("Interrupted"); - else - liberator.echoerr("Processing " + event.type + " event: " + (e.echoerr || e)); - liberator.reportError(e); - } - }; - } - - this._wrappedOnKeyPress = wrapListener("onKeyPress"); - this._wrappedOnKeyUpOrDown = wrapListener("onKeyUpOrDown"); - this.addSessionListener(window, "keypress", this.closure._wrappedOnKeyPress, true); - this.addSessionListener(window, "keydown", this.closure._wrappedOnKeyUpOrDown, true); - this.addSessionListener(window, "keyup", this.closure._wrappedOnKeyUpOrDown, true); - this._activeMenubar = false; - this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true); - this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true); this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true); this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true); + this.addSessionListener(window, "focus", this.wrapListener(this.closure.onFocus), true); + this.addSessionListener(window, "keydown", this.wrapListener(this.closure.onKeyUpOrDown), true); + this.addSessionListener(window, "keypress", this.wrapListener(this.closure.onKeyPress), true); + this.addSessionListener(window, "keyup", this.wrapListener(this.closure.onKeyUpOrDown), true); + this.addSessionListener(window, "mousedown", this.wrapListener(this.closure.onMouseDown), true); + this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true); + this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true); this.addSessionListener(window, "resize", this.closure.onResize, true); }, @@ -151,10 +135,28 @@ const Events = Module("events", { */ addSessionListener: function (target, event, callback, capture) { let args = Array.slice(arguments, 0); - target.addEventListener.apply(target, args.slice(1)); + target.addEventListener.apply(args[0], args.slice(1)); this.sessionListeners.push(args); }, + /** + * Wraps an event listener to ensure that errors are reported. + */ + wrapListener: function wrapListener(method, self) { + return function (event) { + try { + method.apply(self, arguments); + } + catch (e) { + if (e.message == "Interrupted") + liberator.echoerr("Interrupted"); + else + liberator.echoerr("Processing " + event.type + " event: " + (e.echoerr || e)); + liberator.reportError(e); + } + }; + }, + /** * @property {boolean} Whether synthetic key events are currently being * processed. @@ -651,89 +653,14 @@ const Events = Module("events", { return ret; }, - // argument "event" is deliberately not used, as i don't seem to have - // access to the real focus target - // Huh? --djk - onFocusChange: function (event) { - // command line has it's own focus change handler - if (liberator.mode == modes.COMMAND_LINE) - return; - - function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument - - let win = window.document.commandDispatcher.focusedWindow; - let elem = window.document.commandDispatcher.focusedElement; - - if (win && win.top == content && liberator.has("tabs")) - tabs.localStore.focusedFrame = win; - - try { - if (elem && elem.readOnly) - return; - - if ((elem instanceof HTMLInputElement && /^(search|text|password)$/.test(elem.type)) || - (elem instanceof HTMLSelectElement)) { - liberator.mode = modes.INSERT; - if (hasHTMLDocument(win)) - buffer.lastInputField = elem; - return; - } - if (elem instanceof HTMLEmbedElement || elem instanceof HTMLObjectElement) { - liberator.mode = modes.EMBED; - return; - } - - if (elem instanceof HTMLTextAreaElement || (elem && elem.contentEditable == "true")) { - if (options["insertmode"]) - modes.set(modes.INSERT); - else if (elem.selectionEnd - elem.selectionStart > 0) - modes.set(modes.VISUAL, modes.TEXTAREA); - else - modes.main = modes.TEXTAREA; - if (hasHTMLDocument(win)) - buffer.lastInputField = elem; - return; - } - - if (config.focusChange) { - config.focusChange(win); - return; - } - - let urlbar = document.getElementById("urlbar"); - if (elem == null && urlbar && urlbar.inputField == this._lastFocus) - liberator.threadYield(true); - - if (liberator.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL)) - modes.reset(); - } - finally { - this._lastFocus = elem; - } + onDOMMenuBarActive: function () { + this._activeMenubar = true; + modes.add(modes.MENU); }, - onSelectionChange: function (event) { - let couldCopy = false; - let controller = document.commandDispatcher.getControllerForCommand("cmd_copy"); - if (controller && controller.isCommandEnabled("cmd_copy")) - couldCopy = true; - - if (liberator.mode != modes.VISUAL) { - if (couldCopy) { - if ((liberator.mode == modes.TEXTAREA || - (modes.extended & modes.TEXTAREA)) - && !options["insertmode"]) - modes.set(modes.VISUAL, modes.TEXTAREA); - else if (liberator.mode == modes.CARET) - modes.set(modes.VISUAL, modes.CARET); - } - } - // XXX: disabled, as i think automatically starting visual caret mode does more harm than help - // else - // { - // if (!couldCopy && modes.extended & modes.CARET) - // liberator.mode = modes.CARET; - // } + onDOMMenuBarInactive: function () { + this._activeMenubar = false; + modes.remove(modes.MENU); }, /** @@ -808,6 +735,78 @@ const Events = Module("events", { } }, + onFocus: function (event) { + function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument + + let elem = event.originalTarget; + let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem; + + if (hasHTMLDocument(win) && !buffer.focusAllowed(win)) + elem.blur(); + }, + + // argument "event" is deliberately not used, as i don't seem to have + // access to the real focus target + // Huh? --djk + onFocusChange: function (event) { + // command line has it's own focus change handler + if (liberator.mode == modes.COMMAND_LINE) + return; + + function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument + + let win = window.document.commandDispatcher.focusedWindow; + let elem = window.document.commandDispatcher.focusedElement; + + if (win && win.top == content && liberator.has("tabs")) + tabs.localStore.focusedFrame = win; + + try { + if (elem && elem.readOnly) + return; + + if ((elem instanceof HTMLInputElement && /^(search|text|password)$/.test(elem.type)) || + (elem instanceof HTMLSelectElement)) { + liberator.mode = modes.INSERT; + if (hasHTMLDocument(win)) + buffer.lastInputField = elem; + return; + } + + if(isinstance(elem, [HTMLEmbedElement, HTMLEmbedElement])) { + liberator.mode = modes.EMBED; + return; + } + + if (elem instanceof HTMLTextAreaElement || (elem && elem.contentEditable == "true")) { + if (options["insertmode"]) + modes.set(modes.INSERT); + else if (elem.selectionEnd - elem.selectionStart > 0) + modes.set(modes.VISUAL, modes.TEXTAREA); + else + modes.main = modes.TEXTAREA; + if (hasHTMLDocument(win)) + buffer.lastInputField = elem; + return; + } + + if (config.focusChange) { + config.focusChange(win); + return; + } + + let urlbar = document.getElementById("urlbar"); + if (elem == null && urlbar && urlbar.inputField == this._lastFocus) + liberator.threadYield(true); + + if (liberator.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL)) + modes.reset(); + } + finally { + this._lastFocus = elem; + } + }, + // this keypress handler gets always called first, even if e.g. // the commandline has focus // TODO: ...help me...please... @@ -1052,6 +1051,13 @@ const Events = Module("events", { event.stopPropagation(); }, + onMouseDown: function (event) { + let elem = event.target; + let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem; + for(; win; win = win != win.parent && win.parent) + win.liberatorFocusAllowed = true; + }, + onPopupShown: function (event) { if (event.originalTarget.localName == "tooltip" || event.originalTarget.id == "liberator-visualbell") return; @@ -1064,22 +1070,36 @@ const Events = Module("events", { modes.remove(modes.MENU); }, - onDOMMenuBarActive: function () { - this._activeMenubar = true; - modes.add(modes.MENU); - }, - - onDOMMenuBarInactive: function () { - this._activeMenubar = false; - modes.remove(modes.MENU); - }, - onResize: function (event) { if (window.fullScreen != this._fullscreen) { this._fullscreen = window.fullScreen; liberator.triggerObserver("fullscreen", this._fullscreen); autocommands.trigger("Fullscreen", { state: this._fullscreen }); } + }, + + onSelectionChange: function (event) { + let couldCopy = false; + let controller = document.commandDispatcher.getControllerForCommand("cmd_copy"); + if (controller && controller.isCommandEnabled("cmd_copy")) + couldCopy = true; + + if (liberator.mode != modes.VISUAL) { + if (couldCopy) { + if ((liberator.mode == modes.TEXTAREA || + (modes.extended & modes.TEXTAREA)) + && !options["insertmode"]) + modes.set(modes.VISUAL, modes.TEXTAREA); + else if (liberator.mode == modes.CARET) + modes.set(modes.VISUAL, modes.CARET); + } + } + // XXX: disabled, as i think automatically starting visual caret mode does more harm than help + // else + // { + // if (!couldCopy && modes.extended & modes.CARET) + // liberator.mode = modes.CARET; + // } } }, { isInputElemFocused: function () { diff --git a/common/content/javascript.js b/common/content/javascript.js index a5f0f6ce..1c337424 100644 --- a/common/content/javascript.js +++ b/common/content/javascript.js @@ -59,10 +59,13 @@ const JavaScript = Module("javascript", { } // The debugger doesn't list some properties. I can't guess why. // This only lists ENUMERABLE properties. - for (let k in orig) - if (k in orig && !('|' + k in seen) - && Object.hasOwnProperty(orig, k) == toplevel) - yield [k, this.getKey(orig, k)] + try { + for (let k in orig) + if (k in orig && !('|' + k in seen) + && Object.hasOwnProperty(orig, k) == toplevel) + yield [k, this.getKey(orig, k)] + } + catch(e) {} } else { for (let k in allkeys(obj)) diff --git a/common/locale/en-US/gui.xml b/common/locale/en-US/gui.xml index 2250027a..4affd063 100644 --- a/common/locale/en-US/gui.xml +++ b/common/locale/en-US/gui.xml @@ -151,8 +151,9 @@ - :extens :extensions + :exts :extens :extensions :extensions + :exts

List all installed extensions.

diff --git a/common/locale/en-US/index.xml b/common/locale/en-US/index.xml index 2482ad84..0546ff9a 100644 --- a/common/locale/en-US/index.xml +++ b/common/locale/en-US/index.xml @@ -393,7 +393,6 @@ This file contains a list of all available commands, mappings and options.
exrc
Allow reading of an RC file in the current directory
extendedhinttags
XPath string of hintable elements activated by ;
fileencoding
Changes the character encoding that &liberator.appname; uses to read and write files
-
focuscontent
Try to stay in Normal mode after loading a web page
followhints
Change the behaviour of in Hints mode
fullscreen
Show the current window fullscreen
guioptions
Show or hide certain GUI elements like the menu or toolbar
@@ -430,6 +429,7 @@ This file contains a list of all available commands, mappings and options.
showstatuslinks
Show the destination of the link under the cursor in the status bar
showtabline
Control when to show the tab bar of opened web pages
smartcase
Override the ignorecase option if the pattern contains uppercase characters
+
strictfocus
Prevent scripts from focusing input elements without user intervention
suggestengines
Engine Alias which has a feature of suggest
titlestring
Change the title of the window
urlseparator
Set the separator regex used to separate multiple URL args
diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml index e75c5847..5b7ca1f3 100644 --- a/common/locale/en-US/options.xml +++ b/common/locale/en-US/options.xml @@ -519,19 +519,14 @@ - 'nofc' 'nofocuscontent' - 'fc' 'focuscontent' - 'focuscontent' 'fc' + 'nosf' 'nostrictfocus' + 'sf' 'strictfocus' + 'strictfocus' 'sf' boolean - off + on

- Focus the content after a page has loaded. This is useful if you - always want to stay in Normal mode when browsing between web sites. - When on, it blurs any textbox which often is - automatically focused on page load. If you usually like - focuscontent but sometimes you'd like to focus the first - input field, you can use gi to jump to it. + Prevent scripts from focusing input elements without user intervention.

diff --git a/vimperator/NEWS b/vimperator/NEWS index f55c9bf3..dc078e95 100644 --- a/vimperator/NEWS +++ b/vimperator/NEWS @@ -1,11 +1,15 @@ 2009-XX-XX: - * version 2.3a1pre - * add basic plugin authorship documentation - * plugins may now provide full-fleged ':help' documentation - * asciidoc is no longer required to build Vimperator - * the help system is newly modularized - * remove [c]:edit[c], [c]:tabedit[c], and [c]:winedit[c] - * add 'jsdebugger' option - switch on/off javascript debugger service + * Replaced 'focuscontent' with 'strictfocus' + * Replaced previous incremental search implementation + * :open now only opens files begining with / or ./ + * Page zoom information is now shown in the status bar + * Added ZO, ZI, ZM, and ZR as aliases for zO, zI, zM, and zR + * Add basic plugin authorship documentation + * Plugins may now provide full-fleged ':help' documentation + * The help system is newly modularized + * Asciidoc is no longer for building + * Remove [c]:edit[c], [c]:tabedit[c], and [c]:winedit[c] + * Add 'jsdebugger' option - switch on/off javascript debugger service 2009-10-28: * version 2.2 @@ -26,8 +30,6 @@ ................................... * IMPORTANT: shifted key notation now matches Vim's behaviour. E.g. and are equivalent, to map the uppercase character use . - (this might change again, as this is REALLY inconsistent, and i don't - know if I like copying bugs) * IMPORTANT: 'popups' now takes a stringlist rather than a number. * add [c]:winonly[c]