1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-04-14 00:43:33 +02:00

intialize the vimperator global constant with an object literal rather than via

a constructor function; move the init() and unload() global functions to
startup and shutdown slots of vimperator
This commit is contained in:
Doug Kearns
2007-07-25 13:33:31 +00:00
parent 9bab3c8f15
commit 75a72e8791
5 changed files with 471 additions and 501 deletions

View File

@@ -1305,102 +1305,6 @@ function isDirectory(url)
return false; return false;
} }
/////////////////////////////////////////////////////////////////////}}}
// frame related functions /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////{{{
// TODO: allow callback for filtering out unwanted frames? User defined?
Vimperator.prototype.shiftFrameFocus = function(count, forward)
{
try
{
var frames = [];
// find all frames - depth-first search
(function(frame)
{
if (frame.document.body.localName.toLowerCase() == "body")
frames.push(frame);
for (var i = 0; i < frame.frames.length; i++)
arguments.callee(frame.frames[i])
})(window.content);
if (frames.length == 0) // currently top is always included
return;
// remove all unfocusable frames
// TODO: find a better way to do this
var start = document.commandDispatcher.focusedWindow;
frames = frames.filter(function(frame) {
frame.focus();
if (document.commandDispatcher.focusedWindow == frame)
return frame;
});
start.focus();
// find the currently focused frame index
// TODO: If the window is a frameset then the first _frame_ should be
// focused. Since this is not the current FF behaviour,
// we initalise current to -1 so the first call takes us to the
// first frame.
var current = -1;
for (var i = 0; i < frames.length; i++)
{
if (frames[i] == document.commandDispatcher.focusedWindow)
{
var current = i;
break;
}
}
// calculate the next frame to focus
var next = current;
if (forward)
{
if (count > 1)
next = current + count;
else
next++;
if (next > frames.length - 1)
next = frames.length - 1;
}
else
{
if (count > 1)
next = current - count;
else
next--;
if (next < 0)
next = 0;
}
// focus next frame and scroll into view
frames[next].focus();
if (frames[next] != window.content)
frames[next].frameElement.scrollIntoView(false);
// add the frame indicator
var doc = frames[next].document;
var indicator = doc.createElement("div");
indicator.id = "vimperator-frame-indicator";
// NOTE: need to set a high z-index - it's a crapshoot!
var style = "background-color: red; opacity: 0.5; z-index: 999;" +
"position: fixed; top: 0; bottom: 0; left: 0; right: 0;";
indicator.setAttribute("style", style);
doc.body.appendChild(indicator);
// remove the frame indicator
setTimeout(function() { doc.body.removeChild(indicator); }, 500);
}
catch (e)
{
//vimperator.echoerr(e);
// FIXME: fail silently here for now
}
}
/////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////}}}
// location handling /////////////////////////////////////////////////// // location handling ///////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////{{{
@@ -1416,7 +1320,6 @@ function getCurrentTitle()
return window.content.document.title; return window.content.document.title;
} }
/////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////}}}
// scrolling /////////////////////////////////////////////////////////// // scrolling ///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////{{{
@@ -1506,7 +1409,7 @@ function zoom_in(factor)
} }
} }
//Vimperator.prototype.zoom_to = function(value) //vimperator.zoom_to = function(value)
function zoom_to(value) function zoom_to(value)
{ {
var zoomMgr = ZoomManager.prototype.getInstance(); var zoomMgr = ZoomManager.prototype.getInstance();
@@ -1539,11 +1442,39 @@ function zoom_to(value)
vimperator.echo("Zoom value: " + value + "%"); vimperator.echo("Zoom value: " + value + "%");
} }
//}}}
//////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////}}}
// misc helper functions ////////////////////////////////////////////{{{ // DOM related helper functions ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////{{{
function isFormElemFocused()
{
var elt = window.document.commandDispatcher.focusedElement;
if (elt == null)
return false;
try
{ // sometimes the elt doesn't have .localName
var tagname = elt.localName.toLowerCase();
var type = elt.type.toLowerCase();
if ( (tagname == "input" && (type != "image")) ||
tagname == "textarea" ||
// tagName == "SELECT" ||
// tagName == "BUTTON" ||
tagname == "isindex") // isindex is a deprecated one-line input box
return true;
}
catch (e)
{
// FIXME: do nothing?
}
return false;
}
/////////////////////////////////////////////////////////////////////}}}
// misc helper functions ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////{{{
function copyToClipboard(str) function copyToClipboard(str)
{ {
@@ -1572,119 +1503,6 @@ function evaluateXPath(expression, doc, ordered)
); );
return res; return res;
} }
Vimperator.prototype.beep = function()
{
if (!vimperator.options["beep"])
return;
var gBeepService = Components.classes['@mozilla.org/sound;1']
.getService(Components.interfaces.nsISound);
if (gBeepService)
gBeepService.beep();
else
vimperator.echoerr('no beep service found');
}
// quit vimperator, no matter how many tabs/windows are open
Vimperator.prototype.quit = function(save_session)
{
if (save_session)
Options.setFirefoxPref("browser.startup.page", 3); // start with saved session
else
Options.setFirefoxPref("browser.startup.page", 1); // start with default homepage session
goQuitApplication();
}
Vimperator.prototype.restart = function()
{
// if (!arguments[1]) return;
const nsIAppStartup = Components.interfaces.nsIAppStartup;
// Notify all windows that an application quit has been requested.
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
.createInstance(Components.interfaces.nsISupportsPRBool);
os.notifyObservers(cancelQuit, "quit-application-requested", null);
// Something aborted the quit process.
if (cancelQuit.data)
return;
// Notify all windows that an application quit has been granted.
os.notifyObservers(null, "quit-application-granted", null);
// Enumerate all windows and call shutdown handlers
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var windows = wm.getEnumerator(null);
while (windows.hasMoreElements())
{
var win = windows.getNext();
if (("tryToClose" in win) && !win.tryToClose())
return;
}
Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(nsIAppStartup)
.quit(nsIAppStartup.eRestart | nsIAppStartup.eAttemptQuit);
}
Vimperator.prototype.source = function(filename, silent)
{
if (!filename)
return;
function getEnv(variable)
{
var environment = Components.classes["@mozilla.org/process/environment;1"]
.getService(Components.interfaces.nsIEnvironment);
return environment.get(variable);
}
// convert "~" to HOME on Windows
if (navigator.platform == "Win32")
{
// TODO: proper pathname separator translation like Vim
filename = filename.replace('/', '\\', 'g');
var matches = filename.match(/^~(.*)/)
if (matches)
{
var home_dir = getEnv("HOME");
if (!home_dir)
home_dir = getEnv("USERPROFILE");
if (!home_dir)
{
// TODO: are these guaranteed to be set?
home_dir = getEnv("HOMEDRIVE") + getEnv("HOMEPATH");
}
filename = home_dir + "\\" + matches[1];
}
}
try
{
var fd = fopen(filename, "<");
if (!fd)
return;
var s = fd.read();
fd.close();
var prev_match = new Array(5);
var heredoc = '';
var end = false;
s.split('\n').forEach(function(line) {
[prev_match, heredoc, end] = multiliner(line, prev_match, heredoc);
});
}
catch (e)
{
if (!silent)
vimperator.echoerr(e);
}
}
//}}} //}}}
// vim: set fdm=marker sw=4 ts=4 et: // vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -240,7 +240,7 @@ function abs_point (node) {
// Vimperator searcher // Vimperator searcher
// make sure you only create this object when the "vimperator" object is ready // make sure you only create this object when the "vimperator" object is ready
//Vimperator.prototype.search = new function() //vimperator.search = new function()
function Search() //{{{ function Search() //{{{
{ {
var self = this; // needed for callbacks since "this" is the "vimperator" object in a callback var self = this; // needed for callbacks since "this" is the "vimperator" object in a callback

View File

@@ -26,7 +26,7 @@ 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. the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/ }}} ***** END LICENSE BLOCK *****/
Vimperator.prototype.help = function(section, easter) //{{{ vimperator.help = function(section, easter) //{{{
{ {
if (easter) if (easter)
{ {

View File

@@ -848,7 +848,7 @@ function Mappings() //{{{
{ {
short_help: "Escape next key", short_help: "Escape next key",
help: "If you need to pass a certain key to a javascript form field or another extension prefix the key with <code class=\"mapping\">&lt;C-v&gt;</code>.<br/>" + help: "If you need to pass a certain key to a javascript form field or another extension prefix the key with <code class=\"mapping\">&lt;C-v&gt;</code>.<br/>" +
"Also works to unshadow Firefox shortcuts like <code class=\"mapping\">&lt;C-o&gt;</code> which are otherwise hidden in Vimperator.<br/>" + "Also works to unshadow Firefox shortcuts like <code class=\"mapping\">&lt;C-o&gt;</code> which are otherwise hidden in vimperator.<br/>" +
"When in 'ignorekeys' mode (activated by <code class=\"mapping\">&lt;I&gt;</code>), <code class=\"mapping\">&lt;C-v&gt;</code> will pass the next key to Vimperator instead of the web page." "When in 'ignorekeys' mode (activated by <code class=\"mapping\">&lt;I&gt;</code>), <code class=\"mapping\">&lt;C-v&gt;</code> will pass the next key to Vimperator instead of the web page."
} }
)); ));

