mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-21 14:27:59 +01:00
Initial import
This commit is contained in:
970
chrome/content/vimperator/vimperator.js
Normal file
970
chrome/content/vimperator/vimperator.js
Normal file
@@ -0,0 +1,970 @@
|
||||
/***** 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 <stubenschrott@gmx.net>
|
||||
|
||||
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 *****/
|
||||
|
||||
var Modes = { // XXX: not yet used
|
||||
MODE_NORMAL: 1,
|
||||
MODE_INSERT: 2,
|
||||
MODE_HAH_MAGIC: 3 // when we are holding space for hah input
|
||||
};
|
||||
var current_mode = Modes.MODE_NORMAL;
|
||||
var popup_allowed_events; // need to change and reset this firefox pref
|
||||
|
||||
var g_inputbuffer = ""; // here we store partial commands (e.g. 'g' if you want to type 'gg')
|
||||
var g_count = -1; // the parsed integer of g_inputbuffer, or -1 if no count was given
|
||||
|
||||
// handles to our gui elements
|
||||
var preview_window = null;
|
||||
var status_line = null;
|
||||
var completion_list = null;
|
||||
var command_line = null;
|
||||
|
||||
// our status bar fields
|
||||
const STATUSFIELD_URL = 1;
|
||||
const STATUSFIELD_INPUTBUFFER = 2;
|
||||
const STATUSFIELD_PROGRESS = 3;
|
||||
const STATUSFIELD_BUFFERS = 4;
|
||||
const STATUSFIELD_CURSOR_POSITION = 5;
|
||||
|
||||
|
||||
/* this function reacts to status bar and url changes which are sent from
|
||||
the mozilla core */
|
||||
function nsBrowserStatusHandler() /*{{{*/
|
||||
{
|
||||
this.init();
|
||||
}
|
||||
nsBrowserStatusHandler.prototype =
|
||||
{
|
||||
QueryInterface : function(aIID)
|
||||
{
|
||||
if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
|
||||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
|
||||
aIID.equals(Components.interfaces.nsIXULBrowserWindow) ||
|
||||
aIID.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
init : function()
|
||||
{
|
||||
},
|
||||
|
||||
setOverLink : function(link, b)
|
||||
{
|
||||
echo(link);
|
||||
},
|
||||
setJSStatus : function(status)
|
||||
{
|
||||
// echo("setJSStatus");
|
||||
// this.updateStatusField(status);
|
||||
},
|
||||
setJSDefaultStatus : function(status)
|
||||
{
|
||||
// echo("setJSDefaultStatus");
|
||||
// this.updateStatusField(status);
|
||||
},
|
||||
setDefaultStatus : function(status)
|
||||
{
|
||||
// echo("setDefaultStatus");
|
||||
// this.updateStatusField(status);
|
||||
},
|
||||
|
||||
|
||||
onStateChange:function(aProgress,aRequest,aFlag,aStatus)
|
||||
{
|
||||
//alert("state change");
|
||||
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
|
||||
const nsIChannel = Components.interfaces.nsIChannel;
|
||||
if (aFlag & nsIWebProgressListener.STATE_START && aRequest && aRequest.URI)
|
||||
{
|
||||
var toLoadUrl = aRequest.URI.spec;
|
||||
}
|
||||
else if (aFlag & nsIWebProgressListener.STATE_STOP)
|
||||
{
|
||||
updateStatusbar();
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
onLocationChange:function (aWebProgress, aRequest, aLocation)
|
||||
{
|
||||
UpdateBackForwardButtons();
|
||||
var url = aLocation.spec;
|
||||
gURLBar.value = url; // also update the original firefox location bar
|
||||
|
||||
// onLocationChange is also called when switching/deleting tabs
|
||||
if (hah.currentMode() != HINT_MODE_ALWAYS)
|
||||
hah.disableHahMode();
|
||||
|
||||
// updating history cache is not done here but in
|
||||
// the 'pageshow' event handler, because at this point I don't
|
||||
// have access to the url title
|
||||
},
|
||||
onProgressChange:function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
|
||||
{
|
||||
showStatusbarMessage(createProgressBar(aCurTotalProgress/aMaxTotalProgress), STATUSFIELD_PROGRESS);
|
||||
return 0;
|
||||
},
|
||||
onStatusChange:function (aWebProgress, aRequest, aStatus, aMessage)
|
||||
{
|
||||
showStatusbarMessage(aMessage, STATUSFIELD_URL);
|
||||
return 0;
|
||||
},
|
||||
onSecurityChange:function (aWebProgress, aRequest, aState)
|
||||
{
|
||||
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
|
||||
if(aState & nsIWebProgressListener.STATE_IS_INSECURE)
|
||||
setStatusbarColor("transparent");
|
||||
else if(aState & nsIWebProgressListener.STATE_IS_BROKEN)
|
||||
setStatusbarColor("orange");
|
||||
else if(aState & nsIWebProgressListener.STATE_IS_SECURE)
|
||||
setStatusbarColor("yellow");
|
||||
|
||||
return 0;
|
||||
}
|
||||
//onLinkIconAvailable:function(a){}
|
||||
|
||||
};/*}}}*/
|
||||
|
||||
window.addEventListener("load", init, false);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// init/uninit //////////////////////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
function init()
|
||||
{
|
||||
preview_window = document.getElementById("vim-preview_window");
|
||||
status_line = document.getElementById("vim-statusbar");
|
||||
completion_list = document.getElementById("vim-completion");
|
||||
command_line = document.getElementById("vim-commandbar");
|
||||
if (!completion_list || !command_line)
|
||||
alert("GUI not correctly created! Strange things will happen (until I find out, how to exit this script by code)");
|
||||
|
||||
// Setup our status handler - from browser.js
|
||||
window.XULBrowserWindow = new nsBrowserStatusHandler();
|
||||
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;
|
||||
|
||||
|
||||
window.addEventListener("unload", unload, false);
|
||||
window.addEventListener("keypress", onVimperatorKeypress, true);
|
||||
// window.addEventListener("keyup", onVimperatorKeyup, true);
|
||||
// window.addEventListener("keydown", onVimperatorKeydown, true);
|
||||
|
||||
// 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"); };
|
||||
|
||||
// these 4 events require >=firefox-2.0 beta1
|
||||
window.addEventListener("TabMove", updateStatusbar, false);
|
||||
window.addEventListener("TabOpen", updateStatusbar, false);
|
||||
window.addEventListener("TabClose", updateStatusbar, false);
|
||||
//window.addEventListener("TabSelect", updateStatusbar, false);
|
||||
window.addEventListener("TabSelect", function(event)
|
||||
{
|
||||
//alert("select");
|
||||
if (hah.currentMode == HINT_MODE_ALWAYS)
|
||||
{
|
||||
hah.disableHahMode();
|
||||
hah.enableHahMode(HINT_MODE_ALWAYS);
|
||||
}
|
||||
updateStatusbar();
|
||||
}, false);
|
||||
|
||||
/*** load our preferences ***/
|
||||
load_history();
|
||||
|
||||
set_showtabline(get_pref("showtabline"));
|
||||
set_guioptions(get_pref("guioptions"));
|
||||
|
||||
// work around firefox popup blocker
|
||||
popup_allowed_events = get_firefox_pref('dom.popup_allowed_events', 'change click dblclick mouseup reset submit');
|
||||
if (!popup_allowed_events.match("keypress"))
|
||||
set_firefox_pref('dom.popup_allowed_events', popup_allowed_events + " keypress");
|
||||
|
||||
// we have our own typeahead find implementation
|
||||
set_firefox_pref('accessibility.typeaheadfind.autostart', false);
|
||||
set_firefox_pref('accessibility.typeaheadfind', false); // actually the above setting should do it, but has no effect in firefox
|
||||
|
||||
// first time intro message
|
||||
if (get_pref("firsttime", true))
|
||||
{
|
||||
setTimeout(function() {
|
||||
var tab = openURLsInNewTab("about:blank", true);
|
||||
BrowserStop();
|
||||
help();
|
||||
set_pref("firsttime", false);
|
||||
},1000);
|
||||
}
|
||||
|
||||
|
||||
// update our history cache when a new page is shown
|
||||
// XXX: there should be a cleaner way with onload() handler, but it just
|
||||
// does not work out well for me :(
|
||||
window.document.addEventListener("pageshow", function(event)
|
||||
{
|
||||
if (!event.persisted) // only if not bypassing cache
|
||||
{
|
||||
var url = getCurrentLocation();
|
||||
var title = document.title;
|
||||
for(var i=0; i<g_history.length; i++)
|
||||
{
|
||||
if(g_history[i][0] == url)
|
||||
return;
|
||||
}
|
||||
g_history.unshift([url, title]);
|
||||
}
|
||||
}
|
||||
, null);
|
||||
|
||||
// called when the window is scrolled.
|
||||
window.onscroll = function (event)
|
||||
{
|
||||
showStatusbarMessage(createCursorPositionString(), STATUSFIELD_CURSOR_POSITION);
|
||||
};
|
||||
|
||||
gURLBar.blur();
|
||||
focusContent(true, true);
|
||||
|
||||
// everything important is done, register a preload handler to speed up first time history cache
|
||||
if(get_pref("preload"))
|
||||
setTimeout(function() { get_url_completions(""); } , 100);
|
||||
|
||||
logMessage("Initialized");
|
||||
}
|
||||
|
||||
function unload()
|
||||
{
|
||||
/*** save our preferences ***/
|
||||
save_history();
|
||||
|
||||
// reset firefox pref
|
||||
if (get_firefox_pref('dom.popup_allowed_events',
|
||||
'change click dblclick mouseup reset submit') == popup_allowed_events + " keypress")
|
||||
set_firefox_pref('dom.popup_allowed_events', popup_allowed_events);
|
||||
|
||||
// XXX: not needed anymore?: window.getBrowser().removeProgressListener(urlChangeListener);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// keyboard input handling //////////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
function onVimperatorKeypress(event)/*{{{*/
|
||||
{
|
||||
// XXX: for now only, later: input mappings if form element focused
|
||||
if (isFormElemFocused())
|
||||
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;
|
||||
// } }}}
|
||||
|
||||
// change the event to a usable string representation
|
||||
var key = keyToString(event);
|
||||
if (key == null)
|
||||
return false;
|
||||
|
||||
// if Hit-a-hint mode is on, special handling of keys is required
|
||||
// g_hint_mappings is used
|
||||
if (hah.hintsVisible())
|
||||
{
|
||||
// never propagate this key to firefox, when hints are visible
|
||||
event.preventDefault();
|
||||
event.preventBubble();
|
||||
event.stopPropagation();
|
||||
|
||||
for (i = 0; i < g_hint_mappings.length; i++)
|
||||
{
|
||||
if(g_hint_mappings[i][0] == key)
|
||||
{
|
||||
if(g_hint_mappings[i][3] == true || hah.currentState() == 1)
|
||||
{
|
||||
//g_hint_mappings[i][1].call(this, event);
|
||||
eval(g_hint_mappings[i][1]);
|
||||
if (g_hint_mappings[i][2] == true) // stop processing this event
|
||||
{
|
||||
hah.disableHahMode();
|
||||
g_inputbuffer = "";
|
||||
updateStatusbar();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure that YOU update the statusbar message yourself
|
||||
// first in g_hint_mappings when in this mode!
|
||||
updateStatusbar();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no mapping found, beep()
|
||||
if (hah.currentState() == 1)
|
||||
{
|
||||
beep();
|
||||
hah.disableHahMode();
|
||||
g_inputbuffer = "";
|
||||
updateStatusbar();
|
||||
return true;
|
||||
}
|
||||
|
||||
// if we came here, let hit-a-hint process the key as it is part
|
||||
// of a partial link
|
||||
var res = hah.processEvent(event);
|
||||
if (res < 0) // error occured processing this key
|
||||
{
|
||||
beep();
|
||||
if(hah.currentMode() == HINT_MODE_QUICK)
|
||||
hah.disableHahMode();
|
||||
else // ALWAYS mode
|
||||
hah.resetHintedElements();
|
||||
g_inputbuffer = "";
|
||||
}
|
||||
else if (res == 0 || hah.currentMode() == HINT_MODE_EXTENDED) // key processed, part of a larger hint
|
||||
g_inputbuffer += key;
|
||||
else // this key completed a quick hint
|
||||
{
|
||||
// if the hint is all in UPPERCASE, open it in new tab
|
||||
g_inputbuffer += key;
|
||||
if (g_inputbuffer.toUpperCase() == g_inputbuffer)
|
||||
hah.openHints(true, false);
|
||||
else // open in current window
|
||||
hah.openHints(false, false);
|
||||
|
||||
if(hah.currentMode() == HINT_MODE_QUICK)
|
||||
hah.disableHahMode();
|
||||
else // ALWAYS mode
|
||||
hah.resetHintedElements();
|
||||
|
||||
g_inputbuffer = "";
|
||||
}
|
||||
|
||||
updateStatusbar();
|
||||
return true;
|
||||
}
|
||||
|
||||
// set this variable to true, if we have the start of a mapping
|
||||
var couldBecomeCompleteMapping = false;
|
||||
var count_str = g_inputbuffer.match(/^[0-9]*/)[0];
|
||||
|
||||
// counts must be at the start of a complete mapping (10j -> go 10 lines down)
|
||||
if (event.charCode >= 48 && event.charCode <= 57 && !(event.ctrlKey || event.altKey))
|
||||
{
|
||||
if (g_inputbuffer.search(/[^0-9]/) != -1)
|
||||
{
|
||||
g_inputbuffer = "";
|
||||
beep();
|
||||
updateStatusbar();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// handle '0' specially to allow binding of 0
|
||||
if (g_inputbuffer != "" || key != "0")
|
||||
{
|
||||
g_inputbuffer += key;
|
||||
updateStatusbar();
|
||||
return true;
|
||||
}
|
||||
// else let the flow continue, and check if 0 is a mapping
|
||||
}
|
||||
}
|
||||
|
||||
for (var i in g_mappings)
|
||||
{
|
||||
// each internal mapping can have multiple keys
|
||||
for (var j in g_mappings[i][0])
|
||||
{
|
||||
var mapping = g_mappings[i][0][j];
|
||||
// alert("key: " + key +" - mapping: "+ mapping + " - g_input: " + g_inputbuffer);
|
||||
if(count_str + mapping == g_inputbuffer + key)
|
||||
{
|
||||
g_count = parseInt(count_str, 10);
|
||||
if (isNaN(g_count))
|
||||
g_count = -1;
|
||||
|
||||
// allow null (= no operation) mappings
|
||||
if(g_mappings[i][3] != null)
|
||||
g_mappings[i][3].call(this, g_count);
|
||||
|
||||
// command executed, reset input buffer
|
||||
g_inputbuffer = "";
|
||||
updateStatusbar();
|
||||
event.preventDefault();
|
||||
event.preventBubble();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
else if ((count_str+mapping).indexOf(g_inputbuffer + key) == 0)
|
||||
{
|
||||
couldBecomeCompleteMapping = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (couldBecomeCompleteMapping)
|
||||
{
|
||||
g_inputbuffer += key;
|
||||
event.preventDefault();
|
||||
event.preventBubble();
|
||||
event.stopPropagation();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_inputbuffer = "";
|
||||
beep();
|
||||
}
|
||||
|
||||
updateStatusbar();
|
||||
return false;
|
||||
}/*}}}*/
|
||||
function onCommandBarKeypress(evt)/*{{{*/
|
||||
{
|
||||
try
|
||||
{
|
||||
/* parse our command string into tokens */
|
||||
var command = command_line.value;
|
||||
|
||||
var matches1 = command.match(/^:(\d+)/);
|
||||
var matches2 = command.match(/^:(\d+)?([a-zA-Z!]+)/);
|
||||
var matches3 = command.match(/^:(\d+)?([a-zA-Z!]+)\s*(.*?)\s*$/);
|
||||
var count = 0;
|
||||
var cmd = "";
|
||||
var args= "";
|
||||
var special = false;
|
||||
|
||||
if (matches1 != null && matches1.length == 2)
|
||||
count = parseInt(matches1[1], 10);
|
||||
if (matches2 != null && matches2.length >= 3)
|
||||
cmd = matches2[2];
|
||||
if (matches3 != null && matches3.length >= 4)
|
||||
args = matches3[3];
|
||||
|
||||
/* if the user executes a command with ! at the end */
|
||||
if (cmd.length - 1 == cmd.lastIndexOf("!"))
|
||||
{
|
||||
special = true;
|
||||
cmd = cmd.replace(/!$/, "");
|
||||
}
|
||||
else
|
||||
special = false;
|
||||
|
||||
|
||||
/* user pressed ENTER to carry out a command */
|
||||
if (evt.keyCode == KeyEvent.DOM_VK_RETURN)
|
||||
{
|
||||
// unfocus command line first
|
||||
focusContent(false, true); // also sets comp_tab_index to -1
|
||||
add_to_command_history(command);
|
||||
|
||||
execute_command(count, cmd, special, args);
|
||||
}
|
||||
|
||||
else if (evt.keyCode == KeyEvent.DOM_VK_ESCAPE)
|
||||
{
|
||||
add_to_command_history(command);
|
||||
focusContent(true, true);
|
||||
}
|
||||
|
||||
/* user pressed UP or DOWN arrow to cycle completion */
|
||||
else if (evt.keyCode == KeyEvent.DOM_VK_UP || evt.keyCode == KeyEvent.DOM_VK_DOWN)
|
||||
{
|
||||
/* save 'start' position for iterating through the history */
|
||||
if (comp_history_index == -1)
|
||||
{
|
||||
comp_history_index = comp_history.length;
|
||||
comp_history_start = command_line.value;
|
||||
}
|
||||
|
||||
while (comp_history_index >= -1 && comp_history_index <= comp_history.length)
|
||||
{
|
||||
evt.keyCode == KeyEvent.DOM_VK_UP ? comp_history_index-- : comp_history_index++;
|
||||
if (comp_history_index == comp_history.length) // user pressed DOWN when there is no newer history item
|
||||
{
|
||||
command_line.value = comp_history_start;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we are at either end of the list, reset the counter, break the loop and beep */
|
||||
if((evt.keyCode == KeyEvent.DOM_VK_UP && comp_history_index <= -1) ||
|
||||
(evt.keyCode == KeyEvent.DOM_VK_DOWN && comp_history_index >= comp_history.length))
|
||||
{
|
||||
evt.keyCode == KeyEvent.DOM_VK_UP ? comp_history_index++ : comp_history_index--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (comp_history[comp_history_index].indexOf(comp_history_start) == 0)
|
||||
{
|
||||
command_line.value = comp_history[comp_history_index];
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
beep();
|
||||
}
|
||||
|
||||
/* user pressed TAB to get completions of a command */
|
||||
else if (evt.keyCode == KeyEvent.DOM_VK_TAB)
|
||||
{
|
||||
//always reset our completion history so up/down keys will start with new values
|
||||
comp_history_index = -1;
|
||||
|
||||
// we need to build our completion list first
|
||||
if (comp_tab_index == COMPLETION_UNINITIALIZED)
|
||||
{
|
||||
g_completions = [];
|
||||
comp_tab_index = -1;
|
||||
comp_tab_list_offset = 0;
|
||||
comp_tab_startstring = command;
|
||||
|
||||
/* if there is no space between the command name and the cursor
|
||||
* then get completions of the command name
|
||||
*/
|
||||
if(command_line.value.substring(0, command_line.selectionStart).search(/[ \t]/) == -1)
|
||||
{
|
||||
get_command_completions(cmd);
|
||||
}
|
||||
else // dynamically get completions as specified in the g_commands array
|
||||
{
|
||||
var command = get_command(cmd);
|
||||
if (command && command[4])
|
||||
{
|
||||
g_completions = command[4].call(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* now we have the g_completions, so lets show them */
|
||||
if (comp_tab_index >= -1)
|
||||
{
|
||||
// we could also return when no completion is found
|
||||
// but we fall through to the cleanup anyway
|
||||
if (g_completions.length == 0)
|
||||
beep();
|
||||
|
||||
// show the list
|
||||
completion_show_list();
|
||||
|
||||
if (evt.shiftKey)
|
||||
completion_select_previous_item();
|
||||
else
|
||||
completion_select_next_item();
|
||||
//command_line.focus(); // workaraound only need for RICHlistbox
|
||||
|
||||
|
||||
if (comp_tab_index == -1) // wrapped around matches, reset command line
|
||||
{
|
||||
command_line.value = comp_tab_startstring;
|
||||
completion_list.selectedIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var compl = g_completions[comp_tab_index][0];
|
||||
if (compl)
|
||||
{
|
||||
/* if there is no space between the command name and the cursor
|
||||
* the completions are for the command name
|
||||
*/
|
||||
if(command_line.value.substring(0, command_line.selectionStart).search(/[ \t]/) == -1)
|
||||
{
|
||||
command_line.value = ":" + (count ? count.toString() : "") + compl;
|
||||
}
|
||||
else // completions are for an argument
|
||||
{
|
||||
command_line.value = ":" + (count ? count.toString() : "") +
|
||||
cmd + (special ? "!" : "") + " " + compl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prevent tab from moving to the next field
|
||||
evt.preventDefault();
|
||||
evt.preventBubble();
|
||||
evt.stopPropagation();
|
||||
|
||||
}
|
||||
else if (evt.keyCode == KeyEvent.DOM_VK_BACK_SPACE)
|
||||
{
|
||||
if (command_line.value == ":")
|
||||
{
|
||||
evt.preventDefault();
|
||||
focusContent(true, true);
|
||||
}
|
||||
comp_tab_index = COMPLETION_UNINITIALIZED;
|
||||
comp_history_index = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// some key hit, check if the cursor is before the :
|
||||
if (command_line.selectionStart == 0)
|
||||
command_line.selectionStart = 1;
|
||||
|
||||
// and reset the tab completion
|
||||
comp_tab_index = COMPLETION_UNINITIALIZED;
|
||||
comp_history_index = -1;
|
||||
|
||||
}
|
||||
} catch(e) { alert(e); }
|
||||
}/*}}}*/
|
||||
|
||||
function onCommandBarInput(event)
|
||||
{
|
||||
if (command_line.value == "")
|
||||
command_line.value = ":";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// focus and mode handling //////////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/* After pressing Escape, put focus on a non-input field of the browser document */
|
||||
function focusContent(clear_command_line, clear_statusline)
|
||||
{
|
||||
try
|
||||
{
|
||||
g_count = -1; // clear count
|
||||
|
||||
if(clear_command_line)
|
||||
{
|
||||
command_line.value = "";
|
||||
command_line.inputField.setAttribute("style","font-family: monospace;");
|
||||
}
|
||||
|
||||
if(clear_statusline)
|
||||
{
|
||||
completion_list.hidden = true;
|
||||
comp_tab_index = COMPLETION_UNINITIALIZED;
|
||||
comp_history_index = -1;
|
||||
updateStatusbar();
|
||||
}
|
||||
|
||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
if (window == ww.activeWindow && document.commandDispatcher.focusedElement)
|
||||
{
|
||||
document.commandDispatcher.focusedElement.blur();
|
||||
}
|
||||
content.focus();
|
||||
|
||||
} catch(e)
|
||||
{
|
||||
echoerr(e);
|
||||
}
|
||||
}
|
||||
|
||||
function openVimperatorBar(str)
|
||||
{
|
||||
// make sure the input field is not red anymore if we had an echoerr() first
|
||||
command_line.inputField.setAttribute("style","font-family: monospace;");
|
||||
|
||||
if(str == null)
|
||||
str = "";
|
||||
|
||||
if (g_count > 1)
|
||||
command_line.value = ":" + g_count.toString() + str;
|
||||
else
|
||||
command_line.value = ":" + str;
|
||||
|
||||
try {
|
||||
command_line.focus();
|
||||
} catch(e) {
|
||||
echo(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function onEscape()
|
||||
{
|
||||
BrowserStop();
|
||||
focusContent(true, true);
|
||||
hah.disableHahMode();
|
||||
}
|
||||
|
||||
function onBlur() // FIXME: needed?
|
||||
{
|
||||
//alert('blur');
|
||||
//focusContent(false, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// statusbar/progressbar ////////////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/* the statusbar is currently divided into 5 fields, you can set
|
||||
* each one independently */
|
||||
function showStatusbarMessage(msg, field)
|
||||
{
|
||||
var bar = document.getElementById("vim-sb-field-" + field);
|
||||
if (bar)
|
||||
bar.value = msg;
|
||||
}
|
||||
|
||||
function setStatusbarColor(color)
|
||||
{
|
||||
var bar = document.getElementById("vim-statusbar");
|
||||
bar.setAttribute("style", "background-color: " + color);
|
||||
}
|
||||
|
||||
function updateStatusbar()
|
||||
{
|
||||
var buffers = "[" + (gBrowser.tabContainer.selectedIndex + 1).toString() + "/" +
|
||||
gBrowser.tabContainer.childNodes.length.toString() + "]";
|
||||
|
||||
showStatusbarMessage(getCurrentLocation(), STATUSFIELD_URL);
|
||||
showStatusbarMessage(" " + g_inputbuffer + " ", STATUSFIELD_INPUTBUFFER);
|
||||
showStatusbarMessage("", STATUSFIELD_PROGRESS);
|
||||
showStatusbarMessage(buffers, STATUSFIELD_BUFFERS);
|
||||
|
||||
// required to postpone it a little, otherwise we could get the wrong cursor
|
||||
// position when switching tabs
|
||||
setTimeout(function() {
|
||||
showStatusbarMessage(createCursorPositionString(), STATUSFIELD_CURSOR_POSITION);
|
||||
} , 10);
|
||||
}
|
||||
|
||||
/* aProgress is a float between 0 and 1 */
|
||||
function createProgressBar(aProgress)
|
||||
{
|
||||
/* the progress field */
|
||||
var progress;
|
||||
if (aProgress <= 0)
|
||||
progress = "[ Loading... ]";
|
||||
else if (aProgress >= 1)
|
||||
progress = "[====================]";
|
||||
else
|
||||
{
|
||||
progress = /*(aProgress*100).round().toString() + "% */"[";
|
||||
done = Math.floor(aProgress * 20);
|
||||
for (i=0; i < done; i++)
|
||||
progress = progress + "=";
|
||||
progress = progress + ">";
|
||||
for (i=19; i > done; i--)
|
||||
progress = progress + " ";
|
||||
progress = progress + "]";
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
function createCursorPositionString()
|
||||
{
|
||||
var win = document.commandDispatcher.focusedWindow;
|
||||
//var x = win.scrollMaxX == 0 ? 100 : Math.round(win.scrollX / win.scrollMaxX * 100);
|
||||
var y = win.scrollMaxY == 0 ? -1 : Math.round(win.scrollY / win.scrollMaxY * 100);
|
||||
|
||||
var percent;
|
||||
if (y < 0) percent = "All";
|
||||
else if (y == 0) percent = "Top";
|
||||
else if (y < 10) percent = " " + y.toString() + "%";
|
||||
else if (y >= 100) percent = "Bot";
|
||||
else percent = y.toString() + "%";
|
||||
|
||||
return(" " + percent);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// text input functions /////////////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
function isFormElemFocused()
|
||||
{
|
||||
var elt = document.commandDispatcher.focusedElement;
|
||||
if (elt == null) return false;
|
||||
|
||||
var tagName = elt.localName.toUpperCase();
|
||||
|
||||
if (tagName == "INPUT" ||
|
||||
tagName == "TEXTAREA" ||
|
||||
tagName == "SELECT" ||
|
||||
tagName == "BUTTON" ||
|
||||
tagName == "ISINDEX")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// logging //////////////////////////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var gConsoleService = Components.classes['@mozilla.org/consoleservice;1']
|
||||
.getService(Components.interfaces.nsIConsoleService);
|
||||
|
||||
function logMessage(msg)
|
||||
{
|
||||
gConsoleService.logStringMessage('vimperator: ' + msg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// misc helper funcstions ///////////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// this function gets an event as the input and converts it to
|
||||
// a keycode which can be used in mappings
|
||||
// e.g. pressing ctrl+n would result in the string "<c-n>"
|
||||
function keyToString(event)
|
||||
{
|
||||
var key = String.fromCharCode(event.charCode);
|
||||
var modifier = "";
|
||||
if (event.charCode > 0)
|
||||
{
|
||||
if (event.ctrlKey)
|
||||
modifier += "C-";
|
||||
if (event.altKey)
|
||||
modifier += "A-";
|
||||
if (event.metaKey)
|
||||
modifier += "M-";
|
||||
|
||||
if (modifier.length > 0)
|
||||
return "<" + modifier + key + ">";
|
||||
else
|
||||
return key;
|
||||
}
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE)
|
||||
return "<Esc>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_RETURN)
|
||||
return "<Return>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_TAB)
|
||||
return "<Tab>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_DELETE)
|
||||
return "<Del>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_BACK_SPACE)
|
||||
return "<BS>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_HOME)
|
||||
return "<Home>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_END)
|
||||
return "<End>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_LEFT)
|
||||
return "<Left>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_RIGHT)
|
||||
return "<Right>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_UP)
|
||||
return "<Up>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_DOWN)
|
||||
return "<Down>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_PAGE_UP)
|
||||
return "<PageUp>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_PAGE_DOWN)
|
||||
return "<PageDown>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F1)
|
||||
return "<F1>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F2)
|
||||
return "<F2>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F3)
|
||||
return "<F3>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F4)
|
||||
return "<F4>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F5)
|
||||
return "<F5>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F6)
|
||||
return "<F6>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F7)
|
||||
return "<F7>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F8)
|
||||
return "<F8>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F9)
|
||||
return "<F9>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F10)
|
||||
return "<F10>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F11)
|
||||
return "<F11>";
|
||||
else if (event.keyCode == KeyEvent.DOM_VK_F12)
|
||||
return "<F12>";
|
||||
|
||||
// if nothing matches
|
||||
return null;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// DOM related helper functsion /////////////////////////////////// {{{1
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Handle frames if they're present
|
||||
function getPageLinkNodes()
|
||||
{
|
||||
var frames = window._content.frames;
|
||||
|
||||
// The main content may have link nodes as well as it's frames.
|
||||
var nodes = getLinkNodes(_content.content.document);
|
||||
var tmp;
|
||||
for (var i=0; i<frames.length; i++) {
|
||||
tmp = getLinkNodes(frames[i].document);
|
||||
// is javascript this crappy?
|
||||
for (var j=0; j<tmp.length; j++)
|
||||
nodes.push(tmp[j]);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
// For a single document, grab all the nodes
|
||||
function getLinkNodes(doc)
|
||||
{
|
||||
var a_nodes = doc.getElementsByTagName('a');
|
||||
var i_nodes = doc.getElementsByTagName('input');
|
||||
var s_nodes = doc.getElementsByTagName('select');
|
||||
var t_nodes = doc.getElementsByTagName('textarea');
|
||||
|
||||
var links = [];
|
||||
|
||||
for (var i=0; i<t_nodes.length; i++) {
|
||||
links.push(t_nodes[i]);
|
||||
}
|
||||
for (var i=0; i<s_nodes.length; i++) {
|
||||
links.push(s_nodes[i]);
|
||||
}
|
||||
for (var i=0; i<i_nodes.length; i++) {
|
||||
if (i_nodes[i].type == "hidden") continue;
|
||||
links.push(i_nodes[i]);
|
||||
}
|
||||
for (var i=0; i<a_nodes.length; i++) {
|
||||
if (!a_nodes[i].hasAttribute('href')) continue;
|
||||
links.push(a_nodes[i]);
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
// vim: set fdm=marker :
|
||||
Reference in New Issue
Block a user