diff --git a/content/bookmarks.js b/content/bookmarks.js index f30cd366..8df32808 100644 --- a/content/bookmarks.js +++ b/content/bookmarks.js @@ -56,7 +56,7 @@ liberator.Bookmarks = function () //{{{ this.__defineGetter__("keywords", function () [[k[2], k[1], k[0]] for each (k in self.bookmarks) if (k[2])]); - this.__iterator__ = (val for each (val in self.bookmarks)); + this.__iterator__ = function () (val for each (val in self.bookmarks)); function loadBookmark(node) { @@ -242,16 +242,14 @@ liberator.Bookmarks = function () //{{{ liberator.commands.add(["bma[rk]"], "Add a bookmark", - function (args) + function (args, special) { var url = args.arguments.length == 0 ? liberator.buffer.URL : args.arguments[0]; var title = args["-title"] || (args.arguments.length == 0 ? liberator.buffer.title : null); - if (!title) - title = url; var keyword = args["-keyword"] || null; var tags = args["-tags"] || []; - if (liberator.bookmarks.add(false, title, url, keyword, tags)) + if (liberator.bookmarks.add(false, title, url, keyword, tags, special)) { var extra = ""; if (title != url) @@ -310,14 +308,28 @@ liberator.Bookmarks = function () //{{{ }, // if starOnly = true it is saved in the unfiledBookmarksFolder, otherwise in the bookmarksMenuFolder - add: function (starOnly, title, url, keyword, tags) + add: function (starOnly, title, url, keyword, tags, force) { try { var uri = PlacesUIUtils.createFixedURI(url); - var id = bookmarksService.insertBookmark( - bookmarksService[starOnly ? "unfiledBookmarksFolder" : "bookmarksMenuFolder"], - uri, -1, title); + if (!force) + { + for (let bmark in cache) + { + if (bmark[0] == uri.spec) + { + var id = bmark[4]; + if (title) + bookmarksService.setItemTitle(id, title); + break; + } + } + } + if (id == undefined) + id = bookmarksService.insertBookmark( + bookmarksService[starOnly ? "unfiledBookmarksFolder" : "bookmarksMenuFolder"], + uri, -1, title || url); if (!id) return false; diff --git a/content/buffer.js b/content/buffer.js index 0314dc6e..9c155b54 100644 --- a/content/buffer.js +++ b/content/buffer.js @@ -34,11 +34,16 @@ liberator.Buffer = function () //{{{ ////////////////////// PRIVATE SECTION ///////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - const arrayIter = liberator.util.arrayIter; - var zoomLevels = [ 1, 10, 25, 50, 75, 90, 100, 120, 150, 200, 300, 500, 1000, 2000 ]; + const arrayIter = liberator.util.arrayIter; + /* Can't reference liberator inside Styles -- + * it's a global object, and liberator disappears + * with this window. + */ + const util = liberator.util; + function Styles(name, store, serial) { const XHTML = "http://www.w3.org/1999/xhtml"; @@ -60,18 +65,35 @@ liberator.Buffer = function () //{{{ if (sheets.some(function (s) s[0] == filter && s[1] == css)) return null; + let filter = filter.split(","); sheets.push([filter, css]); this.registerSheet(cssUri(wrapCSS(filter, css))); return null; } - this.removeSheet = function (number) + this.removeSheet = function (filter, index) { - if (number >= sheets.length) - return false; - let sheet = sheets.splice(number)[0]; - let uri = - this.unregisterSheet(cssUri(wrapCSS(sheet[0], sheet[1]))); + if (filter == undefined) + filter = ""; + /* Find all sheets which match the filter */ + let matches = [s for (s in Iterator(sheets)) if (filter == "" || s[1][0].indexOf(filter) >= 0)]; + + if (matches.length == 0 && sheets[Number(filter)]) + matches.push([filter, sheets[filter]]); + else if (!isNaN(index)) + matches = (index < matches.length) ? [matches[index]] : []; + else if (index) + matches = [m for each (m in matches) if (m[1][1] == index)]; + + for (let [,[i, sheet]] in Iterator(matches.reverse())) + { + this.unregisterSheet(cssUri(wrapCSS(sheet[0], sheet[1]))); + sheet[0] = sheet[0].filter(function (f) f != filter); + if (sheet[0].length && isNaN(filter)) + this.registerSheet(cssUri(wrapCSS(sheet[0], sheet[1]))); + else + sheets.splice(i, 1); + } return true; } @@ -91,12 +113,15 @@ liberator.Buffer = function () //{{{ function wrapCSS(filter, css) { - if (filter == "*") - return css; - let selector = /[\/:]/.test(filter) ? "url" : "domain"; - filter = filter.replace('"', "%22", "g"); + if (filter[0] == "*") + return "@namespace url(" + XHTML + ");\n" + css; + let selectors = filter.map(function (part) (/\/$/.test(part) ? "url-prefix" : + /\/:/.test(part) ? "url" + : "domain") + + '("' + part.replace(/"/g, "%22") + '")') + .join(", "); return "@namespace url(" + XHTML + ");\n" + - "@-moz-document " + selector + '("' + filter + '") {\n' + css + "\n}\n"; + "@-moz-document " + selectors + "{\n" + css + "\n}\n"; /* } vim */ } @@ -125,7 +150,7 @@ liberator.Buffer = function () //{{{ try { var doc = document.implementation.createDocument(XHTML, "doc", null); - doc.documentElement.appendChild(liberator.util.xmlToDom( + doc.documentElement.appendChild(util.xmlToDom( , doc)); while (true) @@ -151,8 +176,11 @@ liberator.Buffer = function () //{{{ return errors; } } + Styles.prototype = { + get sites() util.uniq(util.flatten([v[0] for ([k, v] in this)])), + }; - let styles = liberator.storage.newObject(styles, Styles, false); + let styles = liberator.storage.newObject("styles", Styles, false); function setZoom(value, fullZoom) { @@ -672,8 +700,8 @@ liberator.Buffer = function () //{{{ { let str = liberator.template.tabular(["", "Filter", "CSS"], ["padding: 0 1em 0 1ex; vertical-align: top", "padding: 0 1em 0 0; vertical-align: top"], - ([i, style[0], style[1]] for ([i, style] in styles) - if (!filter || style[0] == filter))); + ([i, style[0].join(","), style[1]] for ([i, style] in styles) + if (!filter || style[0].indexOf(filter) >= 0))); liberator.commandline.echo(str, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); } else @@ -685,20 +713,23 @@ liberator.Buffer = function () //{{{ } }, { - completer: function (filter) [0, [ - [content.location.host, ""], - [content.location.href, ""]] - .concat([[s[0], ""] for ([i, s] in styles)]) - ], + completer: function (filter) [0, liberator.completion.filter( + [[content.location.host, ""], + [content.location.href, ""]] + .concat([[s, ""] for each (s in styles.sites)]) + , filter)], hereDoc: true, }); liberator.commands.add(["dels[tyle]"], "Remove a user stylesheet", - function (args) { styles.removeSheet(parseInt(args.arguments[0])); }, + function (args) { styles.removeSheet.apply(styles, args.arguments); }, { - completer: function (filter) [0, [[i, s[0] + ": " + s[1].replace("\n", "\\n")] for ([i, s] in styles)]], - argCount: 1 + completer: function (filter) [0, liberator.completion.filter( + [[i, s[0].join(",") + ": " + s[1].replace("\n", "\\n")] for ([i, s] in styles)] + .concat([[s, ""] for each (s in styles.sites)]) + , filter)], + argCount: "*", }); liberator.commands.add(["vie[wsource]"], @@ -1382,9 +1413,7 @@ liberator.Buffer = function () //{{{ // add the frame indicator var doc = frames[next].document; var indicator = -
; +
; doc.body.appendChild(liberator.util.xmlToDom(indicator)); // remove the frame indicator @@ -1910,7 +1939,7 @@ liberator.template = { ({ liberator.template.map(item.extra, function (e) <>{e[0]}: {e[1]}, - <> ) + /* Non-breaking space */) }) } @@ -1930,7 +1959,7 @@ liberator.template = { { this.map2(elems, function (idx, val) - {idx == index ? {">"} : ""} + {idx == index ? ">" : ""} {Math.abs(idx - index)} {val.title} {val.URI.spec} diff --git a/content/completion.js b/content/completion.js index a8b4daed..625bf60a 100644 --- a/content/completion.js +++ b/content/completion.js @@ -72,7 +72,7 @@ liberator.Completion = function () //{{{ var complist = list[i][0] instanceof Array ? list[i][0] : [list[i][0]]; for (let j = 0; j < complist.length; j++) { - var item = complist[j]; + var item = String(complist[j]); if (ignorecase) item = item.toLowerCase(); diff --git a/content/util.js b/content/util.js index 2e532f61..957dfbf6 100644 --- a/content/util.js +++ b/content/util.js @@ -172,6 +172,20 @@ liberator.util = { //{{{ return str.replace(/&/g, "&").replace(//g, ">"); }, + escapeRegex: function (str) + { + return str.replace(/([\\{}()[\].?*+])/g, "\\$1"); + }, + + // Flatten an array: + // [["foo", "bar"], ["baz"]] -> ["foo", "bar", "baz"] + flatten: function (ary) + { + if (ary.length == 0) + return []; + return Array.concat.apply(Array, ary); + }, + formatBytes: function (num, decimalPlaces, humanReadable) { const unitVal = ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; @@ -416,6 +430,18 @@ liberator.util = { //{{{ return urls; }, + uniq: function (ary) + { + let ret = []; + for (let [,item] in Iterator(ary.sort())) + { + if (item != last || !ret.length) + ret.push(item); + var last = item; + } + return ret; + }, + xmlToDom: function (node, doc) { switch (node.nodeKind())