mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-03-12 02:35:47 +01:00
Merge with testing.
This commit is contained in:
@@ -11,6 +11,8 @@ syntax: glob
|
|||||||
*/locale/*/*.html
|
*/locale/*/*.html
|
||||||
*/chrome
|
*/chrome
|
||||||
*/contrib/vim/*.vba
|
*/contrib/vim/*.vba
|
||||||
|
*/bak/*
|
||||||
|
downloads/*
|
||||||
|
|
||||||
## Editor backup and swap files
|
## Editor backup and swap files
|
||||||
*~
|
*~
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ dist: $(XPI)
|
|||||||
|
|
||||||
$(RDF): $(RDF_IN) Makefile
|
$(RDF): $(RDF_IN) Makefile
|
||||||
@echo "Preparing release..."
|
@echo "Preparing release..."
|
||||||
$(SED) -e "s,###VERSION###,$(VERSION),g" \
|
$(SED) -e "s,@VERSION@,$(VERSION),g" \
|
||||||
-e "s,###DATE###,$(BUILD_DATE),g" \
|
-e "s,@DATE@,$(BUILD_DATE),g" \
|
||||||
< $< > $@
|
< $< > $@
|
||||||
@echo "SUCCESS: $@"
|
@echo "SUCCESS: $@"
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/* Adds support for data: URIs with chrome privileges
|
/* Adds support for data: URIs with chrome privileges
|
||||||
* and fragment identifiers.
|
* and fragment identifiers.
|
||||||
@@ -27,7 +27,7 @@ let channel = Components.classesByID["{61ba33c0-3031-11d3-8cd0-0060b0fc14a3}"]
|
|||||||
.QueryInterface(Ci.nsIRequest);
|
.QueryInterface(Ci.nsIRequest);
|
||||||
const systemPrincipal = channel.owner;
|
const systemPrincipal = channel.owner;
|
||||||
channel.cancel(NS_BINDING_ABORTED);
|
channel.cancel(NS_BINDING_ABORTED);
|
||||||
delete channel;
|
channel = null;
|
||||||
|
|
||||||
function dataURL(type, data) "data:" + (type || "application/xml;encoding=UTF-8") + "," + escape(data);
|
function dataURL(type, data) "data:" + (type || "application/xml;encoding=UTF-8") + "," + escape(data);
|
||||||
function makeChannel(url, orig) {
|
function makeChannel(url, orig) {
|
||||||
@@ -152,8 +152,9 @@ Liberator.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var components = [ChromeData, Liberator];
|
if (XPCOMUtils.generateNSGetFactory)
|
||||||
|
const NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeData, Liberator]);
|
||||||
function NSGetModule(compMgr, fileSpec) XPCOMUtils.generateModule(components)
|
else
|
||||||
|
const NSGetModule = XPCOMUtils.generateNSGetModule([ChromeData, Liberator]);
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et:
|
// vim: set fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -274,9 +276,9 @@ const AutoCommands = Module("autocommands", {
|
|||||||
completer: function () config.autocommands.concat([["all", "All events"]])
|
completer: function () config.autocommands.concat([["all", "All events"]])
|
||||||
});
|
});
|
||||||
|
|
||||||
options.add(["focuscontent", "fc"],
|
options.add(["strictfocus", "sf"],
|
||||||
"Try to stay in normal mode after loading a web page",
|
"Prevent scripts from focusing input elements without user intervention",
|
||||||
"boolean", false);
|
"boolean", true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const Cc = Components.classes;
|
const Cc = Components.classes;
|
||||||
const Ci = Components.interfaces;
|
const Ci = Components.interfaces;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const DEFAULT_FAVICON = "chrome://mozapps/skin/places/defaultFavicon.png";
|
const DEFAULT_FAVICON = "chrome://mozapps/skin/places/defaultFavicon.png";
|
||||||
|
|
||||||
@@ -364,7 +366,6 @@ const Bookmarks = Module("bookmarks", {
|
|||||||
|
|
||||||
// ripped from Firefox
|
// ripped from Firefox
|
||||||
function getShortcutOrURI(url) {
|
function getShortcutOrURI(url) {
|
||||||
var shortcutURL = null;
|
|
||||||
var keyword = url;
|
var keyword = url;
|
||||||
var param = "";
|
var param = "";
|
||||||
var offset = url.indexOf(" ");
|
var offset = url.indexOf(" ");
|
||||||
@@ -379,7 +380,7 @@ const Bookmarks = Module("bookmarks", {
|
|||||||
return [submission.uri.spec, submission.postData];
|
return [submission.uri.spec, submission.postData];
|
||||||
}
|
}
|
||||||
|
|
||||||
[shortcutURL, postData] = PlacesUtils.getURLAndPostDataForKeyword(keyword);
|
let [shortcutURL, postData] = PlacesUtils.getURLAndPostDataForKeyword(keyword);
|
||||||
if (!shortcutURL)
|
if (!shortcutURL)
|
||||||
return [url, null];
|
return [url, null];
|
||||||
|
|
||||||
@@ -598,6 +599,18 @@ const Bookmarks = Module("bookmarks", {
|
|||||||
context.completions = [["", "Don't perform searches by default"]].concat(context.completions);
|
context.completions = [["", "Don't perform searches by default"]].concat(context.completions);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
options.add(["suggestengines"],
|
||||||
|
"Engine Alias which has a feature of suggest",
|
||||||
|
"stringlist", "google",
|
||||||
|
{
|
||||||
|
completer: function completer(value) {
|
||||||
|
let engines = services.get("browserSearch").getEngines({})
|
||||||
|
.filter(function (engine) engine.supportsResponseType("application/x-suggestions+json"));
|
||||||
|
|
||||||
|
return engines.map(function (engine) [engine.alias, engine.description]);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
completion: function () {
|
completion: function () {
|
||||||
completion.bookmark = function bookmark(context, tags, extra) {
|
completion.bookmark = function bookmark(context, tags, extra) {
|
||||||
@@ -643,8 +656,11 @@ const Bookmarks = Module("bookmarks", {
|
|||||||
let rest = item.url.length - end.length;
|
let rest = item.url.length - end.length;
|
||||||
let query = item.url.substring(begin.length, rest);
|
let query = item.url.substring(begin.length, rest);
|
||||||
if (item.url.substr(rest) == end && query.indexOf("&") == -1) {
|
if (item.url.substr(rest) == end && query.indexOf("&") == -1) {
|
||||||
item.url = decodeURIComponent(query.replace(/#.*/, ""));
|
try {
|
||||||
return item;
|
item.url = decodeURIComponent(query.replace(/#.*/, ""));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}).filter(util.identity);
|
}).filter(util.identity);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -19,9 +19,10 @@ const Point = Struct("x", "y");
|
|||||||
* @instance buffer
|
* @instance buffer
|
||||||
*/
|
*/
|
||||||
const Buffer = Module("buffer", {
|
const Buffer = Module("buffer", {
|
||||||
requires: ["config"],
|
requires: ["config", "util"],
|
||||||
|
|
||||||
init: function () {
|
init: function () {
|
||||||
|
this.evaluateXPath = util.evaluateXPath;
|
||||||
this.pageInfo = {};
|
this.pageInfo = {};
|
||||||
|
|
||||||
this.addPageInfoSection("f", "Feeds", function (verbose) {
|
this.addPageInfoSection("f", "Feeds", function (verbose) {
|
||||||
@@ -168,7 +169,7 @@ const Buffer = Module("buffer", {
|
|||||||
// called when the active document is scrolled
|
// called when the active document is scrolled
|
||||||
_updateBufferPosition: function _updateBufferPosition() {
|
_updateBufferPosition: function _updateBufferPosition() {
|
||||||
statusline.updateBufferPosition();
|
statusline.updateBufferPosition();
|
||||||
modes.show();
|
modes.show(); // Clear the status line.
|
||||||
},
|
},
|
||||||
|
|
||||||
onDOMContentLoaded: function onDOMContentLoaded(event) {
|
onDOMContentLoaded: function onDOMContentLoaded(event) {
|
||||||
@@ -199,19 +200,7 @@ const Buffer = Module("buffer", {
|
|||||||
// any buffer, even in a background tab
|
// any buffer, even in a background tab
|
||||||
doc.pageIsFullyLoaded = 1;
|
doc.pageIsFullyLoaded = 1;
|
||||||
|
|
||||||
// code which is only relevant if the page load is the current tab goes here:
|
if (doc != config.browser.contentDocument)
|
||||||
if (doc == config.browser.contentDocument) {
|
|
||||||
// we want to stay in command mode after a page has loaded
|
|
||||||
// TODO: move somewhere else, as focusing can already happen earlier than on "load"
|
|
||||||
if (options["focuscontent"]) {
|
|
||||||
setTimeout(function () {
|
|
||||||
let focused = liberator.focus;
|
|
||||||
if (focused && (focused.value != null) && focused.value.length == 0)
|
|
||||||
focused.blur();
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // background tab
|
|
||||||
liberator.echomsg("Background tab loaded: " + doc.title || doc.location.href, 3);
|
liberator.echomsg("Background tab loaded: " + doc.title || doc.location.href, 3);
|
||||||
|
|
||||||
this._triggerLoadAutocmd("PageLoad", doc);
|
this._triggerLoadAutocmd("PageLoad", doc);
|
||||||
@@ -279,7 +268,11 @@ const Buffer = Module("buffer", {
|
|||||||
autocommands.trigger("LocationChange", { url: buffer.URL });
|
autocommands.trigger("LocationChange", { url: buffer.URL });
|
||||||
|
|
||||||
// if this is not delayed we get the position of the old buffer
|
// if this is not delayed we get the position of the old buffer
|
||||||
setTimeout(function () { statusline.updateBufferPosition(); }, 500);
|
setTimeout(function () {
|
||||||
|
statusline.updateBufferPosition();
|
||||||
|
statusline.updateZoomLevel();
|
||||||
|
modes.show(); // Clear the status line.
|
||||||
|
}, 500);
|
||||||
},
|
},
|
||||||
// called at the very end of a page load
|
// called at the very end of a page load
|
||||||
asyncUpdateUI: function () {
|
asyncUpdateUI: function () {
|
||||||
@@ -384,19 +377,18 @@ const Buffer = Module("buffer", {
|
|||||||
get pageHeight() window.content.innerHeight,
|
get pageHeight() window.content.innerHeight,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {number} The current browser's text zoom level, as a
|
* @property {number} The current browser's zoom level, as a
|
||||||
* percentage with 100 as 'normal'. Only affects text size.
|
* percentage with 100 as 'normal'.
|
||||||
*/
|
*/
|
||||||
get textZoom() config.browser.markupDocumentViewer.textZoom * 100,
|
get zoomLevel() config.browser.markupDocumentViewer[this.fullZoom ? "textZoom" : "fullZoom"] * 100,
|
||||||
set textZoom(value) { Buffer.setZoom(value, false); },
|
set zoomLevel(value) { Buffer.setZoom(value, this.fullZoom); },
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {number} The current browser's text zoom level, as a
|
* @property {boolean} Whether the current browser is using full
|
||||||
* percentage with 100 as 'normal'. Affects text size, as well as
|
* zoom, as opposed to text zoom.
|
||||||
* image size and block size.
|
|
||||||
*/
|
*/
|
||||||
get fullZoom() config.browser.markupDocumentViewer.fullZoom * 100,
|
get fullZoom() ZoomManager.useFullZoom,
|
||||||
set fullZoom(value) { Buffer.setZoom(value, true); },
|
set fullZoom(value) { Buffer.setZoom(this.zoomLevel, value); },
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {string} The current document's title.
|
* @property {string} The current document's title.
|
||||||
@@ -470,6 +462,18 @@ const Buffer = Module("buffer", {
|
|||||||
return String(selection);
|
return String(selection);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a scripts are allowed to focus the given input
|
||||||
|
* element or input elements in the given window.
|
||||||
|
*
|
||||||
|
* @param {Node|Window}
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
focusAllowed: function (elem) {
|
||||||
|
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
||||||
|
return !options["strictfocus"] || elem.liberatorFocusAllowed;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focuses the given element. In contrast to a simple
|
* Focuses the given element. In contrast to a simple
|
||||||
* elem.focus() call, this function works for iframes and
|
* elem.focus() call, this function works for iframes and
|
||||||
@@ -479,7 +483,10 @@ const Buffer = Module("buffer", {
|
|||||||
*/
|
*/
|
||||||
focusElement: function (elem) {
|
focusElement: function (elem) {
|
||||||
let doc = window.content.document;
|
let doc = window.content.document;
|
||||||
if (elem instanceof HTMLFrameElement || elem instanceof HTMLIFrameElement)
|
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
||||||
|
win.liberatorFocusAllowed = true;
|
||||||
|
|
||||||
|
if (isinstance(elem, [HTMLFrameElement, HTMLIFrameElement]))
|
||||||
elem.contentWindow.focus();
|
elem.contentWindow.focus();
|
||||||
else if (elem instanceof HTMLInputElement && elem.type == "file") {
|
else if (elem instanceof HTMLInputElement && elem.type == "file") {
|
||||||
Buffer.openUploadPrompt(elem);
|
Buffer.openUploadPrompt(elem);
|
||||||
@@ -960,14 +967,20 @@ const Buffer = Module("buffer", {
|
|||||||
liberator.assert(value >= Buffer.ZOOM_MIN || value <= Buffer.ZOOM_MAX,
|
liberator.assert(value >= Buffer.ZOOM_MIN || value <= Buffer.ZOOM_MAX,
|
||||||
"Zoom value out of range (" + Buffer.ZOOM_MIN + " - " + Buffer.ZOOM_MAX + "%)");
|
"Zoom value out of range (" + Buffer.ZOOM_MIN + " - " + Buffer.ZOOM_MAX + "%)");
|
||||||
|
|
||||||
ZoomManager.useFullZoom = fullZoom;
|
if (fullZoom !== undefined)
|
||||||
|
ZoomManager.useFullZoom = fullZoom;
|
||||||
ZoomManager.zoom = value / 100;
|
ZoomManager.zoom = value / 100;
|
||||||
|
|
||||||
if ("FullZoom" in window)
|
if ("FullZoom" in window)
|
||||||
FullZoom._applySettingToPref();
|
FullZoom._applySettingToPref();
|
||||||
liberator.echomsg((fullZoom ? "Full" : "Text") + " zoom: " + value + "%");
|
|
||||||
|
statusline.updateZoomLevel(value, ZoomManager.useFullZoom);
|
||||||
},
|
},
|
||||||
|
|
||||||
bumpZoomLevel: function bumpZoomLevel(steps, fullZoom) {
|
bumpZoomLevel: function bumpZoomLevel(steps, fullZoom) {
|
||||||
|
if (fullZoom === undefined)
|
||||||
|
fullZoom = ZoomManager.useFullZoom;
|
||||||
|
|
||||||
let values = ZoomManager.zoomValues;
|
let values = ZoomManager.zoomValues;
|
||||||
let cur = values.indexOf(ZoomManager.snap(ZoomManager.zoom));
|
let cur = values.indexOf(ZoomManager.snap(ZoomManager.zoom));
|
||||||
let i = util.Math.constrain(cur + steps, 0, values.length - 1);
|
let i = util.Math.constrain(cur + steps, 0, values.length - 1);
|
||||||
@@ -1138,8 +1151,8 @@ const Buffer = Module("buffer", {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
argCount: "?",
|
argCount: "?",
|
||||||
literal: 0,
|
bang: true,
|
||||||
bang: true
|
literal: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
commands.add(["pa[geinfo]"],
|
commands.add(["pa[geinfo]"],
|
||||||
@@ -1178,8 +1191,8 @@ const Buffer = Module("buffer", {
|
|||||||
"Reload the current web page",
|
"Reload the current web page",
|
||||||
function (args) { tabs.reload(config.browser.mCurrentTab, args.bang); },
|
function (args) { tabs.reload(config.browser.mCurrentTab, args.bang); },
|
||||||
{
|
{
|
||||||
bang: true,
|
argCount: "0",
|
||||||
argCount: "0"
|
bang: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: we're prompted if download.useDownloadDir isn't set and no arg specified - intentional?
|
// TODO: we're prompted if download.useDownloadDir isn't set and no arg specified - intentional?
|
||||||
@@ -1470,16 +1483,19 @@ const Buffer = Module("buffer", {
|
|||||||
if (count < 1 && buffer.lastInputField)
|
if (count < 1 && buffer.lastInputField)
|
||||||
buffer.focusElement(buffer.lastInputField);
|
buffer.focusElement(buffer.lastInputField);
|
||||||
else {
|
else {
|
||||||
let xpath = ["input[not(@type) or @type='text' or @type='password' or @type='file']",
|
let xpath = ["input", "textarea[not(@disabled) and not(@readonly)]"];
|
||||||
"textarea[not(@disabled) and not(@readonly)]"];
|
|
||||||
|
|
||||||
let elements = [m for (m in util.evaluateXPath(xpath))].filter(function (match) {
|
let elements = [m for (m in util.evaluateXPath(xpath))].filter(function (elem) {
|
||||||
let computedStyle = util.computedStyle(match);
|
if (elem.readOnly || elem instanceof HTMLInputElement && ["file", "search", "text", "password"].indexOf(elem.type) < 0)
|
||||||
|
return false;
|
||||||
|
let computedStyle = util.computedStyle(elem);
|
||||||
return computedStyle.visibility != "hidden" && computedStyle.display != "none";
|
return computedStyle.visibility != "hidden" && computedStyle.display != "none";
|
||||||
});
|
});
|
||||||
|
|
||||||
liberator.assert(elements.length > 0);
|
liberator.assert(elements.length > 0);
|
||||||
buffer.focusElement(elements[util.Math.constrain(count, 1, elements.length) - 1]);
|
let elem = elements[util.Math.constrain(count, 1, elements.length) - 1];
|
||||||
|
buffer.focusElement(elem);
|
||||||
|
util.scrollIntoView(elem);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
@@ -1504,7 +1520,7 @@ const Buffer = Module("buffer", {
|
|||||||
function () {
|
function () {
|
||||||
let url = util.readFromClipboard();
|
let url = util.readFromClipboard();
|
||||||
liberator.assert(url);
|
liberator.assert(url);
|
||||||
liberator.open(url, { from: "activate", where: liberator.NEW_TAB });
|
liberator.open(url, { from: "paste", where: liberator.NEW_TAB });
|
||||||
});
|
});
|
||||||
|
|
||||||
// reloading
|
// reloading
|
||||||
@@ -1551,27 +1567,27 @@ const Buffer = Module("buffer", {
|
|||||||
function (count) { buffer.textZoom = count > 1 ? count : 100; },
|
function (count) { buffer.textZoom = count > 1 ? count : 100; },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add(myModes, ["zI"],
|
mappings.add(myModes, ["ZI", "zI"],
|
||||||
"Enlarge full zoom of current web page",
|
"Enlarge full zoom of current web page",
|
||||||
function (count) { buffer.zoomIn(Math.max(count, 1), true); },
|
function (count) { buffer.zoomIn(Math.max(count, 1), true); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add(myModes, ["zM"],
|
mappings.add(myModes, ["ZM", "zM"],
|
||||||
"Enlarge full zoom of current web page by a larger amount",
|
"Enlarge full zoom of current web page by a larger amount",
|
||||||
function (count) { buffer.zoomIn(Math.max(count, 1) * 3, true); },
|
function (count) { buffer.zoomIn(Math.max(count, 1) * 3, true); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add(myModes, ["zO"],
|
mappings.add(myModes, ["ZO", "zO"],
|
||||||
"Reduce full zoom of current web page",
|
"Reduce full zoom of current web page",
|
||||||
function (count) { buffer.zoomOut(Math.max(count, 1), true); },
|
function (count) { buffer.zoomOut(Math.max(count, 1), true); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add(myModes, ["zR"],
|
mappings.add(myModes, ["ZR", "zR"],
|
||||||
"Reduce full zoom of current web page by a larger amount",
|
"Reduce full zoom of current web page by a larger amount",
|
||||||
function (count) { buffer.zoomOut(Math.max(count, 1) * 3, true); },
|
function (count) { buffer.zoomOut(Math.max(count, 1) * 3, true); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add(myModes, ["zZ"],
|
mappings.add(myModes, ["ZZ", "zZ"],
|
||||||
"Set full zoom value of current web page",
|
"Set full zoom value of current web page",
|
||||||
function (count) { buffer.fullZoom = count > 1 ? count : 100; },
|
function (count) { buffer.fullZoom = count > 1 ? count : 100; },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
@@ -1599,7 +1615,7 @@ const Buffer = Module("buffer", {
|
|||||||
"Desired info in the :pageinfo output",
|
"Desired info in the :pageinfo output",
|
||||||
"charlist", "gfm",
|
"charlist", "gfm",
|
||||||
{
|
{
|
||||||
completer: function (context) [[k, v[1]] for ([k, v] in Iterator(this.pageInfo))]
|
completer: function (context) [[k, v[1]] for ([k, v] in Iterator(buffer.pageInfo))]
|
||||||
});
|
});
|
||||||
|
|
||||||
options.add(["scroll", "scr"],
|
options.add(["scroll", "scr"],
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -102,7 +105,7 @@ const CommandLine = Module("commandline", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._autocompleteTimer = new Timer(200, 500, function autocompleteTell(tabPressed) {
|
this._autocompleteTimer = new Timer(200, 500, function autocompleteTell(tabPressed) {
|
||||||
if (!events.feedingKeys && self._completions && options.get("wildoptions").has("auto")) {
|
if (!events.feedingKeys && self._completions && options.get("autocomplete").values.length) {
|
||||||
self._completions.complete(true, false);
|
self._completions.complete(true, false);
|
||||||
self._completions.itemList.show();
|
self._completions.itemList.show();
|
||||||
}
|
}
|
||||||
@@ -329,10 +332,11 @@ const CommandLine = Module("commandline", {
|
|||||||
|
|
||||||
FORCE_MULTILINE : 1 << 0,
|
FORCE_MULTILINE : 1 << 0,
|
||||||
FORCE_SINGLELINE : 1 << 1,
|
FORCE_SINGLELINE : 1 << 1,
|
||||||
DISALLOW_MULTILINE : 1 << 2, // if an echo() should try to use the single line
|
DISALLOW_MULTILINE : 1 << 2, // If an echo() should try to use the single line
|
||||||
// but output nothing when the MOW is open; when also
|
// but output nothing when the MOW is open; when also
|
||||||
// FORCE_MULTILINE is given, FORCE_MULTILINE takes precedence
|
// FORCE_MULTILINE is given, FORCE_MULTILINE takes precedence
|
||||||
APPEND_TO_MESSAGES : 1 << 3, // add the string to the message this._history
|
APPEND_TO_MESSAGES : 1 << 3, // Add the string to the message this._history.
|
||||||
|
ACTIVE_WINDOW : 1 << 4, // Only echo in active window.
|
||||||
|
|
||||||
get completionContext() this._completions.context,
|
get completionContext() this._completions.context,
|
||||||
|
|
||||||
@@ -499,6 +503,10 @@ const CommandLine = Module("commandline", {
|
|||||||
|
|
||||||
if (flags & this.APPEND_TO_MESSAGES)
|
if (flags & this.APPEND_TO_MESSAGES)
|
||||||
this._messageHistory.add({ str: str, highlight: highlightGroup });
|
this._messageHistory.add({ str: str, highlight: highlightGroup });
|
||||||
|
if ((flags & this.ACTIVE_WINDOW) &&
|
||||||
|
window != services.get("windowWatcher").activeWindow &&
|
||||||
|
services.get("windowWatcher").activeWindow.liberator)
|
||||||
|
return;
|
||||||
|
|
||||||
// The DOM isn't threadsafe. It must only be accessed from the main thread.
|
// The DOM isn't threadsafe. It must only be accessed from the main thread.
|
||||||
liberator.callInMainThread(function () {
|
liberator.callInMainThread(function () {
|
||||||
@@ -754,12 +762,12 @@ const CommandLine = Module("commandline", {
|
|||||||
case "<MiddleMouse>":
|
case "<MiddleMouse>":
|
||||||
case "<C-LeftMouse>":
|
case "<C-LeftMouse>":
|
||||||
case "<C-M-LeftMouse>":
|
case "<C-M-LeftMouse>":
|
||||||
openLink(liberator.NEW_BACKGROUND_TAB);
|
openLink({ where: liberator.NEW_TAB, background: true });
|
||||||
break;
|
break;
|
||||||
case "<S-MiddleMouse>":
|
case "<S-MiddleMouse>":
|
||||||
case "<C-S-LeftMouse>":
|
case "<C-S-LeftMouse>":
|
||||||
case "<C-M-S-LeftMouse>":
|
case "<C-M-S-LeftMouse>":
|
||||||
openLink(liberator.NEW_TAB);
|
openLink({ where: liberator.NEW_TAB, background: false });
|
||||||
break;
|
break;
|
||||||
case "<S-LeftMouse>":
|
case "<S-LeftMouse>":
|
||||||
openLink(liberator.NEW_WINDOW);
|
openLink(liberator.NEW_WINDOW);
|
||||||
@@ -964,7 +972,7 @@ const CommandLine = Module("commandline", {
|
|||||||
|
|
||||||
let doc = this._multilineOutputWidget.contentDocument;
|
let doc = this._multilineOutputWidget.contentDocument;
|
||||||
|
|
||||||
availableHeight = config.outputHeight;
|
let availableHeight = config.outputHeight;
|
||||||
if (!this._outputContainer.collapsed)
|
if (!this._outputContainer.collapsed)
|
||||||
availableHeight += parseFloat(this._outputContainer.height);
|
availableHeight += parseFloat(this._outputContainer.height);
|
||||||
doc.body.style.minWidth = this._commandlineWidget.scrollWidth + "px";
|
doc.body.style.minWidth = this._commandlineWidget.scrollWidth + "px";
|
||||||
@@ -1032,7 +1040,7 @@ const CommandLine = Module("commandline", {
|
|||||||
sanitize: function (timespan) {
|
sanitize: function (timespan) {
|
||||||
let range = [0, Number.MAX_VALUE];
|
let range = [0, Number.MAX_VALUE];
|
||||||
if (liberator.has("sanitizer") && (timespan || options["sanitizetimespan"]))
|
if (liberator.has("sanitizer") && (timespan || options["sanitizetimespan"]))
|
||||||
range = sanitizer.getClearRange(timespan || options["sanitizetimespan"]);
|
range = Sanitizer.getClearRange(timespan || options["sanitizetimespan"]);
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
this.store.mutate("filter", function (item) {
|
this.store.mutate("filter", function (item) {
|
||||||
@@ -1107,7 +1115,7 @@ const CommandLine = Module("commandline", {
|
|||||||
*/
|
*/
|
||||||
Completions: Class("Completions", {
|
Completions: Class("Completions", {
|
||||||
init: function (input) {
|
init: function (input) {
|
||||||
this.context = CompletionContext(input.editor);
|
this.context = CompletionContext(input.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
|
||||||
this.context.onUpdate = this.closure._reset;
|
this.context.onUpdate = this.closure._reset;
|
||||||
this.editor = input.editor;
|
this.editor = input.editor;
|
||||||
this.selected = null;
|
this.selected = null;
|
||||||
@@ -1127,7 +1135,7 @@ const CommandLine = Module("commandline", {
|
|||||||
let str = commandline.command;
|
let str = commandline.command;
|
||||||
return str.substring(this.prefix.length, str.length - this.suffix.length);
|
return str.substring(this.prefix.length, str.length - this.suffix.length);
|
||||||
},
|
},
|
||||||
set completion set_completion(completion) {
|
set completion(completion) {
|
||||||
this.previewClear();
|
this.previewClear();
|
||||||
|
|
||||||
// Change the completion text.
|
// Change the completion text.
|
||||||
@@ -1516,84 +1524,6 @@ const CommandLine = Module("commandline", {
|
|||||||
options.add(["showmode", "smd"],
|
options.add(["showmode", "smd"],
|
||||||
"Show the current mode in the command line",
|
"Show the current mode in the command line",
|
||||||
"boolean", true);
|
"boolean", true);
|
||||||
|
|
||||||
options.add(["suggestengines"],
|
|
||||||
"Engine Alias which has a feature of suggest",
|
|
||||||
"stringlist", "google",
|
|
||||||
{
|
|
||||||
completer: function completer(value) {
|
|
||||||
let engines = services.get("browserSearch").getEngines({})
|
|
||||||
.filter(function (engine) engine.supportsResponseType("application/x-suggestions+json"));
|
|
||||||
|
|
||||||
return engines.map(function (engine) [engine.alias, engine.description]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.add(["complete", "cpt"],
|
|
||||||
"Items which are completed at the :open prompts",
|
|
||||||
"charlist", typeof(config.defaults["complete"]) == "string" ? config.defaults["complete"] : "slf",
|
|
||||||
{
|
|
||||||
completer: function (context) array(values(completion.urlCompleters))
|
|
||||||
});
|
|
||||||
|
|
||||||
options.add(["wildcase", "wic"],
|
|
||||||
"Completion case matching mode",
|
|
||||||
"string", "smart",
|
|
||||||
{
|
|
||||||
completer: function () [
|
|
||||||
["smart", "Case is significant when capital letters are typed"],
|
|
||||||
["match", "Case is always significant"],
|
|
||||||
["ignore", "Case is never significant"]
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
options.add(["wildignore", "wig"],
|
|
||||||
"List of file patterns to ignore when completing files",
|
|
||||||
"stringlist", "",
|
|
||||||
{
|
|
||||||
validator: function validator(values) {
|
|
||||||
// TODO: allow for escaping the ","
|
|
||||||
try {
|
|
||||||
RegExp("^(" + values.join("|") + ")$");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.add(["wildmode", "wim"],
|
|
||||||
"Define how command line completion works",
|
|
||||||
"stringlist", "list:full",
|
|
||||||
{
|
|
||||||
completer: function (context) [
|
|
||||||
// Why do we need ""?
|
|
||||||
["", "Complete only the first match"],
|
|
||||||
["full", "Complete the next full match"],
|
|
||||||
["longest", "Complete to longest common string"],
|
|
||||||
["list", "If more than one match, list all matches"],
|
|
||||||
["list:full", "List all and complete first match"],
|
|
||||||
["list:longest", "List all and complete common string"]
|
|
||||||
],
|
|
||||||
checkHas: function (value, val) {
|
|
||||||
let [first, second] = value.split(":", 2);
|
|
||||||
return first == val || second == val;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.add(["wildoptions", "wop"],
|
|
||||||
"Change how command line completion is done",
|
|
||||||
"stringlist", "",
|
|
||||||
{
|
|
||||||
completer: function completer(value) {
|
|
||||||
return [
|
|
||||||
["", "Default completion that won't show or sort the results"],
|
|
||||||
["auto", "Automatically show this._completions while you are typing"],
|
|
||||||
["sort", "Always sort the completion list"]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
styles: function () {
|
styles: function () {
|
||||||
let fontSize = util.computedStyle(document.getElementById(config.mainWindowId)).fontSize;
|
let fontSize = util.computedStyle(document.getElementById(config.mainWindowId)).fontSize;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -73,9 +73,9 @@ const Command = Class("Command", {
|
|||||||
modifiers = modifiers || {};
|
modifiers = modifiers || {};
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
function exec(args) {
|
function exec(command) {
|
||||||
// FIXME: Move to parseCommand?
|
// FIXME: Move to parseCommand?
|
||||||
args = self.parseArgs(args);
|
args = self.parseArgs(command);
|
||||||
if (!args)
|
if (!args)
|
||||||
return;
|
return;
|
||||||
args.count = count;
|
args.count = count;
|
||||||
@@ -237,6 +237,7 @@ const ArgType = Struct("description", "parse");
|
|||||||
const Commands = Module("commands", {
|
const Commands = Module("commands", {
|
||||||
init: function () {
|
init: function () {
|
||||||
this._exCommands = [];
|
this._exCommands = [];
|
||||||
|
this._exMap = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
// FIXME: remove later, when our option handler is better
|
// FIXME: remove later, when our option handler is better
|
||||||
@@ -304,7 +305,7 @@ const Commands = Module("commands", {
|
|||||||
repeat: null,
|
repeat: null,
|
||||||
|
|
||||||
_addCommand: function (command, replace) {
|
_addCommand: function (command, replace) {
|
||||||
if (this._exCommands.some(function (c) c.hasName(command.name))) {
|
if (command.name in this._exMap) {
|
||||||
if (command.user && replace)
|
if (command.user && replace)
|
||||||
commands.removeUserCommand(command.name);
|
commands.removeUserCommand(command.name);
|
||||||
else {
|
else {
|
||||||
@@ -314,6 +315,8 @@ const Commands = Module("commands", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._exCommands.push(command);
|
this._exCommands.push(command);
|
||||||
|
for(let [,name] in Iterator(command.names))
|
||||||
|
this._exMap[name] = command;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@@ -387,7 +390,7 @@ const Commands = Module("commands", {
|
|||||||
* @returns {Command}
|
* @returns {Command}
|
||||||
*/
|
*/
|
||||||
get: function (name) {
|
get: function (name) {
|
||||||
return this._exCommands.filter(function (cmd) cmd.hasName(name))[0] || null;
|
return this._exMap[name] || this._exCommands.filter(function (cmd) cmd.hasName(name))[0] || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -762,6 +765,10 @@ const Commands = Module("commands", {
|
|||||||
* any of the command's names.
|
* any of the command's names.
|
||||||
*/
|
*/
|
||||||
removeUserCommand: function (name) {
|
removeUserCommand: function (name) {
|
||||||
|
for(let [,cmd] in Iterator(this._exCommands))
|
||||||
|
if(cmd.user && cmd.hasName(name))
|
||||||
|
for(let [,name] in Iterator(cmd.names))
|
||||||
|
delete this._exMap[name];
|
||||||
this._exCommands = this._exCommands.filter(function (cmd) !(cmd.user && cmd.hasName(name)));
|
this._exCommands = this._exCommands.filter(function (cmd) !(cmd.user && cmd.hasName(name)));
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -894,10 +901,10 @@ const Commands = Module("commands", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/);
|
[prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/);
|
||||||
let cmdContext = context.fork(cmd, prefix.length);
|
let cmdContext = context.fork(command.name, prefix.length);
|
||||||
let argContext = context.fork("args", prefix.length);
|
let argContext = context.fork("args", prefix.length);
|
||||||
args = command.parseArgs(cmdContext.filter, argContext, { count: count, bang: bang });
|
args = command.parseArgs(cmdContext.filter, argContext, { count: count, bang: bang });
|
||||||
if (args) {
|
if (args && !cmdContext.waitingForTab) {
|
||||||
// FIXME: Move to parseCommand
|
// FIXME: Move to parseCommand
|
||||||
args.count = count;
|
args.count = count;
|
||||||
args.bang = bang;
|
args.bang = bang;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -34,6 +35,11 @@ const CompletionContext = Class("CompletionContext", {
|
|||||||
if (editor instanceof this.constructor) {
|
if (editor instanceof this.constructor) {
|
||||||
let parent = editor;
|
let parent = editor;
|
||||||
name = parent.name + "/" + name;
|
name = parent.name + "/" + name;
|
||||||
|
|
||||||
|
this.autoComplete = options.get("autocomplete").getKey(name);
|
||||||
|
this.sortResults = options.get("wildsort").getKey(name);
|
||||||
|
this.wildcase = options.get("wildcase").getKey(name);
|
||||||
|
|
||||||
this.contexts = parent.contexts;
|
this.contexts = parent.contexts;
|
||||||
if (name in this.contexts)
|
if (name in this.contexts)
|
||||||
self = this.contexts[name];
|
self = this.contexts[name];
|
||||||
@@ -146,6 +152,8 @@ const CompletionContext = Class("CompletionContext", {
|
|||||||
this.top = this;
|
this.top = this;
|
||||||
this.__defineGetter__("incomplete", function () this.contextList.some(function (c) c.parent && c.incomplete));
|
this.__defineGetter__("incomplete", function () this.contextList.some(function (c) c.parent && c.incomplete));
|
||||||
this.__defineGetter__("waitingForTab", function () this.contextList.some(function (c) c.parent && c.waitingForTab));
|
this.__defineGetter__("waitingForTab", function () this.contextList.some(function (c) c.parent && c.waitingForTab));
|
||||||
|
this.__defineSetter__("incomplete", function (val) {});
|
||||||
|
this.__defineSetter__("waitingForTab", function (val) {});
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -243,7 +251,7 @@ const CompletionContext = Class("CompletionContext", {
|
|||||||
get completions() this._completions || [],
|
get completions() this._completions || [],
|
||||||
set completions(items) {
|
set completions(items) {
|
||||||
// Accept a generator
|
// Accept a generator
|
||||||
if ({}.toString.call(items) != '[object Array]')
|
if (!isarray(items))
|
||||||
items = [x for (x in Iterator(items))];
|
items = [x for (x in Iterator(items))];
|
||||||
delete this.cache.filtered;
|
delete this.cache.filtered;
|
||||||
delete this.cache.filter;
|
delete this.cache.filter;
|
||||||
@@ -333,7 +341,7 @@ const CompletionContext = Class("CompletionContext", {
|
|||||||
get ignoreCase() {
|
get ignoreCase() {
|
||||||
if ("_ignoreCase" in this)
|
if ("_ignoreCase" in this)
|
||||||
return this._ignoreCase;
|
return this._ignoreCase;
|
||||||
let mode = options["wildcase"];
|
let mode = this.wildcase;
|
||||||
if (mode == "match")
|
if (mode == "match")
|
||||||
return this._ignoreCase = false;
|
return this._ignoreCase = false;
|
||||||
if (mode == "ignore")
|
if (mode == "ignore")
|
||||||
@@ -367,7 +375,7 @@ const CompletionContext = Class("CompletionContext", {
|
|||||||
if (this.maxItems)
|
if (this.maxItems)
|
||||||
filtered = filtered.slice(0, this.maxItems);
|
filtered = filtered.slice(0, this.maxItems);
|
||||||
|
|
||||||
if (options.get("wildoptions").has("sort") && this.compare)
|
if (this.sortResults && this.compare)
|
||||||
filtered.sort(this.compare);
|
filtered.sort(this.compare);
|
||||||
let quote = this.quote;
|
let quote = this.quote;
|
||||||
if (quote)
|
if (quote)
|
||||||
@@ -404,12 +412,12 @@ const CompletionContext = Class("CompletionContext", {
|
|||||||
let filter = fixCase(this.filter);
|
let filter = fixCase(this.filter);
|
||||||
if (this.anchored) {
|
if (this.anchored) {
|
||||||
var compare = function compare(text, s) text.substr(0, s.length) == s;
|
var compare = function compare(text, s) text.substr(0, s.length) == s;
|
||||||
substrings = util.map(util.range(filter.length, text.length + 1),
|
var substrings = util.map(util.range(filter.length, text.length + 1),
|
||||||
function (end) text.substring(0, end));
|
function (end) text.substring(0, end));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var compare = function compare(text, s) text.indexOf(s) >= 0;
|
var compare = function compare(text, s) text.indexOf(s) >= 0;
|
||||||
substrings = [];
|
var substrings = [];
|
||||||
let start = 0;
|
let start = 0;
|
||||||
let idx;
|
let idx;
|
||||||
let length = filter.length;
|
let length = filter.length;
|
||||||
@@ -498,8 +506,14 @@ const CompletionContext = Class("CompletionContext", {
|
|||||||
completer = self[completer];
|
completer = self[completer];
|
||||||
let context = CompletionContext(this, name, offset);
|
let context = CompletionContext(this, name, offset);
|
||||||
this.contextList.push(context);
|
this.contextList.push(context);
|
||||||
if (completer)
|
|
||||||
|
if (!context.autoComplete && !context.tabPressed && context.editor)
|
||||||
|
context.waitingForTab = true;
|
||||||
|
else if (completer)
|
||||||
return completer.apply(self || this, [context].concat(Array.slice(arguments, arguments.callee.length)));
|
return completer.apply(self || this, [context].concat(Array.slice(arguments, arguments.callee.length)));
|
||||||
|
|
||||||
|
if (completer)
|
||||||
|
return null;
|
||||||
return context;
|
return context;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -682,7 +696,7 @@ const Completion = Module("completion", {
|
|||||||
if (skip)
|
if (skip)
|
||||||
context.advance(skip[0].length);
|
context.advance(skip[0].length);
|
||||||
|
|
||||||
if (typeof complete === "undefined")
|
if (complete == null)
|
||||||
complete = options["complete"];
|
complete = options["complete"];
|
||||||
|
|
||||||
// Will, and should, throw an error if !(c in opts)
|
// Will, and should, throw an error if !(c in opts)
|
||||||
@@ -744,6 +758,80 @@ const Completion = Module("completion", {
|
|||||||
//}}}
|
//}}}
|
||||||
}, {
|
}, {
|
||||||
UrlCompleter: Struct("name", "description", "completer")
|
UrlCompleter: Struct("name", "description", "completer")
|
||||||
|
}, {
|
||||||
|
commands: function () {
|
||||||
|
commands.add(["contexts"],
|
||||||
|
"List the completion contexts used during completion of an ex command",
|
||||||
|
function (args) {
|
||||||
|
commandline.echo(template.commandOutput(
|
||||||
|
<div highlight="Completions">
|
||||||
|
{ template.completionRow(["Context", "Title"], "CompTitle") }
|
||||||
|
{ template.map(completion.contextList || [], function (item) template.completionRow(item, "CompItem")) }
|
||||||
|
</div>),
|
||||||
|
null, commandline.FORCE_MULTILINE);
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
argCount: "1",
|
||||||
|
completer: function (context, args) {
|
||||||
|
let PREFIX = "/ex/contexts";
|
||||||
|
context.fork("ex", 0, completion, "ex");
|
||||||
|
completion.contextList = [[k.substr(PREFIX.length), v.title[0]] for ([k, v] in iter(context.contexts)) if (k.substr(0, PREFIX.length) == PREFIX)];
|
||||||
|
},
|
||||||
|
literal: 0
|
||||||
|
});
|
||||||
|
},
|
||||||
|
options: function () {
|
||||||
|
options.add(["autocomplete", "au"],
|
||||||
|
"Automatically update the completion list on any key press",
|
||||||
|
"regexlist", ".*");
|
||||||
|
|
||||||
|
options.add(["complete", "cpt"],
|
||||||
|
"Items which are completed at the :open prompts",
|
||||||
|
"charlist", typeof(config.defaults["complete"]) == "string" ? config.defaults["complete"] : "slf",
|
||||||
|
{
|
||||||
|
completer: function (context) array(values(completion.urlCompleters))
|
||||||
|
});
|
||||||
|
|
||||||
|
options.add(["wildcase", "wic"],
|
||||||
|
"Completion case matching mode",
|
||||||
|
"regexmap", "smart",
|
||||||
|
{
|
||||||
|
completer: function () [
|
||||||
|
["smart", "Case is significant when capital letters are typed"],
|
||||||
|
["match", "Case is always significant"],
|
||||||
|
["ignore", "Case is never significant"]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
options.add(["wildmode", "wim"],
|
||||||
|
"Define how command line completion works",
|
||||||
|
"stringlist", "list:full",
|
||||||
|
{
|
||||||
|
completer: function (context) [
|
||||||
|
// Why do we need ""?
|
||||||
|
// Because its description is useful during completion. --Kris
|
||||||
|
["", "Complete only the first match"],
|
||||||
|
["full", "Complete the next full match"],
|
||||||
|
["longest", "Complete to longest common string"],
|
||||||
|
["list", "If more than one match, list all matches"],
|
||||||
|
["list:full", "List all and complete first match"],
|
||||||
|
["list:longest", "List all and complete common string"]
|
||||||
|
],
|
||||||
|
checkHas: function (value, val) {
|
||||||
|
let [first, second] = value.split(":", 2);
|
||||||
|
return first == val || second == val;
|
||||||
|
},
|
||||||
|
has: function () {
|
||||||
|
test = function (val) this.values.some(function (value) this.checkHas(value, val), this);
|
||||||
|
return Array.some(arguments, test, this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.add(["wildsort", "wis"],
|
||||||
|
"Regexp list of which contexts to sort",
|
||||||
|
"regexlist", ".*");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et:
|
// vim: set fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const ConfigBase = Class(ModuleBase, {
|
const ConfigBase = Class(ModuleBase, {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -103,32 +103,16 @@ const Events = Module("events", {
|
|||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
function wrapListener(method) {
|
|
||||||
return function (event) {
|
|
||||||
try {
|
|
||||||
self[method](event);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
if (e.message == "Interrupted")
|
|
||||||
liberator.echoerr("Interrupted");
|
|
||||||
else
|
|
||||||
liberator.echoerr("Processing " + event.type + " event: " + (e.echoerr || e));
|
|
||||||
liberator.reportError(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this._wrappedOnKeyPress = wrapListener("onKeyPress");
|
|
||||||
this._wrappedOnKeyUpOrDown = wrapListener("onKeyUpOrDown");
|
|
||||||
this.addSessionListener(window, "keypress", this.closure._wrappedOnKeyPress, true);
|
|
||||||
this.addSessionListener(window, "keydown", this.closure._wrappedOnKeyUpOrDown, true);
|
|
||||||
this.addSessionListener(window, "keyup", this.closure._wrappedOnKeyUpOrDown, true);
|
|
||||||
|
|
||||||
this._activeMenubar = false;
|
this._activeMenubar = false;
|
||||||
this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true);
|
|
||||||
this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true);
|
|
||||||
this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true);
|
this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true);
|
||||||
this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true);
|
this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true);
|
||||||
|
this.addSessionListener(window, "focus", this.wrapListener(this.closure.onFocus), true);
|
||||||
|
this.addSessionListener(window, "keydown", this.wrapListener(this.closure.onKeyUpOrDown), true);
|
||||||
|
this.addSessionListener(window, "keypress", this.wrapListener(this.closure.onKeyPress), true);
|
||||||
|
this.addSessionListener(window, "keyup", this.wrapListener(this.closure.onKeyUpOrDown), true);
|
||||||
|
this.addSessionListener(window, "mousedown", this.wrapListener(this.closure.onMouseDown), true);
|
||||||
|
this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true);
|
||||||
|
this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true);
|
||||||
this.addSessionListener(window, "resize", this.closure.onResize, true);
|
this.addSessionListener(window, "resize", this.closure.onResize, true);
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -151,10 +135,28 @@ const Events = Module("events", {
|
|||||||
*/
|
*/
|
||||||
addSessionListener: function (target, event, callback, capture) {
|
addSessionListener: function (target, event, callback, capture) {
|
||||||
let args = Array.slice(arguments, 0);
|
let args = Array.slice(arguments, 0);
|
||||||
target.addEventListener.apply(target, args.slice(1));
|
target.addEventListener.apply(args[0], args.slice(1));
|
||||||
this.sessionListeners.push(args);
|
this.sessionListeners.push(args);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps an event listener to ensure that errors are reported.
|
||||||
|
*/
|
||||||
|
wrapListener: function wrapListener(method, self) {
|
||||||
|
return function (event) {
|
||||||
|
try {
|
||||||
|
method.apply(self, arguments);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e.message == "Interrupted")
|
||||||
|
liberator.echoerr("Interrupted");
|
||||||
|
else
|
||||||
|
liberator.echoerr("Processing " + event.type + " event: " + (e.echoerr || e));
|
||||||
|
liberator.reportError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {boolean} Whether synthetic key events are currently being
|
* @property {boolean} Whether synthetic key events are currently being
|
||||||
* processed.
|
* processed.
|
||||||
@@ -651,89 +653,14 @@ const Events = Module("events", {
|
|||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
// argument "event" is deliberately not used, as i don't seem to have
|
onDOMMenuBarActive: function () {
|
||||||
// access to the real focus target
|
this._activeMenubar = true;
|
||||||
// Huh? --djk
|
modes.add(modes.MENU);
|
||||||
onFocusChange: function (event) {
|
|
||||||
// command line has it's own focus change handler
|
|
||||||
if (liberator.mode == modes.COMMAND_LINE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument
|
|
||||||
|
|
||||||
let win = window.document.commandDispatcher.focusedWindow;
|
|
||||||
let elem = window.document.commandDispatcher.focusedElement;
|
|
||||||
|
|
||||||
if (win && win.top == content && liberator.has("tabs"))
|
|
||||||
tabs.localStore.focusedFrame = win;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (elem && elem.readOnly)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((elem instanceof HTMLInputElement && /^(text|password)$/.test(elem.type)) ||
|
|
||||||
(elem instanceof HTMLSelectElement)) {
|
|
||||||
liberator.mode = modes.INSERT;
|
|
||||||
if (hasHTMLDocument(win))
|
|
||||||
buffer.lastInputField = elem;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (elem instanceof HTMLEmbedElement || elem instanceof HTMLObjectElement) {
|
|
||||||
liberator.mode = modes.EMBED;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elem instanceof HTMLTextAreaElement || (elem && elem.contentEditable == "true")) {
|
|
||||||
if (options["insertmode"])
|
|
||||||
modes.set(modes.INSERT);
|
|
||||||
else if (elem.selectionEnd - elem.selectionStart > 0)
|
|
||||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
|
||||||
else
|
|
||||||
modes.main = modes.TEXTAREA;
|
|
||||||
if (hasHTMLDocument(win))
|
|
||||||
buffer.lastInputField = elem;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.focusChange) {
|
|
||||||
config.focusChange(win);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let urlbar = document.getElementById("urlbar");
|
|
||||||
if (elem == null && urlbar && urlbar.inputField == this._lastFocus)
|
|
||||||
liberator.threadYield(true);
|
|
||||||
|
|
||||||
if (liberator.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL))
|
|
||||||
modes.reset();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
this._lastFocus = elem;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onSelectionChange: function (event) {
|
onDOMMenuBarInactive: function () {
|
||||||
let couldCopy = false;
|
this._activeMenubar = false;
|
||||||
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
|
modes.remove(modes.MENU);
|
||||||
if (controller && controller.isCommandEnabled("cmd_copy"))
|
|
||||||
couldCopy = true;
|
|
||||||
|
|
||||||
if (liberator.mode != modes.VISUAL) {
|
|
||||||
if (couldCopy) {
|
|
||||||
if ((liberator.mode == modes.TEXTAREA ||
|
|
||||||
(modes.extended & modes.TEXTAREA))
|
|
||||||
&& !options["insertmode"])
|
|
||||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
|
||||||
else if (liberator.mode == modes.CARET)
|
|
||||||
modes.set(modes.VISUAL, modes.CARET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// XXX: disabled, as i think automatically starting visual caret mode does more harm than help
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// if (!couldCopy && modes.extended & modes.CARET)
|
|
||||||
// liberator.mode = modes.CARET;
|
|
||||||
// }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -808,6 +735,78 @@ const Events = Module("events", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onFocus: function (event) {
|
||||||
|
function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument
|
||||||
|
|
||||||
|
let elem = event.originalTarget;
|
||||||
|
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
||||||
|
|
||||||
|
if (hasHTMLDocument(win) && !buffer.focusAllowed(win))
|
||||||
|
elem.blur();
|
||||||
|
},
|
||||||
|
|
||||||
|
// argument "event" is deliberately not used, as i don't seem to have
|
||||||
|
// access to the real focus target
|
||||||
|
// Huh? --djk
|
||||||
|
onFocusChange: function (event) {
|
||||||
|
// command line has it's own focus change handler
|
||||||
|
if (liberator.mode == modes.COMMAND_LINE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument
|
||||||
|
|
||||||
|
let win = window.document.commandDispatcher.focusedWindow;
|
||||||
|
let elem = window.document.commandDispatcher.focusedElement;
|
||||||
|
|
||||||
|
if (win && win.top == content && liberator.has("tabs"))
|
||||||
|
tabs.localStore.focusedFrame = win;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (elem && elem.readOnly)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((elem instanceof HTMLInputElement && /^(search|text|password)$/.test(elem.type)) ||
|
||||||
|
(elem instanceof HTMLSelectElement)) {
|
||||||
|
liberator.mode = modes.INSERT;
|
||||||
|
if (hasHTMLDocument(win))
|
||||||
|
buffer.lastInputField = elem;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isinstance(elem, [HTMLEmbedElement, HTMLEmbedElement])) {
|
||||||
|
liberator.mode = modes.EMBED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elem instanceof HTMLTextAreaElement || (elem && elem.contentEditable == "true")) {
|
||||||
|
if (options["insertmode"])
|
||||||
|
modes.set(modes.INSERT);
|
||||||
|
else if (elem.selectionEnd - elem.selectionStart > 0)
|
||||||
|
modes.set(modes.VISUAL, modes.TEXTAREA);
|
||||||
|
else
|
||||||
|
modes.main = modes.TEXTAREA;
|
||||||
|
if (hasHTMLDocument(win))
|
||||||
|
buffer.lastInputField = elem;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.focusChange) {
|
||||||
|
config.focusChange(win);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let urlbar = document.getElementById("urlbar");
|
||||||
|
if (elem == null && urlbar && urlbar.inputField == this._lastFocus)
|
||||||
|
liberator.threadYield(true);
|
||||||
|
|
||||||
|
if (liberator.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL))
|
||||||
|
modes.reset();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
this._lastFocus = elem;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// this keypress handler gets always called first, even if e.g.
|
// this keypress handler gets always called first, even if e.g.
|
||||||
// the commandline has focus
|
// the commandline has focus
|
||||||
// TODO: ...help me...please...
|
// TODO: ...help me...please...
|
||||||
@@ -1022,7 +1021,9 @@ const Events = Module("events", {
|
|||||||
|
|
||||||
if (liberator.mode == modes.COMMAND_LINE) {
|
if (liberator.mode == modes.COMMAND_LINE) {
|
||||||
if (!(modes.extended & modes.INPUT_MULTILINE))
|
if (!(modes.extended & modes.INPUT_MULTILINE))
|
||||||
commandline.onEvent(event); // reroute event in command line mode
|
liberator.trapErrors(function () {
|
||||||
|
commandline.onEvent(event); // reroute event in command line mode
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else if (!modes.mainMode.input)
|
else if (!modes.mainMode.input)
|
||||||
liberator.beep();
|
liberator.beep();
|
||||||
@@ -1050,6 +1051,13 @@ const Events = Module("events", {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onMouseDown: function (event) {
|
||||||
|
let elem = event.target;
|
||||||
|
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
||||||
|
for(; win; win = win != win.parent && win.parent)
|
||||||
|
win.liberatorFocusAllowed = true;
|
||||||
|
},
|
||||||
|
|
||||||
onPopupShown: function (event) {
|
onPopupShown: function (event) {
|
||||||
if (event.originalTarget.localName == "tooltip" || event.originalTarget.id == "liberator-visualbell")
|
if (event.originalTarget.localName == "tooltip" || event.originalTarget.id == "liberator-visualbell")
|
||||||
return;
|
return;
|
||||||
@@ -1062,22 +1070,36 @@ const Events = Module("events", {
|
|||||||
modes.remove(modes.MENU);
|
modes.remove(modes.MENU);
|
||||||
},
|
},
|
||||||
|
|
||||||
onDOMMenuBarActive: function () {
|
|
||||||
this._activeMenubar = true;
|
|
||||||
modes.add(modes.MENU);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDOMMenuBarInactive: function () {
|
|
||||||
this._activeMenubar = false;
|
|
||||||
modes.remove(modes.MENU);
|
|
||||||
},
|
|
||||||
|
|
||||||
onResize: function (event) {
|
onResize: function (event) {
|
||||||
if (window.fullScreen != this._fullscreen) {
|
if (window.fullScreen != this._fullscreen) {
|
||||||
this._fullscreen = window.fullScreen;
|
this._fullscreen = window.fullScreen;
|
||||||
liberator.triggerObserver("fullscreen", this._fullscreen);
|
liberator.triggerObserver("fullscreen", this._fullscreen);
|
||||||
autocommands.trigger("Fullscreen", { state: this._fullscreen });
|
autocommands.trigger("Fullscreen", { state: this._fullscreen });
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelectionChange: function (event) {
|
||||||
|
let couldCopy = false;
|
||||||
|
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
|
||||||
|
if (controller && controller.isCommandEnabled("cmd_copy"))
|
||||||
|
couldCopy = true;
|
||||||
|
|
||||||
|
if (liberator.mode != modes.VISUAL) {
|
||||||
|
if (couldCopy) {
|
||||||
|
if ((liberator.mode == modes.TEXTAREA ||
|
||||||
|
(modes.extended & modes.TEXTAREA))
|
||||||
|
&& !options["insertmode"])
|
||||||
|
modes.set(modes.VISUAL, modes.TEXTAREA);
|
||||||
|
else if (liberator.mode == modes.CARET)
|
||||||
|
modes.set(modes.VISUAL, modes.CARET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// XXX: disabled, as i think automatically starting visual caret mode does more harm than help
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (!couldCopy && modes.extended & modes.CARET)
|
||||||
|
// liberator.mode = modes.CARET;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
isInputElemFocused: function () {
|
isInputElemFocused: function () {
|
||||||
|
|||||||
@@ -1,465 +1,12 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2008-2010 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
// TODO: proper backwards search - implement our own component?
|
/** @instance rangefinder */
|
||||||
// : implement our own highlighter?
|
|
||||||
// : <ESC> should cancel search highlighting in 'incsearch' mode and jump
|
|
||||||
// back to the presearch page location - can probably use the same
|
|
||||||
// solution as marks
|
|
||||||
// : 'linksearch' searches should highlight link matches only
|
|
||||||
// : changing any search settings should also update the search state including highlighting
|
|
||||||
// : incremental searches shouldn't permanently update search modifiers
|
|
||||||
//
|
|
||||||
// TODO: Clean up this rat's nest. --Kris
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @instance finder
|
|
||||||
*/
|
|
||||||
const Finder = Module("finder", {
|
|
||||||
requires: ["config"],
|
|
||||||
|
|
||||||
init: function () {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
this._found = false; // true if the last search was successful
|
|
||||||
this._backwards = false; // currently searching backwards
|
|
||||||
this._searchString = ""; // current search string (without modifiers)
|
|
||||||
this._searchPattern = ""; // current search string (includes modifiers)
|
|
||||||
this._lastSearchPattern = ""; // the last searched pattern (includes modifiers)
|
|
||||||
this._lastSearchString = ""; // the last searched string (without modifiers)
|
|
||||||
this._lastSearchBackwards = false; // like "backwards", but for the last search, so if you cancel a search with <esc> this is not set
|
|
||||||
this._caseSensitive = false; // search string is case sensitive
|
|
||||||
this._linksOnly = false; // search is limited to link text only
|
|
||||||
|
|
||||||
/* Stolen from toolkit.jar in Firefox, for the time being. The private
|
|
||||||
* methods were unstable, and changed. The new version is not remotely
|
|
||||||
* compatible with what we do.
|
|
||||||
* The following only applies to this object, and may not be
|
|
||||||
* necessary, or accurate, but, just in case:
|
|
||||||
* The Original Code is mozilla.org viewsource frontend.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is
|
|
||||||
* Netscape Communications Corporation.
|
|
||||||
* Portions created by the Initial Developer are Copyright (c) 2003
|
|
||||||
* by the Initial Developer. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Blake Ross <blake@cs.stanford.edu> (Original Author)
|
|
||||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
|
||||||
* Ben Basson <contact@cusser.net>
|
|
||||||
* Jason Barnabe <jason_barnabe@fastmail.fm>
|
|
||||||
* Asaf Romano <mano@mozilla.com>
|
|
||||||
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
|
||||||
* Graeme McCutcheon <graememcc_firefox@graeme-online.co.uk>
|
|
||||||
*/
|
|
||||||
this._highlighter = {
|
|
||||||
|
|
||||||
doc: null,
|
|
||||||
|
|
||||||
spans: [],
|
|
||||||
|
|
||||||
search: function (aWord, matchCase) {
|
|
||||||
var finder = services.create("find");
|
|
||||||
if (matchCase !== undefined)
|
|
||||||
self._caseSensitive = matchCase;
|
|
||||||
|
|
||||||
var range;
|
|
||||||
while ((range = finder.Find(aWord, this.searchRange, this.startPt, this.endPt)))
|
|
||||||
yield range;
|
|
||||||
},
|
|
||||||
|
|
||||||
highlightDoc: function highlightDoc(win, aWord) {
|
|
||||||
this.doc = content.document; // XXX
|
|
||||||
Array.forEach(win.frames, function (frame) this.highlightDoc(frame, aWord), this);
|
|
||||||
|
|
||||||
var doc = win.document;
|
|
||||||
if (!doc || !(doc instanceof HTMLDocument))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!aWord) {
|
|
||||||
let elems = this._highlighter.spans;
|
|
||||||
for (let i = elems.length; --i >= 0;) {
|
|
||||||
let elem = elems[i];
|
|
||||||
let docfrag = doc.createDocumentFragment();
|
|
||||||
let next = elem.nextSibling;
|
|
||||||
let parent = elem.parentNode;
|
|
||||||
|
|
||||||
let child;
|
|
||||||
while ((child = elem.firstChild))
|
|
||||||
docfrag.appendChild(child);
|
|
||||||
|
|
||||||
parent.removeChild(elem);
|
|
||||||
parent.insertBefore(docfrag, next);
|
|
||||||
parent.normalize();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var baseNode = <span highlight="Search"/>;
|
|
||||||
baseNode = util.xmlToDom(baseNode, window.content.document);
|
|
||||||
|
|
||||||
var body = doc.body;
|
|
||||||
var count = body.childNodes.length;
|
|
||||||
this.searchRange = doc.createRange();
|
|
||||||
this.startPt = doc.createRange();
|
|
||||||
this.endPt = doc.createRange();
|
|
||||||
|
|
||||||
this.searchRange.setStart(body, 0);
|
|
||||||
this.searchRange.setEnd(body, count);
|
|
||||||
|
|
||||||
this.startPt.setStart(body, 0);
|
|
||||||
this.startPt.setEnd(body, 0);
|
|
||||||
this.endPt.setStart(body, count);
|
|
||||||
this.endPt.setEnd(body, count);
|
|
||||||
|
|
||||||
liberator.interrupted = false;
|
|
||||||
let n = 0;
|
|
||||||
for (let retRange in this.search(aWord, this._caseSensitive)) {
|
|
||||||
// Highlight
|
|
||||||
var nodeSurround = baseNode.cloneNode(true);
|
|
||||||
var node = this.highlight(retRange, nodeSurround);
|
|
||||||
this.startPt = node.ownerDocument.createRange();
|
|
||||||
this.startPt.setStart(node, node.childNodes.length);
|
|
||||||
this.startPt.setEnd(node, node.childNodes.length);
|
|
||||||
if (n++ % 20 == 0)
|
|
||||||
liberator.threadYield(true);
|
|
||||||
if (liberator.interrupted)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
highlight: function highlight(aRange, aNode) {
|
|
||||||
var startContainer = aRange.startContainer;
|
|
||||||
var startOffset = aRange.startOffset;
|
|
||||||
var endOffset = aRange.endOffset;
|
|
||||||
var docfrag = aRange.extractContents();
|
|
||||||
var before = startContainer.splitText(startOffset);
|
|
||||||
var parent = before.parentNode;
|
|
||||||
aNode.appendChild(docfrag);
|
|
||||||
parent.insertBefore(aNode, before);
|
|
||||||
this.spans.push(aNode);
|
|
||||||
return aNode;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all search highlighting.
|
|
||||||
*/
|
|
||||||
clear: function () {
|
|
||||||
this.spans.forEach(function (span) {
|
|
||||||
if (span.parentNode) {
|
|
||||||
let el = span.firstChild;
|
|
||||||
while (el) {
|
|
||||||
span.removeChild(el);
|
|
||||||
span.parentNode.insertBefore(el, span);
|
|
||||||
el = span.firstChild;
|
|
||||||
}
|
|
||||||
span.parentNode.removeChild(span);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.spans = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
isHighlighted: function (doc) this.doc == doc && this.spans.length > 0
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
// set searchString, searchPattern, caseSensitive, linksOnly
|
|
||||||
_processUserPattern: function (pattern) {
|
|
||||||
//// strip off pattern terminator and offset
|
|
||||||
//if (backwards)
|
|
||||||
// pattern = pattern.replace(/\?.*/, "");
|
|
||||||
//else
|
|
||||||
// pattern = pattern.replace(/\/.*/, "");
|
|
||||||
|
|
||||||
this._searchPattern = pattern;
|
|
||||||
|
|
||||||
// links only search - \l wins if both modifiers specified
|
|
||||||
if (/\\l/.test(pattern))
|
|
||||||
this._linksOnly = true;
|
|
||||||
else if (/\L/.test(pattern))
|
|
||||||
this._linksOnly = false;
|
|
||||||
else if (options["linksearch"])
|
|
||||||
this._linksOnly = true;
|
|
||||||
else
|
|
||||||
this._linksOnly = false;
|
|
||||||
|
|
||||||
// strip links-only modifiers
|
|
||||||
pattern = pattern.replace(/(\\)?\\[lL]/g, function ($0, $1) { return $1 ? $0 : ""; });
|
|
||||||
|
|
||||||
// case sensitivity - \c wins if both modifiers specified
|
|
||||||
if (/\c/.test(pattern))
|
|
||||||
this._caseSensitive = false;
|
|
||||||
else if (/\C/.test(pattern))
|
|
||||||
this._caseSensitive = true;
|
|
||||||
else if (options["ignorecase"] && options["smartcase"] && /[A-Z]/.test(pattern))
|
|
||||||
this._caseSensitive = true;
|
|
||||||
else if (options["ignorecase"])
|
|
||||||
this._caseSensitive = false;
|
|
||||||
else
|
|
||||||
this._caseSensitive = true;
|
|
||||||
|
|
||||||
// strip case-sensitive modifiers
|
|
||||||
pattern = pattern.replace(/(\\)?\\[cC]/g, function ($0, $1) { return $1 ? $0 : ""; });
|
|
||||||
|
|
||||||
// remove any modifier escape \
|
|
||||||
pattern = pattern.replace(/\\(\\[cClL])/g, "$1");
|
|
||||||
|
|
||||||
this._searchString = pattern;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the search dialog is requested.
|
|
||||||
*
|
|
||||||
* @param {number} mode The search mode, either modes.SEARCH_FORWARD or
|
|
||||||
* modes.SEARCH_BACKWARD.
|
|
||||||
* @default modes.SEARCH_FORWARD
|
|
||||||
*/
|
|
||||||
openPrompt: function (mode) {
|
|
||||||
this._backwards = mode == modes.SEARCH_BACKWARD;
|
|
||||||
commandline.open(this._backwards ? "?" : "/", "", mode);
|
|
||||||
// TODO: focus the top of the currently visible screen
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: backwards seems impossible i fear
|
|
||||||
/**
|
|
||||||
* Searches the current buffer for <b>str</b>.
|
|
||||||
*
|
|
||||||
* @param {string} str The string to find.
|
|
||||||
*/
|
|
||||||
find: function (str) {
|
|
||||||
let fastFind = config.browser.fastFind;
|
|
||||||
|
|
||||||
this._processUserPattern(str);
|
|
||||||
fastFind.caseSensitive = this._caseSensitive;
|
|
||||||
this._found = fastFind.find(this._searchString, this._linksOnly) != Ci.nsITypeAheadFind.FIND_NOTFOUND;
|
|
||||||
|
|
||||||
if (!this._found)
|
|
||||||
this.setTimeout(function () liberator.echoerr("E486: Pattern not found: " + this._searchPattern, commandline.FORCE_SINGLELINE), 0);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches the current buffer again for the most recently used search
|
|
||||||
* string.
|
|
||||||
*
|
|
||||||
* @param {boolean} reverse Whether to search forwards or backwards.
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
findAgain: function (reverse) {
|
|
||||||
// This hack is needed to make n/N work with the correct string, if
|
|
||||||
// we typed /foo<esc> after the original search. Since searchString is
|
|
||||||
// readonly we have to call find() again to update it.
|
|
||||||
if (config.browser.fastFind.searchString != this._lastSearchString)
|
|
||||||
this.find(this._lastSearchString);
|
|
||||||
|
|
||||||
let up = reverse ? !this._lastSearchBackwards : this._lastSearchBackwards;
|
|
||||||
let result = config.browser.fastFind.findAgain(up, this._linksOnly);
|
|
||||||
|
|
||||||
if (result == Ci.nsITypeAheadFind.FIND_NOTFOUND)
|
|
||||||
liberator.echoerr("E486: Pattern not found: " + this._lastSearchPattern, commandline.FORCE_SINGLELINE);
|
|
||||||
else if (result == Ci.nsITypeAheadFind.FIND_WRAPPED) {
|
|
||||||
// hack needed, because wrapping causes a "scroll" event which clears
|
|
||||||
// our command line
|
|
||||||
setTimeout(function () {
|
|
||||||
let msg = up ? "search hit TOP, continuing at BOTTOM" : "search hit BOTTOM, continuing at TOP";
|
|
||||||
commandline.echo(msg, commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES | commandline.FORCE_SINGLELINE);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
commandline.echo((up ? "?" : "/") + this._lastSearchPattern, null, commandline.FORCE_SINGLELINE);
|
|
||||||
|
|
||||||
if (options["hlsearch"])
|
|
||||||
this.highlight(this._lastSearchString);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user types a key in the search dialog. Triggers a
|
|
||||||
* search attempt if 'incsearch' is set.
|
|
||||||
*
|
|
||||||
* @param {string} str The search string.
|
|
||||||
*/
|
|
||||||
onKeyPress: function (str) {
|
|
||||||
if (options["incsearch"])
|
|
||||||
this.find(str);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the <Enter> key is pressed to trigger a search.
|
|
||||||
*
|
|
||||||
* @param {string} str The search string.
|
|
||||||
* @param {boolean} forcedBackward Whether to search forwards or
|
|
||||||
* backwards. This overrides the direction set in
|
|
||||||
* (@link #openPrompt).
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
onSubmit: function (str, forcedBackward) {
|
|
||||||
if (typeof forcedBackward === "boolean")
|
|
||||||
this._backwards = forcedBackward;
|
|
||||||
|
|
||||||
if (str)
|
|
||||||
var pattern = str;
|
|
||||||
else {
|
|
||||||
liberator.assert(this._lastSearchPattern, "E35: No previous search pattern");
|
|
||||||
pattern = this._lastSearchPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.clear();
|
|
||||||
|
|
||||||
if (!options["incsearch"] || !str || !this._found) {
|
|
||||||
// prevent any current match from matching again
|
|
||||||
if (!window.content.getSelection().isCollapsed)
|
|
||||||
window.content.getSelection().getRangeAt(0).collapse(this._backwards);
|
|
||||||
|
|
||||||
this.find(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._lastSearchBackwards = this._backwards;
|
|
||||||
//lastSearchPattern = pattern.replace(backwards ? /\?.*/ : /\/.*/, ""); // XXX
|
|
||||||
this._lastSearchPattern = pattern;
|
|
||||||
this._lastSearchString = this._searchString;
|
|
||||||
|
|
||||||
// TODO: move to find() when reverse incremental searching is kludged in
|
|
||||||
// need to find again for reverse searching
|
|
||||||
if (this._backwards)
|
|
||||||
this.setTimeout(function () { this.findAgain(false); }, 0);
|
|
||||||
|
|
||||||
if (options["hlsearch"])
|
|
||||||
this.highlight(this._searchString);
|
|
||||||
|
|
||||||
modes.reset();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the search is canceled. For example, if someone presses
|
|
||||||
* <Esc> while typing a search.
|
|
||||||
*/
|
|
||||||
onCancel: function () {
|
|
||||||
// TODO: code to reposition the document to the place before search started
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Highlights all occurances of <b>str</b> in the buffer.
|
|
||||||
*
|
|
||||||
* @param {string} str The string to highlight.
|
|
||||||
*/
|
|
||||||
highlight: function (str) {
|
|
||||||
// FIXME: Thunderbird incompatible
|
|
||||||
if (config.name == "Muttator")
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._highlighter.isHighlighted(content.document))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!str)
|
|
||||||
str = this._lastSearchString;
|
|
||||||
|
|
||||||
this._highlighter.highlightDoc(window.content, str);
|
|
||||||
|
|
||||||
// recreate selection since highlightDoc collapses the selection
|
|
||||||
if (window.content.getSelection().isCollapsed)
|
|
||||||
config.browser.fastFind.findAgain(this._backwards, this._linksOnly);
|
|
||||||
|
|
||||||
// TODO: remove highlighting from non-link matches (HTML - A/AREA with href attribute; XML - Xlink [type="simple"])
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all search highlighting.
|
|
||||||
*/
|
|
||||||
clear: function () {
|
|
||||||
this._highlighter.clear();
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
}, {
|
|
||||||
commandline: function () {
|
|
||||||
// Event handlers for search - closure is needed
|
|
||||||
commandline.registerCallback("change", modes.SEARCH_FORWARD, this.closure.onKeyPress);
|
|
||||||
commandline.registerCallback("submit", modes.SEARCH_FORWARD, this.closure.onSubmit);
|
|
||||||
commandline.registerCallback("cancel", modes.SEARCH_FORWARD, this.closure.onCancel);
|
|
||||||
// TODO: allow advanced myModes in register/triggerCallback
|
|
||||||
commandline.registerCallback("change", modes.SEARCH_BACKWARD, this.closure.onKeyPress);
|
|
||||||
commandline.registerCallback("submit", modes.SEARCH_BACKWARD, this.closure.onSubmit);
|
|
||||||
commandline.registerCallback("cancel", modes.SEARCH_BACKWARD, this.closure.onCancel);
|
|
||||||
|
|
||||||
},
|
|
||||||
commands: function () {
|
|
||||||
commands.add(["noh[lsearch]"],
|
|
||||||
"Remove the search highlighting",
|
|
||||||
function () { finder.clear(); },
|
|
||||||
{ argCount: "0" });
|
|
||||||
},
|
|
||||||
mappings: function () {
|
|
||||||
var myModes = config.browserModes;
|
|
||||||
myModes = myModes.concat([modes.CARET]);
|
|
||||||
|
|
||||||
mappings.add(myModes,
|
|
||||||
["/"], "Search forward for a pattern",
|
|
||||||
function () { finder.openPrompt(modes.SEARCH_FORWARD); });
|
|
||||||
|
|
||||||
mappings.add(myModes,
|
|
||||||
["?"], "Search backwards for a pattern",
|
|
||||||
function () { finder.openPrompt(modes.SEARCH_BACKWARD); });
|
|
||||||
|
|
||||||
mappings.add(myModes,
|
|
||||||
["n"], "Find next",
|
|
||||||
function () { finder.findAgain(false); });
|
|
||||||
|
|
||||||
mappings.add(myModes,
|
|
||||||
["N"], "Find previous",
|
|
||||||
function () { finder.findAgain(true); });
|
|
||||||
|
|
||||||
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["*"],
|
|
||||||
"Find word under cursor",
|
|
||||||
function () {
|
|
||||||
this._found = false;
|
|
||||||
finder.onSubmit(buffer.getCurrentWord(), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["#"],
|
|
||||||
"Find word under cursor backwards",
|
|
||||||
function () {
|
|
||||||
this._found = false;
|
|
||||||
finder.onSubmit(buffer.getCurrentWord(), true);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
options: function () {
|
|
||||||
options.add(["hlsearch", "hls"],
|
|
||||||
"Highlight previous search pattern matches",
|
|
||||||
"boolean", "false", {
|
|
||||||
setter: function (value) {
|
|
||||||
try {
|
|
||||||
if (value)
|
|
||||||
finder.highlight();
|
|
||||||
else
|
|
||||||
finder.clear();
|
|
||||||
}
|
|
||||||
catch (e) {}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
options.add(["ignorecase", "ic"],
|
|
||||||
"Ignore case in search patterns",
|
|
||||||
"boolean", true);
|
|
||||||
|
|
||||||
options.add(["incsearch", "is"],
|
|
||||||
"Show where the search pattern matches as it is typed",
|
|
||||||
"boolean", true);
|
|
||||||
|
|
||||||
options.add(["linksearch", "lks"],
|
|
||||||
"Limit the search to hyperlink text",
|
|
||||||
"boolean", false);
|
|
||||||
|
|
||||||
options.add(["smartcase", "scs"],
|
|
||||||
"Override the 'ignorecase' option if the pattern contains uppercase characters",
|
|
||||||
"boolean", true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const RangeFinder = Module("rangefinder", {
|
const RangeFinder = Module("rangefinder", {
|
||||||
requires: ["config"],
|
requires: ["config"],
|
||||||
|
|
||||||
@@ -471,6 +18,7 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
let backwards = mode == modes.FIND_BACKWARD;
|
let backwards = mode == modes.FIND_BACKWARD;
|
||||||
commandline.open(backwards ? "?" : "/", "", mode);
|
commandline.open(backwards ? "?" : "/", "", mode);
|
||||||
|
|
||||||
|
this.rangeFind = null;
|
||||||
this.find("", backwards);
|
this.find("", backwards);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -537,6 +85,7 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
|
|
||||||
if (options["hlsearch"])
|
if (options["hlsearch"])
|
||||||
this.highlight();
|
this.highlight();
|
||||||
|
this.rangeFind.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
// Called when the user types a key in the search dialog. Triggers a find attempt if 'incsearch' is set
|
// Called when the user types a key in the search dialog. Triggers a find attempt if 'incsearch' is set
|
||||||
@@ -557,6 +106,7 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
|
|
||||||
if (options["hlsearch"])
|
if (options["hlsearch"])
|
||||||
this.highlight();
|
this.highlight();
|
||||||
|
this.rangeFind.focus();
|
||||||
|
|
||||||
modes.reset();
|
modes.reset();
|
||||||
},
|
},
|
||||||
@@ -603,48 +153,106 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
|
|
||||||
},
|
},
|
||||||
commands: function () {
|
commands: function () {
|
||||||
|
commands.add(["noh[lsearch]"],
|
||||||
|
"Remove the search highlighting",
|
||||||
|
function () { rangefinder.clear(); },
|
||||||
|
{ argCount: "0" });
|
||||||
},
|
},
|
||||||
mappings: function () {
|
mappings: function () {
|
||||||
var myModes = config.browserModes.concat([modes.CARET]);
|
var myModes = config.browserModes.concat([modes.CARET]);
|
||||||
|
|
||||||
mappings.add(myModes,
|
mappings.add(myModes,
|
||||||
["g/"], "Search forward for a pattern",
|
["/"], "Search forward for a pattern",
|
||||||
function () { rangefinder.openPrompt(modes.FIND_FORWARD); });
|
function () { rangefinder.openPrompt(modes.FIND_FORWARD); });
|
||||||
|
|
||||||
mappings.add(myModes,
|
mappings.add(myModes,
|
||||||
["g?"], "Search backwards for a pattern",
|
["?"], "Search backwards for a pattern",
|
||||||
function () { rangefinder.openPrompt(modes.FIND_BACKWARD); });
|
function () { rangefinder.openPrompt(modes.FIND_BACKWARD); });
|
||||||
|
|
||||||
mappings.add(myModes,
|
mappings.add(myModes,
|
||||||
["g."], "Find next",
|
["n"], "Find next",
|
||||||
function () { rangefinder.findAgain(false); });
|
function () { rangefinder.findAgain(false); });
|
||||||
|
|
||||||
mappings.add(myModes,
|
mappings.add(myModes,
|
||||||
["g,"], "Find previous",
|
["N"], "Find previous",
|
||||||
function () { rangefinder.findAgain(true); });
|
function () { rangefinder.findAgain(true); });
|
||||||
|
|
||||||
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["g*"],
|
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["*"],
|
||||||
"Find word under cursor",
|
"Find word under cursor",
|
||||||
function () {
|
function () {
|
||||||
rangefinder._found = false;
|
rangefinder._found = false;
|
||||||
rangefinder.onSubmit(buffer.getCurrentWord(), false);
|
rangefinder.onSubmit(buffer.getCurrentWord(), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["g#"],
|
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["#"],
|
||||||
"Find word under cursor backwards",
|
"Find word under cursor backwards",
|
||||||
function () {
|
function () {
|
||||||
rangefinder._found = false;
|
rangefinder._found = false;
|
||||||
rangefinder.onSubmit(buffer.getCurrentWord(), true);
|
rangefinder.onSubmit(buffer.getCurrentWord(), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
modes: function () {
|
modes: function () {
|
||||||
modes.addMode("FIND_FORWARD", true);
|
modes.addMode("FIND_FORWARD", true);
|
||||||
modes.addMode("FIND_BACKWARD", true);
|
modes.addMode("FIND_BACKWARD", true);
|
||||||
},
|
},
|
||||||
options: function () {
|
options: function () {
|
||||||
|
options.add(["hlsearch", "hls"],
|
||||||
|
"Highlight previous search pattern matches",
|
||||||
|
"boolean", "false", {
|
||||||
|
setter: function (value) {
|
||||||
|
try {
|
||||||
|
if (value)
|
||||||
|
rangefinder.highlight();
|
||||||
|
else
|
||||||
|
rangefinder.clear();
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.add(["ignorecase", "ic"],
|
||||||
|
"Ignore case in search patterns",
|
||||||
|
"boolean", true);
|
||||||
|
|
||||||
|
options.add(["incsearch", "is"],
|
||||||
|
"Show where the search pattern matches as it is typed",
|
||||||
|
"boolean", true);
|
||||||
|
|
||||||
|
options.add(["linksearch", "lks"],
|
||||||
|
"Limit the search to hyperlink text",
|
||||||
|
"boolean", false);
|
||||||
|
|
||||||
|
options.add(["smartcase", "scs"],
|
||||||
|
"Override the 'ignorecase' option if the pattern contains uppercase characters",
|
||||||
|
"boolean", true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class RangeFind
|
||||||
|
*
|
||||||
|
* A fairly sophisticated typeahead-find replacement. It supports
|
||||||
|
* incremental search very much as the builtin component.
|
||||||
|
* Additionally, it supports several features impossible to
|
||||||
|
* implement using the standard component. Incremental searching
|
||||||
|
* works both forwards and backwards. Erasing characters during an
|
||||||
|
* incremental search moves the selection back to the first
|
||||||
|
* available match for the shorter term. The selection and viewport
|
||||||
|
* are restored when the search is canceled.
|
||||||
|
*
|
||||||
|
* Also, in addition to full support for frames and iframes, this
|
||||||
|
* implementation will begin searching from the position of the
|
||||||
|
* caret in the last active frame. This is contrary to the behavior
|
||||||
|
* of the builtin component, which always starts a search from the
|
||||||
|
* begining of the first frame in the case of frameset documents,
|
||||||
|
* and cycles through all frames from begining to end. This makes it
|
||||||
|
* impossible to choose the starting point of a search for such
|
||||||
|
* documents, and represents a major detriment to productivity where
|
||||||
|
* large amounts of data are concerned (e.g., for API documents).
|
||||||
|
*/
|
||||||
const RangeFind = Class("RangeFind", {
|
const RangeFind = Class("RangeFind", {
|
||||||
init: function (matchCase, backward, elementPath) {
|
init: function (matchCase, backward, elementPath) {
|
||||||
this.window = Cu.getWeakReference(window);
|
this.window = Cu.getWeakReference(window);
|
||||||
@@ -655,20 +263,28 @@ const RangeFind = Class("RangeFind", {
|
|||||||
this.finder.caseSensitive = this.matchCase;
|
this.finder.caseSensitive = this.matchCase;
|
||||||
|
|
||||||
this.ranges = this.makeFrameList(content);
|
this.ranges = this.makeFrameList(content);
|
||||||
this.range = RangeFind.Range(tabs.localStore.focusedFrame || content);
|
|
||||||
|
|
||||||
this.startRange = (this.range.selection.rangeCount ? this.range.selection.getRangeAt(0) : this.ranges[0].range).cloneRange();
|
this.reset();
|
||||||
this.startRange.collapse(!backward);
|
|
||||||
this.range = this.findRange(this.startRange);
|
|
||||||
this.ranges.first = this.range;
|
|
||||||
|
|
||||||
this.highlighted = null;
|
this.highlighted = null;
|
||||||
this.lastString = "";
|
this.lastString = "";
|
||||||
this.lastRange = null;
|
|
||||||
this.forward = null;
|
this.forward = null;
|
||||||
this.found = false;
|
this.found = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get selectedRange() {
|
||||||
|
let range = RangeFind.Range(tabs.localStore.focusedFrame || content);
|
||||||
|
return (range.selection.rangeCount ? range.selection.getRangeAt(0) : this.ranges[0].range).cloneRange();
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function () {
|
||||||
|
this.startRange = this.selectedRange;
|
||||||
|
this.startRange.collapse(!this.reverse);
|
||||||
|
this.lastRange = this.selectedRange;
|
||||||
|
this.range = this.findRange(this.startRange);
|
||||||
|
this.ranges.first = this.range;
|
||||||
|
},
|
||||||
|
|
||||||
sameDocument: function (r1, r2) r1 && r2 && r1.endContainer.ownerDocument == r2.endContainer.ownerDocument,
|
sameDocument: function (r1, r2) r1 && r2 && r1.endContainer.ownerDocument == r2.endContainer.ownerDocument,
|
||||||
|
|
||||||
compareRanges: function (r1, r2)
|
compareRanges: function (r1, r2)
|
||||||
@@ -699,6 +315,16 @@ const RangeFind = Class("RangeFind", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
focus: function() {
|
||||||
|
if(this.lastRange)
|
||||||
|
var node = util.evaluateXPath(RangeFind.selectNodePath, this.range.document,
|
||||||
|
this.lastRange.commonAncestorContainer).snapshotItem(0);
|
||||||
|
if(node) {
|
||||||
|
node.focus();
|
||||||
|
this.search(null, false); // Rehighlight collapsed range
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
makeFrameList: function (win) {
|
makeFrameList: function (win) {
|
||||||
const self = this;
|
const self = this;
|
||||||
win = win.top;
|
win = win.top;
|
||||||
@@ -706,15 +332,21 @@ const RangeFind = Class("RangeFind", {
|
|||||||
let backup = null;
|
let backup = null;
|
||||||
|
|
||||||
function pushRange(start, end) {
|
function pushRange(start, end) {
|
||||||
|
function push(r) {
|
||||||
|
r = RangeFind.Range(r, frames.length);
|
||||||
|
if (r)
|
||||||
|
frames.push(r);
|
||||||
|
}
|
||||||
|
|
||||||
let range = start.startContainer.ownerDocument.createRange();
|
let range = start.startContainer.ownerDocument.createRange();
|
||||||
range.setStart(start.startContainer, start.startOffset);
|
range.setStart(start.startContainer, start.startOffset);
|
||||||
range.setEnd(end.startContainer, end.startOffset);
|
range.setEnd(end.startContainer, end.startOffset);
|
||||||
|
|
||||||
if (!self.elementPath)
|
if (!self.elementPath)
|
||||||
frames.push(RangeFind.Range(range, frames.length));
|
push(range);
|
||||||
else
|
else
|
||||||
for (let r in self.findSubRanges(range))
|
for (let r in self.findSubRanges(range))
|
||||||
frames.push(RangeFind.Range(r, frames.length));
|
push(r);
|
||||||
}
|
}
|
||||||
function rec(win) {
|
function rec(win) {
|
||||||
let doc = win.document;
|
let doc = win.document;
|
||||||
@@ -741,8 +373,8 @@ const RangeFind = Class("RangeFind", {
|
|||||||
|
|
||||||
// This doesn't work yet.
|
// This doesn't work yet.
|
||||||
resetCaret: function () {
|
resetCaret: function () {
|
||||||
let equal = function (r1, r2) !r1.compareBoundaryPoints(Range.START_TO_START, r2) && !r1.compareBoundaryPoints(Range.END_TO_END, r2);
|
let equal = RangeFind.equal;
|
||||||
letselection = this.win.getSelection();
|
let selection = this.win.getSelection();
|
||||||
if (selection.rangeCount == 0)
|
if (selection.rangeCount == 0)
|
||||||
selection.addRange(this.pageStart);
|
selection.addRange(this.pageStart);
|
||||||
function getLines() {
|
function getLines() {
|
||||||
@@ -792,6 +424,9 @@ const RangeFind = Class("RangeFind", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
search: function (word, reverse, private_) {
|
search: function (word, reverse, private_) {
|
||||||
|
if (!private_ && this.lastRange && !RangeFind.equal(this.selectedRange, this.lastRange))
|
||||||
|
this.reset();
|
||||||
|
|
||||||
this.wrapped = false;
|
this.wrapped = false;
|
||||||
this.finder.findBackwards = reverse ? !this.reverse : this.reverse;
|
this.finder.findBackwards = reverse ? !this.reverse : this.reverse;
|
||||||
let again = word == null;
|
let again = word == null;
|
||||||
@@ -886,6 +521,7 @@ const RangeFind = Class("RangeFind", {
|
|||||||
parent.insertBefore(node, before);
|
parent.insertBefore(node, before);
|
||||||
range.selectNode(node);
|
range.selectNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unhighlight(range) {
|
function unhighlight(range) {
|
||||||
let elem = range.startContainer;
|
let elem = range.startContainer;
|
||||||
while (!(elem instanceof Element) && elem.parentNode)
|
while (!(elem instanceof Element) && elem.parentNode)
|
||||||
@@ -913,7 +549,7 @@ const RangeFind = Class("RangeFind", {
|
|||||||
else {
|
else {
|
||||||
this.highlighted = this.lastString;
|
this.highlighted = this.lastString;
|
||||||
this.addListeners();
|
this.addListeners();
|
||||||
this.search(null, false);
|
this.search(null, false); // Rehighlight collapsed range
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -952,6 +588,9 @@ const RangeFind = Class("RangeFind", {
|
|||||||
this.window = this.document.defaultView;
|
this.window = this.document.defaultView;
|
||||||
this.range = range;
|
this.range = range;
|
||||||
|
|
||||||
|
if (this.selection == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -989,12 +628,27 @@ const RangeFind = Class("RangeFind", {
|
|||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsISelectionDisplay)
|
.getInterface(Ci.nsISelectionDisplay)
|
||||||
.QueryInterface(Ci.nsISelectionController),
|
.QueryInterface(Ci.nsISelectionController),
|
||||||
get selection() this.selectionController.getSelection(Ci.nsISelectionController.SELECTION_NORMAL)
|
get selection() {
|
||||||
|
try {
|
||||||
|
return this.selectionController.getSelection(Ci.nsISelectionController.SELECTION_NORMAL)
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
|
||||||
}),
|
}),
|
||||||
|
selectNodePath: ["ancestor-or-self::" + s for ([i, s] in Iterator(
|
||||||
|
["a", "xhtml:a", "*[@onclick]"]))].join(" | "),
|
||||||
endpoint: function (range, before) {
|
endpoint: function (range, before) {
|
||||||
range = range.cloneRange();
|
range = range.cloneRange();
|
||||||
range.collapse(before);
|
range.collapse(before);
|
||||||
return range;
|
return range;
|
||||||
|
},
|
||||||
|
equal: function (r1, r2) {
|
||||||
|
try {
|
||||||
|
return !r1.compareBoundaryPoints(Range.START_TO_START, r2) && !r1.compareBoundaryPoints(Range.END_TO_END, r2)
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
function checkFragment() {
|
function checkFragment() {
|
||||||
document.title = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "title")[0].textContent;
|
document.title = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "title")[0].textContent;
|
||||||
|
|||||||
@@ -202,7 +202,7 @@
|
|||||||
<xsl:variable name="type" select="preceding-sibling::liberator:type[1] | following-sibling::liberator:type[1]"/>
|
<xsl:variable name="type" select="preceding-sibling::liberator:type[1] | following-sibling::liberator:type[1]"/>
|
||||||
<span liberator:highlight="HelpDefault">(default:<xsl:text> </xsl:text>
|
<span liberator:highlight="HelpDefault">(default:<xsl:text> </xsl:text>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test="starts-with($type, 'string')">
|
<xsl:when test="starts-with($type, 'string') or starts-with($type, 'regex')">
|
||||||
<span liberator:highlight="HelpString"><xsl:apply-templates/></span>
|
<span liberator:highlight="HelpString"><xsl:apply-templates/></span>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
@@ -351,9 +351,13 @@
|
|||||||
|
|
||||||
<xsl:template match="liberator:ex" mode="pass-2">
|
<xsl:template match="liberator:ex" mode="pass-2">
|
||||||
<span liberator:highlight="HelpEx">
|
<span liberator:highlight="HelpEx">
|
||||||
<xsl:call-template name="linkify-tag">
|
<xsl:variable name="tag" select="str:tokenize(text(), ' [!')[1]"/>
|
||||||
<xsl:with-param name="contents" select="."/>
|
<a href="liberator://help-tag/{$tag}" style="color: inherit;">
|
||||||
</xsl:call-template>
|
<xsl:if test="contains($tags, concat(' ', $tag, ' '))">
|
||||||
|
<xsl:attribute name="href">#<xsl:value-of select="$tag"/></xsl:attribute>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:apply-templates/>
|
||||||
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
/** @instance hints */
|
/** @instance hints */
|
||||||
@@ -40,12 +42,12 @@ const Hints = Module("hints", {
|
|||||||
"?": Mode("Show information for hint", function (elem) buffer.showElementInfo(elem), extended),
|
"?": Mode("Show information for hint", function (elem) buffer.showElementInfo(elem), extended),
|
||||||
s: Mode("Save hint", function (elem) buffer.saveLink(elem, true)),
|
s: Mode("Save hint", function (elem) buffer.saveLink(elem, true)),
|
||||||
a: Mode("Save hint with prompt", function (elem) buffer.saveLink(elem, false)),
|
a: Mode("Save hint with prompt", function (elem) buffer.saveLink(elem, false)),
|
||||||
f: Mode("Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () util.makeXPath(["body"])),
|
f: Mode("Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () ["body"]),
|
||||||
o: Mode("Follow hint", function (elem) buffer.followLink(elem, liberator.CURRENT_TAB)),
|
o: Mode("Follow hint", function (elem) buffer.followLink(elem, liberator.CURRENT_TAB)),
|
||||||
t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, liberator.NEW_TAB)),
|
t: Mode("Follow hint in a new tab", function (elem) buffer.followLink(elem, liberator.NEW_TAB)),
|
||||||
b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB)),
|
b: Mode("Follow hint in a background tab", function (elem) buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB)),
|
||||||
w: Mode("Follow hint in a new window", function (elem) buffer.followLink(elem, liberator.NEW_WINDOW), extended),
|
w: Mode("Follow hint in a new window", function (elem) buffer.followLink(elem, liberator.NEW_WINDOW), extended),
|
||||||
F: Mode("Open multiple hints in tabs", followAndReshow),
|
F: Mode("Open multiple hints in tabs", function (elem) { buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB); hints.show("F") }),
|
||||||
O: Mode("Generate an ':open URL' using hint", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)),
|
O: Mode("Generate an ':open URL' using hint", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)),
|
||||||
T: Mode("Generate a ':tabopen URL' using hint", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)),
|
T: Mode("Generate a ':tabopen URL' using hint", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)),
|
||||||
W: Mode("Generate a ':winopen URL' using hint", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)),
|
W: Mode("Generate a ':winopen URL' using hint", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)),
|
||||||
@@ -57,21 +59,6 @@ const Hints = Module("hints", {
|
|||||||
i: Mode("Show image", function (elem) liberator.open(elem.src), images),
|
i: Mode("Show image", function (elem) liberator.open(elem.src), images),
|
||||||
I: Mode("Show image in a new tab", function (elem) liberator.open(elem.src, liberator.NEW_TAB), images)
|
I: Mode("Show image in a new tab", function (elem) liberator.open(elem.src, liberator.NEW_TAB), images)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Follows the specified hint and then reshows all hints. Used to open
|
|
||||||
* multiple hints in succession.
|
|
||||||
*
|
|
||||||
* @param {Node} elem The selected hint.
|
|
||||||
*/
|
|
||||||
function followAndReshow(elem) {
|
|
||||||
buffer.followLink(elem, liberator.NEW_BACKGROUND_TAB);
|
|
||||||
|
|
||||||
// TODO: Maybe we find a *simple* way to keep the hints displayed rather than
|
|
||||||
// showing them again, or is this short flash actually needed as a "usability
|
|
||||||
// feature"? --mst
|
|
||||||
hints.show("F");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,7 +114,7 @@ const Hints = Module("hints", {
|
|||||||
|
|
||||||
let type = elem.type;
|
let type = elem.type;
|
||||||
|
|
||||||
if (elem instanceof HTMLInputElement && /(submit|button|this._reset)/.test(type))
|
if (elem instanceof HTMLInputElement && /(submit|button|reset)/.test(type))
|
||||||
return [elem.value, false];
|
return [elem.value, false];
|
||||||
else {
|
else {
|
||||||
for (let [, option] in Iterator(options["hintinputs"].split(","))) {
|
for (let [, option] in Iterator(options["hintinputs"].split(","))) {
|
||||||
@@ -266,14 +253,10 @@ const Hints = Module("hints", {
|
|||||||
let hint = { elem: elem, showText: false };
|
let hint = { elem: elem, showText: false };
|
||||||
|
|
||||||
// TODO: for iframes, this calculation is wrong
|
// TODO: for iframes, this calculation is wrong
|
||||||
rect = elem.getBoundingClientRect();
|
let rect = elem.getBoundingClientRect();
|
||||||
if (!rect || rect.top > height || rect.bottom < 0 || rect.left > width || rect.right < 0)
|
if (!rect || rect.top > height || rect.bottom < 0 || rect.left > width || rect.right < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rect = elem.getClientRects()[0];
|
|
||||||
if (!rect)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let computedStyle = doc.defaultView.getComputedStyle(elem, null);
|
let computedStyle = doc.defaultView.getComputedStyle(elem, null);
|
||||||
if (computedStyle.getPropertyValue("visibility") != "visible" || computedStyle.getPropertyValue("display") == "none")
|
if (computedStyle.getPropertyValue("visibility") != "visible" || computedStyle.getPropertyValue("display") == "none")
|
||||||
continue;
|
continue;
|
||||||
@@ -370,7 +353,7 @@ const Hints = Module("hints", {
|
|||||||
|
|
||||||
if (hint.text == "" && hint.elem.firstChild && hint.elem.firstChild instanceof HTMLImageElement) {
|
if (hint.text == "" && hint.elem.firstChild && hint.elem.firstChild instanceof HTMLImageElement) {
|
||||||
if (!hint.imgSpan) {
|
if (!hint.imgSpan) {
|
||||||
rect = hint.elem.firstChild.getBoundingClientRect();
|
var rect = hint.elem.firstChild.getBoundingClientRect();
|
||||||
if (!rect)
|
if (!rect)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -394,11 +377,11 @@ const Hints = Module("hints", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.browser.markupDocumentViewer.authorStyleDisabled) {
|
if (options["usermode"]) {
|
||||||
let css = [];
|
let css = [];
|
||||||
// FIXME: Broken for imgspans.
|
// FIXME: Broken for imgspans.
|
||||||
for (let [, { doc: doc }] in Iterator(this._docs)) {
|
for (let [, { doc: doc }] in Iterator(this._docs)) {
|
||||||
for (let elem in util.evaluateXPath(" {//*[@liberator:highlight and @number]", doc)) {
|
for (let elem in util.evaluateXPath("//*[@liberator:highlight and @number]", doc)) {
|
||||||
let group = elem.getAttributeNS(NS.uri, "highlight");
|
let group = elem.getAttributeNS(NS.uri, "highlight");
|
||||||
css.push(highlight.selector(group) + "[number=" + elem.getAttribute("number").quote() + "] { " + elem.style.cssText + " }");
|
css.push(highlight.selector(group) + "[number=" + elem.getAttribute("number").quote() + "] { " + elem.style.cssText + " }");
|
||||||
}
|
}
|
||||||
@@ -1058,8 +1041,8 @@ const Hints = Module("hints", {
|
|||||||
},
|
},
|
||||||
options: function () {
|
options: function () {
|
||||||
const DEFAULT_HINTTAGS =
|
const DEFAULT_HINTTAGS =
|
||||||
util.makeXPath(["input[not(@type='hidden')]", "a", "area", "iframe", "textarea", "button", "select"])
|
util.makeXPath(["input[not(@type='hidden')]", "a", "area", "iframe", "textarea", "button", "select",
|
||||||
+ " | //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @role='link']";
|
"*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @role='link']"]);
|
||||||
|
|
||||||
function checkXPath(val) {
|
function checkXPath(val) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const History = Module("history", {
|
const History = Module("history", {
|
||||||
requires: ["config"],
|
requires: ["config"],
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
// Some code based on Venkman
|
// Some code based on Venkman
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ const File = Class("File", {
|
|||||||
mode = File.MODE_WRONLY | File.MODE_CREATE | File.MODE_TRUNCATE;
|
mode = File.MODE_WRONLY | File.MODE_CREATE | File.MODE_TRUNCATE;
|
||||||
|
|
||||||
if (!perms)
|
if (!perms)
|
||||||
perms = 0644;
|
perms = parseInt('0644', 8);
|
||||||
|
|
||||||
ofstream.init(this, mode, perms, 0);
|
ofstream.init(this, mode, perms, 0);
|
||||||
let ocstream = getStream(0);
|
let ocstream = getStream(0);
|
||||||
@@ -240,7 +242,7 @@ const File = Class("File", {
|
|||||||
*/
|
*/
|
||||||
MODE_EXCL: 0x80,
|
MODE_EXCL: 0x80,
|
||||||
|
|
||||||
expandPathList: function (list) list.split(",").map(this.expandPath).join(","),
|
expandPathList: function (list) list.map(this.expandPath),
|
||||||
|
|
||||||
expandPath: function (path, relative) {
|
expandPath: function (path, relative) {
|
||||||
|
|
||||||
@@ -338,7 +340,7 @@ const IO = Module("io", {
|
|||||||
let file = download.targetFile.path;
|
let file = download.targetFile.path;
|
||||||
let size = download.size;
|
let size = download.size;
|
||||||
|
|
||||||
liberator.echomsg("Download of " + title + " to " + file + " finished", 1);
|
liberator.echomsg("Download of " + title + " to " + file + " finished", 1, commandline.ACTIVE_WINDOW);
|
||||||
autocommands.trigger("DownloadPost", { url: url, title: title, file: file, size: size });
|
autocommands.trigger("DownloadPost", { url: url, title: title, file: file, size: size });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -485,7 +487,7 @@ const IO = Module("io", {
|
|||||||
let file = services.get("directory").get("TmpD", Ci.nsIFile);
|
let file = services.get("directory").get("TmpD", Ci.nsIFile);
|
||||||
|
|
||||||
file.append(config.tempFile);
|
file.append(config.tempFile);
|
||||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
|
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt('0600', 8));
|
||||||
|
|
||||||
return File(file);
|
return File(file);
|
||||||
},
|
},
|
||||||
@@ -595,6 +597,8 @@ lookup:
|
|||||||
*/
|
*/
|
||||||
source: function (filename, silent) {
|
source: function (filename, silent) {
|
||||||
let wasSourcing = this.sourcing;
|
let wasSourcing = this.sourcing;
|
||||||
|
liberator.dump("sourcing " + filename);
|
||||||
|
let time = Date.now();
|
||||||
try {
|
try {
|
||||||
var file = File(filename);
|
var file = File(filename);
|
||||||
this.sourcing = {
|
this.sourcing = {
|
||||||
@@ -624,8 +628,7 @@ lookup:
|
|||||||
if (/\.js$/.test(filename)) {
|
if (/\.js$/.test(filename)) {
|
||||||
try {
|
try {
|
||||||
liberator.loadScript(uri.spec, Script(file));
|
liberator.loadScript(uri.spec, Script(file));
|
||||||
if (liberator.initialized)
|
liberator.helpInitialized = false;
|
||||||
liberator.initHelp();
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
let err = new Error();
|
let err = new Error();
|
||||||
@@ -713,6 +716,7 @@ lookup:
|
|||||||
liberator.echoerr(message);
|
liberator.echoerr(message);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
liberator.dump("done sourcing " + filename + ": " + (Date.now() - time) + "ms");
|
||||||
this.sourcing = wasSourcing;
|
this.sourcing = wasSourcing;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1028,8 +1032,8 @@ lookup:
|
|||||||
b.isdir - a.isdir || String.localeCompare(a.text, b.text);
|
b.isdir - a.isdir || String.localeCompare(a.text, b.text);
|
||||||
|
|
||||||
if (options["wildignore"]) {
|
if (options["wildignore"]) {
|
||||||
let wigRegexp = RegExp("(^" + options.get("wildignore").values.join("|") + ")$");
|
let wig = options.get("wildignore");
|
||||||
context.filters.push(function ({item: f}) f.isDirectory() || !wigRegexp.test(f.leafName));
|
context.filters.push(function ({item: f}) f.isDirectory() || !wig.getKey(this.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// context.background = true;
|
// context.background = true;
|
||||||
@@ -1061,7 +1065,10 @@ lookup:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
completion.addUrlCompleter("f", "Local files", completion.file);
|
completion.addUrlCompleter("f", "Local files", function (context, full) {
|
||||||
|
if (!/^\.?\//.test(context.filter))
|
||||||
|
completion.file(context, full);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
options: function () {
|
options: function () {
|
||||||
var shell, shellcmdflag;
|
var shell, shellcmdflag;
|
||||||
@@ -1099,6 +1106,10 @@ lookup:
|
|||||||
options.add(["shellcmdflag", "shcf"],
|
options.add(["shellcmdflag", "shcf"],
|
||||||
"Flag passed to shell when executing :! and :run commands",
|
"Flag passed to shell when executing :! and :run commands",
|
||||||
"string", shellcmdflag);
|
"string", shellcmdflag);
|
||||||
|
|
||||||
|
options.add(["wildignore", "wig"],
|
||||||
|
"List of file patterns to ignore when completing files",
|
||||||
|
"regexlist", "");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
// TODO: Clean this up.
|
// TODO: Clean this up.
|
||||||
|
|
||||||
@@ -33,17 +34,18 @@ const JavaScript = Module("javascript", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
iter: function iter(obj, toplevel) {
|
iter: function iter(obj, toplevel) {
|
||||||
|
"use strict";
|
||||||
toplevel = !!toplevel;
|
toplevel = !!toplevel;
|
||||||
let seen = {};
|
let seen = {};
|
||||||
let ret = {};
|
let ret = {};
|
||||||
|
|
||||||
try {
|
if(obj == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(options["jsdebugger"]) {
|
||||||
let orig = obj;
|
let orig = obj;
|
||||||
let top = services.get("debugger").wrapValue(obj);
|
let top = services.get("debugger").wrapValue(obj);
|
||||||
|
|
||||||
if (!toplevel)
|
|
||||||
obj = obj.__proto__;
|
|
||||||
|
|
||||||
for (; obj; obj = !toplevel && obj.__proto__) {
|
for (; obj; obj = !toplevel && obj.__proto__) {
|
||||||
services.get("debugger").wrapValue(obj).getProperties(ret, {});
|
services.get("debugger").wrapValue(obj).getProperties(ret, {});
|
||||||
for (let prop in values(ret.value)) {
|
for (let prop in values(ret.value)) {
|
||||||
@@ -51,18 +53,27 @@ const JavaScript = Module("javascript", {
|
|||||||
if (name in seen)
|
if (name in seen)
|
||||||
continue;
|
continue;
|
||||||
seen[name] = 1;
|
seen[name] = 1;
|
||||||
yield [prop.name.stringValue, top.getProperty(prop.name.stringValue).value.getWrappedValue()]
|
if (toplevel || obj !== orig)
|
||||||
|
yield [prop.name.stringValue, top.getProperty(prop.name.stringValue).value.getWrappedValue()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The debugger doesn't list some properties. I can't guess why.
|
// The debugger doesn't list some properties. I can't guess why.
|
||||||
for (let k in orig)
|
// This only lists ENUMERABLE properties.
|
||||||
if (k in orig && !('|' + k in seen) && obj.hasOwnProperty(k) == toplevel)
|
try {
|
||||||
yield [k, this.getKey(orig, k)]
|
for (let k in orig)
|
||||||
|
if (k in orig && !('|' + k in seen)
|
||||||
|
&& Object.hasOwnProperty(orig, k) == toplevel)
|
||||||
|
yield [k, this.getKey(orig, k)]
|
||||||
|
}
|
||||||
|
catch(e) {}
|
||||||
}
|
}
|
||||||
catch(e) {
|
else {
|
||||||
for (k in allkeys(obj))
|
for (let k in allkeys(obj))
|
||||||
if (obj.hasOwnProperty(k) == toplevel)
|
try {
|
||||||
yield [k, this.getKey(obj, k)];
|
if (Object.hasOwnProperty(obj, k) == toplevel)
|
||||||
|
yield [k, this.getKey(obj, k)];
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -101,7 +112,7 @@ const JavaScript = Module("javascript", {
|
|||||||
return completions;
|
return completions;
|
||||||
},
|
},
|
||||||
|
|
||||||
eval: function eval(arg, key, tmp) {
|
eval: function evalstr(arg, key, tmp) {
|
||||||
let cache = this.context.cache.eval;
|
let cache = this.context.cache.eval;
|
||||||
let context = this.context.cache.evalContext;
|
let context = this.context.cache.evalContext;
|
||||||
|
|
||||||
@@ -230,8 +241,6 @@ const JavaScript = Module("javascript", {
|
|||||||
case "'":
|
case "'":
|
||||||
case "/":
|
case "/":
|
||||||
case "{":
|
case "{":
|
||||||
this._push(this._c);
|
|
||||||
break;
|
|
||||||
case "[":
|
case "[":
|
||||||
this._push(this._c);
|
this._push(this._c);
|
||||||
break;
|
break;
|
||||||
@@ -341,6 +350,10 @@ const JavaScript = Module("javascript", {
|
|||||||
|
|
||||||
_complete: function (objects, key, compl, string, last) {
|
_complete: function (objects, key, compl, string, last) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
|
if(!options["jsdebugger"] && !this.context.message)
|
||||||
|
this.context.message = "For better completion data, please enable the JavaScript debugger (:set jsdebugger)";
|
||||||
|
|
||||||
let orig = compl;
|
let orig = compl;
|
||||||
if (!compl) {
|
if (!compl) {
|
||||||
compl = function (context, obj, recurse) {
|
compl = function (context, obj, recurse) {
|
||||||
@@ -427,7 +440,8 @@ const JavaScript = Module("javascript", {
|
|||||||
// Okay, have parse stack. Figure out what we're completing.
|
// Okay, have parse stack. Figure out what we're completing.
|
||||||
|
|
||||||
// Find any complete statements that we can eval before we eval our object.
|
// Find any complete statements that we can eval before we eval our object.
|
||||||
// This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab>
|
// This allows for things like:
|
||||||
|
// let doc = window.content.document; let elem = doc.createEle<Tab> ...
|
||||||
let prev = 0;
|
let prev = 0;
|
||||||
for (let [, v] in Iterator(this._get(0).fullStatements)) {
|
for (let [, v] in Iterator(this._get(0).fullStatements)) {
|
||||||
let key = this._str.substring(prev, v + 1);
|
let key = this._str.substring(prev, v + 1);
|
||||||
@@ -437,14 +451,13 @@ const JavaScript = Module("javascript", {
|
|||||||
prev = v + 1;
|
prev = v + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In a string. Check if we're dereferencing an object.
|
// In a string. Check if we're dereferencing an object or
|
||||||
// Otherwise, do nothing.
|
// completing a function argument. Otherwise, do nothing.
|
||||||
if (this._last == "'" || this._last == '"') {
|
if (this._last == "'" || this._last == '"') {
|
||||||
//
|
|
||||||
// str = "foo[bar + 'baz"
|
// str = "foo[bar + 'baz"
|
||||||
// obj = "foo"
|
// obj = "foo"
|
||||||
// key = "bar + ''"
|
// key = "bar + ''"
|
||||||
//
|
|
||||||
|
|
||||||
// The top of the stack is the sting we're completing.
|
// The top of the stack is the sting we're completing.
|
||||||
// Wrap it in its delimiters and eval it to process escape sequences.
|
// Wrap it in its delimiters and eval it to process escape sequences.
|
||||||
@@ -497,15 +510,15 @@ const JavaScript = Module("javascript", {
|
|||||||
// Split up the arguments
|
// Split up the arguments
|
||||||
let prev = this._get(-2).offset;
|
let prev = this._get(-2).offset;
|
||||||
let args = [];
|
let args = [];
|
||||||
for (let [, idx] in Iterator(this._get(-2).comma)) {
|
for (let [i, idx] in Iterator(this._get(-2).comma)) {
|
||||||
let arg = this._str.substring(prev + 1, idx);
|
let arg = this._str.substring(prev + 1, idx);
|
||||||
prev = idx;
|
prev = idx;
|
||||||
util.memoize(args, this._i, function () self.eval(arg));
|
util.memoize(args, i, function () self.eval(arg));
|
||||||
}
|
}
|
||||||
let key = this._getKey();
|
let key = this._getKey();
|
||||||
args.push(key + string);
|
args.push(key + string);
|
||||||
|
|
||||||
compl = function (context, obj) {
|
let compl = function (context, obj) {
|
||||||
let res = completer.call(self, context, func, obj, args);
|
let res = completer.call(self, context, func, obj, args);
|
||||||
if (res)
|
if (res)
|
||||||
context.completions = res;
|
context.completions = res;
|
||||||
@@ -520,7 +533,7 @@ const JavaScript = Module("javascript", {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// str = "foo.bar.baz"
|
// str = "foo.bar.baz"
|
||||||
// obj = "foo.bar"
|
// obj = "foo.bar"
|
||||||
// key = "baz"
|
// key = "baz"
|
||||||
@@ -528,11 +541,11 @@ const JavaScript = Module("javascript", {
|
|||||||
// str = "foo"
|
// str = "foo"
|
||||||
// obj = [modules, window]
|
// obj = [modules, window]
|
||||||
// key = "foo"
|
// key = "foo"
|
||||||
//
|
|
||||||
|
|
||||||
let [offset, obj, key] = this._getObjKey(-1);
|
let [offset, obj, key] = this._getObjKey(-1);
|
||||||
|
|
||||||
// Wait for a keypress before completing the default objects.
|
// Wait for a keypress before completing when there's no key
|
||||||
if (!this.context.tabPressed && key == "" && obj.length > 1) {
|
if (!this.context.tabPressed && key == "" && obj.length > 1) {
|
||||||
this.context.waitingForTab = true;
|
this.context.waitingForTab = true;
|
||||||
this.context.message = "Waiting for key press";
|
this.context.message = "Waiting for key press";
|
||||||
@@ -589,7 +602,7 @@ const JavaScript = Module("javascript", {
|
|||||||
let completer = completers[args.length - 1];
|
let completer = completers[args.length - 1];
|
||||||
if (!completer)
|
if (!completer)
|
||||||
return [];
|
return [];
|
||||||
return completer.call(this, context, obj, args);
|
return completer.call(obj, context, obj, args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// Copyright (c) 2008-2009 Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2008 Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
const modules = {};
|
const modules = {};
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -134,7 +136,7 @@ const Liberator = Module("liberator", {
|
|||||||
forceNewWindow: false,
|
forceNewWindow: false,
|
||||||
|
|
||||||
/** @property {string} The Liberator version string. */
|
/** @property {string} The Liberator version string. */
|
||||||
version: "###VERSION### (created: ###DATE###)", // these VERSION and DATE tokens are replaced by the Makefile
|
version: "@VERSION@ (created: @DATE@)", // these VERSION and DATE tokens are replaced by the Makefile
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {Object} The map of command-line options. These are
|
* @property {Object} The map of command-line options. These are
|
||||||
@@ -268,7 +270,7 @@ const Liberator = Module("liberator", {
|
|||||||
let stack = Error().stack.replace(/(?:.*\n){2}/, "");
|
let stack = Error().stack.replace(/(?:.*\n){2}/, "");
|
||||||
if (frames != null)
|
if (frames != null)
|
||||||
[stack] = stack.match(RegExp("(?:.*\n){0," + frames + "}"));
|
[stack] = stack.match(RegExp("(?:.*\n){0," + frames + "}"));
|
||||||
liberator.dump((msg || "Stack") + "\n" + stack);
|
liberator.dump((msg || "Stack") + "\n" + stack + "\n");
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -329,7 +331,7 @@ const Liberator = Module("liberator", {
|
|||||||
// you don't like them you can set verbose=0, or use :silent when
|
// you don't like them you can set verbose=0, or use :silent when
|
||||||
// someone adds it. I reckon another flag and 'class' of messages
|
// someone adds it. I reckon another flag and 'class' of messages
|
||||||
// is just going to unnecessarily complicate things. --djk
|
// is just going to unnecessarily complicate things. --djk
|
||||||
flags |= commandline.APPEND_TO_MESSAGES | commandline.DISALLOW_MULTILINE;
|
flags |= commandline.APPEND_TO_MESSAGES; // | commandline.DISALLOW_MULTILINE;
|
||||||
|
|
||||||
if (verbosity == null)
|
if (verbosity == null)
|
||||||
verbosity = 0; // verbosity level is exclusionary
|
verbosity = 0; // verbosity level is exclusionary
|
||||||
@@ -542,85 +544,88 @@ const Liberator = Module("liberator", {
|
|||||||
* Initialize the help system.
|
* Initialize the help system.
|
||||||
*/
|
*/
|
||||||
initHelp: function () {
|
initHelp: function () {
|
||||||
let namespaces = [config.name.toLowerCase(), "liberator"];
|
if(!this.helpInitialized) {
|
||||||
services.get("liberator:").init({});
|
let namespaces = [config.name.toLowerCase(), "liberator"];
|
||||||
|
services.get("liberator:").init({});
|
||||||
|
|
||||||
let tagMap = services.get("liberator:").HELP_TAGS;
|
let tagMap = services.get("liberator:").HELP_TAGS;
|
||||||
let fileMap = services.get("liberator:").FILE_MAP;
|
let fileMap = services.get("liberator:").FILE_MAP;
|
||||||
let overlayMap = services.get("liberator:").OVERLAY_MAP;
|
let overlayMap = services.get("liberator:").OVERLAY_MAP;
|
||||||
|
|
||||||
// Left as an XPCOM instantiation so it can easilly be moved
|
// Left as an XPCOM instantiation so it can easilly be moved
|
||||||
// into XPCOM code.
|
// into XPCOM code.
|
||||||
function XSLTProcessor(sheet) {
|
function XSLTProcessor(sheet) {
|
||||||
let xslt = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
|
let xslt = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
|
||||||
xslt.importStylesheet(util.httpGet(sheet).responseXML);
|
xslt.importStylesheet(util.httpGet(sheet).responseXML);
|
||||||
return xslt;
|
return xslt;
|
||||||
}
|
|
||||||
|
|
||||||
// Find help and overlay files with the given name.
|
|
||||||
function findHelpFile(file) {
|
|
||||||
let result = [];
|
|
||||||
for (let [, namespace] in Iterator(namespaces)) {
|
|
||||||
let url = ["chrome://", namespace, "/locale/", file, ".xml"].join("");
|
|
||||||
let res = util.httpGet(url);
|
|
||||||
if (res) {
|
|
||||||
if (res.responseXML.documentElement.localName == "document")
|
|
||||||
fileMap[file] = url;
|
|
||||||
if (res.responseXML.documentElement.localName == "overlay")
|
|
||||||
overlayMap[file] = url;
|
|
||||||
result.push(res.responseXML);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// Find the tags in the document.
|
|
||||||
function addTags(file, doc) {
|
|
||||||
doc = XSLT.transformToDocument(doc);
|
|
||||||
for (let elem in util.evaluateXPath("//xhtml:a/@id", doc))
|
|
||||||
tagMap[elem.value] = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
const XSLT = XSLTProcessor("chrome://liberator/content/help-single.xsl");
|
// Find help and overlay files with the given name.
|
||||||
|
function findHelpFile(file) {
|
||||||
|
let result = [];
|
||||||
|
for (let [, namespace] in Iterator(namespaces)) {
|
||||||
|
let url = ["chrome://", namespace, "/locale/", file, ".xml"].join("");
|
||||||
|
let res = util.httpGet(url);
|
||||||
|
if (res) {
|
||||||
|
if (res.responseXML.documentElement.localName == "document")
|
||||||
|
fileMap[file] = url;
|
||||||
|
if (res.responseXML.documentElement.localName == "overlay")
|
||||||
|
overlayMap[file] = url;
|
||||||
|
result.push(res.responseXML);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// Find the tags in the document.
|
||||||
|
function addTags(file, doc) {
|
||||||
|
doc = XSLT.transformToDocument(doc);
|
||||||
|
for (let elem in util.evaluateXPath("//xhtml:a/@id", doc))
|
||||||
|
tagMap[elem.value] = file;
|
||||||
|
}
|
||||||
|
|
||||||
// Scrape the list of help files from all.xml
|
const XSLT = XSLTProcessor("chrome://liberator/content/help-single.xsl");
|
||||||
// Always process main and overlay files, since XSLTProcessor and
|
|
||||||
// XMLHttpRequest don't allow access to chrome documents.
|
|
||||||
tagMap.all = "all";
|
|
||||||
let files = findHelpFile("all").map(function (doc)
|
|
||||||
[f.value for (f in util.evaluateXPath(
|
|
||||||
"//liberator:include/@href", doc))]);
|
|
||||||
|
|
||||||
// Scrape the tags from the rest of the help files.
|
// Scrape the list of help files from all.xml
|
||||||
util.Array.flatten(files).forEach(function (file) {
|
// Always process main and overlay files, since XSLTProcessor and
|
||||||
findHelpFile(file).forEach(function (doc) {
|
// XMLHttpRequest don't allow access to chrome documents.
|
||||||
addTags(file, doc);
|
tagMap.all = "all";
|
||||||
|
let files = findHelpFile("all").map(function (doc)
|
||||||
|
[f.value for (f in util.evaluateXPath(
|
||||||
|
"//liberator:include/@href", doc))]);
|
||||||
|
|
||||||
|
// Scrape the tags from the rest of the help files.
|
||||||
|
util.Array.flatten(files).forEach(function (file) {
|
||||||
|
findHelpFile(file).forEach(function (doc) {
|
||||||
|
addTags(file, doc);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Process plugin help entries.
|
// Process plugin help entries.
|
||||||
XML.ignoreWhiteSpace = false;
|
XML.ignoreWhiteSpace = false;
|
||||||
XML.prettyPrinting = false;
|
XML.prettyPrinting = false;
|
||||||
XML.prettyPrinting = true; // Should be false, but ignoreWhiteSpace=false doesn't work correctly. This is the lesser evil.
|
XML.prettyPrinting = true; // Should be false, but ignoreWhiteSpace=false doesn't work correctly. This is the lesser evil.
|
||||||
XML.prettyIndent = 4;
|
XML.prettyIndent = 4;
|
||||||
|
|
||||||
let body = XML();
|
let body = XML();
|
||||||
for (let [, context] in Iterator(plugins.contexts))
|
for (let [, context] in Iterator(plugins.contexts))
|
||||||
if (context.INFO instanceof XML)
|
if (context.INFO instanceof XML)
|
||||||
body += <h2 xmlns={NS.uri} tag={context.INFO.@name + '-plugin'}>{context.INFO.@summary}</h2> +
|
body += <h2 xmlns={NS.uri} tag={context.INFO.@name + '-plugin'}>{context.INFO.@summary}</h2> +
|
||||||
context.INFO;
|
context.INFO;
|
||||||
|
|
||||||
let help = '<?xml version="1.0"?>\n' +
|
let help = '<?xml version="1.0"?>\n' +
|
||||||
'<?xml-stylesheet type="text/xsl" href="chrome://liberator/content/help.xsl"?>\n' +
|
'<?xml-stylesheet type="text/xsl" href="chrome://liberator/content/help.xsl"?>\n' +
|
||||||
'<!DOCTYPE document SYSTEM "chrome://liberator/content/liberator.dtd">' +
|
'<!DOCTYPE document SYSTEM "chrome://liberator/content/liberator.dtd">' +
|
||||||
<document xmlns={NS}
|
<document xmlns={NS}
|
||||||
name="plugins" title={config.name + " Plugins"}>
|
name="plugins" title={config.name + " Plugins"}>
|
||||||
<h1 tag="using-plugins">Using Plugins</h1>
|
<h1 tag="using-plugins">Using Plugins</h1>
|
||||||
|
|
||||||
{body}
|
{body}
|
||||||
</document>.toXMLString();
|
</document>.toXMLString();
|
||||||
fileMap["plugins"] = function () ['text/xml;charset=UTF-8', help];
|
fileMap["plugins"] = function () ['text/xml;charset=UTF-8', help];
|
||||||
|
|
||||||
addTags("plugins", util.httpGet("liberator://help/plugins").responseXML);
|
addTags("plugins", util.httpGet("liberator://help/plugins").responseXML);
|
||||||
|
this.helpInitialized = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -632,6 +637,7 @@ const Liberator = Module("liberator", {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
help: function (topic, unchunked) {
|
help: function (topic, unchunked) {
|
||||||
|
liberator.initHelp();
|
||||||
if (!topic) {
|
if (!topic) {
|
||||||
let helpFile = unchunked ? "all" : options["helpfile"];
|
let helpFile = unchunked ? "all" : options["helpfile"];
|
||||||
if (helpFile in services.get("liberator:").FILE_MAP)
|
if (helpFile in services.get("liberator:").FILE_MAP)
|
||||||
@@ -737,22 +743,12 @@ const Liberator = Module("liberator", {
|
|||||||
*/
|
*/
|
||||||
open: function (urls, params, force) {
|
open: function (urls, params, force) {
|
||||||
// convert the string to an array of converted URLs
|
// convert the string to an array of converted URLs
|
||||||
// -> see util.stringToURLArray for more details
|
// -> see liberator.stringToURLArray for more details
|
||||||
//
|
//
|
||||||
// This is strange. And counterintuitive. Is it really
|
// This is strange. And counterintuitive. Is it really
|
||||||
// necessary? --Kris
|
// necessary? --Kris
|
||||||
if (typeof urls == "string") {
|
if (typeof urls == "string")
|
||||||
// rather switch to the tab instead of opening a new url in case of "12: Tab Title" like "urls"
|
urls = liberator.stringToURLArray(urls);
|
||||||
if (liberator.has("tabs")) {
|
|
||||||
let matches = urls.match(/^(\d+):/);
|
|
||||||
if (matches) {
|
|
||||||
tabs.select(parseInt(matches[1], 10) - 1, false); // make it zero-based
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
urls = util.stringToURLArray(urls);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urls.length > 20 && !force) {
|
if (urls.length > 20 && !force) {
|
||||||
commandline.input("This will open " + urls.length + " new tabs. Would you like to continue? (yes/[no]) ",
|
commandline.input("This will open " + urls.length + " new tabs. Would you like to continue? (yes/[no]) ",
|
||||||
@@ -765,7 +761,7 @@ const Liberator = Module("liberator", {
|
|||||||
|
|
||||||
let flags = 0;
|
let flags = 0;
|
||||||
params = params || {};
|
params = params || {};
|
||||||
if (params instanceof Array)
|
if (isarray(params))
|
||||||
params = { where: params };
|
params = { where: params };
|
||||||
|
|
||||||
for (let [opt, flag] in Iterator({ replace: "REPLACE_HISTORY", hide: "BYPASS_HISTORY" }))
|
for (let [opt, flag] in Iterator({ replace: "REPLACE_HISTORY", hide: "BYPASS_HISTORY" }))
|
||||||
@@ -773,15 +769,11 @@ const Liberator = Module("liberator", {
|
|||||||
flags |= Ci.nsIWebNavigation["LOAD_FLAGS_" + flag];
|
flags |= Ci.nsIWebNavigation["LOAD_FLAGS_" + flag];
|
||||||
|
|
||||||
let where = params.where || liberator.CURRENT_TAB;
|
let where = params.where || liberator.CURRENT_TAB;
|
||||||
|
let background = ("background" in params) ? params.background : params.where == liberator.NEW_BACKGROUND_TAB;
|
||||||
if ("from" in params && liberator.has("tabs")) {
|
if ("from" in params && liberator.has("tabs")) {
|
||||||
if (!('where' in params) && options.get("newtab").has("all", params.from))
|
if (!('where' in params) && options.get("newtab").has("all", params.from))
|
||||||
where = liberator.NEW_BACKGROUND_TAB;
|
where = liberator.NEW_TAB;
|
||||||
if (options.get("activate").has("all", params.from)) {
|
background = !options.get("activate").has("all", params.from);
|
||||||
if (where == liberator.NEW_TAB)
|
|
||||||
where = liberator.NEW_BACKGROUND_TAB;
|
|
||||||
else if (where == liberator.NEW_BACKGROUND_TAB)
|
|
||||||
where = liberator.NEW_TAB;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urls.length == 0)
|
if (urls.length == 0)
|
||||||
@@ -799,7 +791,6 @@ const Liberator = Module("liberator", {
|
|||||||
browser.loadURIWithFlags(url, flags, null, null, postdata);
|
browser.loadURIWithFlags(url, flags, null, null, postdata);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case liberator.NEW_BACKGROUND_TAB:
|
|
||||||
case liberator.NEW_TAB:
|
case liberator.NEW_TAB:
|
||||||
if (!liberator.has("tabs")) {
|
if (!liberator.has("tabs")) {
|
||||||
open(urls, liberator.NEW_WINDOW);
|
open(urls, liberator.NEW_WINDOW);
|
||||||
@@ -808,7 +799,7 @@ const Liberator = Module("liberator", {
|
|||||||
|
|
||||||
options.withContext(function () {
|
options.withContext(function () {
|
||||||
options.setPref("browser.tabs.loadInBackground", true);
|
options.setPref("browser.tabs.loadInBackground", true);
|
||||||
browser.loadOneTab(url, null, null, postdata, where == liberator.NEW_BACKGROUND_TAB);
|
browser.loadOneTab(url, null, null, postdata, background);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -832,7 +823,7 @@ const Liberator = Module("liberator", {
|
|||||||
|
|
||||||
for (let [, url] in Iterator(urls)) {
|
for (let [, url] in Iterator(urls)) {
|
||||||
open(url, where);
|
open(url, where);
|
||||||
where = liberator.NEW_BACKGROUND_TAB;
|
background = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -865,6 +856,64 @@ const Liberator = Module("liberator", {
|
|||||||
window.goQuitApplication();
|
window.goQuitApplication();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of URLs parsed from <b>str</b>.
|
||||||
|
*
|
||||||
|
* Given a string like 'google bla, www.osnews.com' return an array
|
||||||
|
* ['www.google.com/search?q=bla', 'www.osnews.com']
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
stringToURLArray: function stringToURLArray(str) {
|
||||||
|
let urls;
|
||||||
|
|
||||||
|
if (options["urlseparator"])
|
||||||
|
urls = util.splitLiteral(str, RegExp("\\s*" + options["urlseparator"] + "\\s*"));
|
||||||
|
else
|
||||||
|
urls = [str];
|
||||||
|
|
||||||
|
return urls.map(function (url) {
|
||||||
|
if (/^\.?\//.test(url)) {
|
||||||
|
try {
|
||||||
|
// Try to find a matching file.
|
||||||
|
let file = io.File(url);
|
||||||
|
if (file.exists() && file.isReadable())
|
||||||
|
return services.get("io").newFileURI(file).spec;
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip each 'URL' - makes things simpler later on
|
||||||
|
url = url.replace(/^\s+|\s+$/, "");
|
||||||
|
|
||||||
|
// Look for a valid protocol
|
||||||
|
let proto = url.match(/^([-\w]+):/);
|
||||||
|
if (proto && Cc["@mozilla.org/network/protocol;1?name=" + proto[1]])
|
||||||
|
// Handle as URL, but remove spaces. Useful for copied/'p'asted URLs.
|
||||||
|
return url.replace(/\s*\n+\s*/g, "");
|
||||||
|
|
||||||
|
// Ok, not a valid proto. If it looks like URL-ish (foo.com/bar),
|
||||||
|
// let Gecko figure it out.
|
||||||
|
if (/^[a-zA-Z0-9-.]+(?:\/|$)/.test(url) && /[.\/]/.test(url) && !/\s/.test(url) || /^[a-zA-Z0-9-.]+:\d+(?:\/|$)/.test(url))
|
||||||
|
return url;
|
||||||
|
|
||||||
|
// TODO: it would be clearer if the appropriate call to
|
||||||
|
// getSearchURL was made based on whether or not the first word was
|
||||||
|
// indeed an SE alias rather than seeing if getSearchURL can
|
||||||
|
// process the call usefully and trying again if it fails
|
||||||
|
|
||||||
|
// check for a search engine match in the string, then try to
|
||||||
|
// search for the whole string in the default engine
|
||||||
|
let searchURL = bookmarks.getSearchURL(url, false) || bookmarks.getSearchURL(url, true);
|
||||||
|
if (searchURL)
|
||||||
|
return searchURL;
|
||||||
|
|
||||||
|
// Hmm. No defsearch? Let the host app deal with it, then.
|
||||||
|
return url;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tests a condition and throws a FailedAssertion error on
|
* Tests a condition and throws a FailedAssertion error on
|
||||||
* failure.
|
* failure.
|
||||||
@@ -1271,17 +1320,8 @@ const Liberator = Module("liberator", {
|
|||||||
let arg = args[0];
|
let arg = args[0];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: why are these sorts of properties arrays? --djk
|
liberator.assert(args[0] in config.dialogs, "E475: Invalid argument: " + arg);
|
||||||
let dialogs = config.dialogs;
|
config.dialogs[args[0]][1]();
|
||||||
|
|
||||||
for (let [, dialog] in Iterator(dialogs)) {
|
|
||||||
if (util.compareIgnoreCase(arg, dialog[0]) == 0) {
|
|
||||||
dialog[2]();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
liberator.echoerr("E475: Invalid argument: " + arg);
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
liberator.echoerr("Error opening " + arg.quote() + ": " + e);
|
liberator.echoerr("Error opening " + arg.quote() + ": " + e);
|
||||||
@@ -1331,19 +1371,89 @@ const Liberator = Module("liberator", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
if (typeof AddonManager == "undefined") {
|
||||||
|
modules.AddonManager = {
|
||||||
|
getInstallForFile: function (file, callback, mimetype) {
|
||||||
|
callback({
|
||||||
|
install: function () {
|
||||||
|
services.get("extensionManager").installItemFromFile(file, "app-profile");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getAddonById: function (id, callback) {
|
||||||
|
let addon = id;
|
||||||
|
if (!isobject(addon))
|
||||||
|
addon = services.get("extensionManager").getItemForID(id);
|
||||||
|
if (!addon)
|
||||||
|
return callback(null);
|
||||||
|
|
||||||
|
function getRdfProperty(item, property) {
|
||||||
|
let resource = services.get("rdf").GetResource("urn:mozilla:item:" + item.id);
|
||||||
|
let value = "";
|
||||||
|
|
||||||
|
if (resource) {
|
||||||
|
let target = services.get("extensionManager").datasource.GetTarget(resource,
|
||||||
|
services.get("rdf").GetResource("http://www.mozilla.org/2004/em-rdf#" + property), true);
|
||||||
|
if (target && target instanceof Ci.nsIRDFLiteral)
|
||||||
|
value = target.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
["aboutURL", "creator", "description", "developers",
|
||||||
|
"homepageURL", "iconURL", "installDate", "name",
|
||||||
|
"optionsURL", "releaseNotesURI", "updateDate"].forEach(function (item) {
|
||||||
|
addon[item] = getRdfProperty(addon, item);
|
||||||
|
});
|
||||||
|
addon.isActive = getRdfProperty(addon, "isDisabled") != "true";
|
||||||
|
|
||||||
|
addon.uninstall = function () {
|
||||||
|
services.get("extensionManager").uninstallItem(this.id);
|
||||||
|
};
|
||||||
|
addon.appDisabled = false;
|
||||||
|
addon.__defineGetter("userDisabled", function() getRdfProperty("userDisabled") == "true");
|
||||||
|
addon.__defineSetter__("userDisabled", function(val) {
|
||||||
|
services.get("extensionManager")[val ? "enableItem" : "disableItem"](this.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
return callback(addon);
|
||||||
|
},
|
||||||
|
getAddonsByTypes: function (types, callback) {
|
||||||
|
let res = [];
|
||||||
|
for (let [,type] in Iterator(types))
|
||||||
|
for (let [,item] in Iterator(services.get("extensionManager")
|
||||||
|
.getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {})))
|
||||||
|
res.append(this.getAddonById(item));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function callResult(method) {
|
||||||
|
let args = Array.slice(arguments, 1);
|
||||||
|
return function (result) { result[method].apply(result, args) };
|
||||||
|
}
|
||||||
|
|
||||||
commands.add(["exta[dd]"],
|
commands.add(["exta[dd]"],
|
||||||
"Install an extension",
|
"Install an extension",
|
||||||
function (args) {
|
function (args) {
|
||||||
let file = io.File(args[0]);
|
let url = args[0];
|
||||||
|
let file = io.File(url);
|
||||||
if (file.exists() && file.isReadable() && file.isFile())
|
|
||||||
services.get("extensionManager").installItemFromFile(file, "app-profile");
|
|
||||||
else {
|
|
||||||
if (file.exists() && file.isDirectory())
|
|
||||||
liberator.echomsg("Cannot install a directory: \"" + file.path + "\"", 0);
|
|
||||||
|
|
||||||
|
if (!file.exists())
|
||||||
|
AddonManager.getInstallForURL(url, callResult("install"), "application/x-xpinstall");
|
||||||
|
else if (file.isReadable() && file.isFile())
|
||||||
|
AddonManager.getInstallForFile(file, callResult("install"), "application/x-xpinstall");
|
||||||
|
else if (file.isDirectory())
|
||||||
|
liberator.echomsg("Cannot install a directory: \"" + file.path + "\"", 0);
|
||||||
|
else
|
||||||
liberator.echoerr("E484: Can't open file " + file.path);
|
liberator.echoerr("E484: Can't open file " + file.path);
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
argCount: "1",
|
argCount: "1",
|
||||||
completer: function (context) {
|
completer: function (context) {
|
||||||
@@ -1357,38 +1467,35 @@ const Liberator = Module("liberator", {
|
|||||||
{
|
{
|
||||||
name: "extde[lete]",
|
name: "extde[lete]",
|
||||||
description: "Uninstall an extension",
|
description: "Uninstall an extension",
|
||||||
action: "uninstallItem"
|
action: callResult("uninstall")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "exte[nable]",
|
name: "exte[nable]",
|
||||||
description: "Enable an extension",
|
description: "Enable an extension",
|
||||||
action: "enableItem",
|
action: function (addon) addon.userDisabled = false,
|
||||||
filter: function ({ item: e }) !e.enabled
|
filter: function ({ item: e }) e.userDisabled
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "extd[isable]",
|
name: "extd[isable]",
|
||||||
description: "Disable an extension",
|
description: "Disable an extension",
|
||||||
action: "disableItem",
|
action: function (addon) addon.userDisabled = true,
|
||||||
filter: function ({ item: e }) e.enabled
|
filter: function ({ item: e }) !e.userDisabled
|
||||||
}
|
}
|
||||||
].forEach(function (command) {
|
].forEach(function (command) {
|
||||||
commands.add([command.name],
|
commands.add([command.name],
|
||||||
command.description,
|
command.description,
|
||||||
function (args) {
|
function (args) {
|
||||||
let name = args[0];
|
let name = args[0];
|
||||||
function action(e) { services.get("extensionManager")[command.action](e.id); };
|
|
||||||
|
|
||||||
if (args.bang)
|
if (args.bang)
|
||||||
liberator.extensions.forEach(function (e) { action(e); });
|
liberator.assert(!name, "E488: Trailing characters");
|
||||||
else {
|
else
|
||||||
liberator.assert(name, "E471: Argument required"); // XXX
|
liberator.assert(name, "E471: Argument required");
|
||||||
|
|
||||||
let extension = liberator.getExtension(name);
|
AddonManager.getAddonsByTypes(["extension"], function (list) {
|
||||||
if (extension)
|
if (!args.bang)
|
||||||
action(extension);
|
list = list.filter(function (extension) extension.name == name);
|
||||||
else
|
list.forEach(command.action);
|
||||||
liberator.echoerr("E474: Invalid argument");
|
});
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
argCount: "?", // FIXME: should be "1"
|
argCount: "?", // FIXME: should be "1"
|
||||||
bang: true,
|
bang: true,
|
||||||
@@ -1404,51 +1511,64 @@ const Liberator = Module("liberator", {
|
|||||||
commands.add(["exto[ptions]", "extp[references]"],
|
commands.add(["exto[ptions]", "extp[references]"],
|
||||||
"Open an extension's preference dialog",
|
"Open an extension's preference dialog",
|
||||||
function (args) {
|
function (args) {
|
||||||
let extension = liberator.getExtension(args[0]);
|
AddonManager.getAddonsByTypes(["extension"], function (list) {
|
||||||
liberator.assert(extension && extension.options,
|
list = list.filter(function (extension) extension.name == args[0]);
|
||||||
"E474: Invalid argument");
|
if (!list.length || !list[0].optionsURL)
|
||||||
if (args.bang)
|
liberator.echoerr("E474: Invalid argument");
|
||||||
window.openDialog(extension.options, "_blank", "chrome");
|
else if (args.bang)
|
||||||
else
|
window.openDialog(list[0].optionsURL, "_blank", "chrome");
|
||||||
liberator.open(extension.options, { from: "extoptions" });
|
else
|
||||||
|
liberator.open(list[0].optionsURL, { from: "extoptions" });
|
||||||
|
});
|
||||||
}, {
|
}, {
|
||||||
argCount: "1",
|
argCount: "1",
|
||||||
bang: true,
|
bang: true,
|
||||||
completer: function (context) {
|
completer: function (context) {
|
||||||
completion.extension(context);
|
completion.extension(context);
|
||||||
context.filters.push(function ({ item: e }) e.options);
|
context.filters.push(function ({ item: e }) e.isActive && e.optionsURL);
|
||||||
},
|
},
|
||||||
literal: 0
|
literal: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: maybe indicate pending status too?
|
// TODO: maybe indicate pending status too?
|
||||||
commands.add(["extens[ions]"],
|
commands.add(["extens[ions]", "exts"],
|
||||||
"List available extensions",
|
"List available extensions",
|
||||||
function (args) {
|
function (args) {
|
||||||
let filter = args[0] || "";
|
AddonManager.getAddonsByTypes(["extension"], function (extensions) {
|
||||||
let extensions = liberator.extensions.filter(function (e) e.name.indexOf(filter) >= 0);
|
if (args[0])
|
||||||
|
extensions = extensions.filter(function (extension) extension.name.indexOf(args[0]) >= 0);
|
||||||
|
extensions.sort(function (a, b) String.localeCompare(a.name, b.name));
|
||||||
|
|
||||||
if (extensions.length > 0) {
|
if (extensions.length > 0) {
|
||||||
let list = template.tabular(
|
let list = template.tabular(
|
||||||
["Name", "Version", "Status", "Description"], [],
|
["Name", "Version", "Status", "Description"], [],
|
||||||
([template.icon(e, e.name),
|
([template.icon({ icon: e.iconURL }, e.name),
|
||||||
e.version,
|
e.version,
|
||||||
e.enabled ? <span highlight="Enabled">enabled</span>
|
(e.isActive ? <span highlight="Enabled">enabled</span>
|
||||||
: <span highlight="Disabled">disabled</span>,
|
: <span highlight="Disabled">disabled</span>) +
|
||||||
e.description] for ([, e] in Iterator(extensions)))
|
((e.userDisabled || e.appDisabled) == !e.isActive ? XML() :
|
||||||
);
|
<> ({e.userDisabled || e.appDisabled
|
||||||
|
? <span highlight="Disabled">disabled</span>
|
||||||
|
: <span highlight="Enabled">enabled</span>}
|
||||||
|
on restart)
|
||||||
|
</>),
|
||||||
|
e.description] for ([, e] in Iterator(extensions)))
|
||||||
|
);
|
||||||
|
|
||||||
commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
|
commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (filter)
|
if (filter)
|
||||||
liberator.echoerr("Exxx: No extension matching \"" + filter + "\"");
|
liberator.echoerr("Exxx: No extension matching \"" + filter + "\"");
|
||||||
else
|
else
|
||||||
liberator.echoerr("No extensions installed");
|
liberator.echoerr("No extensions installed");
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
{ argCount: "?" });
|
{ argCount: "?" });
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
commands.add(["exu[sage]"],
|
commands.add(["exu[sage]"],
|
||||||
"List all Ex commands with a short description",
|
"List all Ex commands with a short description",
|
||||||
function (args) { Liberator.showHelpIndex("ex-cmd-index", commands, args.bang); }, {
|
function (args) { Liberator.showHelpIndex("ex-cmd-index", commands, args.bang); }, {
|
||||||
@@ -1704,17 +1824,22 @@ const Liberator = Module("liberator", {
|
|||||||
completion: function () {
|
completion: function () {
|
||||||
completion.dialog = function dialog(context) {
|
completion.dialog = function dialog(context) {
|
||||||
context.title = ["Dialog"];
|
context.title = ["Dialog"];
|
||||||
context.completions = config.dialogs;
|
context.completions = [[k, v[0]] for ([k, v] in Iterator(config.dialogs))];
|
||||||
};
|
};
|
||||||
|
|
||||||
completion.extension = function extension(context) {
|
completion.extension = function extension(context) {
|
||||||
context.title = ["Extension"];
|
context.title = ["Extension"];
|
||||||
context.anchored = false;
|
context.anchored = false;
|
||||||
context.keys = { text: "name", description: "description", icon: "icon" },
|
context.keys = { text: "name", description: "description", icon: "iconURL" },
|
||||||
context.completions = liberator.extensions;
|
context.incomplete = true;
|
||||||
|
AddonManager.getAddonsByTypes(["extension"], function (addons) {
|
||||||
|
context.incomplete = false;
|
||||||
|
context.completions = addons;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
completion.help = function help(context, unchunked) {
|
completion.help = function help(context, unchunked) {
|
||||||
|
liberator.initHelp();
|
||||||
context.title = ["Help"];
|
context.title = ["Help"];
|
||||||
context.anchored = false;
|
context.anchored = false;
|
||||||
context.completions = services.get("liberator:").HELP_TAGS;
|
context.completions = services.get("liberator:").HELP_TAGS;
|
||||||
@@ -1729,6 +1854,7 @@ const Liberator = Module("liberator", {
|
|||||||
context.completions = liberator.menuItems;
|
context.completions = liberator.menuItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var toolbox = document.getElementById("navigator-toolbox");
|
||||||
completion.toolbar = function toolbar(context) {
|
completion.toolbar = function toolbar(context) {
|
||||||
context.title = ["Toolbar"];
|
context.title = ["Toolbar"];
|
||||||
context.keys = { text: function (item) item.getAttribute("toolbarname"), description: function () "" };
|
context.keys = { text: function (item) item.getAttribute("toolbarname"), description: function () "" };
|
||||||
@@ -1817,8 +1943,6 @@ const Liberator = Module("liberator", {
|
|||||||
if (options["loadplugins"])
|
if (options["loadplugins"])
|
||||||
liberator.loadPlugins();
|
liberator.loadPlugins();
|
||||||
|
|
||||||
liberator.initHelp();
|
|
||||||
|
|
||||||
// after sourcing the initialization files, this function will set
|
// after sourcing the initialization files, this function will set
|
||||||
// all gui options to their default values, if they have not been
|
// all gui options to their default values, if they have not been
|
||||||
// set before by any RC file
|
// set before by any RC file
|
||||||
@@ -1841,6 +1965,7 @@ const Liberator = Module("liberator", {
|
|||||||
|
|
||||||
statusline.update();
|
statusline.update();
|
||||||
liberator.log(config.name + " fully initialized", 0);
|
liberator.log(config.name + " fully initialized", 0);
|
||||||
|
liberator.initialized = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
<textbox class="plain" id="liberator-message" flex="1" readonly="true" liberator:highlight="Normal"/>
|
<textbox class="plain" id="liberator-message" flex="1" readonly="true" liberator:highlight="Normal"/>
|
||||||
<hbox id="liberator-commandline" hidden="false" collapsed="true" class="liberator-container" liberator:highlight="Normal">
|
<hbox id="liberator-commandline" hidden="false" collapsed="true" class="liberator-container" liberator:highlight="Normal">
|
||||||
<label class="plain" id="liberator-commandline-prompt" flex="0" crop="end" value="" collapsed="true"/>
|
<label class="plain" id="liberator-commandline-prompt" flex="0" crop="end" value="" collapsed="true"/>
|
||||||
<textbox class="plain" id="liberator-commandline-command" flex="1" type="timed" timeout="100"
|
<textbox class="plain" id="liberator-commandline-command" flex="1" type="search" timeout="100"
|
||||||
oninput="window.liberator ∧ liberator.modules.commandline.onEvent(event);"
|
oninput="window.liberator ∧ liberator.modules.commandline.onEvent(event);"
|
||||||
onkeyup="window.liberator ∧ liberator.modules.commandline.onEvent(event);"
|
onkeyup="window.liberator ∧ liberator.modules.commandline.onEvent(event);"
|
||||||
onfocus="window.liberator ∧ liberator.modules.commandline.onEvent(event);"
|
onfocus="window.liberator ∧ liberator.modules.commandline.onEvent(event);"
|
||||||
@@ -86,12 +86,13 @@
|
|||||||
|
|
||||||
<statusbar id="status-bar" liberator:highlight="StatusLine">
|
<statusbar id="status-bar" liberator:highlight="StatusLine">
|
||||||
<hbox insertbefore="&liberator.statusBefore;" insertafter="&liberator.statusAfter;"
|
<hbox insertbefore="&liberator.statusBefore;" insertafter="&liberator.statusAfter;"
|
||||||
id="liberator-statusline" flex="1" hidden="false" align="center">
|
id="liberator-statusline-field-status" flex="1" hidden="false" align="center">
|
||||||
<textbox class="plain" id="liberator-statusline-field-url" readonly="false" flex="1" crop="end"/>
|
<textbox class="plain" id="liberator-statusline-field-url" readonly="false" flex="1" crop="end"/>
|
||||||
<label class="plain" id="liberator-statusline-field-inputbuffer" flex="0"/>
|
<label class="plain" id="liberator-statusline-field-inputbuffer" flex="0"/>
|
||||||
<label class="plain" id="liberator-statusline-field-progress" flex="0"/>
|
<label class="plain" id="liberator-statusline-field-progress" flex="0"/>
|
||||||
<label class="plain" id="liberator-statusline-field-tabcount" flex="0"/>
|
<label class="plain" id="liberator-statusline-field-tabcount" flex="0"/>
|
||||||
<label class="plain" id="liberator-statusline-field-bufferposition" flex="0"/>
|
<label class="plain" id="liberator-statusline-field-bufferposition" flex="0"/>
|
||||||
|
<label class="plain" id="liberator-statusline-field-zoomlevel" flex="0"/>
|
||||||
</hbox>
|
</hbox>
|
||||||
<!-- just hide them since other elements expect them -->
|
<!-- just hide them since other elements expect them -->
|
||||||
<statusbarpanel id="statusbar-display" hidden="true"/>
|
<statusbarpanel id="statusbar-display" hidden="true"/>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @scope modules
|
* @scope modules
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class ModuleBase
|
* @class ModuleBase
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -22,7 +25,6 @@
|
|||||||
* getter - see {@link Option#getter}
|
* getter - see {@link Option#getter}
|
||||||
* completer - see {@link Option#completer}
|
* completer - see {@link Option#completer}
|
||||||
* valdator - see {@link Option#validator}
|
* valdator - see {@link Option#validator}
|
||||||
* checkHas - see {@link Option#checkHas}
|
|
||||||
* @optional
|
* @optional
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -33,6 +35,17 @@ const Option = Class("Option", {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
|
||||||
|
if (this.type in Option.getKey)
|
||||||
|
this.getKey = Option.getKey[this.type];
|
||||||
|
|
||||||
|
if (this.type in Option.parseValues)
|
||||||
|
this.parseValues = Option.parseValues[this.type];
|
||||||
|
|
||||||
|
if (this.type in Option.joinValues)
|
||||||
|
this.joinValues = Option.joinValues[this.type];
|
||||||
|
|
||||||
|
this._op = Option.ops[this.type];
|
||||||
|
|
||||||
if (arguments.length > 3)
|
if (arguments.length > 3)
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
|
|
||||||
@@ -44,7 +57,7 @@ const Option = Class("Option", {
|
|||||||
this.names = array([name, "no" + name] for (name in values(names))).flatten().__proto__;
|
this.names = array([name, "no" + name] for (name in values(names))).flatten().__proto__;
|
||||||
|
|
||||||
if (this.globalValue == undefined)
|
if (this.globalValue == undefined)
|
||||||
this.globalValue = this.defaultValue;
|
this.globalValue = this.parseValues(this.defaultValue);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @property {value} The option's global value. @see #scope */
|
/** @property {value} The option's global value. @see #scope */
|
||||||
@@ -58,13 +71,7 @@ const Option = Class("Option", {
|
|||||||
* @param {value} value The option value.
|
* @param {value} value The option value.
|
||||||
* @returns {value|string[]}
|
* @returns {value|string[]}
|
||||||
*/
|
*/
|
||||||
parseValues: function (value) {
|
parseValues: function (value) value,
|
||||||
if (this.type == "stringlist")
|
|
||||||
return (value === "") ? [] : value.split(",");
|
|
||||||
if (this.type == "charlist")
|
|
||||||
return Array.slice(value);
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <b>values</b> packed in the appropriate format for the option
|
* Returns <b>values</b> packed in the appropriate format for the option
|
||||||
@@ -73,16 +80,10 @@ const Option = Class("Option", {
|
|||||||
* @param {value|string[]} values The option value.
|
* @param {value|string[]} values The option value.
|
||||||
* @returns {value}
|
* @returns {value}
|
||||||
*/
|
*/
|
||||||
joinValues: function (values) {
|
joinValues: function (vals) vals,
|
||||||
if (this.type == "stringlist")
|
|
||||||
return values.join(",");
|
|
||||||
if (this.type == "charlist")
|
|
||||||
return values.join("");
|
|
||||||
return values;
|
|
||||||
},
|
|
||||||
|
|
||||||
/** @property {value|string[]} The option value or array of values. */
|
/** @property {value|string[]} The option value or array of values. */
|
||||||
get values() this.parseValues(this.value),
|
get values() this.getValues(this.scope),
|
||||||
set values(values) this.setValues(values, this.scope),
|
set values(values) this.setValues(values, this.scope),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,7 +94,26 @@ const Option = Class("Option", {
|
|||||||
* {@link Option#scope}).
|
* {@link Option#scope}).
|
||||||
* @returns {value|string[]}
|
* @returns {value|string[]}
|
||||||
*/
|
*/
|
||||||
getValues: function (scope) this.parseValues(this.get(scope)),
|
getValues: function (scope) {
|
||||||
|
if (scope) {
|
||||||
|
if ((scope & this.scope) == 0) // option doesn't exist in this scope
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
scope = this.scope;
|
||||||
|
|
||||||
|
let values;
|
||||||
|
|
||||||
|
if (liberator.has("tabs") && (scope & Option.SCOPE_LOCAL))
|
||||||
|
values = tabs.options[this.name];
|
||||||
|
if ((scope & Option.SCOPE_GLOBAL) && (values == undefined))
|
||||||
|
values = this.globalValue;
|
||||||
|
|
||||||
|
if (this.getter)
|
||||||
|
return liberator.trapErrors(this.getter, this, values);
|
||||||
|
|
||||||
|
return values;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the option's value from an array of values if the option type is
|
* Sets the option's value from an array of values if the option type is
|
||||||
@@ -102,8 +122,22 @@ const Option = Class("Option", {
|
|||||||
* @param {number} scope The scope to apply these values to (see
|
* @param {number} scope The scope to apply these values to (see
|
||||||
* {@link Option#scope}).
|
* {@link Option#scope}).
|
||||||
*/
|
*/
|
||||||
setValues: function (values, scope) {
|
setValues: function (newValues, scope, skipGlobal) {
|
||||||
this.set(this.joinValues(values), scope || this.scope);
|
scope = scope || this.scope;
|
||||||
|
if ((scope & this.scope) == 0) // option doesn't exist in this scope
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.setter)
|
||||||
|
newValues = liberator.trapErrors(this.setter, this, newValues);
|
||||||
|
if (newValues === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (liberator.has("tabs") && (scope & Option.SCOPE_LOCAL))
|
||||||
|
tabs.options[this.name] = newValues;
|
||||||
|
if ((scope & Option.SCOPE_GLOBAL) && !skipGlobal)
|
||||||
|
this.globalValue = newValues;
|
||||||
|
|
||||||
|
this.hasChanged = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,26 +149,7 @@ const Option = Class("Option", {
|
|||||||
* {@link Option#scope}).
|
* {@link Option#scope}).
|
||||||
* @returns {value}
|
* @returns {value}
|
||||||
*/
|
*/
|
||||||
get: function (scope) {
|
get: function (scope) this.joinValues(this.getValues(scope)),
|
||||||
if (scope) {
|
|
||||||
if ((scope & this.scope) == 0) // option doesn't exist in this scope
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
scope = this.scope;
|
|
||||||
|
|
||||||
let value;
|
|
||||||
|
|
||||||
if (liberator.has("tabs") && (scope & Option.SCOPE_LOCAL))
|
|
||||||
value = tabs.options[this.name];
|
|
||||||
if ((scope & Option.SCOPE_GLOBAL) && (value == undefined))
|
|
||||||
value = this.globalValue;
|
|
||||||
|
|
||||||
if (this.getter)
|
|
||||||
return liberator.trapErrors(this.getter, this, value);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the option value to <b>newValue</b> for the specified <b>scope</b>.
|
* Sets the option value to <b>newValue</b> for the specified <b>scope</b>.
|
||||||
@@ -145,21 +160,7 @@ const Option = Class("Option", {
|
|||||||
* @param {number} scope The scope to apply this value to (see
|
* @param {number} scope The scope to apply this value to (see
|
||||||
* {@link Option#scope}).
|
* {@link Option#scope}).
|
||||||
*/
|
*/
|
||||||
set: function (newValue, scope) {
|
set: function (newValue, scope) this.setValues(this.parseValues(newValue), scope),
|
||||||
scope = scope || this.scope;
|
|
||||||
if ((scope & this.scope) == 0) // option doesn't exist in this scope
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this.setter)
|
|
||||||
newValue = liberator.trapErrors(this.setter, this, newValue);
|
|
||||||
|
|
||||||
if (liberator.has("tabs") && (scope & Option.SCOPE_LOCAL))
|
|
||||||
tabs.options[this.name] = newValue;
|
|
||||||
if ((scope & Option.SCOPE_GLOBAL) && newValue != this.globalValue)
|
|
||||||
this.globalValue = newValue;
|
|
||||||
|
|
||||||
this.hasChanged = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {value} The option's current value. The option's local value,
|
* @property {value} The option's current value. The option's local value,
|
||||||
@@ -169,21 +170,15 @@ const Option = Class("Option", {
|
|||||||
get value() this.get(),
|
get value() this.get(),
|
||||||
set value(val) this.set(val),
|
set value(val) this.set(val),
|
||||||
|
|
||||||
|
getKey: function (key) undefined,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the option value contains one or more of the specified
|
* Returns whether the option value contains one or more of the specified
|
||||||
* arguments.
|
* arguments.
|
||||||
*
|
*
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
has: function () {
|
has: function () Array.some(arguments, function (val) this.values.indexOf(val) >= 0, this),
|
||||||
let self = this;
|
|
||||||
let test = function (val) values.indexOf(val) >= 0;
|
|
||||||
if (this.checkHas)
|
|
||||||
test = function (val) values.some(function (value) self.checkHas(value, val));
|
|
||||||
let values = this.values;
|
|
||||||
// return whether some argument matches
|
|
||||||
return Array.some(arguments, function (val) test(val));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this option is identified by <b>name</b>.
|
* Returns whether this option is identified by <b>name</b>.
|
||||||
@@ -216,97 +211,16 @@ const Option = Class("Option", {
|
|||||||
* @param {boolean} invert Whether this is an invert boolean operation.
|
* @param {boolean} invert Whether this is an invert boolean operation.
|
||||||
*/
|
*/
|
||||||
op: function (operator, values, scope, invert) {
|
op: function (operator, values, scope, invert) {
|
||||||
let newValue = null;
|
|
||||||
let self = this;
|
|
||||||
|
|
||||||
switch (this.type) {
|
let newValues = this._op(operator, values, scope, invert);
|
||||||
case "boolean":
|
|
||||||
if (operator != "=")
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (invert)
|
if (newValues == null)
|
||||||
newValue = !this.value;
|
|
||||||
else
|
|
||||||
newValue = values;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "number":
|
|
||||||
// TODO: support floats? Validators need updating.
|
|
||||||
if (!/^[+-]?(?:0x[0-9a-f]+|0[0-7]+|0|[1-9]\d*)$/i.test(values))
|
|
||||||
return "E521: Number required after := " + this.name + "=" + values;
|
|
||||||
|
|
||||||
let value = parseInt(values/* deduce radix */);
|
|
||||||
|
|
||||||
switch (operator) {
|
|
||||||
case "+":
|
|
||||||
newValue = this.value + value;
|
|
||||||
break;
|
|
||||||
case "-":
|
|
||||||
newValue = this.value - value;
|
|
||||||
break;
|
|
||||||
case "^":
|
|
||||||
newValue = this.value * value;
|
|
||||||
break;
|
|
||||||
case "=":
|
|
||||||
newValue = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "charlist":
|
|
||||||
case "stringlist":
|
|
||||||
values = Array.concat(values);
|
|
||||||
switch (operator) {
|
|
||||||
case "+":
|
|
||||||
newValue = util.Array.uniq(Array.concat(this.values, values), true);
|
|
||||||
break;
|
|
||||||
case "^":
|
|
||||||
// NOTE: Vim doesn't prepend if there's a match in the current value
|
|
||||||
newValue = util.Array.uniq(Array.concat(values, this.values), true);
|
|
||||||
break;
|
|
||||||
case "-":
|
|
||||||
newValue = this.values.filter(function (item) values.indexOf(item) == -1);
|
|
||||||
break;
|
|
||||||
case "=":
|
|
||||||
newValue = values;
|
|
||||||
if (invert) {
|
|
||||||
let keepValues = this.values.filter(function (item) values.indexOf(item) == -1);
|
|
||||||
let addValues = values.filter(function (item) self.values.indexOf(item) == -1);
|
|
||||||
newValue = addValues.concat(keepValues);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "string":
|
|
||||||
switch (operator) {
|
|
||||||
case "+":
|
|
||||||
newValue = this.value + values;
|
|
||||||
break;
|
|
||||||
case "-":
|
|
||||||
newValue = this.value.replace(values, "");
|
|
||||||
break;
|
|
||||||
case "^":
|
|
||||||
newValue = values + this.value;
|
|
||||||
break;
|
|
||||||
case "=":
|
|
||||||
newValue = values;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "E685: Internal error: option type `" + this.type + "' not supported";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newValue == null)
|
|
||||||
return "Operator " + operator + " not supported for option type " + this.type;
|
return "Operator " + operator + " not supported for option type " + this.type;
|
||||||
if (!this.isValidValue(newValue))
|
|
||||||
|
if (!this.isValidValue(newValues))
|
||||||
return "E474: Invalid argument: " + values;
|
return "E474: Invalid argument: " + values;
|
||||||
this.setValues(newValue, scope);
|
|
||||||
|
this.setValues(newValues, scope);
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -319,11 +233,13 @@ const Option = Class("Option", {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {string} The option's data type. One of:
|
* @property {string} The option's data type. One of:
|
||||||
* "boolean" - Boolean E.g. true
|
* "boolean" - Boolean, e.g., true
|
||||||
* "number" - Integer E.g. 1
|
* "number" - Integer, e.g., 1
|
||||||
* "string" - String E.g. "Vimperator"
|
* "string" - String, e.g., "Vimperator"
|
||||||
* "charlist" - Character list E.g. "rb"
|
* "charlist" - Character list, e.g., "rb"
|
||||||
* "stringlist" - String list E.g. "homepage,quickmark,tabopen,paste"
|
* "regexlist" - Regex list, e.g., "^foo,bar$"
|
||||||
|
* "stringmap" - String map, e.g., "key=v,foo=bar"
|
||||||
|
* "regexmap" - Regex map, e.g., "^key=v,foo$=bar"
|
||||||
*/
|
*/
|
||||||
type: null,
|
type: null,
|
||||||
|
|
||||||
@@ -370,12 +286,6 @@ const Option = Class("Option", {
|
|||||||
return Option.validateCompleter.apply(this, arguments);
|
return Option.validateCompleter.apply(this, arguments);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* @property The function called to determine whether the option already
|
|
||||||
* contains a specified value.
|
|
||||||
* @see #has
|
|
||||||
*/
|
|
||||||
checkHas: null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {boolean} Set to true whenever the option is first set. This
|
* @property {boolean} Set to true whenever the option is first set. This
|
||||||
@@ -410,6 +320,132 @@ const Option = Class("Option", {
|
|||||||
*/
|
*/
|
||||||
SCOPE_BOTH: 3,
|
SCOPE_BOTH: 3,
|
||||||
|
|
||||||
|
parseRegex: function (val, result) {
|
||||||
|
let [, bang, val] = /^(!?)(.*)/.exec(val);
|
||||||
|
let re = RegExp(val);
|
||||||
|
re.bang = bang;
|
||||||
|
re.result = arguments.length == 2 ? result : !bang;
|
||||||
|
return re;
|
||||||
|
},
|
||||||
|
unparseRegex: function (re) re.bang + re.source + (typeof re.result == "string" ? "=" + re.result : ""),
|
||||||
|
|
||||||
|
getKey: {
|
||||||
|
stringlist: function (k) this.values.indexOf(k) >= 0,
|
||||||
|
regexlist: function (k) {
|
||||||
|
for (let re in values(this.values))
|
||||||
|
if (re.test(k))
|
||||||
|
return re.result;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
joinValues: {
|
||||||
|
charlist: function (vals) vals.join(""),
|
||||||
|
stringlist: function (vals) vals.join(","),
|
||||||
|
stringmap: function (vals) [k + "=" + v for ([k, v] in Iterator(vals))].join(","),
|
||||||
|
regexlist: function (vals) vals.map(Option.unparseRegex).join(","),
|
||||||
|
},
|
||||||
|
|
||||||
|
parseValues: {
|
||||||
|
number: function (value) Number(value),
|
||||||
|
boolean: function (value) value == "true" || value == true ? true : false,
|
||||||
|
charlist: function (value) Array.slice(value),
|
||||||
|
stringlist: function (value) (value === "") ? [] : value.split(","),
|
||||||
|
stringmap: function (value) array(v.split("=") for (v in values(value.split(",")))).toObject(),
|
||||||
|
regexlist: function (value) (value === "") ? [] : value.split(",").map(Option.parseRegex),
|
||||||
|
regexmap: function (value) value.split(",").map(function (v) v.split("="))
|
||||||
|
.map(function ([k, v]) v != null ? Option.parseRegex(k, v) : Option.parseRegex('.?', k))
|
||||||
|
},
|
||||||
|
|
||||||
|
ops: {
|
||||||
|
boolean: function (operator, values, scope, invert) {
|
||||||
|
if (operator != "=")
|
||||||
|
return null;
|
||||||
|
if (invert)
|
||||||
|
return !this.value;
|
||||||
|
return values;
|
||||||
|
},
|
||||||
|
|
||||||
|
number: function (operator, values, scope, invert) {
|
||||||
|
// TODO: support floats? Validators need updating.
|
||||||
|
if (!/^[+-]?(?:0x[0-9a-f]+|0[0-7]*|[1-9]+)$/i.test(values))
|
||||||
|
return "E521: Number required after := " + this.name + "=" + values;
|
||||||
|
|
||||||
|
let value = parseInt(values);
|
||||||
|
|
||||||
|
switch (operator) {
|
||||||
|
case "+":
|
||||||
|
return this.value + value;
|
||||||
|
case "-":
|
||||||
|
return this.value - value;
|
||||||
|
case "^":
|
||||||
|
return this.value * value;
|
||||||
|
case "=":
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
stringmap: function (operator, values, scope, invert) {
|
||||||
|
values = Array.concat(values);
|
||||||
|
orig = [k + "=" + v for ([k, v] in Iterator(this.values))];
|
||||||
|
|
||||||
|
switch (operator) {
|
||||||
|
case "+":
|
||||||
|
return util.Array.uniq(Array.concat(orig, values), true);
|
||||||
|
case "^":
|
||||||
|
// NOTE: Vim doesn't prepend if there's a match in the current value
|
||||||
|
return util.Array.uniq(Array.concat(values, orig), true);
|
||||||
|
case "-":
|
||||||
|
return orig.filter(function (item) values.indexOf(item) == -1);
|
||||||
|
case "=":
|
||||||
|
if (invert) {
|
||||||
|
let keepValues = orig.filter(function (item) values.indexOf(item) == -1);
|
||||||
|
let addValues = values.filter(function (item) self.values.indexOf(item) == -1);
|
||||||
|
return addValues.concat(keepValues);
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
stringlist: function (operator, values, scope, invert) {
|
||||||
|
const self = this;
|
||||||
|
values = Array.concat(values);
|
||||||
|
switch (operator) {
|
||||||
|
case "+":
|
||||||
|
return util.Array.uniq(Array.concat(this.values, values), true);
|
||||||
|
case "^":
|
||||||
|
// NOTE: Vim doesn't prepend if there's a match in the current value
|
||||||
|
return util.Array.uniq(Array.concat(values, this.values), true);
|
||||||
|
case "-":
|
||||||
|
return this.values.filter(function (item) values.indexOf(item) == -1);
|
||||||
|
case "=":
|
||||||
|
if (invert) {
|
||||||
|
let keepValues = this.values.filter(function (item) values.indexOf(item) == -1);
|
||||||
|
let addValues = values.filter(function (item) self.values.indexOf(item) == -1);
|
||||||
|
return addValues.concat(keepValues);
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
string: function (operator, values, scope, invert) {
|
||||||
|
switch (operator) {
|
||||||
|
case "+":
|
||||||
|
return this.value + values;
|
||||||
|
case "-":
|
||||||
|
return this.value.replace(values, "");
|
||||||
|
case "^":
|
||||||
|
return values + this.value;
|
||||||
|
case "=":
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// TODO: Run this by default?
|
// TODO: Run this by default?
|
||||||
/**
|
/**
|
||||||
* Validates the specified <b>values</b> against values generated by the
|
* Validates the specified <b>values</b> against values generated by the
|
||||||
@@ -423,10 +459,21 @@ const Option = Class("Option", {
|
|||||||
let res = context.fork("", 0, this, this.completer);
|
let res = context.fork("", 0, this, this.completer);
|
||||||
if (!res)
|
if (!res)
|
||||||
res = context.allItems.items.map(function (item) [item.text]);
|
res = context.allItems.items.map(function (item) [item.text]);
|
||||||
|
if (this.type == "regexmap")
|
||||||
|
return Array.concat(values).every(function (re) res.some(function (item) item[0] == re.result));
|
||||||
return Array.concat(values).every(function (value) res.some(function (item) item[0] == value));
|
return Array.concat(values).every(function (value) res.some(function (item) item[0] == value));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Option.joinValues["regexmap"] = Option.joinValues["regexlist"];
|
||||||
|
|
||||||
|
Option.getKey["charlist"] = Option.getKey["stringlist"];
|
||||||
|
Option.getKey["regexmap"] = Option.getKey["regexlist"];
|
||||||
|
|
||||||
|
Option.ops["charlist"] = Option.ops["stringlist"];
|
||||||
|
Option.ops["regexlist"] = Option.ops["stringlist"];
|
||||||
|
Option.ops["regexmap"] = Option.ops["stringlist"];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @instance options
|
* @instance options
|
||||||
*/
|
*/
|
||||||
@@ -462,7 +509,7 @@ const Options = Module("options", {
|
|||||||
// Trigger any setters.
|
// Trigger any setters.
|
||||||
let opt = options.get(option);
|
let opt = options.get(option);
|
||||||
if (event == "change" && opt)
|
if (event == "change" && opt)
|
||||||
opt.set(opt.value, Option.SCOPE_GLOBAL);
|
opt.setValues(opt.globalValue, Option.SCOPE_GLOBAL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.newMap("options", { store: false });
|
storage.newMap("options", { store: false });
|
||||||
@@ -1008,8 +1055,6 @@ const Options = Module("options", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// write access
|
// write access
|
||||||
// NOTE: the behavior is generally Vim compatible but could be
|
|
||||||
// improved. i.e. Vim's behavior is pretty sloppy to no real benefit
|
|
||||||
else {
|
else {
|
||||||
option.setFrom = modifiers.setFrom || null;
|
option.setFrom = modifiers.setFrom || null;
|
||||||
|
|
||||||
@@ -1017,7 +1062,12 @@ const Options = Module("options", {
|
|||||||
liberator.assert(!opt.valueGiven, "E474: Invalid argument: " + arg);
|
liberator.assert(!opt.valueGiven, "E474: Invalid argument: " + arg);
|
||||||
opt.values = !opt.unsetBoolean;
|
opt.values = !opt.unsetBoolean;
|
||||||
}
|
}
|
||||||
let res = opt.option.op(opt.operator || "=", opt.values, opt.scope, opt.invert);
|
try {
|
||||||
|
var res = opt.option.op(opt.operator || "=", opt.values, opt.scope, opt.invert);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
res = e;
|
||||||
|
}
|
||||||
if (res)
|
if (res)
|
||||||
liberator.echoerr(res);
|
liberator.echoerr(res);
|
||||||
}
|
}
|
||||||
@@ -1244,8 +1294,15 @@ const Options = Module("options", {
|
|||||||
if (!completer)
|
if (!completer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let curValues = curValue != null ? opt.parseValues(curValue) : opt.values;
|
try {
|
||||||
let newValues = opt.parseValues(context.filter);
|
var curValues = curValue != null ? opt.parseValues(curValue) : opt.values;
|
||||||
|
var newValues = opt.parseValues(context.filter);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
context.message = "Error: " + e;
|
||||||
|
context.completions = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let len = context.filter.length;
|
let len = context.filter.length;
|
||||||
switch (opt.type) {
|
switch (opt.type) {
|
||||||
@@ -1253,9 +1310,18 @@ const Options = Module("options", {
|
|||||||
if (!completer)
|
if (!completer)
|
||||||
completer = function () [["true", ""], ["false", ""]];
|
completer = function () [["true", ""], ["false", ""]];
|
||||||
break;
|
break;
|
||||||
|
case "regexlist":
|
||||||
|
newValues = context.filter.split(",");
|
||||||
|
// Fallthrough
|
||||||
case "stringlist":
|
case "stringlist":
|
||||||
let target = newValues.pop();
|
let target = newValues.pop() || "";
|
||||||
len = target ? target.length : 0;
|
len = target.length;
|
||||||
|
break;
|
||||||
|
case "stringmap":
|
||||||
|
case "regexmap":
|
||||||
|
let vals = context.filter.split(",");
|
||||||
|
target = vals.pop() || "";
|
||||||
|
len = target.length - (target.indexOf("=") + 1);
|
||||||
break;
|
break;
|
||||||
case "charlist":
|
case "charlist":
|
||||||
len = 0;
|
len = 0;
|
||||||
@@ -1268,9 +1334,10 @@ const Options = Module("options", {
|
|||||||
let completions = completer(context);
|
let completions = completer(context);
|
||||||
if (!completions)
|
if (!completions)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Not Vim compatible, but is a significant enough improvement
|
// Not Vim compatible, but is a significant enough improvement
|
||||||
// that it's worth breaking compatibility.
|
// that it's worth breaking compatibility.
|
||||||
if (newValues instanceof Array) {
|
if (isarray(newValues)) {
|
||||||
completions = completions.filter(function (val) newValues.indexOf(val[0]) == -1);
|
completions = completions.filter(function (val) newValues.indexOf(val[0]) == -1);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case "+":
|
case "+":
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - fix Sanitize autocommand
|
// - fix Sanitize autocommand
|
||||||
@@ -19,6 +20,7 @@ const Sanitizer = Module("sanitizer", {
|
|||||||
init: function () {
|
init: function () {
|
||||||
const self = this;
|
const self = this;
|
||||||
liberator.loadScript("chrome://browser/content/sanitize.js", Sanitizer);
|
liberator.loadScript("chrome://browser/content/sanitize.js", Sanitizer);
|
||||||
|
Sanitizer.getClearRange = Sanitizer.Sanitizer.getClearRange;
|
||||||
this.__proto__.__proto__ = new Sanitizer.Sanitizer; // Good enough.
|
this.__proto__.__proto__ = new Sanitizer.Sanitizer; // Good enough.
|
||||||
|
|
||||||
// TODO: remove this version test
|
// TODO: remove this version test
|
||||||
@@ -213,10 +215,9 @@ const Sanitizer = Module("sanitizer", {
|
|||||||
{
|
{
|
||||||
setter: function (values) {
|
setter: function (values) {
|
||||||
for (let [, pref] in Iterator(sanitizer.prefNames)) {
|
for (let [, pref] in Iterator(sanitizer.prefNames)) {
|
||||||
continue;
|
|
||||||
options.setPref(pref, false);
|
options.setPref(pref, false);
|
||||||
|
|
||||||
for (let [, value] in Iterator(this.parseValues(values))) {
|
for (let [, value] in Iterator(values)) {
|
||||||
if (Sanitizer.prefToArg(pref) == value) {
|
if (Sanitizer.prefToArg(pref) == value) {
|
||||||
options.setPref(pref, true);
|
options.setPref(pref, true);
|
||||||
break;
|
break;
|
||||||
@@ -226,7 +227,7 @@ const Sanitizer = Module("sanitizer", {
|
|||||||
|
|
||||||
return values;
|
return values;
|
||||||
},
|
},
|
||||||
getter: function () sanitizer.prefNames.filter(function (pref) options.getPref(pref)).map(Sanitizer.prefToArg).join(","),
|
getter: function () sanitizer.prefNames.filter(function (pref) options.getPref(pref)).map(Sanitizer.prefToArg),
|
||||||
completer: function (value) [
|
completer: function (value) [
|
||||||
["cache", "Cache"],
|
["cache", "Cache"],
|
||||||
["commandline", "Command-line history"],
|
["commandline", "Command-line history"],
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -47,6 +48,10 @@ const Services = Module("services", {
|
|||||||
this.addClass("file:", "@mozilla.org/network/protocol;1?name=file", Ci.nsIFileProtocolHandler);
|
this.addClass("file:", "@mozilla.org/network/protocol;1?name=file", Ci.nsIFileProtocolHandler);
|
||||||
this.addClass("find", "@mozilla.org/embedcomp/rangefind;1", Ci.nsIFind);
|
this.addClass("find", "@mozilla.org/embedcomp/rangefind;1", Ci.nsIFind);
|
||||||
this.addClass("process", "@mozilla.org/process/util;1", Ci.nsIProcess);
|
this.addClass("process", "@mozilla.org/process/util;1", Ci.nsIProcess);
|
||||||
|
this.addClass("zipWriter", "@mozilla.org/zipwriter;1", Ci.nsIZipWriter);
|
||||||
|
|
||||||
|
if (!this.get("extensionManager"))
|
||||||
|
Components.utils.import("resource://gre/modules/AddonManager.jsm", modules);
|
||||||
},
|
},
|
||||||
|
|
||||||
_create: function (classes, ifaces, meth) {
|
_create: function (classes, ifaces, meth) {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -11,12 +14,8 @@ const StatusLine = Module("statusline", {
|
|||||||
this._statusBar.collapsed = true; // it is later restored unless the user sets laststatus=0
|
this._statusBar.collapsed = true; // it is later restored unless the user sets laststatus=0
|
||||||
|
|
||||||
// our status bar fields
|
// our status bar fields
|
||||||
this._statuslineWidget = document.getElementById("liberator-statusline");
|
this.widgets = dict(["status", "url", "inputbuffer", "progress", "tabcount", "bufferposition", "zoomlevel"].map(
|
||||||
this._urlWidget = document.getElementById("liberator-statusline-field-url");
|
function (field) [field, document.getElementById("liberator-statusline-field-" + field)]));
|
||||||
this._inputBufferWidget = document.getElementById("liberator-statusline-field-inputbuffer");
|
|
||||||
this._progressWidget = document.getElementById("liberator-statusline-field-progress");
|
|
||||||
this._tabCountWidget = document.getElementById("liberator-statusline-field-tabcount");
|
|
||||||
this._bufferPositionWidget = document.getElementById("liberator-statusline-field-bufferposition");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +46,7 @@ const StatusLine = Module("statusline", {
|
|||||||
this.updateProgress();
|
this.updateProgress();
|
||||||
this.updateTabCount();
|
this.updateTabCount();
|
||||||
this.updateBufferPosition();
|
this.updateBufferPosition();
|
||||||
|
this.updateZoomLevel();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,20 +61,17 @@ const StatusLine = Module("statusline", {
|
|||||||
updateUrl: function updateUrl(url) {
|
updateUrl: function updateUrl(url) {
|
||||||
// ripped from Firefox; modified
|
// ripped from Firefox; modified
|
||||||
function losslessDecodeURI(url) {
|
function losslessDecodeURI(url) {
|
||||||
// Countermeasure for "Error: malformed URI sequence".
|
|
||||||
// This error occurs when URL is encoded by not UTF-8 encoding.
|
|
||||||
function _decodeURI(url) {
|
|
||||||
try {
|
|
||||||
return decodeURI(url);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 1. decodeURI decodes %25 to %, which creates unintended
|
// 1. decodeURI decodes %25 to %, which creates unintended
|
||||||
// encoding sequences.
|
// encoding sequences.
|
||||||
url = url.split("%25").map(_decodeURI).join("%25");
|
url = url.split("%25").map(function (url) {
|
||||||
|
// Non-UTF-8 complient URLs cause "malformed URI sequence" errors.
|
||||||
|
try {
|
||||||
|
return decodeURI(url);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}).join("%25");
|
||||||
// 2. Re-encode whitespace so that it doesn't get eaten away
|
// 2. Re-encode whitespace so that it doesn't get eaten away
|
||||||
// by the location bar (bug 410726).
|
// by the location bar (bug 410726).
|
||||||
url = url.replace(/[\r\n\t]/g, encodeURIComponent);
|
url = url.replace(/[\r\n\t]/g, encodeURIComponent);
|
||||||
@@ -125,7 +122,7 @@ const StatusLine = Module("statusline", {
|
|||||||
if (modified)
|
if (modified)
|
||||||
url += " [" + modified + "]";
|
url += " [" + modified + "]";
|
||||||
|
|
||||||
this._urlWidget.value = url;
|
this.widgets.url.value = url;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +137,7 @@ const StatusLine = Module("statusline", {
|
|||||||
if (!buffer || typeof buffer != "string")
|
if (!buffer || typeof buffer != "string")
|
||||||
buffer = "";
|
buffer = "";
|
||||||
|
|
||||||
this._inputBufferWidget.value = buffer;
|
this.widgets.inputbuffer.value = buffer;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -157,7 +154,7 @@ const StatusLine = Module("statusline", {
|
|||||||
progress = "";
|
progress = "";
|
||||||
|
|
||||||
if (typeof progress == "string")
|
if (typeof progress == "string")
|
||||||
this._progressWidget.value = progress;
|
this.widgets.progress.value = progress;
|
||||||
else if (typeof progress == "number") {
|
else if (typeof progress == "number") {
|
||||||
let progressStr = "";
|
let progressStr = "";
|
||||||
if (progress <= 0)
|
if (progress <= 0)
|
||||||
@@ -170,7 +167,7 @@ const StatusLine = Module("statusline", {
|
|||||||
+ " ".substr(0, 19 - progress)
|
+ " ".substr(0, 19 - progress)
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
this._progressWidget.value = progressStr;
|
this.widgets.progress.value = progressStr;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -194,7 +191,7 @@ const StatusLine = Module("statusline", {
|
|||||||
for (let [i, tab] in util.Array.iteritems(config.browser.mTabs))
|
for (let [i, tab] in util.Array.iteritems(config.browser.mTabs))
|
||||||
tab.setAttribute("ordinal", i + 1);
|
tab.setAttribute("ordinal", i + 1);
|
||||||
|
|
||||||
this._tabCountWidget.value = "[" + (tabs.index() + 1) + "/" + tabs.count + "]";
|
this.widgets.tabcount.value = "[" + (tabs.index() + 1) + "/" + tabs.count + "]";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -205,7 +202,7 @@ const StatusLine = Module("statusline", {
|
|||||||
* @param {number} percent The position, as a percentage. @optional
|
* @param {number} percent The position, as a percentage. @optional
|
||||||
*/
|
*/
|
||||||
updateBufferPosition: function updateBufferPosition(percent) {
|
updateBufferPosition: function updateBufferPosition(percent) {
|
||||||
if (!percent || typeof percent != "number") {
|
if (typeof percent != "number") {
|
||||||
let win = document.commandDispatcher.focusedWindow;
|
let win = document.commandDispatcher.focusedWindow;
|
||||||
if (!win)
|
if (!win)
|
||||||
return;
|
return;
|
||||||
@@ -218,14 +215,35 @@ const StatusLine = Module("statusline", {
|
|||||||
bufferPositionStr = "All";
|
bufferPositionStr = "All";
|
||||||
else if (percent == 0)
|
else if (percent == 0)
|
||||||
bufferPositionStr = "Top";
|
bufferPositionStr = "Top";
|
||||||
else if (percent < 10)
|
|
||||||
bufferPositionStr = " " + percent + "%";
|
|
||||||
else if (percent >= 100)
|
else if (percent >= 100)
|
||||||
bufferPositionStr = "Bot";
|
bufferPositionStr = "Bot";
|
||||||
|
else if (percent < 10)
|
||||||
|
bufferPositionStr = " " + percent + "%";
|
||||||
else
|
else
|
||||||
bufferPositionStr = percent + "%";
|
bufferPositionStr = percent + "%";
|
||||||
|
|
||||||
this._bufferPositionWidget.value = bufferPositionStr;
|
this.widgets.bufferposition.value = bufferPositionStr;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the main content's zoom level.
|
||||||
|
*
|
||||||
|
* @param {number} percent The zoom level, as a percentage. @optional
|
||||||
|
* @param {boolean} full True if full zoom is in operation. @optional
|
||||||
|
*/
|
||||||
|
updateZoomLevel: function updateZoomLevel(percent, full) {
|
||||||
|
if (arguments.length == 0)
|
||||||
|
[percent, full] = [buffer.zoomLevel, buffer.fullZoom];
|
||||||
|
|
||||||
|
if (percent == 100)
|
||||||
|
this.widgets.zoomlevel.value = "";
|
||||||
|
else {
|
||||||
|
percent = (" " + percent).substr(-3);
|
||||||
|
if (full)
|
||||||
|
this.widgets.zoomlevel.value = " [" + percent + "%]";
|
||||||
|
else
|
||||||
|
this.widgets.zoomlevel.value = " (" + percent + "%)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -167,6 +168,8 @@ Highlights.prototype.CSS = <![CDATA[
|
|||||||
HelpString display: inline-block; color: green; font-weight: normal; vertical-align: text-top;
|
HelpString display: inline-block; color: green; font-weight: normal; vertical-align: text-top;
|
||||||
HelpString::before content: '"';
|
HelpString::before content: '"';
|
||||||
HelpString::after content: '"';
|
HelpString::after content: '"';
|
||||||
|
HelpString[delim]::before content: attr(delim);
|
||||||
|
HelpString[delim]::after content: attr(delim);
|
||||||
|
|
||||||
HelpHead,html|h1,liberator://help/* {
|
HelpHead,html|h1,liberator://help/* {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -699,10 +702,10 @@ Module("styles", {
|
|||||||
JavaScript.setCompleter(["get", "addSheet", "removeSheet", "findSheets"].map(function (m) styles[m]),
|
JavaScript.setCompleter(["get", "addSheet", "removeSheet", "findSheets"].map(function (m) styles[m]),
|
||||||
[ // Prototype: (system, name, filter, css, index)
|
[ // Prototype: (system, name, filter, css, index)
|
||||||
null,
|
null,
|
||||||
function (context, obj, args) args[0] ? styles.systemNames : styles.userNames,
|
function (context, obj, args) args[0] ? this.systemNames : this.userNames,
|
||||||
function (context, obj, args) styles.completeSite(context, content),
|
function (context, obj, args) this.completeSite(context, content),
|
||||||
null,
|
null,
|
||||||
function (context, obj, args) args[0] ? styles.systemSheets : styles.userSheets
|
function (context, obj, args) args[0] ? this.systemSheets : this.userSheets
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -797,14 +797,7 @@ const Tabs = Module("tabs", {
|
|||||||
commands.add(["tabopen", "t[open]", "tabnew"],
|
commands.add(["tabopen", "t[open]", "tabnew"],
|
||||||
"Open one or more URLs in a new tab",
|
"Open one or more URLs in a new tab",
|
||||||
function (args) {
|
function (args) {
|
||||||
let special = args.bang;
|
liberator.open(args.string || "about:blank", { from: "tabopen", where: liberator.NEW_TAB, background: args.bang });
|
||||||
args = args.string;
|
|
||||||
|
|
||||||
let where = special ? liberator.NEW_TAB : liberator.NEW_BACKGROUND_TAB;
|
|
||||||
if (args)
|
|
||||||
liberator.open(args, { from: "tabopen", where: where });
|
|
||||||
else
|
|
||||||
liberator.open("about:blank", { from: "tabopen", where: where });
|
|
||||||
}, {
|
}, {
|
||||||
bang: true,
|
bang: true,
|
||||||
completer: function (context) completion.url(context),
|
completer: function (context) completion.url(context),
|
||||||
@@ -1094,9 +1087,9 @@ const Tabs = Module("tabs", {
|
|||||||
"Where to show requested popup windows",
|
"Where to show requested popup windows",
|
||||||
"stringlist", "tab",
|
"stringlist", "tab",
|
||||||
{
|
{
|
||||||
setter: function (value) {
|
setter: function (values) {
|
||||||
let [open, restriction] = [1, 0];
|
let [open, restriction] = [1, 0];
|
||||||
for (let [, opt] in Iterator(this.parseValues(value))) {
|
for (let [, opt] in Iterator(values)) {
|
||||||
if (opt == "tab")
|
if (opt == "tab")
|
||||||
open = 3;
|
open = 3;
|
||||||
else if (opt == "window")
|
else if (opt == "window")
|
||||||
@@ -1107,7 +1100,7 @@ const Tabs = Module("tabs", {
|
|||||||
|
|
||||||
options.safeSetPref("browser.link.open_newwindow", open, "See 'popups' option.");
|
options.safeSetPref("browser.link.open_newwindow", open, "See 'popups' option.");
|
||||||
options.safeSetPref("browser.link.open_newwindow.restriction", restriction, "See 'popups' option.");
|
options.safeSetPref("browser.link.open_newwindow.restriction", restriction, "See 'popups' option.");
|
||||||
return value;
|
return values;
|
||||||
},
|
},
|
||||||
completer: function (context) [
|
completer: function (context) [
|
||||||
["tab", "Open popups in a new tab"],
|
["tab", "Open popups in a new tab"],
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2006-2009 by Kris Maglione <maglione.k at Gmail>
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -194,8 +194,6 @@ const Template = Module("template", {
|
|||||||
return <>:{commandline.command}<br/>{xml}</>;
|
return <>:{commandline.command}<br/>{xml}</>;
|
||||||
},
|
},
|
||||||
|
|
||||||
// every item must have a .xml property which defines how to draw itself
|
|
||||||
// @param headers is an array of strings, the text for the header columns
|
|
||||||
genericTable: function genericTable(items, format) {
|
genericTable: function genericTable(items, format) {
|
||||||
completion.listCompleter(function (context) {
|
completion.listCompleter(function (context) {
|
||||||
context.filterFunc = null;
|
context.filterFunc = null;
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||||
|
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
|
||||||
|
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
|
||||||
//
|
//
|
||||||
// This work is licensed for reuse under an MIT license. Details are
|
// This work is licensed for reuse under an MIT license. Details are
|
||||||
// given in the LICENSE.txt file included with this file.
|
// given in the LICENSE.txt file included with this file.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
@@ -91,6 +94,55 @@ const Util = Module("util", {
|
|||||||
return fixup.createFixupURI(str, fixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP);
|
return fixup.createFixupURI(str, fixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands brace globbing patterns in a string.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* "a{b,c}d" => ["abd", "acd"]
|
||||||
|
*
|
||||||
|
* @param {string} pattern The pattern to deglob.
|
||||||
|
* @returns [string] The resulting strings.
|
||||||
|
*/
|
||||||
|
debrace: function deglobBrace(pattern) {
|
||||||
|
function split(pattern, re, fn, dequote) {
|
||||||
|
let end = 0, match, res = [];
|
||||||
|
while (match = re.exec(pattern)) {
|
||||||
|
end = match.index + match[0].length;
|
||||||
|
res.push(match[1]);
|
||||||
|
if (fn)
|
||||||
|
fn(match);
|
||||||
|
}
|
||||||
|
res.push(pattern.substr(end));
|
||||||
|
return res.map(function (s) util.dequote(s, dequote));
|
||||||
|
}
|
||||||
|
let patterns = [], res = [];
|
||||||
|
let substrings = split(pattern, /((?:[^\\{]|\\.)*)\{((?:[^\\}]|\\.)*)\}/gy,
|
||||||
|
function (match) {
|
||||||
|
patterns.push(split(match[2], /((?:[^\\,]|\\.)*),/gy,
|
||||||
|
null, ",{}"));
|
||||||
|
}, "{}");
|
||||||
|
function rec(acc) {
|
||||||
|
if (acc.length == patterns.length)
|
||||||
|
res.push(util.Array.zip(substrings, acc).join(""));
|
||||||
|
else
|
||||||
|
for (let [, pattern] in Iterator(patterns[acc.length]))
|
||||||
|
rec(acc.concat(pattern));
|
||||||
|
}
|
||||||
|
rec([]);
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes certain backslash-quoted characters while leaving other
|
||||||
|
* backslash-quoting sequences untouched.
|
||||||
|
*
|
||||||
|
* @param {string} pattern The string to unquote.
|
||||||
|
* @param {string} chars The characters to unquote.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
dequote: function dequote(pattern, chars)
|
||||||
|
pattern.replace(/\\(.)/, function (m0, m1) chars.indexOf(m1) >= 0 ? m1 : m0),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts HTML special characters in <b>str</b> to the equivalent HTML
|
* Converts HTML special characters in <b>str</b> to the equivalent HTML
|
||||||
* entities.
|
* entities.
|
||||||
@@ -158,7 +210,8 @@ const Util = Module("util", {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
makeXPath: function makeXPath(nodes) {
|
makeXPath: function makeXPath(nodes) {
|
||||||
return util.Array(nodes).map(function (node) [node, "xhtml:" + node]).flatten()
|
return util.Array(nodes).map(util.debrace).flatten()
|
||||||
|
.map(function (node) [node, "xhtml:" + node]).flatten()
|
||||||
.map(function (node) "//" + node).join(" | ");
|
.map(function (node) "//" + node).join(" | ");
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -257,8 +310,9 @@ const Util = Module("util", {
|
|||||||
const PATH = FILE.leafName.replace(/\..*/, "") + "/";
|
const PATH = FILE.leafName.replace(/\..*/, "") + "/";
|
||||||
const TIME = Date.now();
|
const TIME = Date.now();
|
||||||
|
|
||||||
|
liberator.initHelp();
|
||||||
let zip = services.create("zipWriter");
|
let zip = services.create("zipWriter");
|
||||||
zip.open(FILE, io.MODE_CREATE | io.MODE_WRONLY | io.MODE_TRUNCATE);
|
zip.open(FILE, File.MODE_CREATE | File.MODE_WRONLY | File.MODE_TRUNCATE);
|
||||||
function addURIEntry(file, uri)
|
function addURIEntry(file, uri)
|
||||||
zip.addEntryChannel(PATH + file, TIME, 9,
|
zip.addEntryChannel(PATH + file, TIME, 9,
|
||||||
services.get("io").newChannel(uri, null, null), false);
|
services.get("io").newChannel(uri, null, null), false);
|
||||||
@@ -407,11 +461,12 @@ const Util = Module("util", {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
result.__iterator__ = asIterator
|
return {
|
||||||
|
__proto__: result,
|
||||||
|
__iterator__: asIterator
|
||||||
? function () { let elem; while ((elem = this.iterateNext())) yield elem; }
|
? function () { let elem; while ((elem = this.iterateNext())) yield elem; }
|
||||||
: function () { for (let i = 0; i < this.snapshotLength; i++) yield this.snapshotItem(i); };
|
: function () { for (let i = 0; i < this.snapshotLength; i++) yield this.snapshotItem(i); }
|
||||||
|
}
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -664,61 +719,16 @@ const Util = Module("util", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of URLs parsed from <b>str</b>.
|
* Scrolls an element into view if and only if it's not already
|
||||||
|
* fully visible.
|
||||||
*
|
*
|
||||||
* Given a string like 'google bla, www.osnews.com' return an array
|
* @param {Node} elem The element to make visible.
|
||||||
* ['www.google.com/search?q=bla', 'www.osnews.com']
|
|
||||||
*
|
|
||||||
* @param {string} str
|
|
||||||
* @returns {string[]}
|
|
||||||
*/
|
*/
|
||||||
stringToURLArray: function stringToURLArray(str) {
|
scrollIntoView: function scrollIntoView(elem) {
|
||||||
let urls;
|
let win = elem.ownerDocument.defaultView;
|
||||||
|
let rect = elem.getBoundingClientRect();
|
||||||
if (options["urlseparator"])
|
if (!(rect && rect.top < win.innerHeight && rect.bottom >= 0 && rect.left < win.innerWidth && rect.right >= 0))
|
||||||
urls = util.splitLiteral(str, RegExp("\\s*" + options["urlseparator"] + "\\s*"));
|
elem.scrollIntoView();
|
||||||
else
|
|
||||||
urls = [str];
|
|
||||||
|
|
||||||
return urls.map(function (url) {
|
|
||||||
if (url.substr(0, 5) != "file:") {
|
|
||||||
try {
|
|
||||||
// Try to find a matching file.
|
|
||||||
let file = io.File(url);
|
|
||||||
if (file.exists() && file.isReadable())
|
|
||||||
return services.get("io").newFileURI(file).spec;
|
|
||||||
}
|
|
||||||
catch (e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// strip each 'URL' - makes things simpler later on
|
|
||||||
url = url.replace(/^\s+|\s+$/, "");
|
|
||||||
|
|
||||||
// Look for a valid protocol
|
|
||||||
let proto = url.match(/^([-\w]+):/);
|
|
||||||
if (proto && Cc["@mozilla.org/network/protocol;1?name=" + proto[1]])
|
|
||||||
// Handle as URL, but remove spaces. Useful for copied/'p'asted URLs.
|
|
||||||
return url.replace(/\s*\n+\s*/g, "");
|
|
||||||
|
|
||||||
// Ok, not a valid proto. If it looks like URL-ish (foo.com/bar),
|
|
||||||
// let Gecko figure it out.
|
|
||||||
if (/[.\/]/.test(url) && !/\s/.test(url) || /^[\w-.]+:\d+(?:\/|$)/.test(url))
|
|
||||||
return url;
|
|
||||||
|
|
||||||
// TODO: it would be clearer if the appropriate call to
|
|
||||||
// getSearchURL was made based on whether or not the first word was
|
|
||||||
// indeed an SE alias rather than seeing if getSearchURL can
|
|
||||||
// process the call usefully and trying again if it fails
|
|
||||||
|
|
||||||
// check for a search engine match in the string, then try to
|
|
||||||
// search for the whole string in the default engine
|
|
||||||
let searchURL = bookmarks.getSearchURL(url, false) || bookmarks.getSearchURL(url, true);
|
|
||||||
if (searchURL)
|
|
||||||
return searchURL;
|
|
||||||
|
|
||||||
// Hmm. No defsearch? Let the host app deal with it, then.
|
|
||||||
return url;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -740,7 +750,7 @@ const Util = Module("util", {
|
|||||||
}
|
}
|
||||||
switch (node.nodeKind()) {
|
switch (node.nodeKind()) {
|
||||||
case "text":
|
case "text":
|
||||||
return doc.createTextNode(node);
|
return doc.createTextNode(String(node));
|
||||||
case "element":
|
case "element":
|
||||||
let domnode = doc.createElementNS(node.namespace(), node.localName());
|
let domnode = doc.createElementNS(node.namespace(), node.localName());
|
||||||
for each (let attr in node.@*)
|
for each (let attr in node.@*)
|
||||||
@@ -814,7 +824,7 @@ const Util = Module("util", {
|
|||||||
* @param {Array} ary
|
* @param {Array} ary
|
||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
flatten: function flatten(ary) Array.concat.apply([], ary),
|
flatten: function flatten(ary) ary.length ? Array.concat.apply([], ary) : [],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an Iterator for an array's values.
|
* Returns an Iterator for an array's values.
|
||||||
@@ -864,6 +874,22 @@ const Util = Module("util", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zips the contents of two arrays. The resulting array is twice the
|
||||||
|
* length of ary1, with any shortcomings of ary2 replaced with null
|
||||||
|
* strings.
|
||||||
|
*
|
||||||
|
* @param {Array} ary1
|
||||||
|
* @param {Array} ary2
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
zip: function zip(ary1, ary2) {
|
||||||
|
let res = []
|
||||||
|
for(let [i, item] in Iterator(ary1))
|
||||||
|
res.push(item, i in ary2 ? ary2[i] : "");
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -417,8 +417,8 @@ preference.
|
|||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>zI</tags>
|
<tags>ZI zI</tags>
|
||||||
<spec><oa>count</oa>zI</spec>
|
<spec><oa>count</oa>ZI</spec>
|
||||||
<description>
|
<description>
|
||||||
<p>Enlarge full zoom of current web page. Mnemonic: zoom in.</p>
|
<p>Enlarge full zoom of current web page. Mnemonic: zoom in.</p>
|
||||||
</description>
|
</description>
|
||||||
@@ -426,8 +426,8 @@ preference.
|
|||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>zM</tags>
|
<tags>ZM zM</tags>
|
||||||
<spec><oa>count</oa>zM</spec>
|
<spec><oa>count</oa>ZM</spec>
|
||||||
<description>
|
<description>
|
||||||
<p>Enlarge full zoom of current web page by a larger amount. Mnemonic: zoom more.</p>
|
<p>Enlarge full zoom of current web page by a larger amount. Mnemonic: zoom more.</p>
|
||||||
</description>
|
</description>
|
||||||
@@ -435,8 +435,8 @@ preference.
|
|||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>zO</tags>
|
<tags>ZO zO</tags>
|
||||||
<spec><oa>count</oa>zO</spec>
|
<spec><oa>count</oa>ZO</spec>
|
||||||
<description>
|
<description>
|
||||||
<p>Reduce full zoom of current web page. Mnemonic: zoom out.</p>
|
<p>Reduce full zoom of current web page. Mnemonic: zoom out.</p>
|
||||||
</description>
|
</description>
|
||||||
@@ -444,8 +444,8 @@ preference.
|
|||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>zR</tags>
|
<tags>ZR zR</tags>
|
||||||
<spec><oa>count</oa>zR</spec>
|
<spec><oa>count</oa>ZR</spec>
|
||||||
<description>
|
<description>
|
||||||
<p>Reduce full zoom of current web page by a larger amount. Mnemonic: zoom reduce.</p>
|
<p>Reduce full zoom of current web page by a larger amount. Mnemonic: zoom reduce.</p>
|
||||||
</description>
|
</description>
|
||||||
@@ -453,8 +453,8 @@ preference.
|
|||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>zZ</tags>
|
<tags>ZZ zZ</tags>
|
||||||
<spec><oa>count</oa>zZ</spec>
|
<spec><oa>count</oa>ZZ</spec>
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Set full zoom value of current web page. Zoom value can be between 30 and
|
Set full zoom value of current web page. Zoom value can be between 30 and
|
||||||
|
|||||||
@@ -151,8 +151,9 @@
|
|||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>:extens :extensions</tags>
|
<tags>:exts :extens :extensions</tags>
|
||||||
<spec>:extens<oa>ions</oa></spec>
|
<spec>:extens<oa>ions</oa></spec>
|
||||||
|
<spec>:exts</spec>
|
||||||
<description>
|
<description>
|
||||||
<p>List all installed extensions.</p>
|
<p>List all installed extensions.</p>
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -393,7 +393,6 @@ This file contains a list of all available commands, mappings and options.
|
|||||||
<dt><o>exrc</o></dt> <dd>Allow reading of an RC file in the current directory</dd>
|
<dt><o>exrc</o></dt> <dd>Allow reading of an RC file in the current directory</dd>
|
||||||
<dt><o>extendedhinttags</o></dt> <dd>XPath string of hintable elements activated by <k>;</k></dd>
|
<dt><o>extendedhinttags</o></dt> <dd>XPath string of hintable elements activated by <k>;</k></dd>
|
||||||
<dt><o>fileencoding</o></dt> <dd>Changes the character encoding that &liberator.appname; uses to read and write files</dd>
|
<dt><o>fileencoding</o></dt> <dd>Changes the character encoding that &liberator.appname; uses to read and write files</dd>
|
||||||
<dt><o>focuscontent</o></dt> <dd>Try to stay in Normal mode after loading a web page</dd>
|
|
||||||
<dt><o>followhints</o></dt> <dd>Change the behaviour of <k name="Return"/> in Hints mode</dd>
|
<dt><o>followhints</o></dt> <dd>Change the behaviour of <k name="Return"/> in Hints mode</dd>
|
||||||
<dt><o>fullscreen</o></dt> <dd>Show the current window fullscreen</dd>
|
<dt><o>fullscreen</o></dt> <dd>Show the current window fullscreen</dd>
|
||||||
<dt><o>guioptions</o></dt> <dd>Show or hide certain GUI elements like the menu or toolbar</dd>
|
<dt><o>guioptions</o></dt> <dd>Show or hide certain GUI elements like the menu or toolbar</dd>
|
||||||
@@ -430,6 +429,7 @@ This file contains a list of all available commands, mappings and options.
|
|||||||
<dt><o>showstatuslinks</o></dt> <dd>Show the destination of the link under the cursor in the status bar</dd>
|
<dt><o>showstatuslinks</o></dt> <dd>Show the destination of the link under the cursor in the status bar</dd>
|
||||||
<dt><o>showtabline</o></dt> <dd>Control when to show the tab bar of opened web pages</dd>
|
<dt><o>showtabline</o></dt> <dd>Control when to show the tab bar of opened web pages</dd>
|
||||||
<dt><o>smartcase</o></dt> <dd>Override the <o>ignorecase</o> option if the pattern contains uppercase characters</dd>
|
<dt><o>smartcase</o></dt> <dd>Override the <o>ignorecase</o> option if the pattern contains uppercase characters</dd>
|
||||||
|
<dt><o>strictfocus</o></dt> <dd>Prevent scripts from focusing input elements without user intervention</dd>
|
||||||
<dt><o>suggestengines</o></dt> <dd>Engine Alias which has a feature of suggest</dd>
|
<dt><o>suggestengines</o></dt> <dd>Engine Alias which has a feature of suggest</dd>
|
||||||
<dt><o>titlestring</o></dt> <dd>Change the title of the window</dd>
|
<dt><o>titlestring</o></dt> <dd>Change the title of the window</dd>
|
||||||
<dt><o>urlseparator</o></dt> <dd>Set the separator regex used to separate multiple URL args</dd>
|
<dt><o>urlseparator</o></dt> <dd>Set the separator regex used to separate multiple URL args</dd>
|
||||||
|
|||||||
@@ -17,11 +17,27 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>boolean</dt> <dd>can only be on or off</dd>
|
<dt>boolean</dt> <dd>Can only be on or off</dd>
|
||||||
<dt>number</dt> <dd>has a numeric value</dd>
|
<dt>number</dt> <dd>A numeric value</dd>
|
||||||
<dt>string</dt> <dd>has a string value</dd>
|
<dt>string</dt> <dd>A string value</dd>
|
||||||
<dt>charlist</dt> <dd>like a string but with unique characters</dd>
|
<dt>charlist</dt> <dd>A string containing a discrete set of distinct characters</dd>
|
||||||
<dt>stringlist</dt> <dd>a comma-separated list of strings</dd>
|
<dt>stringlist</dt> <dd>A comma-separated list of strings</dd>
|
||||||
|
<dt>stringmap</dt> <dd>A comma-separated list of key-value pairs, e.g., <str>key=val,foo=bar</str></dd>
|
||||||
|
<dt>regexlist</dt>
|
||||||
|
<dd>
|
||||||
|
A comma-separated list of regular expressions. Expressions may be
|
||||||
|
prefixed with a <em>!</em>, in which case the match will be negated. A
|
||||||
|
literal <em>!</em> at the begining of the expression may be matched with
|
||||||
|
<em>[!]</em>. Generally, the first matching regular expression is used.
|
||||||
|
</dd>
|
||||||
|
<dt>regexmap</dt>
|
||||||
|
<dd>
|
||||||
|
A combination of a <em>stringmap</em> and a <em>regexlist</em>. Each key
|
||||||
|
in the <a>key</a>=<a>value</a> pair is a regexp. If the regexp begins with a
|
||||||
|
<em>!</em>, the sense match is negated, such that a non-matching
|
||||||
|
expression will be considered a match and <html:i>vice versa</html:i>.
|
||||||
|
The first <a>key</a> to match yields value.
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h2 tag="set-option E764">Setting options</h2>
|
<h2 tag="set-option E764">Setting options</h2>
|
||||||
@@ -293,6 +309,40 @@
|
|||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<tags>'au' 'autocomplete'</tags>
|
||||||
|
<spec>'autocomplete' 'au'</spec>
|
||||||
|
<type>regexlist</type>
|
||||||
|
<default>.*</default>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
A list of regexps defining which completion contexts should be
|
||||||
|
autocompleted. When the value is non-empty, the completion list is
|
||||||
|
automatically opened along with the commandline. Thereafter, any key
|
||||||
|
press triggers a completion update for the matching contexts.
|
||||||
|
Non-matching contexts will only be updated when the tab key is
|
||||||
|
pressed. This option is useful for disabling autocompletion for
|
||||||
|
computationally intense contexts that don't perform well on your
|
||||||
|
system under load.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
To enable autocompletion for everything but <ex>:history</ex> or
|
||||||
|
<ex>:bmarks</ex>, you would choose a value such as,
|
||||||
|
<str delim="'">!/ex/bmarks,.?</str>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
Completion contexts have names very much like Unix path names. This
|
||||||
|
denotes the tree in which they're called. A completer will never be
|
||||||
|
called unless every completer preceding it in the tree was also
|
||||||
|
called. For example, if your completer excludes <str>/ex/</str>, it
|
||||||
|
will also exclude <str>/ex/bmarks</str>, and so on.
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<p>See also <ex>:contexts</ex></p>
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>$CDPATH</tags>
|
<tags>$CDPATH</tags>
|
||||||
@@ -469,19 +519,14 @@
|
|||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'nofc' 'nofocuscontent'</tags>
|
<tags>'nosf' 'nostrictfocus'</tags>
|
||||||
<tags>'fc' 'focuscontent'</tags>
|
<tags>'sf' 'strictfocus'</tags>
|
||||||
<spec>'focuscontent' 'fc'</spec>
|
<spec>'strictfocus' 'sf'</spec>
|
||||||
<type>boolean</type>
|
<type>boolean</type>
|
||||||
<default>off</default>
|
<default>on</default>
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Focus the content after a page has loaded. This is useful if you
|
Prevent scripts from focusing input elements without user intervention.
|
||||||
always want to stay in Normal mode when browsing between web sites.
|
|
||||||
When <str>on</str>, it blurs any textbox which often is
|
|
||||||
automatically focused on page load. If you usually like
|
|
||||||
<o>focuscontent</o> but sometimes you'd like to focus the first
|
|
||||||
input field, you can use <k>gi</k> to jump to it.
|
|
||||||
</p>
|
</p>
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
@@ -1249,41 +1294,50 @@
|
|||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'wildcase' 'wic'</tags>
|
<tags>'wic' 'wildcase'</tags>
|
||||||
<spec>'wildcase' 'wic'</spec>
|
<spec>'wildcase' 'wic'</spec>
|
||||||
<type>string</type>
|
<type>regexmap</type>
|
||||||
<default>smart</default>
|
<default>smart</default>
|
||||||
<description>
|
<description>
|
||||||
<p>Defines how completions are matched with regard to character case. Possible values:</p>
|
<p>
|
||||||
|
Defines how completions are matched for a given completion context
|
||||||
|
with regard to character case.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Possible values:</p>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt><str>smart</str></dt> <dd>Case is significant when capital letters are typed</dd>
|
<dt><str>smart</str></dt> <dd>Case is significant when capital letters are typed</dd>
|
||||||
<dt><str>match</str></dt> <dd>Case is always significant</dd>
|
<dt><str>match</str></dt> <dd>Case is always significant</dd>
|
||||||
<dt><str>ignore</str></dt> <dd>Case is never significant</dd>
|
<dt><str>ignore</str></dt> <dd>Case is never significant</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
<p>See also <ex>:contexts</ex></p>
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'wildignore' 'wig'</tags>
|
<tags>'wildignore' 'wig'</tags>
|
||||||
<spec>'wildignore' 'wig'</spec>
|
<spec>'wildignore' 'wig'</spec>
|
||||||
<type>stringlist</type>
|
<type>regexlist</type>
|
||||||
<default></default>
|
<default></default>
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
List of file patterns to ignore when completing files. E.g., to ignore object
|
List of file patterns to ignore when completing files. E.g., to ignore object
|
||||||
files and Vim swap files
|
files and Vim swap files
|
||||||
<ex>:set wildignore=<str>.<em>\\.o,\\..</em>\\.s[a-z]\\<a>2</a></str></ex>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<code><ex>:set wildignore=<str delim="'">\.o$</str>,<str delim="'">^\..*\.s[a-z]<a>2</a>$</str></ex></code>
|
||||||
|
|
||||||
<note>Unlike Vim each pattern is a regex rather than a glob.</note>
|
<note>Unlike Vim each pattern is a regex rather than a glob.</note>
|
||||||
|
<note>
|
||||||
|
The only way to include a literal comma in a pattern is with the
|
||||||
|
escape <str>\u0044</str>.
|
||||||
|
</note>
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'wim' 'wildmode'</tags>
|
<tags>'wim' 'wildmode'</tags>
|
||||||
<spec>'wildmode' 'wim'</spec>
|
<spec>'wildmode' 'wim'</spec>
|
||||||
@@ -1318,25 +1372,23 @@
|
|||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'wop' 'wildoptions'</tags>
|
<tags>'wis' 'wildsort'</tags>
|
||||||
<spec>'wildoptions' 'wop'</spec>
|
<spec>'wildsort' 'wis'</spec>
|
||||||
<type>stringlist</type>
|
<type>regexlist</type>
|
||||||
<default></default>
|
<default>.*</default>
|
||||||
<description>
|
<description>
|
||||||
<p>A list of words that change how command-line completion is done.</p>
|
<p>
|
||||||
|
A list of regexps defining which completion contexts
|
||||||
|
should be sorted. The main purpose of this option is to
|
||||||
|
prevent sorting of certain completion lists that don't
|
||||||
|
perform well under load.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>Possible words:</p>
|
<p>See also <ex>:contexts</ex></p>
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>auto</dt> <dd>Automatically show completions while you are typing.</dd>
|
|
||||||
<dt>sort</dt> <dd>Always sort the completion list, overriding the <o>complete</o> option.</dd>
|
|
||||||
</dl>
|
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'wsp' 'wordseparators'</tags>
|
<tags>'wsp' 'wordseparators'</tags>
|
||||||
<spec>'wordseparators' 'wsp'</spec>
|
<spec>'wordseparators' 'wsp'</spec>
|
||||||
|
|||||||
@@ -17,16 +17,27 @@
|
|||||||
<tags>:beep</tags>
|
<tags>:beep</tags>
|
||||||
<spec>:beep</spec>
|
<spec>:beep</spec>
|
||||||
<description>
|
<description>
|
||||||
<p>Play a system beep.</p>
|
<p>
|
||||||
|
Play a system beep. This should not be used for any purpose other
|
||||||
|
than testing the visual bell.
|
||||||
|
</p>
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags><![CDATA[<C-l> CTRL-L :redr :redraw]]></tags>
|
<tags>:contexts</tags>
|
||||||
<spec>:redr<oa>aw</oa></spec>
|
<spec>:contexts <a>ex-command</a></spec>
|
||||||
<description>
|
<description>
|
||||||
<p>Redraws the screen. Useful to update the screen halfway executing a script or function.</p>
|
<p>
|
||||||
|
Lists the completion contexts used during the completion of its
|
||||||
|
arguments. These context names are used in options such as
|
||||||
|
<o>autocomplete</o> and <o>wildcase</o>. Note that completion must
|
||||||
|
be triggered in order for this command to be effective, so if
|
||||||
|
autocompletion is not active, you'll need to press the
|
||||||
|
<k name="Tab"/> key at least once. You should also be aware that
|
||||||
|
this command is only useful from the commandline.
|
||||||
|
</p>
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
@@ -46,6 +57,15 @@
|
|||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<tags><![CDATA[<C-l> CTRL-L :redr :redraw]]></tags>
|
||||||
|
<spec>:redr<oa>aw</oa></spec>
|
||||||
|
<description>
|
||||||
|
<p>Redraws the screen. Useful to update the screen halfway executing a script or function.</p>
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>:run :! :!cmd</tags>
|
<tags>:run :! :!cmd</tags>
|
||||||
<spec>:!<a>cmd</a></spec>
|
<spec>:!<a>cmd</a></spec>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ getfiles () {
|
|||||||
find "$@" -not -path '*\.hg*' 2>/dev/null | grep -E "$filter" || true
|
find "$@" -not -path '*\.hg*' 2>/dev/null | grep -E "$filter" || true
|
||||||
}
|
}
|
||||||
copytext () {
|
copytext () {
|
||||||
sed -e "s,###VERSION###,$VERSION,g" \
|
sed -e "s,@VERSION@,$VERSION,g" \
|
||||||
-e "s,###DATE###,$BUILD_DATE,g" \
|
-e "s,@DATE@,$BUILD_DATE,g" \
|
||||||
<"$1" >"$2"
|
<"$1" >"$2"
|
||||||
cmp -s "$1" "$2" ||
|
cmp -s "$1" "$2" ||
|
||||||
( echo "modified: $1"; diff -u "$1" "$2" | grep '^[-+][^-+]' )
|
( echo "modified: $1"; diff -u "$1" "$2" | grep '^[-+][^-+]' )
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
DEALINGS IN THE SOFTWARE.
|
DEALINGS IN THE SOFTWARE.
|
||||||
}}} ***** END LICENSE BLOCK *****/
|
}}} ***** END LICENSE BLOCK *****/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["storage", "Timer"];
|
var EXPORTED_SYMBOLS = ["storage", "Timer"];
|
||||||
|
|
||||||
@@ -102,12 +103,12 @@ function readFile(file) {
|
|||||||
|
|
||||||
function writeFile(file, data) {
|
function writeFile(file, data) {
|
||||||
if (!file.exists())
|
if (!file.exists())
|
||||||
file.create(file.NORMAL_FILE_TYPE, 0600);
|
file.create(file.NORMAL_FILE_TYPE, parseInt('0600', 8));
|
||||||
|
|
||||||
let fileStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
|
let fileStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
|
||||||
let stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
|
let stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
|
||||||
|
|
||||||
fileStream.init(file, 0x20 | 0x08 | 0x02, 0600, 0); // PR_TRUNCATE | PR_CREATE | PR_WRITE
|
fileStream.init(file, 0x20 | 0x08 | 0x02, parseInt('0600', 8), 0); // PR_TRUNCATE | PR_CREATE | PR_WRITE
|
||||||
stream.init(fileStream, "UTF-8", 0, 0);
|
stream.init(fileStream, "UTF-8", 0, 0);
|
||||||
|
|
||||||
stream.writeString(data);
|
stream.writeString(data);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@namespace liberator url("http://vimperator.org/namespaces/liberator");
|
@namespace liberator url("http://vimperator.org/namespaces/liberator");
|
||||||
|
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||||
|
|
||||||
/* Applied to all content */
|
/* Applied to all content */
|
||||||
[liberator|activeframe] {
|
[liberator|activeframe] {
|
||||||
@@ -122,6 +123,12 @@ statusbarpanel {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
#liberator-commandline-command html|*:focus {
|
||||||
|
outline-width: 0px !important
|
||||||
|
}
|
||||||
|
#liberator-commandline-command .textbox-search-icons {
|
||||||
|
visibility: collapse !important;
|
||||||
|
}
|
||||||
#liberator-message {
|
#liberator-message {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
2009-XX-XX:
|
2009-XX-XX:
|
||||||
* version 2.3a1pre
|
* Replaced 'focuscontent' with 'strictfocus'
|
||||||
* add basic plugin authorship documentation
|
* Replaced previous incremental search implementation
|
||||||
* plugins may now provide full-fleged ':help' documentation
|
* :open now only opens files begining with / or ./
|
||||||
* asciidoc is no longer required to build Vimperator
|
* Page zoom information is now shown in the status bar
|
||||||
* the help system is newly modularized
|
* Added ZO, ZI, ZM, and ZR as aliases for zO, zI, zM, and zR
|
||||||
* remove [c]:edit[c], [c]:tabedit[c], and [c]:winedit[c]
|
* Add basic plugin authorship documentation
|
||||||
* add 'jsdebugger' option - switch on/off javascript debugger service
|
* Plugins may now provide full-fleged ':help' documentation
|
||||||
* add "addons", "downloads", "extoptions" and "help" to the 'activate' option.
|
* The help system is newly modularized
|
||||||
|
* Asciidoc is no longer for building
|
||||||
|
* Remove [c]:edit[c], [c]:tabedit[c], and [c]:winedit[c]
|
||||||
|
* Add 'jsdebugger' option - switch on/off javascript debugger service
|
||||||
|
* Add "addons", "downloads", "extoptions" and "help" to the 'activate' option.
|
||||||
|
|
||||||
2009-10-28:
|
2009-10-28:
|
||||||
* version 2.2
|
* version 2.2
|
||||||
@@ -27,8 +31,6 @@
|
|||||||
...................................
|
...................................
|
||||||
* IMPORTANT: shifted key notation now matches Vim's behaviour. E.g. <C-a>
|
* IMPORTANT: shifted key notation now matches Vim's behaviour. E.g. <C-a>
|
||||||
and <C-A> are equivalent, to map the uppercase character use <C-S-A>.
|
and <C-A> are equivalent, to map the uppercase character use <C-S-A>.
|
||||||
(this might change again, as this is REALLY inconsistent, and i don't
|
|
||||||
know if I like copying bugs)
|
|
||||||
* IMPORTANT: 'popups' now takes a stringlist rather than a number.
|
* IMPORTANT: 'popups' now takes a stringlist rather than a number.
|
||||||
|
|
||||||
* add [c]:winonly[c]
|
* add [c]:winonly[c]
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ BUGS:
|
|||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
8 Document Textarea, Caret and Visual modes.
|
8 Document Textarea, Caret and Visual modes.
|
||||||
8 Incremental searches should retreat to their starting position on <Backspace>
|
|
||||||
8 Replace config.name tests in liberator with more specific feature
|
8 Replace config.name tests in liberator with more specific feature
|
||||||
tests or overridable APIs where at all feasible.
|
tests or overridable APIs where at all feasible.
|
||||||
8 change the extension ID to vimperator@vimperator.org rather than
|
8 change the extension ID to vimperator@vimperator.org rather than
|
||||||
@@ -65,25 +64,11 @@ FEATURES:
|
|||||||
8 :redir and 'verbosefile'
|
8 :redir and 'verbosefile'
|
||||||
8 middleclick in content == p, and if command line is open, paste there the clipboard buffer
|
8 middleclick in content == p, and if command line is open, paste there the clipboard buffer
|
||||||
8 all search commands should start searching from the top of the visible viewport
|
8 all search commands should start searching from the top of the visible viewport
|
||||||
8 :addsearch wikpedia http://en.wikipedia.org/wiki/Special:Search?search=%s to allow saving of
|
|
||||||
quick searches in the RC file.
|
|
||||||
Why not just add a bookmark? --Kris
|
|
||||||
This would require performance tests, how fast it is to add 20 keywords that way, as we need
|
|
||||||
to search all existing bookmarks to see if the keyword is already defined, and then just update
|
|
||||||
that bookmark. --mst
|
|
||||||
|
|
||||||
Wah? I don't see how that's especially relevant, since they only
|
|
||||||
need to be added once, but, if you insist:
|
|
||||||
:100time bookmarks.getKeywords().some(function(k) k.keyword == "wikipedia")
|
|
||||||
Code execution summary
|
|
||||||
Executed: 100 times
|
|
||||||
Average time: 2.48 msec
|
|
||||||
Total time: 0.25 sec
|
|
||||||
--Kris
|
|
||||||
|
|
||||||
8 allow for multiple ex commands separated with | (see #24)
|
8 allow for multiple ex commands separated with | (see #24)
|
||||||
8 <C-o>/<C-i> should work as in vim (i.e., save page positions as well as
|
8 <C-o>/<C-i> should work as in vim (i.e., save page positions as well as
|
||||||
locations in the history list).
|
locations in the history list).
|
||||||
|
8 jump to the next heading with ]h, next image ]i, previous textbox [t and so on
|
||||||
|
8 pipe selected text/link/website to an external command
|
||||||
7 use ctrl-n/p in insert mode for word completion
|
7 use ctrl-n/p in insert mode for word completion
|
||||||
7 implement QuickFix window based on ItemList
|
7 implement QuickFix window based on ItemList
|
||||||
7 wherever possible: get rid of dialogs and ask console-like dialog questions
|
7 wherever possible: get rid of dialogs and ask console-like dialog questions
|
||||||
@@ -93,7 +78,7 @@ FEATURES:
|
|||||||
opera's fast forward does something like this
|
opera's fast forward does something like this
|
||||||
7 make an option to disable session saving by default when you close Firefox
|
7 make an option to disable session saving by default when you close Firefox
|
||||||
7 The output of the pageinfo-command should contain the security-information of ssl-encrypted sites
|
7 The output of the pageinfo-command should contain the security-information of ssl-encrypted sites
|
||||||
7 Add :every command
|
7 :grep support (needs location list)
|
||||||
6 :mksession
|
6 :mksession
|
||||||
6 add [count] support to :b* and :tab* commands where missing
|
6 add [count] support to :b* and :tab* commands where missing
|
||||||
6 registers
|
6 registers
|
||||||
@@ -101,12 +86,10 @@ FEATURES:
|
|||||||
always be the default register. --Ted
|
always be the default register. --Ted
|
||||||
6 check/correct spellings in insert mode with some mappings
|
6 check/correct spellings in insert mode with some mappings
|
||||||
6 add more autocommands (TabClose, TabOpen, TabChanged etc)
|
6 add more autocommands (TabClose, TabOpen, TabChanged etc)
|
||||||
6 jump to the next heading with ]h, next image ]i, previous textbox [t and so on
|
|
||||||
6 :grep support (needs location list)
|
|
||||||
6 pipe selected text/link/website to an external command
|
|
||||||
6 Use ctrl-w+j/k/w to switch between sidebar, content, preview window
|
6 Use ctrl-w+j/k/w to switch between sidebar, content, preview window
|
||||||
6 Command :tags for getting a list of used tags
|
6 Command :tags for getting a list of used tags
|
||||||
6 ;?<hint> should show more information
|
6 ;?<hint> should show more information
|
||||||
|
6 Add information to liberator/HACKING file about testing and optimization
|
||||||
5 when looking at a zoomed out image (because it's large), zi should zoom in
|
5 when looking at a zoomed out image (because it's large), zi should zoom in
|
||||||
maybe with this? : http://mxr.mozilla.org/seamonkey/source/content/html/document/public/nsIImageDocument.idl
|
maybe with this? : http://mxr.mozilla.org/seamonkey/source/content/html/document/public/nsIImageDocument.idl
|
||||||
5 make a command to search within google search results
|
5 make a command to search within google search results
|
||||||
@@ -117,8 +100,5 @@ FEATURES:
|
|||||||
3 add a command-line window (:help cmdline-window in Vim).
|
3 add a command-line window (:help cmdline-window in Vim).
|
||||||
3 Splitting Windows with [:sp :vsp ctrl-w,s ctrl-w,v] and closing with [ctrl-w,q], moving with [ctrl-w,w or tab]
|
3 Splitting Windows with [:sp :vsp ctrl-w,s ctrl-w,v] and closing with [ctrl-w,q], moving with [ctrl-w,w or tab]
|
||||||
have a look into the split browser extension
|
have a look into the split browser extension
|
||||||
1 Add information to liberator/HACKING file about testing and optimization
|
|
||||||
1 Document remote branches in liberator/HACKING
|
|
||||||
1 Reformat liberator/HACKING so that git diff can find sections and report changes @ somewhere
|
1 Reformat liberator/HACKING so that git diff can find sections and report changes @ somewhere
|
||||||
- many other ideas are listed in the wiki
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
# Firefox
|
# Firefox
|
||||||
content vimperator content/
|
content vimperator content/
|
||||||
skin vimperator classic/1.0 skin/
|
skin vimperator classic/1.0 skin/
|
||||||
locale vimperator en-US locale/en-US/
|
locale vimperator en-US locale/en-US/
|
||||||
locale liberator en-US ../common/locale/en-US/
|
locale liberator en-US ../common/locale/en-US/
|
||||||
|
|
||||||
content liberator ../common/content/
|
content liberator ../common/content/
|
||||||
resource liberator ../common/modules/
|
resource liberator ../common/modules/
|
||||||
skin liberator classic/1.0 ../common/skin/
|
skin liberator classic/1.0 ../common/skin/
|
||||||
|
|
||||||
override chrome://liberator/content/liberator.dtd chrome://vimperator/content/liberator.dtd
|
override chrome://liberator/content/liberator.dtd chrome://vimperator/content/liberator.dtd
|
||||||
override chrome://liberator/content/config.js chrome://vimperator/content/config.js
|
override chrome://liberator/content/config.js chrome://vimperator/content/config.js
|
||||||
|
|
||||||
overlay chrome://browser/content/browser.xul chrome://liberator/content/liberator.xul
|
overlay chrome://browser/content/browser.xul chrome://liberator/content/liberator.xul
|
||||||
overlay chrome://browser/content/browser.xul chrome://vimperator/content/vimperator.xul
|
overlay chrome://browser/content/browser.xul chrome://vimperator/content/vimperator.xul
|
||||||
|
|
||||||
|
component {81495d80-89ee-4c36-a88d-ea7c4e5ac63f} components/about-handler.js
|
||||||
|
contract @mozilla.org/network/protocol/about;1?what=vimperator {81495d80-89ee-4c36-a88d-ea7c4e5ac63f}
|
||||||
|
|
||||||
|
component {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69} components/commandline-handler.js
|
||||||
|
contract @mozilla.org/commandlinehandler/general-startup;1?type=vimperator {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}
|
||||||
|
category command-line-handler m-vimperator @mozilla.org/commandlinehandler/general-startup;1?type=vimperator
|
||||||
|
|
||||||
|
component {c1b67a07-18f7-4e13-b361-2edcc35a5a0d} components/protocols.js
|
||||||
|
contract @mozilla.org/network/protocol;1?name=chrome-data {c1b67a07-18f7-4e13-b361-2edcc35a5a0d}
|
||||||
|
component {9c8f2530-51c8-4d41-b356-319e0b155c44} components/protocols.js
|
||||||
|
contract @mozilla.org/network/protocol;1?name=liberator {9c8f2530-51c8-4d41-b356-319e0b155c44}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Header:
|
// Header:
|
||||||
|
"use strict";
|
||||||
const Name = "Vimperator";
|
const Name = "Vimperator";
|
||||||
/*
|
/*
|
||||||
* We can't load our modules here, so the following code is sadly
|
* We can't load our modules here, so the following code is sadly
|
||||||
@@ -38,6 +39,9 @@ AboutHandler.prototype = {
|
|||||||
getURIFlags: function (uri) Ci.nsIAboutModule.ALLOW_SCRIPT,
|
getURIFlags: function (uri) Ci.nsIAboutModule.ALLOW_SCRIPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
function NSGetModule(compMgr, fileSpec) XPCOMUtils.generateModule([AboutHandler])
|
if (XPCOMUtils.generateNSGetFactory)
|
||||||
|
const NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutHandler]);
|
||||||
|
else
|
||||||
|
const NSGetModule = XPCOMUtils.generateNSGetModule([AboutHandler]);
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et:
|
// vim: set fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Header:
|
// Header:
|
||||||
|
"use strict";
|
||||||
const Name = "Vimperator";
|
const Name = "Vimperator";
|
||||||
/*
|
/*
|
||||||
* We can't load our modules here, so the following code is sadly
|
* We can't load our modules here, so the following code is sadly
|
||||||
@@ -43,6 +44,9 @@ CommandLineHandler.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function NSGetModule(compMgr, fileSpec) XPCOMUtils.generateModule([CommandLineHandler])
|
if (XPCOMUtils.generateNSGetFactory)
|
||||||
|
const NSGetFactory = XPCOMUtils.generateNSGetFactory([CommandLineHandler]);
|
||||||
|
else
|
||||||
|
const NSGetModule = XPCOMUtils.generateNSGetModule([CommandLineHandler]);
|
||||||
|
|
||||||
// vim: set ft=javascript fdm=marker sw=4 ts=4 et:
|
// vim: set ft=javascript fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -46,58 +46,58 @@ const Config = Module("config", ConfigBase, {
|
|||||||
["VimperatorLeavePre", "Triggered before exiting Firefox, just before destroying each module"],
|
["VimperatorLeavePre", "Triggered before exiting Firefox, just before destroying each module"],
|
||||||
["VimperatorLeave", "Triggered before exiting Firefox"]],
|
["VimperatorLeave", "Triggered before exiting Firefox"]],
|
||||||
|
|
||||||
dialogs: [
|
dialogs: {
|
||||||
["about", "About Firefox",
|
about: ["About Firefox",
|
||||||
function () { window.openDialog("chrome://browser/content/aboutDialog.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
|
function () { window.openDialog("chrome://browser/content/aboutDialog.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
|
||||||
["addbookmark", "Add bookmark for the current page",
|
addbookmark: ["Add bookmark for the current page",
|
||||||
function () { PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksRootId); }],
|
function () { PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksRootId); }],
|
||||||
["addons", "Manage Add-ons",
|
addons: ["Manage Add-ons",
|
||||||
function () { window.BrowserOpenAddonsMgr(); }],
|
function () { window.BrowserOpenAddonsMgr(); }],
|
||||||
["bookmarks", "List your bookmarks",
|
bookmarks: ["List your bookmarks",
|
||||||
function () { window.openDialog("chrome://browser/content/bookmarks/bookmarksPanel.xul", "Bookmarks", "dialog,centerscreen,width=600,height=600"); }],
|
function () { window.openDialog("chrome://browser/content/bookmarks/bookmarksPanel.xul", "Bookmarks", "dialog,centerscreen,width=600,height=600"); }],
|
||||||
["checkupdates", "Check for updates",
|
checkupdates: ["Check for updates",
|
||||||
function () { window.checkForUpdates(); }],
|
function () { window.checkForUpdates(); }],
|
||||||
["cleardata", "Clear private data",
|
cleardata: ["Clear private data",
|
||||||
function () { Cc[GLUE_CID].getService(Ci.nsIBrowserGlue).sanitize(window || null); }],
|
function () { Cc[GLUE_CID].getService(Ci.nsIBrowserGlue).sanitize(window || null); }],
|
||||||
["cookies", "List your cookies",
|
cookies: ["List your cookies",
|
||||||
function () { window.toOpenWindowByType("Browser:Cookies", "chrome://browser/content/preferences/cookies.xul", "chrome,dialog=no,resizable"); }],
|
function () { window.toOpenWindowByType("Browser:Cookies", "chrome://browser/content/preferences/cookies.xul", "chrome,dialog=no,resizable"); }],
|
||||||
["console", "JavaScript console",
|
console: ["JavaScript console",
|
||||||
function () { window.toJavaScriptConsole(); }],
|
function () { window.toJavaScriptConsole(); }],
|
||||||
["customizetoolbar", "Customize the Toolbar",
|
customizetoolbar: ["Customize the Toolbar",
|
||||||
function () { window.BrowserCustomizeToolbar(); }],
|
function () { window.BrowserCustomizeToolbar(); }],
|
||||||
["dominspector", "DOM Inspector",
|
dominspector: ["DOM Inspector",
|
||||||
function () { try { window.inspectDOMDocument(content.document); } catch (e) { liberator.echoerr("DOM Inspector extension not installed"); } }],
|
function () { try { window.inspectDOMDocument(content.document); } catch (e) { liberator.echoerr("DOM Inspector extension not installed"); } }],
|
||||||
["downloads", "Manage Downloads",
|
downloads: ["Manage Downloads",
|
||||||
function () { window.toOpenWindowByType("Download:Manager", "chrome://mozapps/content/downloads/downloads.xul", "chrome,dialog=no,resizable"); }],
|
function () { window.toOpenWindowByType("Download:Manager", "chrome://mozapps/content/downloads/downloads.xul", "chrome,dialog=no,resizable"); }],
|
||||||
["history", "List your history",
|
history: ["List your history",
|
||||||
function () { window.openDialog("chrome://browser/content/history/history-panel.xul", "History", "dialog,centerscreen,width=600,height=600"); }],
|
function () { window.openDialog("chrome://browser/content/history/history-panel.xul", "History", "dialog,centerscreen,width=600,height=600"); }],
|
||||||
["import", "Import Preferences, Bookmarks, History, etc. from other browsers",
|
import: ["Import Preferences, Bookmarks, History, etc. from other browsers",
|
||||||
function () { window.BrowserImport(); }],
|
function () { window.BrowserImport(); }],
|
||||||
["openfile", "Open the file selector dialog",
|
openfile: ["Open the file selector dialog",
|
||||||
function () { window.BrowserOpenFileWindow(); }],
|
function () { window.BrowserOpenFileWindow(); }],
|
||||||
["pageinfo", "Show information about the current page",
|
pageinfo: ["Show information about the current page",
|
||||||
function () { window.BrowserPageInfo(); }],
|
function () { window.BrowserPageInfo(); }],
|
||||||
["pagesource", "View page source",
|
pagesource: ["View page source",
|
||||||
function () { window.BrowserViewSourceOfDocument(content.document); }],
|
function () { window.BrowserViewSourceOfDocument(content.document); }],
|
||||||
["places", "Places Organizer: Manage your bookmarks and history",
|
places: ["Places Organizer: Manage your bookmarks and history",
|
||||||
function () { PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_BOOKMARKS); }],
|
function () { PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_BOOKMARKS); }],
|
||||||
["preferences", "Show Firefox preferences dialog",
|
preferences: ["Show Firefox preferences dialog",
|
||||||
function () { window.openPreferences(); }],
|
function () { window.openPreferences(); }],
|
||||||
["printpreview", "Preview the page before printing",
|
printpreview: ["Preview the page before printing",
|
||||||
function () { PrintUtils.printPreview(onEnterPrintPreview, onExitPrintPreview); }],
|
function () { PrintUtils.printPreview(onEnterPrintPreview, onExitPrintPreview); }],
|
||||||
["printsetup", "Setup the page size and orientation before printing",
|
printsetup: ["Setup the page size and orientation before printing",
|
||||||
function () { PrintUtils.showPageSetup(); }],
|
function () { PrintUtils.showPageSetup(); }],
|
||||||
["print", "Show print dialog",
|
print: ["Show print dialog",
|
||||||
function () { PrintUtils.print(); }],
|
function () { PrintUtils.print(); }],
|
||||||
["saveframe", "Save frame to disk",
|
saveframe: ["Save frame to disk",
|
||||||
function () { window.saveFrameDocument(); }],
|
function () { window.saveFrameDocument(); }],
|
||||||
["savepage", "Save page to disk",
|
savepage: ["Save page to disk",
|
||||||
function () { window.saveDocument(window.content.document); }],
|
function () { window.saveDocument(window.content.document); }],
|
||||||
["searchengines", "Manage installed search engines",
|
searchengines: ["Manage installed search engines",
|
||||||
function () { window.openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
|
function () { window.openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
|
||||||
["selectionsource", "View selection source",
|
selectionsource: ["View selection source",
|
||||||
function () { buffer.viewSelectionSource(); }]
|
function () { buffer.viewSelectionSource(); }]
|
||||||
],
|
},
|
||||||
|
|
||||||
hasTabbrowser: true,
|
hasTabbrowser: true,
|
||||||
|
|
||||||
@@ -232,13 +232,20 @@ const Config = Module("config", ConfigBase, {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
context.anchored = false;
|
context.anchored = false;
|
||||||
context.title = ["Smart Completions"];
|
|
||||||
context.keys.icon = 2;
|
|
||||||
context.incomplete = true;
|
|
||||||
context.hasItems = context.completions.length > 0; // XXX
|
|
||||||
context.filterFunc = null;
|
|
||||||
context.cancel = function () { if (searchRunning) { services.get("autoCompleteSearch").stopSearch(); searchRunning = false; } };
|
|
||||||
context.compare = CompletionContext.Sort.unsorted;
|
context.compare = CompletionContext.Sort.unsorted;
|
||||||
|
context.filterFunc = null;
|
||||||
|
context.hasItems = context.completions.length > 0; // XXX
|
||||||
|
context.incomplete = true;
|
||||||
|
context.keys.icon = 2;
|
||||||
|
context.title = ["Smart Completions"];
|
||||||
|
context.cancel = function () {
|
||||||
|
if (searchRunning) {
|
||||||
|
services.get("autoCompleteSearch").stopSearch();
|
||||||
|
searchRunning = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (searchRunning)
|
||||||
|
services.get("autoCompleteSearch").stopSearch();
|
||||||
let timer = new Timer(50, 100, function (result) {
|
let timer = new Timer(50, 100, function (result) {
|
||||||
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
|
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
|
||||||
context.completions = [
|
context.completions = [
|
||||||
@@ -246,9 +253,6 @@ const Config = Module("config", ConfigBase, {
|
|||||||
for (i in util.range(0, result.matchCount))
|
for (i in util.range(0, result.matchCount))
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
if (searchRunning)
|
|
||||||
services.get("autoCompleteSearch").stopSearch();
|
|
||||||
searchRunning = true;
|
|
||||||
services.get("autoCompleteSearch").startSearch(context.filter, "", context.result, {
|
services.get("autoCompleteSearch").startSearch(context.filter, "", context.result, {
|
||||||
onSearchResult: function onSearchResult(search, result) {
|
onSearchResult: function onSearchResult(search, result) {
|
||||||
timer.tell(result);
|
timer.tell(result);
|
||||||
@@ -258,6 +262,7 @@ const Config = Module("config", ConfigBase, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
searchRunning = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
completion.sidebar = function sidebar(context) {
|
completion.sidebar = function sidebar(context) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<Description about="urn:mozilla:install-manifest">
|
<Description about="urn:mozilla:install-manifest">
|
||||||
<em:id>vimperator@mozdev.org</em:id>
|
<em:id>vimperator@mozdev.org</em:id>
|
||||||
<em:name>Vimperator</em:name>
|
<em:name>Vimperator</em:name>
|
||||||
<em:version>###VERSION###</em:version>
|
<em:version>@VERSION@</em:version>
|
||||||
<em:description>Make Firefox behave like Vim</em:description>
|
<em:description>Make Firefox behave like Vim</em:description>
|
||||||
<em:creator>Martin Stubenschrott</em:creator>
|
<em:creator>Martin Stubenschrott</em:creator>
|
||||||
<em:homepageURL>http://vimperator.org</em:homepageURL>
|
<em:homepageURL>http://vimperator.org</em:homepageURL>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<Description>
|
<Description>
|
||||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||||
<em:minVersion>3.5</em:minVersion>
|
<em:minVersion>3.5</em:minVersion>
|
||||||
<em:maxVersion>3.6b3</em:maxVersion>
|
<em:maxVersion>4.0</em:maxVersion>
|
||||||
</Description>
|
</Description>
|
||||||
</em:targetApplication>
|
</em:targetApplication>
|
||||||
</Description>
|
</Description>
|
||||||
|
|||||||
Reference in New Issue
Block a user