View File

@@ -26,128 +26,13 @@ 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. the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/ }}} ***** END LICENSE BLOCK *****/
// The only global object, a handler to the main Vimperator object const vimperator = (function() //{{{
var vimperator = null;
var popup_allowed_events; // need to change and reset this firefox pref XXX: move to options class
// called when the chrome is fully loaded and before the main window is shown
window.addEventListener("load", init, false);
////////////////////////////////////////////////////////////////////////
// init/uninit /////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////{{{
function init() //{{{
{
window.dump("Vimperator init\n");
// init the main object
vimperator = new Vimperator();
vimperator.log("Initializing vimperator object...", 1);
// these inner classes are created here, because outside the init()
// function, the chrome:// is not ready
vimperator.log("Loading module options...", 3);
Vimperator.prototype.options = new Options();
vimperator.log("Loading module events...", 3);
Vimperator.prototype.events = new Events();
vimperator.log("Loading module commands...", 3);
Vimperator.prototype.commands = new Commands();
vimperator.log("Loading module bookmarks...", 3);
Vimperator.prototype.bookmarks = new Bookmarks();
vimperator.log("Loading module history...", 3);
Vimperator.prototype.history = new History();
vimperator.log("Loading module commandline...", 3);
Vimperator.prototype.commandline = new CommandLine();
vimperator.log("Loading module search...", 3);
Vimperator.prototype.search = new Search();
vimperator.log("Loading module preview window...", 3);
Vimperator.prototype.previewwindow = new InformationList("vimperator-previewwindow", { incremental_fill: false, max_items: 10 });
vimperator.log("Loading module buffer window...", 3);
Vimperator.prototype.bufferwindow = new InformationList("vimperator-bufferwindow", { incremental_fill: false, max_items: 10 });
vimperator.log("Loading module mappings...", 3);
Vimperator.prototype.mappings = new Mappings();
vimperator.log("Loading module statusline...", 3);
Vimperator.prototype.statusline = new StatusLine();
vimperator.log("Loading module tabs...", 3);
Vimperator.prototype.tabs = new Tabs();
vimperator.log("Loading module marks...", 3);
Vimperator.prototype.marks = new Marks();
vimperator.log("Loading module quickmarks...", 3);
Vimperator.prototype.quickmarks = new QuickMarks();
vimperator.log("Loading module hints...", 3);
Vimperator.prototype.hints = new Hints();
vimperator.log("All modules loaded", 3);
// DJK FIXME
Vimperator.prototype.echo = vimperator.commandline.echo;
Vimperator.prototype.echoerr = vimperator.commandline.echoErr;
// XXX: move elsewhere
vimperator.registerCallback("submit", vimperator.modes.EX, function(command) { /*vimperator.*/execute(command); } );
vimperator.registerCallback("complete", vimperator.modes.EX, function(str) { return exTabCompletion(str); } );
// this function adds all our required listeners to react on events
// also stuff like window.onScroll is handled there.
//addEventListeners();
//vimperator.events();
// work around firefox popup blocker
popup_allowed_events = Options.getFirefoxPref('dom.popup_allowed_events', 'change click dblclick mouseup reset submit');
if (!popup_allowed_events.match("keypress"))
Options.setFirefoxPref('dom.popup_allowed_events', popup_allowed_events + " keypress");
// we have our own typeahead find implementation
Options.setFirefoxPref('accessibility.typeaheadfind.autostart', false);
Options.setFirefoxPref('accessibility.typeaheadfind', false); // actually the above setting should do it, but has no effect in firefox
// first time intro message
if (Options.getPref("firsttime", true))
{
setTimeout(function() {
vimperator.help(null, null, null, { inTab: true });
Options.setPref("firsttime", false);
}, 1000);
}
gURLBar.blur();
vimperator.focusContent();
// firefox preferences which we need to be changed to work well with vimperator
Options.setFirefoxPref("browser.startup.page", 3); // start with saved session
// Finally, read a ~/.vimperatorrc
// Make sourcing asynchronous, otherwise commands that open new tabs won't work
setTimeout(function() {
vimperator.source("~/.vimperatorrc", true);
vimperator.log("~/.vimperatorrc sourced", 1);
}, 50);
window.addEventListener("unload", unload, false);
vimperator.log("Vimperator fully initialized", 1);
} //}}}
function unload() //{{{
{
/*** save our preferences ***/
vimperator.commandline.destroy();
vimperator.events.destroy();
vimperator.quickmarks.destroy();
// reset some modified firefox prefs
if (Options.getFirefoxPref('dom.popup_allowed_events', 'change click dblclick mouseup reset submit')
== popup_allowed_events + " keypress")
Options.setFirefoxPref('dom.popup_allowed_events', popup_allowed_events);
} //}}}
//}}}
function Vimperator() //{{{
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
////////////////////// PRIVATE SECTION ///////////////////////////////////////// ////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
this.modes = { // actually not private, but Firefox complains if this doesn't come first var modes = {
// main modes // main modes
NONE: 0, NONE: 0,
NORMAL: 1 << 0, NORMAL: 1 << 0,
@@ -166,25 +51,33 @@ function Vimperator() //{{{
EXTENDED_HINT: 1 << 17, EXTENDED_HINT: 1 << 17,
ALWAYS_HINT: 1 << 18 ALWAYS_HINT: 1 << 18
} }
var mode_messages = {};
mode_messages[this.modes.NORMAL] = "";
mode_messages[this.modes.INSERT] = "INSERT";
mode_messages[this.modes.VISUAL] = "VISUAL";
mode_messages[this.modes.HINTS] = "HINTS";
mode_messages[this.modes.ESCAPE_ONE_KEY] = "escape one key";
mode_messages[this.modes.ESCAPE_ALL_KEYS] = "escape all keys";
mode_messages[this.modes.ESCAPE_ONE_KEY | this.modes.ESCAPE_ALL_KEYS] = "pass one key";
mode_messages[this.modes.QUICK_HINT] = "quick";
mode_messages[this.modes.EXTENDED_HINT] = "extended";
mode_messages[this.modes.ALWAYS_HINT] = "always";
var callbacks = new Array(); var mode_messages = {};
var mode = this.modes.NORMAL; mode_messages[modes.NORMAL] = "";
var extended_mode = this.modes.NONE; mode_messages[modes.INSERT] = "INSERT";
mode_messages[modes.VISUAL] = "VISUAL";
mode_messages[modes.HINTS] = "HINTS";
mode_messages[modes.ESCAPE_ONE_KEY] = "escape one key";
mode_messages[modes.ESCAPE_ALL_KEYS] = "escape all keys";
mode_messages[modes.ESCAPE_ONE_KEY | modes.ESCAPE_ALL_KEYS] = "pass one key";
mode_messages[modes.QUICK_HINT] = "quick";
mode_messages[modes.EXTENDED_HINT] = "extended";
mode_messages[modes.ALWAYS_HINT] = "always";
var mode = modes.NORMAL;
var extended_mode = modes.NONE;
var callbacks = [];
var popup_allowed_events; // need to change and reset this firefox pref XXX: move to options class
// our services // our services
var sound_service = Components.classes['@mozilla.org/sound;1']
.getService(Components.interfaces.nsISound);
var console_service = Components.classes['@mozilla.org/consoleservice;1'] var console_service = Components.classes['@mozilla.org/consoleservice;1']
.getService(Components.interfaces.nsIConsoleService); .getService(Components.interfaces.nsIConsoleService);
var environment_service = Components.classes["@mozilla.org/process/environment;1"]
.getService(Components.interfaces.nsIEnvironment);
function showMode() function showMode()
{ {
@@ -214,169 +107,428 @@ function Vimperator() //{{{
////////////////////// PUBLIC SECTION ////////////////////////////////////////// ////////////////////// PUBLIC SECTION //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
this.version = "###VERSION### CVS (created: ###DATE###)"; return {
this.input = { modes: modes,
buffer: "", // partial command storage
pendingMap: null, // pending map storage
count: -1 // parsed count from the input buffer
};
/////////////// callbacks //////////////////////////// version: "###VERSION### CVS (created: ###DATE###)",
// XXX: shouldn't that callback be moved to commandline? --mst
/**
* @param type Can be:
* "submit": when the user pressed enter in the command line
* "change"
* "cancel"
* "complete"
*/
this.registerCallback = function(type, mode, func)
{
// TODO: check if callback is already registered
callbacks.push([type, mode, func]);
}
this.triggerCallback = function(type, data) input: {
{ buffer: "", // partial command storage
for (var i in callbacks) pendingMap: null, // pending map storage
{ count: -1 // parsed count from the input buffer
var [thistype, thismode, thisfunc] = callbacks[i]; },
if (vimperator.hasMode(thismode) && type == thistype)
return thisfunc.call(this, data);
}
return false;
}
// just forward these echo commands /**
// DJK FIXME: this.echo = this.commandline.echo; * @param type Can be:
// DJK FIXME: this.echoerr = this.commandline.echoErr; * "submit": when the user pressed enter in the command line
* "change"
* "cancel"
this.getMode = function() * "complete"
{ */
return [mode, extended_mode]; registerCallback: function(type, mode, func)
}
// set current mode
// use "null" if you only want to set one of those modes
this.setMode = function(main, extended, silent)
{
// if a main mode is set, the extended is always cleared
if (main)
{ {
mode = main; // TODO: check if callback is already registered
extended_mode = this.modes.NONE; callbacks.push([type, mode, func]);
} },
if (typeof extended === "number")
extended_mode = extended;
if (!silent) triggerCallback: function(type, data)
showMode(); {
} for (var i in callbacks)
{
// returns true if "whichmode" is found in either the main or var [thistype, thismode, thisfunc] = callbacks[i];
// extended mode if (vimperator.hasMode(thismode) && type == thistype)
this.hasMode = function(whichmode) return thisfunc.call(this, data);
{ }
return ((mode & whichmode) || (extended_mode & whichmode) > 0) ? true : false;
}
this.addMode = function(main, extended)
{
if (main)
mode |= main;
if (extended)
extended_mode |= extended;
showMode();
}
// always show the new mode in the statusline
this.removeMode = function(main, extended)
{
if (main)
mode = (mode | main) ^ main;
if (extended)
extended_mode = (extended_mode | extended) ^ extended;
showMode();
}
// After pressing Escape, put focus on a non-input field of the browser document
this.focusContent = function()
{
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();
}
/**
* logs any object to the javascript error console
* also prints all properties of thie object
*/
this.log = function(msg, level)
{
// if (Options.getPref("verbose") >= level) // FIXME: hangs vimperator, probably timing issue --mst
console_service.logStringMessage('vimperator: ' + msg);
}
/**
* logs any object to the javascript error console
* also prints all properties of the object
*/
this.logObject = function(object, level)
{
if (typeof object != 'object')
return false; return false;
},
var string = object + '::\n'; getMode: function()
for (var i in object)
{ {
var value; return [mode, extended_mode];
try { },
var value = object[i];
} catch (e) { value = '' }
string += i + ': ' + value + '\n'; // set current mode
// use "null" if you only want to set one of those modes
setMode: function(main, extended, silent)
{
// if a main mode is set, the extended is always cleared
if (main)
{
mode = main;
extended_mode = this.modes.NONE;
}
if (typeof extended === "number")
extended_mode = extended;
if (!silent)
showMode();
},
// returns true if "whichmode" is found in either the main or
// extended mode
hasMode: function(whichmode)
{
return ((mode & whichmode) || (extended_mode & whichmode) > 0) ? true : false;
},
addMode: function(main, extended)
{
if (main)
mode |= main;
if (extended)
extended_mode |= extended;
showMode();
},
// always show the new mode in the statusline
removeMode: function(main, extended)
{
if (main)
mode = (mode | main) ^ main;
if (extended)
extended_mode = (extended_mode | extended) ^ extended;
showMode();
},
beep: function()
{
if (vimperator.options["beep"])
sound_service.beep();
},
// After pressing Escape, put focus on a non-input field of the browser document
focusContent: function()
{
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();
},
/**
* logs a message to the javascript error console
*/
log: function(msg, level)
{
// if (Options.getPref("verbose") >= level) // FIXME: hangs vimperator, probably timing issue --mst
console_service.logStringMessage('vimperator: ' + msg);
},
/**
* logs an object to the javascript error console also prints all
* properties of the object
*/
logObject: function(object, level)
{
if (typeof object != 'object')
return false;
var string = object + '::\n';
for (var i in object)
{
var value;
try {
var value = object[i];
} catch (e) { value = '' }
string += i + ': ' + value + '\n';
}
this.log(string, level);
},
// quit vimperator, no matter how many tabs/windows are open
quit: function(save_session)
{
if (save_session)
Options.setFirefoxPref("browser.startup.page", 3); // start with saved session
else
Options.setFirefoxPref("browser.startup.page", 1); // start with default homepage session
goQuitApplication();
},
restart: function()
{
// if (!arguments[1]) return;
const nsIAppStartup = Components.interfaces.nsIAppStartup;
// Notify all windows that an application quit has been requested.
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
.createInstance(Components.interfaces.nsISupportsPRBool);
os.notifyObservers(cancelQuit, "quit-application-requested", null);
// Something aborted the quit process.
if (cancelQuit.data)
return;
// Notify all windows that an application quit has been granted.
os.notifyObservers(null, "quit-application-granted", null);
// Enumerate all windows and call shutdown handlers
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var windows = wm.getEnumerator(null);
while (windows.hasMoreElements())
{
var win = windows.getNext();
if (("tryToClose" in win) && !win.tryToClose())
return;
}
Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(nsIAppStartup)
.quit(nsIAppStartup.eRestart | nsIAppStartup.eAttemptQuit);
},
// TODO: allow callback for filtering out unwanted frames? User defined?
shiftFrameFocus: function(count, forward)
{
try
{
var frames = [];
// find all frames - depth-first search
(function(frame)
{
if (frame.document.body.localName.toLowerCase() == "body")
frames.push(frame);
for (var i = 0; i < frame.frames.length; i++)
arguments.callee(frame.frames[i])
})(window.content);
if (frames.length == 0) // currently top is always included
return;
// remove all unfocusable frames
// TODO: find a better way to do this
var start = document.commandDispatcher.focusedWindow;
frames = frames.filter(function(frame) {
frame.focus();
if (document.commandDispatcher.focusedWindow == frame)
return frame;
});
start.focus();
// find the currently focused frame index
// TODO: If the window is a frameset then the first _frame_ should be
// focused. Since this is not the current FF behaviour,
// we initalise current to -1 so the first call takes us to the
// first frame.
var current = -1;
for (var i = 0; i < frames.length; i++)
{
if (frames[i] == document.commandDispatcher.focusedWindow)
{
var current = i;
break;
}
}
// calculate the next frame to focus
var next = current;
if (forward)
{
if (count > 1)
next = current + count;
else
next++;
if (next > frames.length - 1)
next = frames.length - 1;
}
else
{
if (count > 1)
next = current - count;
else
next--;
if (next < 0)
next = 0;
}
// focus next frame and scroll into view
frames[next].focus();
if (frames[next] != window.content)
frames[next].frameElement.scrollIntoView(false);
// add the frame indicator
var doc = frames[next].document;
var indicator = doc.createElement("div");
indicator.id = "vimperator-frame-indicator";
// NOTE: need to set a high z-index - it's a crapshoot!
var style = "background-color: red; opacity: 0.5; z-index: 999;" +
"position: fixed; top: 0; bottom: 0; left: 0; right: 0;";
indicator.setAttribute("style", style);
doc.body.appendChild(indicator);
// remove the frame indicator
setTimeout(function() { doc.body.removeChild(indicator); }, 500);
}
catch (e)
{
//vimperator.echoerr(e);
// FIXME: fail silently here for now
}
},
source: function(filename, silent)
{
if (!filename)
return;
// convert "~" to HOME on Windows
if (navigator.platform == "Win32")
{
// TODO: proper pathname separator translation like Vim
filename = filename.replace('/', '\\', 'g');
var matches = filename.match(/^~(.*)/)
if (matches)
{
var home_dir = environment_service.get("HOME");
if (!home_dir)
home_dir = environment_service.get("USERPROFILE");
if (!home_dir)
{
// TODO: are these guaranteed to be set?
home_dir = environment_service.get("HOMEDRIVE") + environment_service.get("HOMEPATH");
}
filename = home_dir + "\\" + matches[1];
}
}
try
{
var fd = fopen(filename, "<");
if (!fd)
return;
var s = fd.read();
fd.close();
var prev_match = new Array(5);
var heredoc = '';
var end = false;
s.split('\n').forEach(function(line) {
[prev_match, heredoc, end] = multiliner(line, prev_match, heredoc);
});
}
catch (e)
{
if (!silent)
vimperator.echoerr(e);
}
},
startup: function()
{
window.dump("Vimperator startup\n");
vimperator.log("Initializing vimperator object...", 1);
// these objects are created here only after the chrome is ready
vimperator.log("Loading module options...", 3);
vimperator.options = new Options();
vimperator.log("Loading module events...", 3);
vimperator.events = new Events();
vimperator.log("Loading module commands...", 3);
vimperator.commands = new Commands();
vimperator.log("Loading module bookmarks...", 3);
vimperator.bookmarks = new Bookmarks();
vimperator.log("Loading module history...", 3);
vimperator.history = new History();
vimperator.log("Loading module commandline...", 3);
vimperator.commandline = new CommandLine();
vimperator.log("Loading module search...", 3);
vimperator.search = new Search();
vimperator.log("Loading module preview window...", 3);
vimperator.previewwindow = new InformationList("vimperator-previewwindow", { incremental_fill: false, max_items: 10 });
vimperator.log("Loading module buffer window...", 3);
vimperator.bufferwindow = new InformationList("vimperator-bufferwindow", { incremental_fill: false, max_items: 10 });
vimperator.log("Loading module mappings...", 3);
vimperator.mappings = new Mappings();
vimperator.log("Loading module statusline...", 3);
vimperator.statusline = new StatusLine();
vimperator.log("Loading module tabs...", 3);
vimperator.tabs = new Tabs();
vimperator.log("Loading module marks...", 3);
vimperator.marks = new Marks();
vimperator.log("Loading module quickmarks...", 3);
vimperator.quickmarks = new QuickMarks();
vimperator.log("Loading module hints...", 3);
vimperator.hints = new Hints();
vimperator.log("All modules loaded", 3);
vimperator.echo = vimperator.commandline.echo;
vimperator.echoerr = vimperator.commandline.echoErr;
// XXX: move elsewhere
vimperator.registerCallback("submit", vimperator.modes.EX, function(command) { /*vimperator.*/execute(command); } );
vimperator.registerCallback("complete", vimperator.modes.EX, function(str) { return exTabCompletion(str); } );
// this function adds all our required listeners to react on events
// also stuff like window.onScroll is handled there.
//addEventListeners();
//vimperator.events();
// work around firefox popup blocker
popup_allowed_events = Options.getFirefoxPref('dom.popup_allowed_events', 'change click dblclick mouseup reset submit');
if (!popup_allowed_events.match("keypress"))
Options.setFirefoxPref('dom.popup_allowed_events', popup_allowed_events + " keypress");
// we have our own typeahead find implementation
Options.setFirefoxPref('accessibility.typeaheadfind.autostart', false);
Options.setFirefoxPref('accessibility.typeaheadfind', false); // actually the above setting should do it, but has no effect in firefox
// first time intro message
if (Options.getPref("firsttime", true))
{
setTimeout(function() {
vimperator.help(null, null, null, { inTab: true });
Options.setPref("firsttime", false);
}, 1000);
}
//gURLBar.blur(); // TODO: needed anymore?
vimperator.focusContent();
// firefox preferences which we need to be changed to work well with vimperator
Options.setFirefoxPref("browser.startup.page", 3); // start with saved session
// Finally, read a ~/.vimperatorrc
// Make sourcing asynchronous, otherwise commands that open new tabs won't work
setTimeout(function() {
vimperator.source("~/.vimperatorrc", true);
vimperator.log("~/.vimperatorrc sourced", 1);
}, 50);
vimperator.log("Vimperator fully initialized", 1);
},
shutdown: function()
{
window.dump("Vimperator shutdown\n");
/*** save our preferences ***/
vimperator.commandline.destroy();
vimperator.events.destroy();
vimperator.quickmarks.destroy();
// reset some modified firefox prefs
if (Options.getFirefoxPref('dom.popup_allowed_events', 'change click dblclick mouseup reset submit')
== popup_allowed_events + " keypress")
Options.setFirefoxPref('dom.popup_allowed_events', popup_allowed_events);
} }
this.log(string, level); } //}}}
} })(); //}}}
//}}}
} //}}}
//////////////////////////////////////////////////////////////////////// // called when the chrome is fully loaded and before the main window is shown
// DOM related helper functions //////////////////////////////////////// window.addEventListener("load", vimperator.startup, false);
/////////////////////////////////////////////////////////////////////{{{ window.addEventListener("unload", vimperator.shutdown, false);
function isFormElemFocused()
{
var elt = window.document.commandDispatcher.focusedElement;
if (elt == null)
return false;
try
{ // sometimes the elt doesn't have .localName
var tagname = elt.localName.toLowerCase();
var type = elt.type.toLowerCase();
if ( (tagname == "input" && (type != "image")) ||
tagname == "textarea" ||
// tagName == "SELECT" ||
// tagName == "BUTTON" ||
tagname == "isindex") // isindex is a deprecated one-line input box
return true;
}
catch (e)
{
// FIXME: do nothing?
}
return false;
}
//}}}
// vim: set fdm=marker sw=4 ts=4 et: // vim: set fdm=marker sw=4 ts=4 et: