From e0245fe57598b5bdf0c12f1e3cbdc3a24ce058e6 Mon Sep 17 00:00:00 2001 From: Doug Kearns Date: Fri, 13 Jul 2007 14:11:00 +0000 Subject: [PATCH] move the Events and Tabs objects to files of their own and add a license header to files without one --- chrome/content/vimperator/bookmarks.js | 28 + chrome/content/vimperator/completion.js | 28 + chrome/content/vimperator/events.js | 594 +++++++++++++++++ chrome/content/vimperator/mappings.js | 28 + chrome/content/vimperator/options.js | 28 + chrome/content/vimperator/tabs.js | 239 +++++++ chrome/content/vimperator/ui.js | 28 + chrome/content/vimperator/vimperator.js | 775 ----------------------- chrome/content/vimperator/vimperator.xul | 2 + 9 files changed, 975 insertions(+), 775 deletions(-) create mode 100644 chrome/content/vimperator/events.js create mode 100644 chrome/content/vimperator/tabs.js diff --git a/chrome/content/vimperator/bookmarks.js b/chrome/content/vimperator/bookmarks.js index 2d4e87e7..6f08a56c 100644 --- a/chrome/content/vimperator/bookmarks.js +++ b/chrome/content/vimperator/bookmarks.js @@ -1,3 +1,31 @@ +/***** BEGIN LICENSE BLOCK ***** {{{ +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 *****/ + /* * also includes methods for dealing with * keywords and search engines diff --git a/chrome/content/vimperator/completion.js b/chrome/content/vimperator/completion.js index 8915b535..bc3c4b1b 100644 --- a/chrome/content/vimperator/completion.js +++ b/chrome/content/vimperator/completion.js @@ -1,3 +1,31 @@ +/***** BEGIN LICENSE BLOCK ***** {{{ +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 *****/ + // The completion substrings, used for showing the longest common match var g_substrings = []; diff --git a/chrome/content/vimperator/events.js b/chrome/content/vimperator/events.js new file mode 100644 index 00000000..baf5db68 --- /dev/null +++ b/chrome/content/vimperator/events.js @@ -0,0 +1,594 @@ +/***** BEGIN LICENSE BLOCK ***** {{{ +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 *****/ + +function Events() //{{{ +{ + //////////////////////////////////////////////////////////////////////////////// + ////////////////////// CONSTRUCTOR ///////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + + // this handler is for middle click only in the content + //window.addEventListener("mousedown", onVimperatorKeypress, true); + //content.mPanelContainer.addEventListener("mousedown", onVimperatorKeypress, true); + //document.getElementById("content").onclick = function(event) { alert("foo"); }; + + // any tab related events + var tabcontainer = getBrowser().tabContainer; + tabcontainer.addEventListener("TabMove", function(event) { + vimperator.statusline.updateTabCount() + vimperator.tabs.updateBufferList(); + }, false); + tabcontainer.addEventListener("TabOpen", function(event) { + vimperator.statusline.updateTabCount(); + vimperator.tabs.updateBufferList(); + vimperator.setMode(); // trick to reshow the mode in the command line + }, false); + tabcontainer.addEventListener("TabClose", function(event) { + vimperator.statusline.updateTabCount() + vimperator.tabs.updateBufferList(); + vimperator.setMode(); // trick to reshow the mode in the command line + }, false); + tabcontainer.addEventListener("TabSelect", function(event) { + vimperator.statusline.updateTabCount(); + vimperator.tabs.updateBufferList(); + vimperator.setMode(); // trick to reshow the mode in the command line + vimperator.tabs.updateSelectionHistory(); + }, false); + + // this adds an event which is is called on each page load, even if the + // page is loaded in a background tab + getBrowser().addEventListener("load", onPageLoad, true); + + // called when the active document is scrolled + getBrowser().addEventListener("scroll", function (event) + { + vimperator.statusline.updateBufferPosition(); + vimperator.setMode(); // trick to reshow the mode in the command line + }, null); + + window.document.addEventListener("DOMTitleChanged", function(event) + { + //alert("titlechanged"); + }, null); + + /////////////////////////////////////////////////////////////////////////////}}} + ////////////////////// PRIVATE SECTION ///////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + + function onPageLoad(event) + { + if (event.originalTarget instanceof HTMLDocument) + { + var doc = event.originalTarget; + // document is part of a frameset + if (doc.defaultView.frameElement) + { + // hacky way to get rid of "Transfering data from ..." on sites with frames + // when you click on a link inside a frameset, because asyncUpdateUI + // is not triggered there (firefox bug?) + setTimeout(vimperator.statusline.updateUrl, 10); + return; + } + + // code which should happen for all (also background) newly loaded tabs goes here: + vimperator.tabs.updateBufferList(); + + //update history + var url = getCurrentLocation(); + var title = getCurrentTitle(); // not perfect "- Vimperator" in the title + vimperator.history.add(url, title); + + // code which is only relevant if the page load is the current tab goes here: + if (doc == getBrowser().selectedBrowser.contentDocument) + { + /* none yet */ + //vimperator.statusline.updateUrl(); + //logMessage("onpageLoad"); + } + } + } + + /////////////////////////////////////////////////////////////////////////////}}} + ////////////////////// PUBLIC SECTION ////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + + this.destroy = function() + { + // BIG TODO: removeEventListeners() to avoid mem leaks + window.dump("TODO: remove eventlisteners"); + } + + this.onEscape = function() + { + if (!vimperator.hasMode(vimperator.modes.ESCAPE_ONE_KEY)) + { + vimperator.setMode(vimperator.modes.NORMAL); + vimperator.echo(""); + vimperator.hints.disableHahMode(); + vimperator.focusContent(); + vimperator.statusline.updateUrl(); + } + } + + this.onKeyPress = function(event) + { +// alert(event) +// if (event.type != "keypress") +// return false; +// vimperator.logObject(event); + var key = event.toString() +// alert(key); + if (!key) + return false; +// event.stopPropagation(); +// event.preventDefault(); + // sometimes the non-content area has focus, making our keys not work + // if (event.target.id == "main-window") + // alert("focusContent();"); + + + // XXX: ugly hack for now pass certain keys to firefox as they are without beeping + // also fixes key navigation in menus, etc. + if (key == "" || key == "" || key == "" || key == "" || key == "") + return false; + + // XXX: for now only, later: input mappings if form element focused + if (isFormElemFocused()) + { + if (key == "") + { + var elt = window.document.commandDispatcher.focusedElement; + + if (elt.setSelectionRange && readFromClipboard()) + // readFromClipboard would return 'undefined' if not checked + // dunno about .setSelectionRange + { + var rangeStart = elt.selectionStart; // caret position + var rangeEnd = elt.selectionEnd; + var tempStr1 = elt.value.substring(0,rangeStart); + var tempStr2 = readFromClipboard(); + var tempStr3 = elt.value.substring(rangeEnd); + elt.value = tempStr1 + tempStr2 + tempStr3; + elt.selectionStart = rangeStart + tempStr2.length; + elt.selectionEnd = elt.selectionStart; + event.preventDefault(); + // prevents additional firefox-clipboard pasting + } + } + return false; + } + + + // handle Escape-one-key mode (Ctrl-v) + if (vimperator.hasMode(vimperator.modes.ESCAPE_ONE_KEY) && !vimperator.hasMode(vimperator.modes.ESCAPE_ALL_KEYS)) + { + vimperator.removeMode(null, vimperator.modes.ESCAPE_ONE_KEY); + return false; + } + // handle Escape-all-keys mode (I) + if (vimperator.hasMode(vimperator.modes.ESCAPE_ALL_KEYS)) + { + if (vimperator.hasMode(vimperator.modes.ESCAPE_ONE_KEY)) + vimperator.removeMode(null, vimperator.modes.ESCAPE_ONE_KEY); // and then let flow continue + else if (key == "" || key == "" || key == "") + ; // let flow continue to handle these keys + else + return false; + } + + // // FIXME: handle middle click in content area {{{ + // // alert(event.target.id); + // if (/*event.type == 'mousedown' && */event.button == 1 && event.target.id == 'content') + // { + // //echo("foo " + event.target.id); + // //if (document.commandDispatcher.focusedElement == command_line.inputField) + // { + // //alert(command_line.value.substring(0, command_line.selectionStart)); + // command_line.value = command_line.value.substring(0, command_line.selectionStart) + + // readFromClipboard() + + // command_line.value.substring(command_line.selectionEnd, command_line.value.length); + // alert(command_line.value); + // } + // //else + // // { + // // openURLs(readFromClipboard()); + // // } + // return true; + // } }}} + + + + // if Hit-a-hint mode is on, special handling of keys is required + // FIXME: total mess + if (vimperator.hasMode(vimperator.modes.HINTS)) + { + // 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 (map.always_active || vimperator.hints.currentState() == 1) + { + //g_hint_mappings[i][1].call(this, event); + map.execute(); + 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; + } + } + } + + // 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.hints.currentMode() == HINT_MODE_QUICK) + if (vimperator.hasMode(vimperator.modes.QUICK_HINT)) + vimperator.hints.disableHahMode(); + else // ALWAYS mode + vimperator.hints.resetHintedElements(); + vimperator.input.buffer = ""; + } + //else if (res == 0 || vimperator.hints.currentMode() == HINT_MODE_EXTENDED) // key processed, part of a larger hint + else if (res == 0 || vimperator.hasMode(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.hints.currentMode() == HINT_MODE_QUICK) + if (vimperator.hasMode(vimperator.modes.QUICK_HINT)) + vimperator.hints.disableHahMode(); + else // ALWAYS mode + vimperator.hints.resetHintedElements(); + + vimperator.input.buffer = ""; + } + + vimperator.statusline.updateInputBuffer(vimperator.input.buffer); + return true; + } + + if (vimperator.hasMode(vimperator.modes.NORMAL)) + { + var count_str = vimperator.input.buffer.match(/^[0-9]*/)[0]; + var candidate_command = (vimperator.input.buffer + key).replace(count_str, ''); + var map; + + // counts must be at the start of a complete mapping (10j -> go 10 lines down) + if ((vimperator.input.buffer + key).match(/^[1-9][0-9]*$/)) + { + vimperator.input.buffer += key; + vimperator.statusline.updateInputBuffer(vimperator.input.buffer); + return true; + } + + if (vimperator.input.pendingMap) + { + if (key != "" && key != "") + vimperator.input.pendingMap.execute(null, vimperator.input.count, key); + + vimperator.input.pendingMap = null; + vimperator.input.buffer = ""; + event.preventDefault(); + event.stopPropagation(); + } + else if (map = vimperator.mappings.get(vimperator.modes.NORMAL, candidate_command)) + { + vimperator.input.count = parseInt(count_str, 10); + if (isNaN(vimperator.input.count)) + vimperator.input.count = -1; + if (map.flags & Mappings.flags.ARGUMENT) + { + vimperator.input.pendingMap = map; + vimperator.input.buffer += key; + } + else + { + map.execute(null, vimperator.input.count); + vimperator.input.buffer = ""; + } + + event.preventDefault(); + event.stopPropagation(); + } + else if (vimperator.mappings.getCandidates(vimperator.modes.NORMAL, candidate_command).length > 0) + { + vimperator.input.buffer += key; + event.preventDefault(); + event.stopPropagation(); + } + else + { + vimperator.input.buffer = ""; + vimperator.input.pendingMap = null; + vimperator.beep(); + } + } + vimperator.statusline.updateInputBuffer(vimperator.input.buffer); + return false; + } + window.addEventListener("keypress", this.onKeyPress, true); + + + this.progressListener = + { + QueryInterface: function(aIID) + { + if (aIID.equals(Components.interfaces.nsIWebProgressListener) || + aIID.equals(Components.interfaces.nsIXULBrowserWindow) || // for setOverLink(); + aIID.equals(Components.interfaces.nsISupportsWeakReference) || + aIID.equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_NOINTERFACE; + }, + + // XXX: function may later be needed to detect a canceled synchronous openURL() + onStateChange: function(webProgress, aRequest, flags, aStatus) + { + // STATE_IS_DOCUMENT | STATE_IS_WINDOW is important, because we also + // receive statechange events for loading images and other parts of the web page + if (flags & (Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT | + Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW)) + { + // This fires when the load event is initiated + if (flags & Components.interfaces.nsIWebProgressListener.STATE_START) + { + vimperator.statusline.updateProgress(0); + } + else if (flags & Components.interfaces.nsIWebProgressListener.STATE_STOP) + ;// vimperator.statusline.updateUrl(); + } + }, + // for notifying the user about secure web pages + onSecurityChange: function (webProgress, aRequest, aState) + { + const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener; + if (aState & nsIWebProgressListener.STATE_IS_INSECURE) + vimperator.statusline.setClass("insecure"); + else if (aState & nsIWebProgressListener.STATE_IS_BROKEN) + vimperator.statusline.setClass("broken"); + else if (aState & nsIWebProgressListener.STATE_IS_SECURE) + vimperator.statusline.setClass("secure"); + }, + onStatusChange: function(webProgress, request, status, message) + { + vimperator.statusline.updateUrl(message); + }, + onProgressChange: function(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) + { + vimperator.statusline.updateProgress(curTotalProgress/maxTotalProgress); + }, + // happens when the users switches tabs + onLocationChange: function() + { + // if (vimperator.hasMode(vimperator.modes.HINTS) && !vimperator.hasMode(vimperator.modes.ALWAYS_HINT)) + // vimperator.hints.disableHahMode(); + + vimperator.statusline.updateUrl(); + vimperator.statusline.updateProgress(); + + // if this is not delayed we get the wrong position of the old buffer + setTimeout(function() { vimperator.statusline.updateBufferPosition(); }, 100); + }, + // called at the very end of a page load + asyncUpdateUI: function() + { + setTimeout(vimperator.statusline.updateUrl, 100); + }, + setOverLink : function(link, b) + { + var ssli = vimperator.options["showstatuslinks"]; + if (link && ssli) + { + if (ssli == 1) + vimperator.statusline.updateUrl("Link: " + link); + else if (ssli == 2) + vimperator.echo("Link: " + link); + } + + if (link == "") + { + if (ssli == 1) + vimperator.statusline.updateUrl(); + else if (ssli == 2) + vimperator.setMode(); // trick to reshow the mode in the command line + } + }, + + // stub functions for the interfaces + setJSStatus : function(status) { ; }, + setJSDefaultStatus : function(status) { ; }, + setDefaultStatus : function(status) { ; }, + onLinkIconAvailable: function() { ; } + }; + + window.XULBrowserWindow = this.progressListener; + window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsIDocShellTreeItem).treeOwner + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIXULWindow) + .XULBrowserWindow = window.XULBrowserWindow; + getBrowser().addProgressListener(this.progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL); + //}}} +} //}}} + +// this function converts the given event to +// a keycode which can be used in mappings +// e.g. pressing ctrl+n would result in the string "" +// null if unknown key +KeyboardEvent.prototype.toString = function() //{{{ +{ + var key = String.fromCharCode(this.charCode); + var modifier = ""; + if (this.ctrlKey) + modifier += "C-"; + if (this.altKey) + modifier += "A-"; + if (this.metaKey) + modifier += "M-"; + + if (this.charCode == 0) + { + if (this.shiftKey) + modifier += "S-"; + if (this.keyCode == KeyEvent.DOM_VK_ESCAPE) + key = "Esc"; + else if (this.keyCode == KeyEvent.DOM_VK_LEFT_SHIFT) + key = "<"; + else if (this.keyCode == KeyEvent.DOM_VK_RIGHT_SHIFT) + key = ">"; + else if (this.keyCode == KeyEvent.DOM_VK_RETURN) + key = "Return"; + else if (this.keyCode == KeyEvent.DOM_VK_TAB) + key = "Tab"; + else if (this.keyCode == KeyEvent.DOM_VK_DELETE) + key = "Del"; + else if (this.keyCode == KeyEvent.DOM_VK_BACK_SPACE) + key = "BS"; + else if (this.keyCode == KeyEvent.DOM_VK_HOME) + key = "Home"; + else if (this.keyCode == KeyEvent.DOM_VK_INSERT) + key = "Insert"; + else if (this.keyCode == KeyEvent.DOM_VK_END) + key = "End"; + else if (this.keyCode == KeyEvent.DOM_VK_LEFT) + key = "Left"; + else if (this.keyCode == KeyEvent.DOM_VK_RIGHT) + key = "Right"; + else if (this.keyCode == KeyEvent.DOM_VK_UP) + key = "Up"; + else if (this.keyCode == KeyEvent.DOM_VK_DOWN) + key = "Down"; + else if (this.keyCode == KeyEvent.DOM_VK_PAGE_UP) + key = "PageUp"; + else if (this.keyCode == KeyEvent.DOM_VK_PAGE_DOWN) + key = "PageDown"; + else if (this.keyCode == KeyEvent.DOM_VK_F1) + key = "F1"; + else if (this.keyCode == KeyEvent.DOM_VK_F2) + key = "F2"; + else if (this.keyCode == KeyEvent.DOM_VK_F3) + key = "F3"; + else if (this.keyCode == KeyEvent.DOM_VK_F4) + key = "F4"; + else if (this.keyCode == KeyEvent.DOM_VK_F5) + key = "F5"; + else if (this.keyCode == KeyEvent.DOM_VK_F6) + key = "F6"; + else if (this.keyCode == KeyEvent.DOM_VK_F7) + key = "F7"; + else if (this.keyCode == KeyEvent.DOM_VK_F8) + key = "F8"; + else if (this.keyCode == KeyEvent.DOM_VK_F9) + key = "F9"; + else if (this.keyCode == KeyEvent.DOM_VK_F10) + key = "F10"; + else if (this.keyCode == KeyEvent.DOM_VK_F11) + key = "F11"; + else if (this.keyCode == KeyEvent.DOM_VK_F12) + key = "F12"; + else if (this.keyCode == KeyEvent.DOM_VK_F13) + key = "F13"; + else if (this.keyCode == KeyEvent.DOM_VK_F14) + key = "F14"; + else if (this.keyCode == KeyEvent.DOM_VK_F15) + key = "F15"; + else if (this.keyCode == KeyEvent.DOM_VK_F16) + key = "F16"; + else if (this.keyCode == KeyEvent.DOM_VK_F17) + key = "F17"; + else if (this.keyCode == KeyEvent.DOM_VK_F18) + key = "F18"; + else if (this.keyCode == KeyEvent.DOM_VK_F19) + key = "F19"; + else if (this.keyCode == KeyEvent.DOM_VK_F20) + key = "F20"; + else if (this.keyCode == KeyEvent.DOM_VK_F21) + key = "F21"; + else if (this.keyCode == KeyEvent.DOM_VK_F22) + key = "F22"; + else if (this.keyCode == KeyEvent.DOM_VK_F23) + key = "F23"; + else if (this.keyCode == KeyEvent.DOM_VK_F24) + key = "F24"; + else + return null; + } + + // special handling of the Space key + if (this.charCode == 32) + { + if (this.shiftKey) + modifier += "S-"; + key = "Space"; + } + + // a normal key like a, b, c, 0, etc. + if (this.charCode > 0) + { + if (modifier.length > 0 || this.charCode == 32) + return "<" + modifier + key + ">"; + else + return key; + } + else // a key like F1 is always enclosed in < and > + return "<" + modifier + key + ">"; +} //}}} + +// vim: set fdm=marker sw=4 ts=4 et: diff --git a/chrome/content/vimperator/mappings.js b/chrome/content/vimperator/mappings.js index 7615c19b..f0dc0602 100644 --- a/chrome/content/vimperator/mappings.js +++ b/chrome/content/vimperator/mappings.js @@ -1,3 +1,31 @@ +/***** BEGIN LICENSE BLOCK ***** {{{ +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 *****/ + function Map(mode, cmds, act, extra_info) //{{{ { if (!mode || (!cmds || !cmds.length) || !act) diff --git a/chrome/content/vimperator/options.js b/chrome/content/vimperator/options.js index 34f20ba8..ba158135 100644 --- a/chrome/content/vimperator/options.js +++ b/chrome/content/vimperator/options.js @@ -1,3 +1,31 @@ +/***** BEGIN LICENSE BLOCK ***** {{{ +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 *****/ + function Option(names, type, extra_info) //{{{ { if (!names || !type) diff --git a/chrome/content/vimperator/tabs.js b/chrome/content/vimperator/tabs.js new file mode 100644 index 00000000..dab829ec --- /dev/null +++ b/chrome/content/vimperator/tabs.js @@ -0,0 +1,239 @@ +/***** BEGIN LICENSE BLOCK ***** {{{ +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 *****/ + +/** provides functions for working with tabs + * XXX: ATTENTION: We are planning to move to the FUEL API once we switch to + * Firefox 3.0, then this class should go away and their tab methods should be used + * @deprecated + */ +function Tabs() //{{{ +{ + //////////////////////////////////////////////////////////////////////////////// + ////////////////////// PRIVATE SECTION ///////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + /** @param spec can either be: + * - an absolute integer + * - "" for the current tab + * - "+1" for the next tab + * - "-3" for the tab, which is 3 positions left of the current + * - "$" for the last tab + */ + function indexFromSpec(spec, wrap) + { + var position = getBrowser().tabContainer.selectedIndex; + var length = getBrowser().mTabs.length; + var last = length - 1; + + if (spec === undefined || spec === "") + return position; + + if (typeof spec === "number") + position = spec; + else if (spec === "$") + return last; + else if (!spec.match(/^([+-]?\d+|)$/)) + { + // TODO: move error reporting to ex-command? + vimperator.echoerr("E488: Trailing characters"); + return false; + } + else + { + if (spec.match(/^([+-]\d+)$/)) // relative position +/-N + position += parseInt(spec); + else // absolute position + position = parseInt(spec); + } + + if (position > last) + position = wrap ? position % length : last; + else if (position < 0) + position = wrap ? (position % length) + length: 0; + + return position; + } + + var alternates = [null, null]; + + /////////////////////////////////////////////////////////////////////////////}}} + ////////////////////// PUBLIC SECTION ////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////{{{ + // @returns the index of the currently selected tab starting with 0 + this.index = function(tab) + { + if (tab) + { + var length = getBrowser().mTabs.length; + for (var i = 0; i < length; i++) + { + if (getBrowser().mTabs[i] == tab) + return i; + } + return -1; + } + + return getBrowser().tabContainer.selectedIndex; + } + + this.count = function() + { + return getBrowser().mTabs.length; + } + + // TODO: implement filter + // @returns an array of tabs which match filter + this.get = function(filter) + { + var buffers = []; + var browsers = getBrowser().browsers; + for (var i in browsers) + { + var title = browsers[i].contentTitle || "(Untitled)"; + var uri = browsers[i].currentURI.spec; + var number = i + 1; + buffers.push([number, title, uri]); + } + return buffers; + } + + this.getTab = function(index) + { + if (index) + return getBrowser().mTabs[index]; + + return getBrowser().tabContainer.selectedItem; + } + + /* spec == "" moves the tab to the last position as per Vim + * wrap causes the movement to wrap around the start and end of the tab list + * NOTE: position is a 0 based index + * FIXME: tabmove! N should probably produce an error + */ + this.move = function(tab, spec, wrap) + { + if (spec === "") + spec = "$"; // if not specified, move to the last tab -> XXX: move to ex handling? + + var index = indexFromSpec(spec, false); // XXX: really no wrap? + getBrowser().moveTabTo(tab, index); + } + + /* quit_on_last_tab = 1: quit without saving session + * quit_on_last_tab = 2: quit and save session + */ + this.remove = function(tab, count, focus_left_tab, quit_on_last_tab) + { + if (count < 1) count = 1; + + if (quit_on_last_tab >= 1 && getBrowser().mTabs.length <= count) + vimperator.quit(quit_on_last_tab == 2); + + if (focus_left_tab && tab.previousSibling) + this.select("-1", false); + + getBrowser().removeTab(tab); + } + + this.keepOnly = function(tab) + { + getBrowser().removeAllTabsBut(tab); + } + + this.select = function(spec, wrap) + { + var index = indexFromSpec(spec, wrap); + if (index === false) + { + vimperator.beep(); // XXX: move to ex-handling? + return false; + } + getBrowser().mTabContainer.selectedIndex = index; + } + + // TODO: when restarting a session FF selects the first tab and then the + // tab that was selected when the session was created. As a result the + // alternate after a restart is often incorrectly tab 1 when there + // shouldn't be one yet. + this.updateSelectionHistory = function() + { + alternates = [this.getTab(), alternates[0]]; + this.alternate = alternates[1]; + } + + this.alternate = this.getTab(); + + // updates the buffer preview in place only if list is visible + this.updateBufferList = function() + { + if (!vimperator.bufferwindow.visible()) + return false; + + var items = get_buffer_completions(""); + vimperator.bufferwindow.show(items); + vimperator.bufferwindow.selectItem(getBrowser().mTabContainer.selectedIndex); + } + + this.reload = function(tab, bypass_cache) + { + if (bypass_cache) + { + const nsIWebNavigation = Components.interfaces.nsIWebNavigation; + const flags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; + getBrowser().getBrowserForTab(tab).reloadWithFlags(flags); + } + else + { + getBrowser().reloadTab(tab); + } + } + + this.reloadAll = function(bypass_cache) + { + if (bypass_cache) + { + for (var i = 0; i < getBrowser().mTabs.length; i++) + { + try + { + this.reload(getBrowser().mTabs[i], bypass_cache) + } + catch (e) { + // FIXME: can we do anything useful here without stopping the + // other tabs from reloading? + } + } + } + else + { + getBrowser().reloadAllTabs(); + } + } + //}}} +} //}}} + +// vim: set fdm=marker sw=4 ts=4 et: diff --git a/chrome/content/vimperator/ui.js b/chrome/content/vimperator/ui.js index 495849bd..bc6b926a 100644 --- a/chrome/content/vimperator/ui.js +++ b/chrome/content/vimperator/ui.js @@ -1,3 +1,31 @@ +/***** BEGIN LICENSE BLOCK ***** {{{ +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 *****/ + // XXX: move somehere else! function multiliner(line, prev_match, heredoc) //{{{ { diff --git a/chrome/content/vimperator/vimperator.js b/chrome/content/vimperator/vimperator.js index 0851448d..fda326bb 100644 --- a/chrome/content/vimperator/vimperator.js +++ b/chrome/content/vimperator/vimperator.js @@ -349,781 +349,6 @@ function Vimperator() //{{{ //}}} } //}}} -function Events() //{{{ -{ - //////////////////////////////////////////////////////////////////////////////// - ////////////////////// CONSTRUCTOR ///////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////{{{ - - // this handler is for middle click only in the content - //window.addEventListener("mousedown", onVimperatorKeypress, true); - //content.mPanelContainer.addEventListener("mousedown", onVimperatorKeypress, true); - //document.getElementById("content").onclick = function(event) { alert("foo"); }; - - // any tab related events - var tabcontainer = getBrowser().tabContainer; - tabcontainer.addEventListener("TabMove", function(event) { - vimperator.statusline.updateTabCount() - vimperator.tabs.updateBufferList(); - }, false); - tabcontainer.addEventListener("TabOpen", function(event) { - vimperator.statusline.updateTabCount(); - vimperator.tabs.updateBufferList(); - vimperator.setMode(); // trick to reshow the mode in the command line - }, false); - tabcontainer.addEventListener("TabClose", function(event) { - vimperator.statusline.updateTabCount() - vimperator.tabs.updateBufferList(); - vimperator.setMode(); // trick to reshow the mode in the command line - }, false); - tabcontainer.addEventListener("TabSelect", function(event) { - vimperator.statusline.updateTabCount(); - vimperator.tabs.updateBufferList(); - vimperator.setMode(); // trick to reshow the mode in the command line - vimperator.tabs.updateSelectionHistory(); - }, false); - - // this adds an event which is is called on each page load, even if the - // page is loaded in a background tab - getBrowser().addEventListener("load", onPageLoad, true); - - // called when the active document is scrolled - getBrowser().addEventListener("scroll", function (event) - { - vimperator.statusline.updateBufferPosition(); - vimperator.setMode(); // trick to reshow the mode in the command line - }, null); - - window.document.addEventListener("DOMTitleChanged", function(event) - { - //alert("titlechanged"); - }, null); - - /////////////////////////////////////////////////////////////////////////////}}} - ////////////////////// PRIVATE SECTION ///////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////{{{ - - function onPageLoad(event) - { - if (event.originalTarget instanceof HTMLDocument) - { - var doc = event.originalTarget; - // document is part of a frameset - if (doc.defaultView.frameElement) - { - // hacky way to get rid of "Transfering data from ..." on sites with frames - // when you click on a link inside a frameset, because asyncUpdateUI - // is not triggered there (firefox bug?) - setTimeout(vimperator.statusline.updateUrl, 10); - return; - } - - // code which should happen for all (also background) newly loaded tabs goes here: - vimperator.tabs.updateBufferList(); - - //update history - var url = getCurrentLocation(); - var title = getCurrentTitle(); // not perfect "- Vimperator" in the title - vimperator.history.add(url, title); - - // code which is only relevant if the page load is the current tab goes here: - if (doc == getBrowser().selectedBrowser.contentDocument) - { - /* none yet */ - //vimperator.statusline.updateUrl(); - //logMessage("onpageLoad"); - } - } - } - - /////////////////////////////////////////////////////////////////////////////}}} - ////////////////////// PUBLIC SECTION ////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////{{{ - - this.destroy = function() - { - // BIG TODO: removeEventListeners() to avoid mem leaks - window.dump("TODO: remove eventlisteners"); - } - - this.onEscape = function() - { - if (!vimperator.hasMode(vimperator.modes.ESCAPE_ONE_KEY)) - { - vimperator.setMode(vimperator.modes.NORMAL); - vimperator.echo(""); - vimperator.hints.disableHahMode(); - vimperator.focusContent(); - vimperator.statusline.updateUrl(); - } - } - - this.onKeyPress = function(event) - { -// alert(event) -// if (event.type != "keypress") -// return false; -// vimperator.logObject(event); - var key = event.toString() -// alert(key); - if (!key) - return false; -// event.stopPropagation(); -// event.preventDefault(); - // sometimes the non-content area has focus, making our keys not work - // if (event.target.id == "main-window") - // alert("focusContent();"); - - - // XXX: ugly hack for now pass certain keys to firefox as they are without beeping - // also fixes key navigation in menus, etc. - if (key == "" || key == "" || key == "" || key == "" || key == "") - return false; - - // XXX: for now only, later: input mappings if form element focused - if (isFormElemFocused()) - { - if (key == "") - { - var elt = window.document.commandDispatcher.focusedElement; - - if (elt.setSelectionRange && readFromClipboard()) - // readFromClipboard would return 'undefined' if not checked - // dunno about .setSelectionRange - { - var rangeStart = elt.selectionStart; // caret position - var rangeEnd = elt.selectionEnd; - var tempStr1 = elt.value.substring(0,rangeStart); - var tempStr2 = readFromClipboard(); - var tempStr3 = elt.value.substring(rangeEnd); - elt.value = tempStr1 + tempStr2 + tempStr3; - elt.selectionStart = rangeStart + tempStr2.length; - elt.selectionEnd = elt.selectionStart; - event.preventDefault(); - // prevents additional firefox-clipboard pasting - } - } - return false; - } - - - // handle Escape-one-key mode (Ctrl-v) - if (vimperator.hasMode(vimperator.modes.ESCAPE_ONE_KEY) && !vimperator.hasMode(vimperator.modes.ESCAPE_ALL_KEYS)) - { - vimperator.removeMode(null, vimperator.modes.ESCAPE_ONE_KEY); - return false; - } - // handle Escape-all-keys mode (I) - if (vimperator.hasMode(vimperator.modes.ESCAPE_ALL_KEYS)) - { - if (vimperator.hasMode(vimperator.modes.ESCAPE_ONE_KEY)) - vimperator.removeMode(null, vimperator.modes.ESCAPE_ONE_KEY); // and then let flow continue - else if (key == "" || key == "" || key == "") - ; // let flow continue to handle these keys - else - return false; - } - - // // FIXME: handle middle click in content area {{{ - // // alert(event.target.id); - // if (/*event.type == 'mousedown' && */event.button == 1 && event.target.id == 'content') - // { - // //echo("foo " + event.target.id); - // //if (document.commandDispatcher.focusedElement == command_line.inputField) - // { - // //alert(command_line.value.substring(0, command_line.selectionStart)); - // command_line.value = command_line.value.substring(0, command_line.selectionStart) + - // readFromClipboard() + - // command_line.value.substring(command_line.selectionEnd, command_line.value.length); - // alert(command_line.value); - // } - // //else - // // { - // // openURLs(readFromClipboard()); - // // } - // return true; - // } }}} - - - - // if Hit-a-hint mode is on, special handling of keys is required - // FIXME: total mess - if (vimperator.hasMode(vimperator.modes.HINTS)) - { - // 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 (map.always_active || vimperator.hints.currentState() == 1) - { - //g_hint_mappings[i][1].call(this, event); - map.execute(); - 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; - } - } - } - - // 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.hints.currentMode() == HINT_MODE_QUICK) - if (vimperator.hasMode(vimperator.modes.QUICK_HINT)) - vimperator.hints.disableHahMode(); - else // ALWAYS mode - vimperator.hints.resetHintedElements(); - vimperator.input.buffer = ""; - } - //else if (res == 0 || vimperator.hints.currentMode() == HINT_MODE_EXTENDED) // key processed, part of a larger hint - else if (res == 0 || vimperator.hasMode(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.hints.currentMode() == HINT_MODE_QUICK) - if (vimperator.hasMode(vimperator.modes.QUICK_HINT)) - vimperator.hints.disableHahMode(); - else // ALWAYS mode - vimperator.hints.resetHintedElements(); - - vimperator.input.buffer = ""; - } - - vimperator.statusline.updateInputBuffer(vimperator.input.buffer); - return true; - } - - if (vimperator.hasMode(vimperator.modes.NORMAL)) - { - var count_str = vimperator.input.buffer.match(/^[0-9]*/)[0]; - var candidate_command = (vimperator.input.buffer + key).replace(count_str, ''); - var map; - - // counts must be at the start of a complete mapping (10j -> go 10 lines down) - if ((vimperator.input.buffer + key).match(/^[1-9][0-9]*$/)) - { - vimperator.input.buffer += key; - vimperator.statusline.updateInputBuffer(vimperator.input.buffer); - return true; - } - - if (vimperator.input.pendingMap) - { - if (key != "" && key != "") - vimperator.input.pendingMap.execute(null, vimperator.input.count, key); - - vimperator.input.pendingMap = null; - vimperator.input.buffer = ""; - event.preventDefault(); - event.stopPropagation(); - } - else if (map = vimperator.mappings.get(vimperator.modes.NORMAL, candidate_command)) - { - vimperator.input.count = parseInt(count_str, 10); - if (isNaN(vimperator.input.count)) - vimperator.input.count = -1; - if (map.flags & Mappings.flags.ARGUMENT) - { - vimperator.input.pendingMap = map; - vimperator.input.buffer += key; - } - else - { - map.execute(null, vimperator.input.count); - vimperator.input.buffer = ""; - } - - event.preventDefault(); - event.stopPropagation(); - } - else if (vimperator.mappings.getCandidates(vimperator.modes.NORMAL, candidate_command).length > 0) - { - vimperator.input.buffer += key; - event.preventDefault(); - event.stopPropagation(); - } - else - { - vimperator.input.buffer = ""; - vimperator.input.pendingMap = null; - vimperator.beep(); - } - } - vimperator.statusline.updateInputBuffer(vimperator.input.buffer); - return false; - } - window.addEventListener("keypress", this.onKeyPress, true); - - - this.progressListener = - { - QueryInterface: function(aIID) - { - if (aIID.equals(Components.interfaces.nsIWebProgressListener) || - aIID.equals(Components.interfaces.nsIXULBrowserWindow) || // for setOverLink(); - aIID.equals(Components.interfaces.nsISupportsWeakReference) || - aIID.equals(Components.interfaces.nsISupports)) - return this; - throw Components.results.NS_NOINTERFACE; - }, - - // XXX: function may later be needed to detect a canceled synchronous openURL() - onStateChange: function(webProgress, aRequest, flags, aStatus) - { - // STATE_IS_DOCUMENT | STATE_IS_WINDOW is important, because we also - // receive statechange events for loading images and other parts of the web page - if (flags & (Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT | - Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW)) - { - // This fires when the load event is initiated - if (flags & Components.interfaces.nsIWebProgressListener.STATE_START) - { - vimperator.statusline.updateProgress(0); - } - else if (flags & Components.interfaces.nsIWebProgressListener.STATE_STOP) - ;// vimperator.statusline.updateUrl(); - } - }, - // for notifying the user about secure web pages - onSecurityChange: function (webProgress, aRequest, aState) - { - const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener; - if (aState & nsIWebProgressListener.STATE_IS_INSECURE) - vimperator.statusline.setClass("insecure"); - else if (aState & nsIWebProgressListener.STATE_IS_BROKEN) - vimperator.statusline.setClass("broken"); - else if (aState & nsIWebProgressListener.STATE_IS_SECURE) - vimperator.statusline.setClass("secure"); - }, - onStatusChange: function(webProgress, request, status, message) - { - vimperator.statusline.updateUrl(message); - }, - onProgressChange: function(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) - { - vimperator.statusline.updateProgress(curTotalProgress/maxTotalProgress); - }, - // happens when the users switches tabs - onLocationChange: function() - { - // if (vimperator.hasMode(vimperator.modes.HINTS) && !vimperator.hasMode(vimperator.modes.ALWAYS_HINT)) - // vimperator.hints.disableHahMode(); - - vimperator.statusline.updateUrl(); - vimperator.statusline.updateProgress(); - - // if this is not delayed we get the wrong position of the old buffer - setTimeout(function() { vimperator.statusline.updateBufferPosition(); }, 100); - }, - // called at the very end of a page load - asyncUpdateUI: function() - { - setTimeout(vimperator.statusline.updateUrl, 100); - }, - setOverLink : function(link, b) - { - var ssli = vimperator.options["showstatuslinks"]; - if (link && ssli) - { - if (ssli == 1) - vimperator.statusline.updateUrl("Link: " + link); - else if (ssli == 2) - vimperator.echo("Link: " + link); - } - - if (link == "") - { - if (ssli == 1) - vimperator.statusline.updateUrl(); - else if (ssli == 2) - vimperator.setMode(); // trick to reshow the mode in the command line - } - }, - - // stub functions for the interfaces - setJSStatus : function(status) { ; }, - setJSDefaultStatus : function(status) { ; }, - setDefaultStatus : function(status) { ; }, - onLinkIconAvailable: function() { ; } - }; - - window.XULBrowserWindow = this.progressListener; - window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIWebNavigation) - .QueryInterface(Components.interfaces.nsIDocShellTreeItem).treeOwner - .QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIXULWindow) - .XULBrowserWindow = window.XULBrowserWindow; - getBrowser().addProgressListener(this.progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL); - //}}} -} //}}} - -// this function converts the given event to -// a keycode which can be used in mappings -// e.g. pressing ctrl+n would result in the string "" -// null if unknown key -KeyboardEvent.prototype.toString = function() //{{{ -{ - var key = String.fromCharCode(this.charCode); - var modifier = ""; - if (this.ctrlKey) - modifier += "C-"; - if (this.altKey) - modifier += "A-"; - if (this.metaKey) - modifier += "M-"; - - if (this.charCode == 0) - { - if (this.shiftKey) - modifier += "S-"; - if (this.keyCode == KeyEvent.DOM_VK_ESCAPE) - key = "Esc"; - else if (this.keyCode == KeyEvent.DOM_VK_LEFT_SHIFT) - key = "<"; - else if (this.keyCode == KeyEvent.DOM_VK_RIGHT_SHIFT) - key = ">"; - else if (this.keyCode == KeyEvent.DOM_VK_RETURN) - key = "Return"; - else if (this.keyCode == KeyEvent.DOM_VK_TAB) - key = "Tab"; - else if (this.keyCode == KeyEvent.DOM_VK_DELETE) - key = "Del"; - else if (this.keyCode == KeyEvent.DOM_VK_BACK_SPACE) - key = "BS"; - else if (this.keyCode == KeyEvent.DOM_VK_HOME) - key = "Home"; - else if (this.keyCode == KeyEvent.DOM_VK_INSERT) - key = "Insert"; - else if (this.keyCode == KeyEvent.DOM_VK_END) - key = "End"; - else if (this.keyCode == KeyEvent.DOM_VK_LEFT) - key = "Left"; - else if (this.keyCode == KeyEvent.DOM_VK_RIGHT) - key = "Right"; - else if (this.keyCode == KeyEvent.DOM_VK_UP) - key = "Up"; - else if (this.keyCode == KeyEvent.DOM_VK_DOWN) - key = "Down"; - else if (this.keyCode == KeyEvent.DOM_VK_PAGE_UP) - key = "PageUp"; - else if (this.keyCode == KeyEvent.DOM_VK_PAGE_DOWN) - key = "PageDown"; - else if (this.keyCode == KeyEvent.DOM_VK_F1) - key = "F1"; - else if (this.keyCode == KeyEvent.DOM_VK_F2) - key = "F2"; - else if (this.keyCode == KeyEvent.DOM_VK_F3) - key = "F3"; - else if (this.keyCode == KeyEvent.DOM_VK_F4) - key = "F4"; - else if (this.keyCode == KeyEvent.DOM_VK_F5) - key = "F5"; - else if (this.keyCode == KeyEvent.DOM_VK_F6) - key = "F6"; - else if (this.keyCode == KeyEvent.DOM_VK_F7) - key = "F7"; - else if (this.keyCode == KeyEvent.DOM_VK_F8) - key = "F8"; - else if (this.keyCode == KeyEvent.DOM_VK_F9) - key = "F9"; - else if (this.keyCode == KeyEvent.DOM_VK_F10) - key = "F10"; - else if (this.keyCode == KeyEvent.DOM_VK_F11) - key = "F11"; - else if (this.keyCode == KeyEvent.DOM_VK_F12) - key = "F12"; - else if (this.keyCode == KeyEvent.DOM_VK_F13) - key = "F13"; - else if (this.keyCode == KeyEvent.DOM_VK_F14) - key = "F14"; - else if (this.keyCode == KeyEvent.DOM_VK_F15) - key = "F15"; - else if (this.keyCode == KeyEvent.DOM_VK_F16) - key = "F16"; - else if (this.keyCode == KeyEvent.DOM_VK_F17) - key = "F17"; - else if (this.keyCode == KeyEvent.DOM_VK_F18) - key = "F18"; - else if (this.keyCode == KeyEvent.DOM_VK_F19) - key = "F19"; - else if (this.keyCode == KeyEvent.DOM_VK_F20) - key = "F20"; - else if (this.keyCode == KeyEvent.DOM_VK_F21) - key = "F21"; - else if (this.keyCode == KeyEvent.DOM_VK_F22) - key = "F22"; - else if (this.keyCode == KeyEvent.DOM_VK_F23) - key = "F23"; - else if (this.keyCode == KeyEvent.DOM_VK_F24) - key = "F24"; - else - return null; - } - - // special handling of the Space key - if (this.charCode == 32) - { - if (this.shiftKey) - modifier += "S-"; - key = "Space"; - } - - // a normal key like a, b, c, 0, etc. - if (this.charCode > 0) - { - if (modifier.length > 0 || this.charCode == 32) - return "<" + modifier + key + ">"; - else - return key; - } - else // a key like F1 is always enclosed in < and > - return "<" + modifier + key + ">"; -} //}}} - -/** provides functions for working with tabs - * XXX: ATTENTION: We are planning to move to the FUEL API once we switch to - * Firefox 3.0, then this class should go away and their tab methods should be used - * @deprecated - */ -function Tabs() //{{{ -{ - //////////////////////////////////////////////////////////////////////////////// - ////////////////////// PRIVATE SECTION ///////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////{{{ - /** @param spec can either be: - * - an absolute integer - * - "" for the current tab - * - "+1" for the next tab - * - "-3" for the tab, which is 3 positions left of the current - * - "$" for the last tab - */ - function indexFromSpec(spec, wrap) - { - var position = getBrowser().tabContainer.selectedIndex; - var length = getBrowser().mTabs.length; - var last = length - 1; - - if (spec === undefined || spec === "") - return position; - - if (typeof spec === "number") - position = spec; - else if (spec === "$") - return last; - else if (!spec.match(/^([+-]?\d+|)$/)) - { - // TODO: move error reporting to ex-command? - vimperator.echoerr("E488: Trailing characters"); - return false; - } - else - { - if (spec.match(/^([+-]\d+)$/)) // relative position +/-N - position += parseInt(spec); - else // absolute position - position = parseInt(spec); - } - - if (position > last) - position = wrap ? position % length : last; - else if (position < 0) - position = wrap ? (position % length) + length: 0; - - return position; - } - - var alternates = [null, null]; - - /////////////////////////////////////////////////////////////////////////////}}} - ////////////////////// PUBLIC SECTION ////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////{{{ - // @returns the index of the currently selected tab starting with 0 - this.index = function(tab) - { - if (tab) - { - var length = getBrowser().mTabs.length; - for (var i = 0; i < length; i++) - { - if (getBrowser().mTabs[i] == tab) - return i; - } - return -1; - } - - return getBrowser().tabContainer.selectedIndex; - } - - this.count = function() - { - return getBrowser().mTabs.length; - } - - // TODO: implement filter - // @returns an array of tabs which match filter - this.get = function(filter) - { - var buffers = []; - var browsers = getBrowser().browsers; - for (var i in browsers) - { - var title = browsers[i].contentTitle || "(Untitled)"; - var uri = browsers[i].currentURI.spec; - var number = i + 1; - buffers.push([number, title, uri]); - } - return buffers; - } - - this.getTab = function(index) - { - if (index) - return getBrowser().mTabs[index]; - - return getBrowser().tabContainer.selectedItem; - } - - /* spec == "" moves the tab to the last position as per Vim - * wrap causes the movement to wrap around the start and end of the tab list - * NOTE: position is a 0 based index - * FIXME: tabmove! N should probably produce an error - */ - this.move = function(tab, spec, wrap) - { - if (spec === "") - spec = "$"; // if not specified, move to the last tab -> XXX: move to ex handling? - - var index = indexFromSpec(spec, false); // XXX: really no wrap? - getBrowser().moveTabTo(tab, index); - } - - /* quit_on_last_tab = 1: quit without saving session - * quit_on_last_tab = 2: quit and save session - */ - this.remove = function(tab, count, focus_left_tab, quit_on_last_tab) - { - if (count < 1) count = 1; - - if (quit_on_last_tab >= 1 && getBrowser().mTabs.length <= count) - vimperator.quit(quit_on_last_tab == 2); - - if (focus_left_tab && tab.previousSibling) - this.select("-1", false); - - getBrowser().removeTab(tab); - } - - this.keepOnly = function(tab) - { - getBrowser().removeAllTabsBut(tab); - } - - this.select = function(spec, wrap) - { - var index = indexFromSpec(spec, wrap); - if (index === false) - { - vimperator.beep(); // XXX: move to ex-handling? - return false; - } - getBrowser().mTabContainer.selectedIndex = index; - } - - // TODO: when restarting a session FF selects the first tab and then the - // tab that was selected when the session was created. As a result the - // alternate after a restart is often incorrectly tab 1 when there - // shouldn't be one yet. - this.updateSelectionHistory = function() - { - alternates = [this.getTab(), alternates[0]]; - this.alternate = alternates[1]; - } - - this.alternate = this.getTab(); - - // updates the buffer preview in place only if list is visible - this.updateBufferList = function() - { - if (!vimperator.bufferwindow.visible()) - return false; - - var items = get_buffer_completions(""); - vimperator.bufferwindow.show(items); - vimperator.bufferwindow.selectItem(getBrowser().mTabContainer.selectedIndex); - } - - this.reload = function(tab, bypass_cache) - { - if (bypass_cache) - { - const nsIWebNavigation = Components.interfaces.nsIWebNavigation; - const flags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; - getBrowser().getBrowserForTab(tab).reloadWithFlags(flags); - } - else - { - getBrowser().reloadTab(tab); - } - } - - this.reloadAll = function(bypass_cache) - { - if (bypass_cache) - { - for (var i = 0; i < getBrowser().mTabs.length; i++) - { - try - { - this.reload(getBrowser().mTabs[i], bypass_cache) - } - catch (e) { - // FIXME: can we do anything useful here without stopping the - // other tabs from reloading? - } - } - } - else - { - getBrowser().reloadAllTabs(); - } - } - //}}} -} //}}} - //////////////////////////////////////////////////////////////////////// // DOM related helper functions //////////////////////////////////////// /////////////////////////////////////////////////////////////////////{{{ diff --git a/chrome/content/vimperator/vimperator.xul b/chrome/content/vimperator/vimperator.xul index 288dbcee..91b1147f 100644 --- a/chrome/content/vimperator/vimperator.xul +++ b/chrome/content/vimperator/vimperator.xul @@ -40,6 +40,8 @@ the terms of any one of the MPL, the GPL or the LGPL. xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">