diff --git a/chrome.manifest b/chrome.manifest index 1d72d897..ed4476f9 100644 --- a/chrome.manifest +++ b/chrome.manifest @@ -4,3 +4,4 @@ resource vimperator modules/ locale vimperator en-US locale/en-US/ skin vimperator classic/1.0 skin/ overlay chrome://browser/content/browser.xul chrome://vimperator/content/vimperator.xul + diff --git a/content/bookmarks.js b/content/bookmarks.js index 42b5c156..56e7193b 100644 --- a/content/bookmarks.js +++ b/content/bookmarks.js @@ -504,8 +504,8 @@ liberator.Bookmarks = function () //{{{ { url: item[0], title: item[1], - extra: [['keyword', item[2], 'red'], - ['tags', (item[3]||[]).join(', '), 'blue']].filter(function (i) i[1]) + extra: [['keyword', item[2], "hl-Keyword"], + ['tags', (item[3]||[]).join(', '), "hl-Tag"]].filter(function (i) i[1]) } for each (item in items))); liberator.commandline.echo(list, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); }, diff --git a/content/buffer.js b/content/buffer.js index 6d0f0137..e5d8c875 100644 --- a/content/buffer.js +++ b/content/buffer.js @@ -46,6 +46,7 @@ liberator.Buffer = function () //{{{ const consoleService = Components.classes["@mozilla.org/consoleservice;1"] .getService(Components.interfaces.nsIConsoleService); const sleep = liberator.sleep; + const storage = liberator.storage; function Styles(name, store, serial) { const XHTML = "http://www.w3.org/1999/xhtml"; @@ -56,11 +57,22 @@ liberator.Buffer = function () //{{{ let cssUri = function (css) "data:text/css," + encodeURI(css); - let sheets = []; - this.__iterator__ = function () Iterator(sheets); + let userSheets = []; + let systemSheets = []; - this.addSheet = function (filter, css) + this.__iterator__ = function () Iterator(userSheets); + this.__defineGetter__("systemSheets", function () Iterator(systemSheets)); + + this.__defineGetter__("chromeCSS", function () { + let css = [v[1] for ([k, v] in this) if (v[0].indexOf("chrome") >= 0)]; + return cssUri(css.join("\n/**/\n")); + }); + + this.addSheet = function (filter, css, system) + { + let sheets = system ? systemSheets : userSheets; + let errors = checkSyntax(css); if (errors.length) return errors.map(function (e) "CSS: " + filter + ": " + e).join("\n"); @@ -70,11 +82,16 @@ liberator.Buffer = function () //{{{ filter = filter.split(","); sheets.push([filter, css]); this.registerSheet(cssUri(wrapCSS(filter, css))); + + if (filter.indexOf("chrome") > -1) + storage.fireEvent(name, "chrome-added") return null; } - this.removeSheet = function (filter, index) + this.removeSheet = function (filter, index, system) { + let sheets = system ? systemSheets : userSheets; + if (filter == undefined) filter = ""; /* Find all sheets which match the filter */ @@ -87,15 +104,25 @@ liberator.Buffer = function () //{{{ else if (index) matches = [m for each (m in matches) if (m[1][1] == index)]; + let foundChrome = false; for (let [,[i, sheet]] in Iterator(matches.reverse())) { + let sites = sheet[0]; this.unregisterSheet(cssUri(wrapCSS(sheet[0], sheet[1]))); - sheet[0] = sheet[0].filter(function (f) f != filter); + sheet[0] = sites.filter(function (f) f != filter); if (sheet[0].length && isNaN(filter)) this.registerSheet(cssUri(wrapCSS(sheet[0], sheet[1]))); else sheets.splice(i, 1); + /* Crazy, I know. If we had chrome before, and either we don't have it now, or we've removed + * the whole entry, we've found chrome. + * Perhaps we out to just refresh the chrome stylesheet any time anything is removed. + */ + if (!foundChrome && sites.indexOf("chrome") > -1 && (sheet[0].indexOf("chrome") == -1 || !isNaN(filter))) + foundChrome = true; } + if (foundChrome) + storage.fireEvent(name, "chrome-removed"); return true; } @@ -184,6 +211,15 @@ liberator.Buffer = function () //{{{ let styles = liberator.storage.newObject("styles", Styles, false); + let stylesheet = document.createProcessingInstruction("xml-stylesheet", ""); + document.insertBefore(stylesheet, document.firstChild); + + let chromeObserver = function () { stylesheet.data = 'type="text/css" href="' + styles.chromeCSS + '"' }; + storage.addObserver("styles", chromeObserver); + liberator.registerObserver("shutdown", function () { + liberator.storage.removeObserver("styles", chromeObserver) + }); + /* FIXME: This doesn't belong here. */ let mainWindowID = liberator.config.mainWindowID || "main-window"; let fontSize = document.defaultView.getComputedStyle(document.getElementById(mainWindowID), null) @@ -192,7 +228,7 @@ liberator.Buffer = function () //{{{ let name = liberator.config.name.toLowerCase(); styles.registerSheet("chrome://" + name + "/skin/vimperator.css"); let error = styles.addSheet("chrome://" + name + "/content/buffer.xhtml", - "body { font-size: " + fontSize + "}"); + "body { font-size: " + fontSize + "}", true); function setZoom(value, fullZoom) { @@ -862,7 +898,7 @@ liberator.Buffer = function () //{{{ nFeed++; var type = feedTypes[feed.type] || feedTypes["application/rss+xml"]; if (verbose) - yield [feed.title, liberator.util.highlightURL(feed.href, true) + ({type})]; + yield [feed.title, liberator.util.highlightURL(feed.href, true) + ({type})]; } } } @@ -1947,10 +1983,10 @@ liberator.template = { {item.url} { !(item.extra && item.extra.length) ? "" : - + ({ liberator.template.map(item.extra, function (e) - <>{e[0]}: {e[1]}>, + <>{e[0]}: {e[1]}>, /* Non-breaking space */) }) @@ -1971,7 +2007,7 @@ liberator.template = { { this.map2(elems, function (idx, val) - {idx == index ? ">" : ""} + {idx == index ? ">" : ""} {Math.abs(idx - index)} {val.title} {val.URI.spec} @@ -1992,7 +2028,7 @@ liberator.template = { {opt.pre}{opt.name}{opt.value} - {opt.isDefault || opt.default == null ? "" : (default: {opt.default})} + {opt.isDefault || opt.default == null ? "" : (default: {opt.default})} ) } diff --git a/content/liberator.js b/content/liberator.js index 79ac99c2..4d8bc312 100644 --- a/content/liberator.js +++ b/content/liberator.js @@ -454,9 +454,9 @@ const liberator = (function () //{{{ Code execution summary - Executed:{count}times - Average time:{each.toFixed(2)}{eachUnits} - Total time:{total.toFixed(2)}{totalUnits} + Executed:{count}times + Average time:{each.toFixed(2)}{eachUnits} + Total time:{total.toFixed(2)}{totalUnits} ); liberator.commandline.echo(str, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); } @@ -685,6 +685,18 @@ const liberator = (function () //{{{ dump(liberator.config.name.toLowerCase() + ": " + message); }, + dumpStack: function (msg) + { + try + { + someStatisticallyImprobableVariableName.foo = 1; + } + catch (e) + { + liberator.dump((msg || "") + e.stack); + } + }, + // with (liberator) means, liberator is the default namespace "inside" eval eval: function (str) { diff --git a/content/muttator.xul b/content/muttator.xul index 964d801e..4e1a0412 100644 --- a/content/muttator.xul +++ b/content/muttator.xul @@ -80,12 +80,14 @@ the terms of any one of the MPL, the GPL or the LGPL. oncommandupdate="if (typeof liberator.events != 'undefined') liberator.events.onSelectionChange(event);"/> - - diff --git a/content/muttatorcompose.xul b/content/muttatorcompose.xul index 64c84121..7e71fc4c 100644 --- a/content/muttatorcompose.xul +++ b/content/muttatorcompose.xul @@ -89,12 +89,14 @@ the terms of any one of the MPL, the GPL or the LGPL. - - diff --git a/content/tabs.js b/content/tabs.js index 89a83e57..8a4d5f41 100644 --- a/content/tabs.js +++ b/content/tabs.js @@ -724,7 +724,7 @@ liberator.Tabs = function () //{{{ items.* += {number} - {indicator} + {indicator} {title} {item[1]} ; diff --git a/content/ui.js b/content/ui.js index 73f98267..c96c5042 100644 --- a/content/ui.js +++ b/content/ui.js @@ -105,7 +105,7 @@ liberator.CommandLine = function () //{{{ var wildIndex = 0; // keep track how often we press in a row var startHints = false; // whether we're waiting to start hints mode - var statusTimer = new liberator.util.Timer(50, 100, function () + var statusTimer = new liberator.util.Timer(51, 100, function () liberator.statusline.updateProgress("match " + (completionIndex + 1) + " of " + completions.length)); var autocompleteTimer = new liberator.util.Timer(50, 100, function (command) { let res = liberator.completion.ex(command); @@ -121,7 +121,7 @@ liberator.CommandLine = function () //{{{ // the widget used for multiline output var multilineOutputWidget = document.getElementById("liberator-multiline-output"); - liberator.util.blankDocument(multilineOutputWidget, "liberator-multiline-output-content"); + multilineOutputWidget.contentDocument.body.id = "liberator-multiline-output-content"; var outputContainer = multilineOutputWidget.parentNode; @@ -1193,15 +1193,17 @@ liberator.ItemList = function (id) //{{{ return; } - var doc; + var doc = iframe.contentDocument; var container = iframe.parentNode; - liberator.util.blankDocument(iframe, id + "-content"); + doc.body.id = id + "-content"; var completions = []; // a reference to the Array of completions - var listOffset = -1; // how many items is the displayed list shifted from the internal tab index - var listIndex = -1; // listOffset + listIndex = completions[item] - var selectedElement = null; + var startIndex = -1; // The index of the first displayed item + var endIndex = -1; // The index one *after* the last displayed item + var selIndex = -1; // The index of the currently selected element + var completionBody = null; + var completionElements = null; var minHeight = 0; // TODO: temporary, to be changed/removed @@ -1231,9 +1233,9 @@ liberator.ItemList = function (id) //{{{ if (completionElements.length == 0) return Math.max(minHeight, doc.height); - var wanted = Math.min(maxItems + listOffset, - completionElements.length); - minHeight = Math.max(minHeight, completionElements[wanted - 1].getBoundingClientRect().bottom); + minHeight = Math.max(minHeight, + completionElements[completionElements.length - 1] + .getBoundingClientRect().bottom); return minHeight; } @@ -1252,37 +1254,33 @@ liberator.ItemList = function (id) //{{{ */ function fill(offset) { - if (listOffset == offset || offset < 0 || offset >= completions.length && completions.length) + let diff = offset - startIndex; + if (diff == 0 || offset < 0 || completions.length && offset >= completions.length) return; - if (listIndex > -1 && offset == listOffset + 1) - { - let item = completions[offset + maxItems - 1]; - listOffset = offset; - var row = createRow(item[0], item[1], item[2], true); - var e = doc.getElementsByTagName("tbody"); - e = e[e.length - 1]; + startIndex = offset; + endIndex = Math.min(startIndex + maxItems, completions.length); - e.removeChild(e.firstChild); - e.appendChild(row); - completionElements = e.children; + if (selIndex > -1 && Math.abs(diff) == 1) /* Scroll one position */ + { + let tbody = completionBody; + + if (diff == 1) /* Scroll down */ + { + let item = completions[endIndex - 1]; + let row = createRow(item[0], item[1], item[2], true); + tbody.removeChild(tbody.firstChild); + tbody.appendChild(row); + } + else /* Scroll up */ + { + let item = completions[offset]; + let row = createRow(item[0], item[1], item[2], true); + tbody.removeChild(tbody.lastChild); + tbody.insertBefore(row, tbody.firstChild); + } return; } - else if (listIndex > -1 && offset == listOffset - 1) - { - let item = completions[offset]; - listOffset = offset; - var row = createRow(item[0], item[1], item[2], true); - var e = doc.getElementsByTagName("tbody"); - e = e[e.length - 1]; - - e.removeChild(e.lastChild); - e.insertBefore(row, e.firstChild); - completionElements = e.children; - return; - } - - listOffset = offset; // do a full refill of the list: doc.body.innerHTML = ""; @@ -1292,18 +1290,20 @@ liberator.ItemList = function (id) //{{{ Completions: ; - let tbody = div..tbody; - for (let i in liberator.util.range(offset, Math.min(offset + maxItems, - completions.length))) + let tbody = div..tbody; + for (let i in liberator.util.range(offset, endIndex)) { let elem = completions[i]; tbody.* += createRow(elem[0], elem[1], elem[2]); } - doc.body.appendChild(liberator.util.xmlToDom(div, doc)); + let dom = liberator.util.xmlToDom(div, doc); + doc.body.appendChild(dom); + + completionBody = dom.getElementsByTagName("tbody")[0]; + completionElements = completionBody.childNodes; - completionElements = doc.getElementsByClassName("compitem"); autoSize(); } @@ -1332,8 +1332,7 @@ liberator.ItemList = function (id) //{{{ // if @param selectedItem is given, show the list and select that item setItems: function (items, selectedItem) { - doc = iframe.contentDocument; - listOffset = listIndex = -1; + startIndex = endIndex = selIndex = -1; completions = items || []; if (typeof selectedItem == "number") { @@ -1350,37 +1349,31 @@ liberator.ItemList = function (id) //{{{ if (index == -1 || index == completions.length) // wrapped around { - if (listIndex >= 0) - completionElements[listIndex - listOffset].style.backgroundColor = ""; + if (selIndex >= 0) + completionElements[selIndex - startIndex].removeAttribute("selected"); else // list is shown the first time fill(0); - - listIndex = index; + selIndex = -1; return; } // find start index - var newOffset = 0; - if (index >= listOffset + maxItems - CONTEXT_LINES) - newOffset = index - maxItems + CONTEXT_LINES + 1; - else if (index <= listOffset + CONTEXT_LINES) + let newOffset = startIndex; + if (index >= endIndex - CONTEXT_LINES) + newOffset = index + CONTEXT_LINES - maxItems + 1; + else if (index <= startIndex + CONTEXT_LINES) newOffset = index - CONTEXT_LINES; - else - newOffset = listOffset; - if (newOffset + maxItems > completions.length) - newOffset = completions.length - maxItems; - if (newOffset < 0) - newOffset = 0; + newOffset = Math.min(newOffset, completions.length - maxItems); + newOffset = Math.max(newOffset, 0); + + if (selIndex > -1) + completionElements[selIndex - startIndex].removeAttribute("selected"); fill(newOffset); + selIndex = index; + completionElements[index - startIndex].setAttribute("selected", "true"); - if (selectedElement) - selectedElement.removeAttribute("selected"); - selectedElement = completionElements[index - newOffset]; - selectedElement.setAttribute("selected", "true"); - - listIndex = index; return; }, diff --git a/content/util.js b/content/util.js index c90e70c4..75bde82c 100644 --- a/content/util.js +++ b/content/util.js @@ -45,16 +45,18 @@ liberator.util = { //{{{ { if (arg !== undefined) this.arg = arg; + + let now = Date.now(); if (this.doneAt == -1) timer.cancel(); - else if (Date.now() >= this.doneAt) + else if (now >= this.doneAt || now >= this.latest) return this.notify(); let timeout = minInterval; if (this.latest) - timeout = Math.min(minInterval, this.latest - Date.now()); + timeout = Math.min(minInterval, this.latest - now); else - this.latest = Date.now() + maxInterval; + this.latest = now + maxInterval; timer.initWithCallback(this, timeout, timer.TYPE_ONE_SHOT); this.doneAt = -1; } @@ -77,12 +79,6 @@ liberator.util = { //{{{ yield ary[i]; }, - blankDocument: function (iframe, bodyId) - { - iframe.addEventListener("load", function () { iframe.contentDocument.body.setAttribute("id", bodyId) }, true); - iframe.setAttribute("src", "chrome://" + liberator.config.name.toLowerCase() + "/content/buffer.xhtml"); - }, - clip: function (str, length) { return str.length <= length ? str : str.substr(0, length - 3) + "..."; @@ -100,22 +96,22 @@ liberator.util = { //{{{ { if (type == "number") { - return {arg}; + return {arg}; } else if (type == "string") { if (processStrings) arg = <>"{arg.replace(/\n/, "\\n")}">; - return {arg}; + return {arg}; } else if (type == "boolean") { - return {arg}; + return {arg}; } else if (arg == null || arg == "undefined") { - return {arg}; + return {arg}; } else if (type == "object" || type == "function") { diff --git a/content/vimperator.xul b/content/vimperator.xul index 15579845..c840a71b 100644 --- a/content/vimperator.xul +++ b/content/vimperator.xul @@ -81,12 +81,14 @@ the terms of any one of the MPL, the GPL or the LGPL. - -