1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-01-06 02:44:12 +01:00

Merge branch 'master' of kmaglione@git.vimperator.org:/git/vimperator/liberator

This commit is contained in:
Kris Maglione
2009-05-19 13:06:48 -04:00
20 changed files with 452 additions and 171 deletions

View File

@@ -135,6 +135,19 @@ function Buffer() //{{{
pageInfo[option] = [fn, title];
}
function openUploadPrompt(elem)
{
commandline.input("Upload file: ", function (path) {
let file = io.getFile(path);
if (!file.exists())
return liberator.beep();
elem.value = file.path;
},
{ completer: completion.file, default: elem.value });
}
/////////////////////////////////////////////////////////////////////////////}}}
////////////////////// OPTIONS /////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
@@ -360,16 +373,13 @@ function Buffer() //{{{
function (count)
{
if (count < 1 && buffer.lastInputField)
{
buffer.lastInputField.focus();
}
buffer.focusElement(buffer.lastInputField);
else
{
let elements = [];
let matches = buffer.evaluateXPath(
// TODO: type="file"
"//input[not(@type) or @type='text' or @type='password'] | //textarea[not(@disabled) and not(@readonly)] |" +
"//xhtml:input[not(@type) or @type='text' or @type='password'] | //xhtml:textarea[not(@disabled) and not(@readonly)]"
"//input[not(@type) or @type='text' or @type='password' or @type='file'] | //textarea[not(@disabled) and not(@readonly)] |" +
"//xhtml:input[not(@type) or @type='text' or @type='password' or @type='file'] | //xhtml:textarea[not(@disabled) and not(@readonly)]"
);
for (let match in matches)
@@ -382,12 +392,10 @@ function Buffer() //{{{
if (elements.length > 0)
{
count = Math.min(Math.max(count, 1), elements.length);
elements[count - 1].focus();
buffer.focusElement(elements[count - 1]);
}
else
{
liberator.beep();
}
}
},
{ flags: Mappings.flags.COUNT });
@@ -509,6 +517,14 @@ function Buffer() //{{{
////////////////////// COMMANDS ////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
commands.add(["frameo[nly]"],
"Show only the current frame's page",
function (args)
{
liberator.open(tabs.localStore.focusedFrame.document.documentURI);
},
{ argCount: "0" });
commands.add(["ha[rdcopy]"],
"Print current document",
function (args)
@@ -1063,18 +1079,10 @@ function Buffer() //{{{
elem.contentWindow.focus();
return;
}
else if (elemTagName == "input" && elem.getAttribute('type').toLowerCase() == "file")
else if (elemTagName == "input" && elem.type.toLowerCase() == "file")
{
commandline.input("Upload file: ", function (path)
{
let file = io.getFile(path);
if (!file.exists())
return liberator.beep();
elem.value = file.path;
}
, {completer: completion.file, default: elem.value});
openUploadPrompt(elem);
buffer.lastInputField = elem;
return;
}
@@ -1182,18 +1190,9 @@ function Buffer() //{{{
offsetX = Number(coords[0]) + 1;
offsetY = Number(coords[1]) + 1;
}
else if (localName == "input" && elem.getAttribute('type').toLowerCase() == "file")
else if (localName == "input" && elem.type.toLowerCase() == "file")
{
commandline.input("Upload file: ", function (path)
{
let file = io.getFile(path);
if (!file.exists())
return liberator.beep();
elem.value = file.path;
}
, {completer: completion.file, default: elem.value});
openUploadPrompt(elem);
return;
}
@@ -1931,7 +1930,7 @@ function Marks() //{{{
}
if (!ok)
liberator.echoerr("E20: Mark not set"); // FIXME: move up?
liberator.echoerr("E20: Mark not set");
},
/**

View File

@@ -34,13 +34,25 @@ the terms of any one of the MPL, the GPL or the LGPL.
* A class representing Ex commands. Instances are created by
* the {@link Commands} class.
*
* @param {string[]} specs The names by which this command can be invoked.
* These are specified in the form "com[mand]" where "com" is a unique
* command name prefix.
* @param {string} description A short one line description of the command.
* @param {function} action The action invoked by this command when executed.
* @param {Object} extraInfo An optional extra configuration hash. The
* following properties are supported.
* argCount - See (@link Command#argCount)
* bang - See (@link Command#bang)
* completer - See (@link Command#completer)
* count - See (@link Command#count)
* heredoc - See (@link Command#heredoc)
* literal - See (@link Command#literal)
* options - See (@link Command#options)
* serial - See (@link Command#serial)
* @private
*/
function Command(specs, description, action, extraInfo) //{{{
{
if (!specs || !action)
return null;
if (!extraInfo)
extraInfo = {};
@@ -91,7 +103,7 @@ function Command(specs, description, action, extraInfo) //{{{
/** @property {string[]} All of this command's long and short names. */
this.names = expandedSpecs.names; // return all command name aliases
/** @property {string} This command's description, as shown in :exinfo */
/** @property {string} This command's description, as shown in :exusage */
this.description = description || "";
/** @property {function (Args)} The function called to execute this command. */
this.action = action;

View File

@@ -46,7 +46,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
* @author Kris Maglione <maglione.k@gmail.com>
* @constructor
*/
function CompletionContext(editor, name, offset) //{{{
{
if (!(this instanceof arguments.callee))

View File

@@ -690,7 +690,7 @@ function Editor() //{{{
// motion = b, 0, gg, G, etc.
executeCommandWithMotion: function (cmd, motion, count)
{
if (!typeof count == "number" || count < 1)
if (typeof count != "number" || count < 1)
count = 1;
if (cmd == motion)
@@ -705,12 +705,12 @@ function Editor() //{{{
{
case "j":
this.executeCommand("cmd_beginLine", 1);
this.executeCommand("cmd_selectLineNext", count+1);
this.executeCommand("cmd_selectLineNext", count + 1);
break;
case "k":
this.executeCommand("cmd_beginLine", 1);
this.executeCommand("cmd_lineNext", 1);
this.executeCommand("cmd_selectLinePrevious", count+1);
this.executeCommand("cmd_selectLinePrevious", count + 1);
break;
case "h":
this.executeCommand("cmd_selectCharPrevious", count);

View File

@@ -1733,38 +1733,6 @@ function Events() //{{{
// Stub for something else, presumably. Not in any documented
// interface.
onLinkIconAvailable: function () {}
},
// TODO: move to options.js?
prefObserver: {
register: function ()
{
// better way to monitor all changes?
this._branch = services.get("pref").getBranch("").QueryInterface(Ci.nsIPrefBranch2);
this._branch.addObserver("", this, false);
},
unregister: function ()
{
if (this._branch)
this._branch.removeObserver("", this);
},
observe: function (aSubject, aTopic, aData)
{
if (aTopic != "nsPref:changed")
return;
// aSubject is the nsIPrefBranch we're observing (after appropriate QI)
// aData is the name of the pref that's been changed (relative to aSubject)
switch (aData)
{
case "accessibility.browsewithcaret":
let value = options.getPref("accessibility.browsewithcaret", false);
liberator.mode = value ? modes.CARET : modes.NORMAL;
break;
}
}
}
}; //}}}
@@ -1782,10 +1750,8 @@ function Events() //{{{
}
catch (e) {}
self.prefObserver.register();
liberator.registerObserver("shutdown", function () {
self.destroy();
self.prefObserver.unregister();
});
window.addEventListener("keypress", wrapListener("onKeyPress"), true);

View File

@@ -30,7 +30,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
// TODO: proper backwards search - implement our own component?
// : implement our own highlighter?
// : frameset pages
// : <ESC> should cancel search highlighting in 'incsearch' mode and jump
// back to the presearch page location - can probably use the same
// solution as marks
@@ -48,8 +47,6 @@ function Finder() //{{{
////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
// FIXME:
//var self = this; // needed for callbacks since "this" is the "liberator" object in a callback
var found = false; // true if the last search was successful
var backwards = false; // currently searching backwards
var searchString = ""; // current search string (without modifiers)

View File

@@ -638,8 +638,8 @@ function Hints() //{{{
* @param {boolean} allowWordOverleaping Whether to allow non-contiguous
* words to match.
*
* @return {function(String):bool} A function that will filter only
* hints that match as above.
* @return {function(String):boolean} A function that will filter only
* hints that match as above.
*/
function wordStartsWithMatcher(hintString, allowWordOverleaping) //{{{
{
@@ -886,7 +886,7 @@ function Hints() //{{{
context.completions = [[k, v.prompt] for ([k, v] in Iterator(hintModes))];
},
onChange: function () { modes.pop() },
onCancel: function (arg) { arg && setTimeout(function () hints.show(arg), 0); },
onCancel: function (arg) { arg && setTimeout(function () hints.show(arg), 0); }
});
}, { flags: Mappings.flags.COUNT });
@@ -897,14 +897,16 @@ function Hints() //{{{
return {
/**
* Create a new hint mode
* Creates a new hint mode.
*
* @param {String} mode The letter that identifies this mode.
* @param {String} description The description to display to the user about this mode.
* @param {function(Node)} callback The function to be called with the element that matches.
* @param {function():String} selector The function that returns an XPath selector to decide
* which elements can be hinted (the default returns
* options.hinttags)
* @param {String} description The description to display to the user
* about this mode.
* @param {function(Node)} callback The function to be called with the
* element that matches.
* @param {function():String} selector The function that returns an
* XPath selector to decide which elements can be hinted (the
* default returns options.hinttags).
*/
addMode: function (mode)
{
@@ -912,11 +914,11 @@ function Hints() //{{{
},
/**
* Update the display of hints.
* Updates the display of hints.
*
* @param {String} minor Which hint mode to use.
* @param {String} filter The filter to use.
* @param {Object} win The window in which we are showing hints
* @param {Object} win The window in which we are showing hints.
*/
show: function (minor, filter, win)
{
@@ -968,7 +970,7 @@ function Hints() //{{{
},
/**
* Handle an event
* Handle an event.
*
* @param {Event} event The event to handle.
*/

View File

@@ -335,7 +335,7 @@ function IO() //{{{
function ()
{
let list = template.tabular(["<SNR>", "Filename"], ["text-align: right; padding-right: 1em;"],
([i + 1, file] for ([i, file] in Iterator(scriptNames)))); // TODO: add colon?
([i + 1, file] for ([i, file] in Iterator(scriptNames)))); // TODO: add colon and remove column titles for pedantic Vim compatibility?
commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
},
@@ -345,11 +345,13 @@ function IO() //{{{
"Read Ex commands from a file",
function (args)
{
// FIXME: "E172: Only one file name allowed"
io.source(args[0], args.bang);
if (args.length > 1)
liberator.echoerr("E172: Only one file name allowed");
else
io.source(args[0], args.bang);
},
{
argCount: "1",
argCount: "+", // FIXME: should be "1" but kludged for proper error message
bang: true,
completer: function (context) completion.file(context, true)
});
@@ -878,7 +880,6 @@ lookup:
let dirs = getPathsFromPathList(options["runtimepath"]);
let found = false;
// FIXME: should use original arg string
liberator.echomsg("Searching for \"" + paths.join(" ") + "\" in \"" + options["runtimepath"] + "\"", 2);
outer:
@@ -902,7 +903,7 @@ lookup:
}
if (!found)
liberator.echomsg("not found in 'runtimepath': \"" + paths.join(" ") + "\"", 1); // FIXME: should use original arg string
liberator.echomsg("not found in 'runtimepath': \"" + paths.join(" ") + "\"", 1);
return found;
},
@@ -1001,7 +1002,7 @@ lookup:
{
let lineNumber = i + 1;
// FIXME: messages need to be able to specify
// TODO: messages need to be able to specify
// whether they can be cleared/overwritten or
// should be appended to and the MOW opened
liberator.echoerr("Error detected while processing " + file.path, commandline.FORCE_MULTILINE);

View File

@@ -1069,7 +1069,7 @@ const liberator = (function () //{{{
* Opens one or more URLs. Returns true when load was initiated, or
* false on error.
*
* @param {FIXME} urls Either a URL string or an array of URLs.
* @param {string|string[]} urls Either a URL string or an array of URLs.
* The array can look like this:
* ["url1", "url2", "url3", ...]
* or:

View File

@@ -30,33 +30,68 @@ the terms of any one of the MPL, the GPL or the LGPL.
// Do NOT create instances of this class yourself, use the helper method
// mappings.add() instead
function Map(modes, cmds, description, action, extraInfo) //{{{
/**
* A class representing key mappings. Instances are created by the
* {@link Mappings} class.
*
* @param {number[]} modes The modes in which this mapping is active.
* @param {string[]} keys The key sequences which are bound to
* <b>action</b>.
* @param {string} description A short one line description of the key mapping.
* @param {function} action The action invoked by each key sequence.
* @param {Object} extraInfo An optional extra configuration hash. The
* following properties are supported.
* flags - See (@link Map#flags)
* noremap - See (@link Map#noremap)
* rhs - See (@link Map#rhs)
* silent - See (@link Map#silent)
* @private
*/
function Map(modes, keys, description, action, extraInfo) //{{{
{
if (!modes || (!cmds || !cmds.length) || !action)
return null;
if (!extraInfo)
extraInfo = {};
/** @property {number[]} All of the modes for which this mapping applies. */
this.modes = modes;
// only store keysyms with uppercase modifier strings
this.names = cmds.map(function (cmd) cmd.replace(/[casm]-/g, String.toUpperCase));
/** @property {string[]} All of this mapping's names (key sequences). */
this.names = keys.map(function (cmd) cmd.replace(/[casm]-/g, String.toUpperCase)); // only store keysyms with uppercase modifier strings
/** @property {function (number)} The function called to execute this mapping. */
this.action = action;
/** @property {number} See (@link Mappings#flags) */
this.flags = extraInfo.flags || 0;
/** @property {string} This mapping's description, as shown in :viusage. */
this.description = description || "";
/** @property {string} The literal RHS expansion of this mapping. */
this.rhs = extraInfo.rhs || null;
/** @property {boolean} Whether the RHS of the mapping should expand mappings recursively. */
this.noremap = extraInfo.noremap || false;
/** @property {boolean} Whether any output from the mapping should be echoed on the command line. */
this.silent = extraInfo.silent || false;
};
Map.prototype = {
hasName: function (name)
{
return this.names.indexOf(name) >= 0;
},
/**
* Returns whether this mapping can be invoked by a key sequence matching
* <b>name</b>.
*
* @param {string} name The name to query.
* @returns {boolean}
*/
hasName: function (name) this.names.indexOf(name) >= 0,
/**
* Execute the action for this mapping.
*
* @param {string} motion The motion argument if accepted by this mapping.
* E.g. "w" for "dw"
* @param {number} count The associated count. E.g. "5" for "5j"
* @default -1
* @param {string} argument The normal argument if accepted by this
* mapping. E.g. "a" for "ma"
*/
execute: function (motion, count, argument)
{
let args = [];
@@ -100,9 +135,9 @@ function Mappings() //{{{
{
let where = userMap ? user : main;
map.modes.forEach(function (mode) {
if (!(mode in where))
where[mode] = [];
where[mode].push(map);
if (!(mode in where))
where[mode] = [];
where[mode].push(map);
});
}
@@ -255,6 +290,7 @@ function Mappings() //{{{
/////////////////////////////////////////////////////////////////////////////{{{
addMapCommands("", [modes.NORMAL, modes.VISUAL], "");
for (let mode in modes.mainModes)
if (mode.char)
addMapCommands(mode.char,
@@ -296,13 +332,40 @@ function Mappings() //{{{
__iterator__: function () mappingsIterator([modes.NORMAL], main),
// used by :mkvimperatorrc to save mappings
/**
* Returns a user-defined mappings iterator for the specified
* <b>mode</b>.
*
* @param {number} mode The mode to return mappings from.
* @returns {Iterator(Map)}
*/
getUserIterator: function (mode) mappingsIterator(mode, user),
/**
* Add a new default key mapping.
*
* @param {number[]} modes The modes that this mapping applies to.
* @param {string[]} keys The key sequences which are bound to
* <b>action</b>.
* @param {string} description A description of the key mapping.
* @param {function} action The action invoked by each key sequence.
* @param {Object} extra An optional extra configuration hash.
*/
add: function (modes, keys, description, action, extra)
{
addMap(new Map(modes, keys, description, action, extra), false);
},
/**
* Add a new user-defined key mapping.
*
* @param {number[]} modes The modes that this mapping applies to.
* @param {string[]} keys The key sequences which are bound to
* <b>action</b>.
* @param {string} description A description of the key mapping.
* @param {function} action The action invoked by each key sequence.
* @param {Object} extra An optional extra configuration hash.
*/
addUserMap: function (modes, keys, description, action, extra)
{
keys = keys.map(expandLeader);
@@ -318,20 +381,41 @@ function Mappings() //{{{
addMap(map, true);
},
/**
* Returns the map from <b>mode</b> named <b>cmd</b>.
*
* @param {number} mode The mode to search.
* @param {string} cmd The map name to match.
* @returns {Map}
*/
get: function (mode, cmd)
{
mode = mode || modes.NORMAL;
return getMap(mode, cmd, user) || getMap(mode, cmd, main);
},
/**
* Returns the default map from <b>mode</b> named <b>cmd</b>.
*
* @param {number} mode The mode to search.
* @param {string} cmd The map name to match.
* @returns {Map}
*/
getDefault: function (mode, cmd)
{
mode = mode || modes.NORMAL;
return getMap(mode, cmd, main);
},
// returns an array of mappings with names which START with "cmd" (but are NOT "cmd")
getCandidates: function (mode, cmd)
/**
* Returns an array of maps with names starting with but not equal to
* <b>prefix</b>.
*
* @param {number} mode The mode to search.
* @param {string} prefix The map prefix string to match.
* @returns {Map[]}
*/
getCandidates: function (mode, prefix)
{
let mappings = user[mode].concat(main[mode]);
let matches = [];
@@ -340,10 +424,10 @@ function Mappings() //{{{
{
for (let [,name] in Iterator(map.names))
{
if (name.indexOf(cmd) == 0 && name.length > cmd.length)
if (name.indexOf(prefix) == 0 && name.length > prefix.length)
{
// for < only return a candidate if it doesn't look like a <c-x> mapping
if (cmd != "<" || !/^<.+>/.test(name))
if (prefix != "<" || !/^<.+>/.test(name))
matches.push(map);
}
}
@@ -352,28 +436,57 @@ function Mappings() //{{{
return matches;
},
/*
* Returns the map leader string used to replace the special token
* "<Leader>" when user mappings are defined.
*
* @returns {string}
*/
// FIXME: property
getMapLeader: function ()
{
let leaderRef = liberator.variableReference("mapleader");
return leaderRef[0] ? leaderRef[0][leaderRef[1]] : "\\";
},
// returns whether the user added a custom user map
hasMap: function (mode, cmd)
{
return user[mode].some(function (map) map.hasName(cmd));
},
/**
* Returns whether there is a user-defined mapping <b>cmd</b> for the
* specified <b>mode</b>.
*
* @param {number} mode The mode to search.
* @param {string} cmd The candidate key mapping.
* @returns {boolean}
*/
hasMap: function (mode, cmd) user[mode].some(function (map) map.hasName(cmd)),
/**
* Remove the user-defined mapping named <b>cmd</b> for <b>mode</b>.
*
* @param {number} mode The mode to search.
* @param {string} cmd The map name to match.
*/
remove: function (mode, cmd)
{
removeMap(mode, cmd);
},
/**
* Remove all user-defined mappings for <b>mode</b>.
*
* @param {number} mode The mode to remove all mappings from.
*/
removeAll: function (mode)
{
user[mode] = [];
},
/**
* Lists all user-defined mappings matching <b>filter</b> for the
* specified <b>modes</b>.
*
* @param {number[]} modes An array of modes to search.
* @param {string} filter The filter string to match.
*/
list: function (modes, filter)
{
let modeSign = "";
@@ -413,7 +526,6 @@ function Mappings() //{{{
}
commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
}
};
//}}}
}; //}}}

View File

@@ -32,9 +32,6 @@ the terms of any one of the MPL, the GPL or the LGPL.
// options.add() instead
function Option(names, description, type, defaultValue, extraInfo) //{{{
{
if (!names || !type)
return null;
if (!extraInfo)
extraInfo = {};
@@ -808,7 +805,7 @@ function Options() //{{{
.map(function (pref) [pref, ""])]);
});
return {
const self = {
OPTION_SCOPE_GLOBAL: 1,
OPTION_SCOPE_LOCAL: 2,
@@ -820,6 +817,37 @@ function Options() //{{{
return (v for ([k, v] in Iterator(sorted)));
},
prefObserver: {
register: function ()
{
// better way to monitor all changes?
this._branch = services.get("pref").getBranch("").QueryInterface(Ci.nsIPrefBranch2);
this._branch.addObserver("", this, false);
},
unregister: function ()
{
if (this._branch)
this._branch.removeObserver("", this);
},
observe: function (subject, topic, data)
{
if (topic != "nsPref:changed")
return;
// subject is the nsIPrefBranch we're observing (after appropriate QI)
// data is the name of the pref that's been changed (relative to subject)
switch (data)
{
case "accessibility.browsewithcaret":
let value = options.getPref("accessibility.browsewithcaret", false);
liberator.mode = value ? modes.CARET : modes.NORMAL;
break;
}
}
},
add: function (names, description, type, defaultValue, extraInfo)
{
if (!extraInfo)
@@ -1067,8 +1095,15 @@ function Options() //{{{
this.popContext();
}
}
};
//}}}
}; //}}}
self.prefObserver.register();
liberator.registerObserver("shutdown", function () {
self.prefObserver.unregister();
});
return self;
}; //}}}
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -30,6 +30,9 @@ the terms of any one of the MPL, the GPL or the LGPL.
// TODO: many methods do not work with Thunderbird correctly yet
/**
* @instance tabs
*/
function Tabs() //{{{
{
////////////////////////////////////////////////////////////////////////////////
@@ -307,7 +310,6 @@ function Tabs() //{{{
if (arg)
{
arg = arg.toLowerCase();
let removed = 0;
let matches = arg.match(/^(\d+):?/);
@@ -318,15 +320,27 @@ function Tabs() //{{{
}
else
{
let str = arg.toLowerCase();
let browsers = getBrowser().browsers;
for (let i = browsers.length - 1; i >= 0; i--)
{
let title = browsers[i].contentTitle.toLowerCase() || "";
let uri = browsers[i].currentURI.spec.toLowerCase();
let host = browsers[i].currentURI.host.toLowerCase();
let host, title, uri = browsers[i].currentURI.spec;
if (browsers[i].currentURI.schemeIs("about"))
{
host = "";
title = "(Untitled)";
}
else
{
host = browsers[i].currentURI.host;
title = browsers[i].contentTitle;
}
if (host.indexOf(arg) >= 0 || uri == arg ||
(special && (title.indexOf(arg) >= 0 || uri.indexOf(arg) >= 0)))
[host, title, uri] = [host, title, uri].map(String.toLowerCase);
if (host.indexOf(str) >= 0 || uri == str ||
(special && (title.indexOf(str) >= 0 || uri.indexOf(str) >= 0)))
{
tabs.remove(tabs.getTab(i));
removed++;
@@ -398,7 +412,7 @@ function Tabs() //{{{
if (arg)
{
if (/^\d+$/.test(arg))
tabs.select("-" + arg, true); // FIXME: urgh!
tabs.select("-" + arg, true);
else
liberator.echoerr("E488: Trailing characters");
}
@@ -676,8 +690,16 @@ function Tabs() //{{{
return {
/**
* @property {Object} The previously accessed tab or null if no tab
* other than the current one has been accessed.
*/
get alternate() alternates[1],
/**
* @property {Iterator(Object)} A genenerator that returns all browsers
* in the current window.
*/
get browsers()
{
let browsers = getBrowser().browsers;
@@ -685,10 +707,13 @@ function Tabs() //{{{
yield [i, browsers[i]];
},
get tabsBound() {
return Boolean(styles.get(true, "tab-binding"))
},
set tabsBound(val) {
/**
* @property {boolean} Whether the tab numbering XBL binding has been
* applied.
*/
get tabsBound() Boolean(styles.get(true, "tab-binding")),
set tabsBound(val)
{
let fragment = liberator.has("MacUnix") ? "tab-mac" : "tab";
if (!val)
styles.removeSheet(true, "tab-binding");
@@ -699,8 +724,14 @@ function Tabs() //{{{
".tabbrowser-tab[busy] > .tab-icon > .tab-icon-image { list-style-image: url('chrome://global/skin/icons/loading_16.png') !important; }");
},
/**
* @property {number} The number of tabs in the current window.
*/
get count() getBrowser().mTabs.length,
/**
* @property {Object} The local options store for the current tab.
*/
get options()
{
let store = this.localStore;
@@ -709,6 +740,15 @@ function Tabs() //{{{
return store.options;
},
/**
* Returns the local state store for the tab at the specified
* <b>tabIndex</b>. If <b>tabIndex</b> is not specified then the
* current tab is used.
*
* @param {number} tabIndex
* @returns {Object}
*/
// FIXME: why not a tab arg? Why this and the property?
getLocalStore: function (tabIndex)
{
let tab = this.getTab(tabIndex);
@@ -717,8 +757,15 @@ function Tabs() //{{{
return tab.liberatorStore;
},
/**
* @property {Object} The local state store for the currently selected
* tab.
*/
get localStore() this.getLocalStore(),
/**
* @property {Object} The tab browser strip.
*/
get tabStrip()
{
let tabStrip = null;
@@ -732,18 +779,40 @@ function Tabs() //{{{
return tabStrip;
},
// @returns the index of the currently selected tab starting with 0
/**
* @property {Object[]} The array of closed tabs for the current
* session.
*/
get closedTabs()
{
return services.get("json").decode(services.get("sessionStore").getClosedTabData(window));
},
/**
* Returns the index of <b>tab</b> or the index of the currently
* selected tab if <b>tab</b> is not specified. This is a 0-based
* index.
*
* @param {Object} tab A tab from the current tab list.
* @returns {number}
*/
index: function (tab)
{
if (tab)
return Array.indexOf(getBrowser().mTabs, tab);
return getBrowser().mTabContainer.selectedIndex;
else
return getBrowser().mTabContainer.selectedIndex;
},
// TODO: implement filter
// @returns an array of tabs which match filter
get: function (filter)
/**
* Returns an array of all tabs in the tab list.
*
* @returns {Object[]}
*/
// FIXME: why not return the tab element?
// : unused? Remove me.
get: function ()
{
let buffers = [];
for (let [i, browser] in this.browsers)
@@ -756,6 +825,13 @@ function Tabs() //{{{
return buffers;
},
/**
* Returns the index of the tab containing <b>content</b>.
*
* @param {Object} content Either a content window or a content
* document.
*/
// FIXME: Only called once...necessary?
getContentIndex: function (content)
{
for (let [i, browser] in this.browsers)
@@ -766,6 +842,14 @@ function Tabs() //{{{
return -1;
},
/**
* Returns the tab at the specified <b>index</b> or the currently
* selected tab if <b>index</b> is not specified. This is a 0-based
* index.
*
* @param {number} index The index of the tab required.
* @returns {Object}
*/
getTab: function (index)
{
if (index != undefined)
@@ -774,26 +858,44 @@ function Tabs() //{{{
return getBrowser().mCurrentTab;
},
get closedTabs()
{
return services.get("json").decode(services.get("sessionStore").getClosedTabData(window));
},
/**
* Lists all tabs matching <b>filter</b>.
*
* @param {string} filter A filter matching a substring of the tab's
* document title or URL.
*/
list: function (filter)
{
completion.listCompleter("buffer", filter);
},
// wrap causes the movement to wrap around the start and end of the tab list
// NOTE: position is a 0 based index
/**
* Moves a tab to a new position in the tab list.
*
* @param {Object} tab The tab to move.
* @param {string} spec See {@link indexFromSpec}.
* @param {boolean} wrap Whether an out of bounds <b>spec</b> causes
* the destination position to wrap around the start/end of the tab
* list.
*/
move: function (tab, spec, wrap)
{
let index = indexFromSpec(spec, wrap);
getBrowser().moveTabTo(tab, index);
},
// quitOnLastTab = 1: quit without saving session
// quitOnLastTab = 2: quit and save session
/**
* Removes the specified <b>tab</b> from the tab list.
*
* @param {Object} tab
* @param {number} count
* @param {boolean} focusLeftTab Focus the tab to the left of the removed tab.
* @param {number} quitOnLastTab Whether to quit if the tab being
* deleted is the only tab in the tab list:
* 1 - quit without saving session
* 2 - quit and save session
*/
// FIXME: what is quitOnLastTab {1,2} all about then, eh? --djk
remove: function (tab, count, focusLeftTab, quitOnLastTab)
{
let removeOrBlankTab = {
@@ -874,25 +976,38 @@ function Tabs() //{{{
}
},
/**
* Removes all tabs from the tab list except the specified <b>tab</b>.
*
* @param {Object} tab The tab to keep.
*/
keepOnly: function (tab)
{
getBrowser().removeAllTabsBut(tab);
},
/**
* Selects the tab at the position specified by <b>spec</b>.
*
* @param {string} spec See {@link indexFromSpec}
* @param {boolean} wrap Whether an out of bounds <b>spec</b> causes
* the selection position to wrap around the start/end of the tab
* list.
*/
select: function (spec, wrap)
{
let index = indexFromSpec(spec, wrap);
// FIXME:
if (index == -1)
{
liberator.beep(); // XXX: move to ex-handling?
liberator.beep();
return;
}
getBrowser().mTabContainer.selectedIndex = index;
},
/**
* Reload the specified tab.
* Reloads the specified tab.
*
* @param {Object} tab The tab to reload.
* @param {boolean} bypassCache Whether to bypass the cache when
@@ -912,7 +1027,7 @@ function Tabs() //{{{
},
/**
* Reload all tabs.
* Reloads all tabs.
*
* @param {boolean} bypassCache Whether to bypass the cache when
* reloading.
@@ -941,7 +1056,7 @@ function Tabs() //{{{
},
/**
* Stop loading the specified tab.
* Stops loading the specified tab.
*
* @param {Object} tab The tab to stop loading.
*/
@@ -954,7 +1069,7 @@ function Tabs() //{{{
},
/**
* Stop loading all tabs.
* Stops loading all tabs.
*/
stopAll: function ()
{
@@ -962,8 +1077,20 @@ function Tabs() //{{{
browser.stop();
},
// "buffer" is a string which matches the URL or title of a buffer, if it
// is null, the last used string is used again
/**
* Selects the tab containing the specified <b>buffer</b>.
*
* @param {string} buffer A string which matches the URL or title of a
* buffer, if it is null, the last used string is used again.
* @param {boolean} allowNonUnique Whether to select the first of
* multiple matches.
* @param {number} count If there are multiple matches select the
* count'th match.
* @param {boolean} reverse Whether to search the buffer list in
* reverse order.
*
*/
// FIXME: help!
switchTo: function (buffer, allowNonUnique, count, reverse)
{
if (buffer == "")
@@ -1037,6 +1164,12 @@ function Tabs() //{{{
}
},
/**
* Clones the specified <b>tab</b> and append it to the tab list.
*
* @param {Object} tab The tab to clone.
* @param {boolean} activate Whether to select the newly cloned tab.
*/
cloneTab: function (tab, activate)
{
let newTab = getBrowser().addTab();
@@ -1048,6 +1181,12 @@ function Tabs() //{{{
return newTab;
},
/**
* Detaches the specified <b>tab</b> and open it in a new window. If no
* tab is specified the currently selected tab is detached.
*
* @param {Object} tab The tab to detach.
*/
detachTab: function (tab)
{
if (!tab)
@@ -1060,6 +1199,9 @@ function Tabs() //{{{
this.remove(tab, 1, false, 1);
},
/**
* Selects the alternate tab.
*/
selectAlternateTab: function ()
{
if (tabs.alternate == null || tabs.getTab() == tabs.alternate)
@@ -1085,6 +1227,10 @@ function Tabs() //{{{
// 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.
/**
* Called on each TabSelect event to update the tab selection history.
* See (@link tabs.alternate).
*/
updateSelectionHistory: function ()
{
alternates = [this.getTab(), alternates[0]];

View File

@@ -44,12 +44,12 @@ const template = {
return <>{xml}</>;
},
completionRow: function completionRow(item, class)
completionRow: function completionRow(item, highlightGroup)
{
if (typeof icon == "function")
icon = icon();
if (class)
if (highlightGroup)
{
var text = item[0] || "";
var desc = item[1] || "";
@@ -61,7 +61,7 @@ const template = {
}
// <e4x>
return <div highlight={class || "CompItem"} style="white-space: nowrap">
return <div highlight={highlightGroup || "CompItem"} style="white-space: nowrap">
<!-- The non-breaking spaces prevent empty elements
- from pushing the baseline down and enlarging
- the row.

View File

@@ -187,9 +187,9 @@ const config = { //{{{
var stateListener =
{
QueryInterface: function (aIID)
QueryInterface: function (id)
{
if (aIID.equals(Components.interfaces.nsIDocumentStateListener))
if (id.equals(Components.interfaces.nsIDocumentStateListener))
return this;
throw Components.results.NS_NOINTERFACE;
},

View File

@@ -4,6 +4,7 @@
* TabMixPlus (and other tab extensions) should work much better now
together with Vimperator unless you :set guioptions+=[nN]
* remove 'preload' option. You can fake it by some custom javascript in your init file
* add :frameonly
* add :stopall
* add :tabdo
* add 'encoding'

View File

@@ -5,6 +5,7 @@ ARCHITECTURE:
- modular help system
BUGS:
- :mkvimperatorrc now adds spurious vmap and nmap entries
- add window resize support to hints
- searching backwards incrementally does not work i.e. with 'incsearch' set
- http://msdn2.microsoft.com/en-us/library/ms535258.aspx does not scroll with j/k/etc.

View File

@@ -601,19 +601,19 @@ function Bookmarks() //{{{
getSearchURL: function getSearchURL(text, useDefsearch)
{
let url = null;
let aPostDataRef = {};
let postData = {};
let searchString = (useDefsearch ? options["defsearch"] + " " : "") + text;
// we need to make sure our custom alias have been set, even if the user
// did not :open <tab> once before
this.getSearchEngines();
url = window.getShortcutOrURI(searchString, aPostDataRef);
url = window.getShortcutOrURI(searchString, postData);
if (url == searchString)
url = null;
if (aPostDataRef && aPostDataRef.value)
return [url, aPostDataRef.value];
if (postData && postData.value)
return [url, postData.value];
else
return url; // can be null
},

View File

@@ -327,6 +327,14 @@ Normally this command operates on the text zoom; if used with [!], it
operates on full zoom.
________________________________________________________________________________
section:Working{nbsp}with{nbsp}frames[frames]
|:frameo| |:frameonly|
||:frameo[nly]|| +
________________________________________________________________________________
Show only the current frame's page.
________________________________________________________________________________
section:Copying{nbsp}text[copying,yanking]
When running in X11, the text of the following commands is not only

View File

@@ -183,6 +183,7 @@ section:Ex{nbsp}commands[ex-cmd-index,:index]
||[c]:execute[c]|| Execute the argument as an Ex command +
||[c]:exusage[c]|| List all Ex commands with a short description +
||[c]:finish[c]|| Stop sourcing a script file +
||[c]:frameonly[c]|| Show only the current frame's page +
||[c]:forward[c]|| Go forward in the browser history +
||[c]:hardcopy[c]|| Print current document +
||[c]:help[c]|| Display help +

View File

@@ -601,13 +601,14 @@ function Bookmarks() //{{{
getSearchURL: function getSearchURL(text, useDefsearch)
{
let url = null;
let aPostDataRef = {};
let postData = {};
let searchString = (useDefsearch ? options["defsearch"] + " " : "") + text;
// we need to make sure our custom alias have been set, even if the user
// did not :open <tab> once before
this.getSearchEngines();
// ripped from Firefox
function getShortcutOrURI(aURL, aPostDataRef)
{
var shortcutURL = null;
@@ -676,13 +677,13 @@ function Bookmarks() //{{{
return shortcutURL;
}
url = getShortcutOrURI(searchString, aPostDataRef);
url = getShortcutOrURI(searchString, postData);
if (url == searchString)
url = null;
if (aPostDataRef && aPostDataRef.value)
return [url, aPostDataRef.value];
if (postData && postData.value)
return [url, postData.value];
else
return url; // can be null
},