diff --git a/content/bookmarks.js b/content/bookmarks.js index 7d5f27ba..311ebb96 100644 --- a/content/bookmarks.js +++ b/content/bookmarks.js @@ -429,16 +429,7 @@ liberator.Bookmarks = function () //{{{ } if (openItems) - { - // FIXME: use yes/no question - if (items.length > 50) - return liberator.echoerr("For now, you can only open a hard limit of 50 items at once"); - - for (var i = 0; i < items.length; i++) - liberator.open(items[i][0], liberator.NEW_TAB); - - return; - } + return liberator.openTabs((i[0] for (i in items)), items.length); var title, url, tags, keyword, extra; var list = ":" + liberator.util.escapeHTML(liberator.commandline.getCommand()) + "
" + @@ -739,14 +730,7 @@ liberator.History = function () //{{{ if (openItems) { - // FIXME: use yes/no question - if (items.length > 50) - return liberator.echoerr("For now, you can only open a hard limit of 50 items at once"); - - for (var i = 0; i < items.length; i++) - liberator.open(items[i][0], liberator.NEW_TAB); - - return; + return liberator.openTabs((i[0] for (i in items)), items.length); } else { diff --git a/content/buffer.js b/content/buffer.js index 411aa7bb..bbbc27e6 100644 --- a/content/buffer.js +++ b/content/buffer.js @@ -338,9 +338,8 @@ liberator.Buffer = function () //{{{ "//xhtml:input[not(@type) or @type='text' or @type='password'] | //xhtml:textarea[not(@disabled) and not(@readonly)]" ); - for (let i = 0; i < matches.snapshotLength; i++) + for (match in matches) { - let match = matches.snapshotItem(i); let computedStyle = window.content.getComputedStyle(match, null); if (computedStyle.getPropertyValue("visibility") != "hidden" && computedStyle.getPropertyValue("display") != "none") @@ -693,6 +692,10 @@ liberator.Buffer = function () //{{{ null ); + result.__iterator__ = asIterator + ? function() { let elem; while((elem = this.iterateNext())) yield elem } + : function() { for(let i = 0; i < this.snapshotLength; i++) yield this.snapshotItem(i) }; + return result; }, diff --git a/content/completion.js b/content/completion.js index 27869abc..162fb773 100644 --- a/content/completion.js +++ b/content/completion.js @@ -242,18 +242,12 @@ liberator.Completion = function () //{{{ { var wigRegexp = new RegExp("(^" + liberator.options["wildignore"].replace(",", "|", "g") + ")$"); - files = files.filter(function (f) { - return f.isDirectory() || !wigRegexp.test(f.leafName); - }); + files = files.filter(function (f) f.isDirectory() || !wigRegexp.test(f.leafName)) } - mapped = files.map(function (file) { - return [tail ? file.leafName : (dir + file.leafName), file.isDirectory() ? "Directory" : "File"]; - }).sort(function (a, b) { - return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0; - }).sort(function (a, b) { - return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0; - }); + mapped = files.map(function (file) [tail ? file.leafName : (dir + file.leafName), + file.isDirectory() ? "Directory" : "File"]) + .sort(function (a, b) a[1].localeCompare(b[1]) || a[0].localeCompare(b[0])) } catch (e) { diff --git a/content/hints.js b/content/hints.js index 6222690e..b196c26c 100644 --- a/content/hints.js +++ b/content/hints.js @@ -96,7 +96,7 @@ liberator.Hints = function () //{{{ var fragment = doc.createDocumentFragment(); var start = hints.length; - while ((elem = res.iterateNext()) != null) + for (let elem in res) { // TODO: for iframes, this calculation is wrong rect = elem.getBoundingClientRect(); @@ -604,8 +604,8 @@ liberator.Hints = function () //{{{ }); liberator.options.add(["wordseparators", "wsp"], - "How words are splitted for hintmatching", - "string", '[\\.,!\\?:;/\\\"\\^\\$%&§\\(\\)\\[\\]\\{\\}<>#\\*\\+\\|=~ _\\-]'); + "How words are split for hintmatching", + "string", '[\\.,!\\?:;/\\\"\\^\\$%&?\\(\\)\\[\\]\\{\\}<>#\\*\\+\\|=~ _\\-]'); /////////////////////////////////////////////////////////////////////////////}}} ////////////////////// MAPPINGS //////////////////////////////////////////////// diff --git a/content/io.js b/content/io.js index 5517bd41..cfb72f6a 100644 --- a/content/io.js +++ b/content/io.js @@ -759,8 +759,9 @@ lookup: } catch (e) { + Components.utils.reportError("Sourcing file: " + filename + ": " + e); if (!silent) - liberator.echoerr(e); + liberator.echoerr("Sourcing file: " + filename + ": " + e); } } }; //}}} diff --git a/content/liberator.js b/content/liberator.js index a52e924c..acbc8e6c 100644 --- a/content/liberator.js +++ b/content/liberator.js @@ -37,6 +37,7 @@ const liberator = (function () //{{{ function loadModule(name, func) { liberator.log("Loading module " + name + "...", 0); + liberator.dump("Loading module " + name + "..."); liberator[name] = func(); } @@ -915,6 +916,24 @@ const liberator = (function () //{{{ return true; }, + /* Not really ideal. I'd like open to do this. */ + openTabs: function(uris, length) + { + let open = function() + { + for each (let uri in uris) + liberator.open(uri, liberator.NEW_TAB); + } + if ((length || uris.length) > 50) + liberator.commandline.input("This will open " + (length || uris.length) + " new tabs. Would you like to continue? (yes/[no])", + function(resp) { if(resp.match(/^y(es)?$/i)) open() }, + { + completer: function(filter) [0, [["yes", "Open all in tabs"], ["no", "Cancel"]]], + }); + else + open(); + }, + // namespace for plugins/scripts. Actually (only) the active plugin must/can set a // v.plugins.mode = string to show on v.modes.CUSTOM // v.plugins.stop = hooked on a v.modes.reset() @@ -967,7 +986,7 @@ const liberator = (function () //{{{ // TODO: move to {muttator,vimperator,...}.js - // this function is called, when the chrome is ready + // this function is called when the chrome is ready startup: function () { liberator.log("Initializing liberator object...", 0); @@ -1030,7 +1049,7 @@ const liberator = (function () //{{{ { var files = liberator.io.readDirectory(pluginDir.path); liberator.log("Sourcing plugin directory...", 3); - files.forEach(function (file) { + files.sort(function(a, b) String(a.path).localeCompare(b.path)).forEach(function (file) { if (!file.isDirectory() && /\.(js|vimp)$/i.test(file.path)) liberator.io.source(file.path, false); }); diff --git a/content/modes.js b/content/modes.js index 16323428..d2330e26 100644 --- a/content/modes.js +++ b/content/modes.js @@ -40,6 +40,8 @@ liberator.modes = (function () //{{{ var isRecording = false; var isReplaying = false; // playing a macro + var modeStack = []; + function getModeMessage() { if (passNextKey && !passAllKeys) @@ -179,6 +181,7 @@ liberator.modes = (function () //{{{ MENU: 1 << 19, // a popupmenu is active LINE: 1 << 20, // linewise visual mode RECORDING: 1 << 21, + PROMPT: 1 << 22, __iterator__: function () { @@ -237,6 +240,18 @@ liberator.modes = (function () //{{{ this.show(); }, + push: function(mainMode, extendedMode, silent) + { + modeStack.push([main, extended]); + this.set(mainMode, extendedMode, silent); + }, + + pop: function() { + var a = modeStack.pop(); + if (a) + [main, extended] = a; + }, + setCustomMode: function (modestr, oneventfunc, stopfunc) { // TODO this.plugin[id]... ('id' maybe submode or what..) @@ -248,6 +263,7 @@ liberator.modes = (function () //{{{ // keeps recording state reset: function (silent) { + modeStack = []; if (liberator.config.isComposeWindow) this.set(liberator.modes.COMPOSE, liberator.modes.NONE, silent); else @@ -260,19 +276,19 @@ liberator.modes = (function () //{{{ this.show(); }, - get passNextKey() { return passNextKey; }, + get passNextKey() passNextKey, set passNextKey(value) { passNextKey = value; this.show(); }, - get passAllKeys() { return passAllKeys; }, + get passAllKeys() passAllKeys, set passAllKeys(value) { passAllKeys = value; this.show(); }, - get isRecording() { return isRecording; }, + get isRecording() isRecording, set isRecording(value) { isRecording = value; this.show(); }, - get isReplaying() { return isReplaying; }, + get isReplaying() isReplaying, set isReplaying(value) { isReplaying = value; }, - get main() { return main; }, + get main() main, set main(value) { if (value != main) handleModeChange(main, value); @@ -283,7 +299,7 @@ liberator.modes = (function () //{{{ this.show(); }, - get extended() { return extended; }, + get extended() extended, set extended(value) { extended = value; this.show(); } diff --git a/content/ui.js b/content/ui.js index 5f4380e4..64ca1946 100644 --- a/content/ui.js +++ b/content/ui.js @@ -123,13 +123,15 @@ liberator.CommandLine = function () //{{{ var currentExtendedMode = null; // the extended mode which we last openend the command line for var currentPrompt = null; var currentCommand = null; - var oldMode = null; // when we leave the command prompt this mode is restored - var oldExtendedMode = null; // save the arguments for the inputMultiline method which are needed in the event handler var multilineRegexp = null; var multilineCallback = null; + // callback for prompt mode + var promptCallback = null; + var promptCompleter = null; + liberator.registerCallback("change", liberator.modes.EX, function (command) { if (liberator.options["wildoptions"].indexOf("auto") >= 0) { @@ -138,13 +140,26 @@ liberator.CommandLine = function () //{{{ } }); + function closePrompt(value) + { + let callback = promptCallback; + promptCallback = null; + currentExtendedMode = null; + liberator.commandline.clear(); + callback(value); + } + liberator.registerCallback("cancel", liberator.modes.PROMPT, closePrompt); + liberator.registerCallback("submit", liberator.modes.PROMPT, closePrompt); + liberator.registerCallback("complete", liberator.modes.PROMPT, + function (str) { if (promptCompleter) return promptCompleter(str); }); + function setHighlightGroup(group) { commandlineWidget.setAttribute("class", group); } // sets the prompt - for example, : or / - function setPrompt(pmt) + function setPrompt(pmt, highlightGroup) { promptWidget.value = pmt; @@ -157,6 +172,7 @@ liberator.CommandLine = function () //{{{ { promptWidget.collapsed = true; } + promptWidget.setAttribute("class", highlightGroup || liberator.commandline.HL_QUESTION); } // sets the command - e.g. 'tabopen', 'open http://example.com/' @@ -232,7 +248,7 @@ liberator.CommandLine = function () //{{{ multilineOutputWidget.contentWindow.focus(); - liberator.modes.set(liberator.modes.COMMAND_LINE, liberator.modes.OUTPUT_MULTILINE); + liberator.modes.push(liberator.modes.COMMAND_LINE, liberator.modes.OUTPUT_MULTILINE); } function autosizeMultilineInputWidget() @@ -439,6 +455,8 @@ liberator.CommandLine = function () //{{{ // FORCE_MULTILINE is given, FORCE_MULTILINE takes precedence APPEND_TO_MESSAGES : 1 << 3, // will show the string in :messages + get mode() (liberator.modes.extended == liberator.modes.EX) ? "cmd" : "search", + getCommand: function () { return commandWidget.value; @@ -455,10 +473,7 @@ liberator.CommandLine = function () //{{{ historyIndex = UNINITIALIZED; completionIndex = UNINITIALIZED; - // save the mode, because we need to restore it - oldMode = liberator.mode; - oldExtendedMode = liberator.mode.extended; - liberator.modes.set(liberator.modes.COMMAND_LINE, currentExtendedMode); + liberator.modes.push(liberator.modes.COMMAND_LINE, currentExtendedMode); setHighlightGroup(this.HL_NORMAL); setPrompt(currentPrompt); setCommand(currentCommand); @@ -536,13 +551,17 @@ liberator.CommandLine = function () //{{{ // this will prompt the user for a string // liberator.commandline.input("(s)ave or (o)pen the file?") - input: function (str) + input: function (prompt, callback, extra) { - // TODO: unfinished, need to find out how/if we can block the execution of code - // to make this code synchronous or at least use a callback - setLine(str, this.HL_QUESTION); + extra = extra || {}; + + promptCallback = callback; + promptCompleter = extra.completer; + liberator.modes.push(liberator.modes.COMMAND_LINE, liberator.modes.PROMPT); + currentExtendedMode = liberator.modes.PROMPT; + setPrompt(prompt + " ", this.HL_QUESTION); + setCommand(extra.default || ""); commandWidget.focus(); - return "not implemented"; }, // reads a multi line input and returns the string once the last line matches @@ -550,9 +569,7 @@ liberator.CommandLine = function () //{{{ inputMultiline: function (untilRegexp, callbackFunc) { // save the mode, because we need to restore it - oldMode = liberator.mode; - oldExtendedMode = liberator.mode.extended; - liberator.modes.set(liberator.modes.COMMAND_LINE, liberator.modes.INPUT_MULTILINE); + liberator.modes.push(liberator.modes.COMMAND_LINE, liberator.modes.INPUT_MULTILINE); // save the arguments, they are needed in the event handler onEvent multilineRegexp = untilRegexp; @@ -600,11 +617,12 @@ liberator.CommandLine = function () //{{{ // user pressed ENTER to carry out a command // user pressing ESCAPE is handled in the global onEscape + // FIXME: should trigger "cancel" event if (liberator.events.isAcceptKey(key)) { var mode = currentExtendedMode; // save it here, as setMode() resets it history.add(command); - liberator.modes.reset(true); //FIXME: use mode stack + liberator.modes.pop(); completionlist.hide(); liberator.focusContent(false); liberator.statusline.updateProgress(""); // we may have a "match x of y" visible @@ -790,7 +808,7 @@ liberator.CommandLine = function () //{{{ if (command.length == 0) { liberator.triggerCallback("cancel", currentExtendedMode); - liberator.modes.reset(); // FIXME: use mode stack + liberator.modes.pop(); // FIXME: use mode stack } } else // any other key @@ -812,14 +830,14 @@ liberator.CommandLine = function () //{{{ if (text.match(multilineRegexp)) { text = text.replace(multilineRegexp, ""); - liberator.modes.set(oldMode, oldExtendedMode); + liberator.modes.pop(); multilineInputWidget.collapsed = true; multilineCallback.call(this, text); } } else if (liberator.events.isCancelKey(key)) { - liberator.modes.set(oldMode, oldExtendedMode); + liberator.modes.pop(); multilineInputWidget.collapsed = true; } } @@ -1016,7 +1034,7 @@ liberator.CommandLine = function () //{{{ if (passEvent || closeWindow) { // FIXME: use mode stack - liberator.modes.reset(); + liberator.modes.pop(); this.clear(); if (passEvent)