1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 16:32:27 +01:00

Make bookmark cache window independent and more dynamic.

This commit is contained in:
Kris Maglione
2008-09-14 01:16:23 +00:00
parent 59f861ad00
commit a863083360
7 changed files with 213 additions and 191 deletions

View File

@@ -206,9 +206,7 @@ liberator.Addressbook = function () //{{{
"<table><tr align=\"left\" class=\"hl-Title\"><th>Name</th><th>Address</th></tr>"; "<table><tr align=\"left\" class=\"hl-Title\"><th>Name</th><th>Address</th></tr>";
for (var i = 0; i < addresses.length; i++) for (var i = 0; i < addresses.length; i++)
{ {
var displayName = liberator.util.escapeHTML(addresses[i][0]); var displayName = liberator.util.escapeHTML(liberator.util.clip(addresses[i][0], 50));
if (displayName.length > 50)
displayName = displayName.substr(0, 47) + "...";
var mailAddr = liberator.util.escapeHTML(addresses[i][1]); var mailAddr = liberator.util.escapeHTML(addresses[i][1]);
list += "<tr><td>" + displayName + "</td><td style=\"width: 100%\"><a href=\"#\" class=\"hl-URL\">" + mailAddr + "</a></td></tr>"; list += "<tr><td>" + displayName + "</td><td style=\"width: 100%\"><a href=\"#\" class=\"hl-URL\">" + mailAddr + "</a></td></tr>";
} }

View File

@@ -33,91 +33,155 @@ liberator.Bookmarks = function () //{{{
////////////////////// PRIVATE SECTION ///////////////////////////////////////// ////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
const historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"] const historyService = PlacesUtils.history;
.getService(Components.interfaces.nsINavHistoryService); const bookmarksService = PlacesUtils.bookmarks;
const bookmarksService = Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"] const taggingService = PlacesUtils.tagging;
.getService(Components.interfaces.nsINavBookmarksService);
const taggingService = Components.classes["@mozilla.org/browser/tagging-service;1"]
.getService(Components.interfaces.nsITaggingService);
const searchService = Components.classes["@mozilla.org/browser/search-service;1"] const searchService = Components.classes["@mozilla.org/browser/search-service;1"]
.getService(Components.interfaces.nsIBrowserSearchService); .getService(Components.interfaces.nsIBrowserSearchService);
const ioService = Components.classes["@mozilla.org/network/io-service;1"] const ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService); .getService(Components.interfaces.nsIIOService);
var bookmarks = null; function Cache(name, store, serial)
var keywords = null;
if (liberator.options["preload"])
setTimeout(function () { load(); }, 100);
function load()
{ {
// update our bookmark cache const properties = { uri: 0, title: 1, keyword: 2, tags: 3, id: 4 };
bookmarks = []; const rootFolders = [bookmarksService.toolbarFolder, bookmarksService.bookmarksMenuFolder, bookmarksService.unfiledBookmarksFolder];
keywords = [];
var folders = [bookmarksService.toolbarFolder, bookmarksService.bookmarksMenuFolder, bookmarksService.unfiledBookmarksFolder]; var bookmarks = [];
var query = historyService.getNewQuery(); var self = this;
var options = historyService.getNewQueryOptions();
while (folders.length > 0) this.__defineGetter__("name", function () key);
this.__defineGetter__("store", function () store);
this.__defineGetter__("bookmarks", function () { this.load(); return bookmarks });
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));
function loadBookmark(node)
{ {
//comment out the next line for now; the bug hasn't been fixed; final version should include the next line var keyword = bookmarksService.getKeywordForBookmark(node.itemId);
//options.setGroupingMode(options.GROUP_BY_FOLDER); var tags = taggingService.getTagsForURI(ioService.newURI(node.uri, null, null), {});
query.setFolders(folders, 1); bookmarks.push([node.uri, node.title, keyword, tags, node.itemId]);
var result = historyService.executeQuery(query, options); }
//result.sortingMode = options.SORT_BY_DATE_DESCENDING;
result.sortingMode = options.SORT_BY_VISITCOUNT_DESCENDING;
var rootNode = result.root;
rootNode.containerOpen = true;
folders.shift(); function readBookmark(id)
// iterate over the immediate children of this folder {
for (var i = 0; i < rootNode.childCount; i++) return {
{ itemId: id,
var node = rootNode.getChild(i); uri: bookmarksService.getBookmarkURI(id).spec,
if (node.type == node.RESULT_TYPE_FOLDER) // folder title: bookmarksService.getItemTitle(id),
folders.push(node.itemId);
else if (node.type == node.RESULT_TYPE_URI) // bookmark
{
var kw = bookmarksService.getKeywordForBookmark(node.itemId);
if (kw)
keywords.push([kw, node.title, node.uri]);
var count = {};
var tags = taggingService.getTagsForURI(ioService.newURI(node.uri, null, null), count);
bookmarks.push([node.uri, node.title, kw, tags]);
}
} }
// close a container after using it!
rootNode.containerOpen = false;
} }
function deleteBookmark(id)
{
var length = bookmarks.length;
bookmarks = bookmarks.filter(function (item) item[properties.id] != id);
return bookmarks.length < length;
}
function findRoot(id)
{
do
{
var root = id;
id = bookmarksService.getFolderIdForItem(id);
} while (id != bookmarksService.placesRoot && id != root);
return root;
}
this.load = function load()
{
liberator.dump("cache.load()\n");
// update our bookmark cache
bookmarks = [];
this.__defineGetter__("bookmarks", function () bookmarks);
var folders = rootFolders.concat([]);
var query = historyService.getNewQuery();
var options = historyService.getNewQueryOptions();
while (folders.length > 0)
{
//comment out the next line for now; the bug hasn't been fixed; final version should include the next line
//options.setGroupingMode(options.GROUP_BY_FOLDER);
query.setFolders(folders, 1);
folders.shift();
var result = historyService.executeQuery(query, options);
result.sortingMode = options.SORT_BY_VISITCOUNT_DESCENDING; /* This is silly. Results are still sorted by folder first. --Kris */
var rootNode = result.root;
rootNode.containerOpen = true;
// iterate over the immediate children of this folder
for (var i = 0; i < rootNode.childCount; i++)
{
var node = rootNode.getChild(i);
if (node.type == node.RESULT_TYPE_FOLDER) // folder
folders.push(node.itemId);
else if (node.type == node.RESULT_TYPE_URI) // bookmark
loadBookmark(node);
}
// close a container after using it!
rootNode.containerOpen = false;
}
};
var observer = {
onBeginUpdateBatch: function () {},
onEndUpdateBatch: function () {},
onItemVisited: function () {},
onItemMoved: function () {},
onItemAdded: function (itemId, folder, index)
{
// liberator.dump("onItemAdded(" + itemId + ", " + folder + ", " + index + ")\n");
if (bookmarksService.getItemType(itemId) == bookmarksService.TYPE_BOOKMARK)
{
if (rootFolders.indexOf(findRoot(itemId)) >= 0)
{
loadBookmark(readBookmark(itemId));
liberator.storage.fireEvent(name, "add", itemId);
}
}
},
onItemRemoved: function (itemId, folder, index)
{
// liberator.dump("onItemRemoved(" + itemId + ", " + folder + ", " + index + ")\n");
if (deleteBookmark(itemId))
liberator.storage.fireEvent(name, "remove", itemId);
},
onItemChanged: function (itemId, property, isAnnotation, value)
{
if(isAnnotation)
return;
// liberator.dump("onItemChanged(" + itemId + ", " + property + ", " + value + ")\n");
var bookmark = bookmarks.filter(function (item) item[properties.id] == itemId)[0];
if(bookmark)
{
if(property == "tags")
value = taggingService.getTagsForURI(ioService.newURI(bookmark[properties.uri], null, null), {});
if(property in properties)
bookmark[properties[property]] = value;
liberator.storage.fireEvent(name, "change", itemId);
}
},
QueryInterface: function (iid) {
if (iid.equals(Components.interfaces.nsINavBookmarkObserver) || iid.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
bookmarksService.addObserver(observer, false);
} }
function flush() var cache = liberator.storage.newObject("bookmark-cache", Cache, false);
liberator.storage.addObserver("bookmark-cache", function (key, event, arg)
{ {
bookmarks = null; if(event == "add")
if (liberator.options["preload"]) liberator.autocommands.trigger("BookmarkAdd", "");
load(); liberator.statusline.updateUrl();
} });
var observer = {
onBeginUpdateBatch: function () {},
onEndUpdateBatch: function () {},
onItemVisited: function () {},
/* FIXME: Should probably just update the given bookmark. */
onItemMoved: flush,
onItemAdded: flush,
onItemRemoved: flush,
onItemChanged: flush,
QueryInterface: function (iid) {
if (iid.equals(Components.interfaces.nsINavBookmarkObserver) || iid.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
bookmarksService.addObserver(observer, false);
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
////////////////////// OPTIONS ///////////////////////////////////////////////// ////////////////////// OPTIONS /////////////////////////////////////////////////
@@ -256,38 +320,23 @@ liberator.Bookmarks = function () //{{{
// takes about 1 sec // takes about 1 sec
get: function (filter, tags, bypassCache) get: function (filter, tags, bypassCache)
{ {
if (!bookmarks || bypassCache) return liberator.completion.filterURLArray(cache.bookmarks, filter, tags);
load();
return liberator.completion.filterURLArray(bookmarks, filter, tags);
}, },
// if starOnly = true it is saved in the unfiledBookmarksFolder, otherwise in the bookmarksMenuFolder // 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)
{ {
if (!bookmarks)
load();
// if no protocol specified, default to http://, isn't there a better way?
if (!/^[\w-]+:/.test(url))
url = "http://" + url;
try try
{ {
var uri = ioService.newURI(url, null, null); var uri = PlacesUIUtils.createFixedURI(url);
var id = bookmarksService.insertBookmark( var id = bookmarksService.insertBookmark(
starOnly ? bookmarksService.unfiledBookmarksFolder : bookmarksService.bookmarksMenuFolder, bookmarksService[starOnly ? "unfiledBookmarksFolder" : "bookmarksMenuFolder"],
uri, -1, title); uri, -1, title);
if (!id) if (!id)
return false; return false;
if (keyword) if (keyword)
{
bookmarksService.setKeywordForBookmark(id, keyword); bookmarksService.setKeywordForBookmark(id, keyword);
keywords.unshift([keyword, title, url]);
}
if (tags) if (tags)
taggingService.tagURI(uri, tags); taggingService.tagURI(uri, tags);
} }
@@ -297,11 +346,6 @@ liberator.Bookmarks = function () //{{{
return false; return false;
} }
// update the display of our "bookmarked" symbol
liberator.statusline.updateUrl();
liberator.autocommands.trigger("BookmarkAdd", "");
return true; return true;
}, },
@@ -331,15 +375,12 @@ liberator.Bookmarks = function () //{{{
try try
{ {
var uri = ioService.newURI(url, null, null); var uri = ioService.newURI(url, null, null);
var count = {}; return (bookmarksService.getBookmarkedURIFor(uri) != null)
bookmarksService.getBookmarkIdsForURI(uri, count);
} }
catch (e) catch (e)
{ {
return false; return false;
} }
return count.value > 0;
}, },
// returns number of deleted bookmarks // returns number of deleted bookmarks
@@ -408,10 +449,7 @@ liberator.Bookmarks = function () //{{{
// [keyword, helptext, url] // [keyword, helptext, url]
getKeywords: function () getKeywords: function ()
{ {
if (!keywords) return cache.keywords;
load();
return keywords;
}, },
// full search string including engine name as first word in @param text // full search string including engine name as first word in @param text
@@ -457,16 +495,14 @@ liberator.Bookmarks = function () //{{{
} }
if (openItems) if (openItems)
return liberator.open([i[0] for (i in items)], liberator.NEW_TAB); return liberator.open([i[0] for each (i in items)], liberator.NEW_TAB);
var title, url, tags, keyword, extra; var title, url, tags, keyword, extra;
var list = ":" + liberator.util.escapeHTML(liberator.commandline.getCommand()) + "<br/>" + var list = ":" + liberator.util.escapeHTML(liberator.commandline.getCommand()) + "<br/>" +
"<table><tr align=\"left\" class=\"hl-Title\"><th>title</th><th>URL</th></tr>"; "<table><tr align=\"left\" class=\"hl-Title\"><th>title</th><th>URL</th></tr>";
for (var i = 0; i < items.length; i++) for (var i = 0; i < items.length; i++)
{ {
title = liberator.util.escapeHTML(items[i][1]); title = liberator.util.escapeHTML(liberator.util.clip(items[i][1], 50));
if (title.length > 50)
title = title.substr(0, 47) + "...";
url = liberator.util.escapeHTML(items[i][0]); url = liberator.util.escapeHTML(items[i][0]);
keyword = items[i][2]; keyword = items[i][2];
tags = items[i][3].join(", "); tags = items[i][3].join(", ");
@@ -762,7 +798,7 @@ liberator.History = function () //{{{
if (openItems) if (openItems)
{ {
return liberator.open([i[0] for (i in items)], liberator.NEW_TAB); return liberator.open([i[0] for each (i in items)], liberator.NEW_TAB);
} }
else else
{ {
@@ -770,9 +806,7 @@ liberator.History = function () //{{{
"<table><tr align=\"left\" class=\"hl-Title\"><th>title</th><th>URL</th></tr>"; "<table><tr align=\"left\" class=\"hl-Title\"><th>title</th><th>URL</th></tr>";
for (var i = 0; i < items.length; i++) for (var i = 0; i < items.length; i++)
{ {
var title = liberator.util.escapeHTML(items[i][1]); var title = liberator.util.escapeHTML(liberator.util.clip(items[i][1], 50));
if (title.length > 50)
title = title.substr(0, 47) + "...";
var url = liberator.util.escapeHTML(items[i][0]); var url = liberator.util.escapeHTML(items[i][0]);
list += "<tr><td>" + title + "</td><td><a href=\"#\" class=\"hl-URL\">" + url + "</a></td></tr>"; list += "<tr><td>" + title + "</td><td><a href=\"#\" class=\"hl-URL\">" + url + "</a></td></tr>";
} }
@@ -922,21 +956,13 @@ liberator.QuickMarks = function () //{{{
list: function (filter) list: function (filter)
{ {
var lowercaseMarks = []; var marks = [key for ([key,val] in qmarks)];
var uppercaseMarks = []; // This was a lot nicer without the lambda...
var numberMarks = []; var lowercaseMarks = marks.filter(function (x) /[a-z]/.test(x)).sort();
var uppercaseMarks = marks.filter(function (x) /[A-Z]/.test(x)).sort();
var numberMarks = marks.filter(function (x) /[0-9]/.test(x)).sort();
for (var [qmark,] in qmarks) marks = Array.concat(lowercaseMarks, uppercaseMarks, numberMarks);
{
if (/[a-z]/.test(qmark))
lowercaseMarks.push(qmark);
else if (/[A-Z]/.test(qmark))
uppercaseMarks.push(qmark);
else
numberMarks.push(qmark);
}
var marks = lowercaseMarks.sort().concat(uppercaseMarks.sort()).concat(numberMarks.sort());
if (marks.length == 0) if (marks.length == 0)
{ {
@@ -946,11 +972,7 @@ liberator.QuickMarks = function () //{{{
if (filter.length > 0) if (filter.length > 0)
{ {
marks = marks.filter(function (qmark) { marks = marks.filter(function (qmark) filter.indexOf(qmark) >= 0)
if (filter.indexOf(qmark) > -1)
return qmark;
});
if (marks.length == 0) if (marks.length == 0)
{ {
liberator.echoerr("E283: No QuickMarks matching \"" + filter + "\""); liberator.echoerr("E283: No QuickMarks matching \"" + filter + "\"");

View File

@@ -891,16 +891,16 @@ liberator.Buffer = function () //{{{
offsetY = Number(coords[1]) + 1; offsetY = Number(coords[1]) + 1;
} }
var newTab = false, newWindow = false; var ctrlKey = false, shiftKey = false;
switch (where) switch (where)
{ {
case liberator.NEW_TAB: case liberator.NEW_TAB:
case liberator.NEW_BACKGROUND_TAB: case liberator.NEW_BACKGROUND_TAB:
newTab = true; ctrlKey = true;
newWindow = (where == liberator.NEW_BACKGROUND_TAB); shiftKey = (where == liberator.NEW_BACKGROUND_TAB);
break; break;
case liberator.NEW_WINDOW: case liberator.NEW_WINDOW:
newWindow = true; shiftKey = true;
break; break;
case liberator.CURRENT_TAB: case liberator.CURRENT_TAB:
break; break;
@@ -913,9 +913,8 @@ liberator.Buffer = function () //{{{
var evt = doc.createEvent("MouseEvents"); var evt = doc.createEvent("MouseEvents");
for each (event in ["mousedown", "mouseup", "click"]) for each (event in ["mousedown", "mouseup", "click"])
{ {
evt.initMouseEvent(event, true, true, view, 1, offsetX, offsetY, evt.initMouseEvent(event, true, true, view, 1, offsetX, offsetY, 0, 0,
0, 0, /*ctrl*/ newTab, /*event.altKey*/0, /*event.shiftKey*/ newWindow, ctrlKey, /*altKey*/0, shiftKey, /*metaKey*/ ctrlKey, 0, null);
/*event.metaKey*/ newTab, 0, null);
elem.dispatchEvent(evt); elem.dispatchEvent(evt);
} }
}, },
@@ -1016,8 +1015,7 @@ liberator.Buffer = function () //{{{
{ {
if (frame.document.body.localName.toLowerCase() == "body") if (frame.document.body.localName.toLowerCase() == "body")
frames.push(frame); frames.push(frame);
for (var i = 0; i < frame.frames.length; i++) Array.forEach(frame.frames, arguments.callee);
arguments.callee(frame.frames[i]);
})(window.content); })(window.content);
if (frames.length == 0) // currently top is always included if (frames.length == 0) // currently top is always included
@@ -1038,15 +1036,7 @@ liberator.Buffer = function () //{{{
// focused. Since this is not the current FF behaviour, // focused. Since this is not the current FF behaviour,
// we initalize current to -1 so the first call takes us to the // we initalize current to -1 so the first call takes us to the
// first frame. // first frame.
var current = -1; var current = frames.indexOf(document.commandDispatcher.focusedWindow);
for (var i = 0; i < frames.length; i++)
{
if (frames[i] == document.commandDispatcher.focusedWindow)
{
var current = i;
break;
}
}
// calculate the next frame to focus // calculate the next frame to focus
var next = current; var next = current;
@@ -1497,19 +1487,21 @@ liberator.Marks = function () //{{{
function getSortedMarks() function getSortedMarks()
{ {
var lmarks, umarks; var location = window.content.location.href;
var lmarks = [];
// local marks // local marks
lmarks = [[[mark, value[i]] for (i in value) for (let [mark, value] in Iterator(localMarks))
if (value[i].location == window.content.location.href)] {
for ([mark, value] in localMarks)]; for each (val in value.filter(function (val) val.location == location))
lmarks = Array.concat.apply(Array, lmarks); lmarks.push([mark, val]);
}
lmarks.sort(); lmarks.sort();
// URL marks // URL marks
// FIXME: why does umarks.sort() cause a "Component is not available = // FIXME: why does umarks.sort() cause a "Component is not available =
// NS_ERROR_NOT_AVAILABLE" exception when used here? // NS_ERROR_NOT_AVAILABLE" exception when used here?
umarks = [[key, mark] for ([key, mark] in urlMarks)]; var umarks = [[key, mark] for ([key, mark] in urlMarks)];
umarks.sort(function (a, b) a[0].localeCompare(b[0])); umarks.sort(function (a, b) a[0].localeCompare(b[0]));
return lmarks.concat(umarks); return lmarks.concat(umarks);

View File

@@ -506,7 +506,7 @@ liberator.Completion = function () //{{{
// discard all entries in the 'urls' array, which don't match 'filter // discard all entries in the 'urls' array, which don't match 'filter
// urls must be of type [["url", "title"], [...]] or optionally // urls must be of type [["url", "title"], [...]] or optionally
// [["url", "title", keyword, [tags]], [...]] // [["url", "title", keyword, [tags]], [...]]
filterURLArray: function (urls, filter, tags) filterURLArray: function (urls, filter, filterTags)
{ {
var filtered = []; var filtered = [];
// completions which don't match the url but just the description // completions which don't match the url but just the description
@@ -518,49 +518,40 @@ liberator.Completion = function () //{{{
var hasTags = urls[0].length >= 4; var hasTags = urls[0].length >= 4;
// TODO: create a copy of urls? // TODO: create a copy of urls?
if (!filter && (!hasTags || !tags)) if (!filter && (!hasTags || !filterTags))
return urls; return urls;
tags = tags || []; filterTags = filterTags || [];
// TODO: use ignorecase and smartcase settings // TODO: use ignorecase and smartcase settings
var ignorecase = true; var ignorecase = (filter == filter.toLowerCase() && filterTags.join(",") == filterTags.join(",").toLowerCase());
if (filter != filter.toLowerCase() || tags.join(",") != tags.join(",").toLowerCase())
ignorecase = false;
if (ignorecase) if (ignorecase)
{ {
filter = filter.toLowerCase(); filter = filter.toLowerCase();
tags = tags.map(function (t) { return t.toLowerCase(); }); filterTags = filterTags.map(String.toLowerCase);
} }
// Longest Common Subsequence // Longest Common Subsequence
// This shouldn't use buildLongestCommonSubstring for performance // This shouldn't use buildLongestCommonSubstring for performance
// reasons, so as not to cycle through the urls twice // reasons, so as not to cycle through the urls twice
outer: for each (elem in urls)
for (var i = 0; i < urls.length; i++)
{ {
var url = urls[i][0] || ""; var url = elem[0] || "";
var title = urls[i][1] || ""; var title = elem[1] || "";
var tag = urls[i][3] || []; var tags = elem[3] || [];
if (ignorecase) if (ignorecase)
{ {
url = url.toLowerCase(); url = url.toLowerCase();
title = title.toLowerCase(); title = title.toLowerCase();
tag = tag.map(function (t) { return t.toLowerCase(); }); tags = tags.map(String.toLowerCase);
} }
// filter on tags // filter on tags
for (var j = 0; j < tags.length; j++) if(filterTags.some(function (tag) tag && tags.indexOf(tag) == -1))
{
if (!tags[j])
continue; continue;
if (tag.indexOf(tags[j]) == -1)
continue outer;
}
if (url.indexOf(filter) == -1) if (url.indexOf(filter) == -1)
{ {
// no direct match of filter in the url, but still accept this item // no direct match of filter in the url, but still accept this item
@@ -568,7 +559,7 @@ liberator.Completion = function () //{{{
if (filter.split(/\s+/).every(function (token) { if (filter.split(/\s+/).every(function (token) {
return (url.indexOf(token) > -1 || title.indexOf(token) > -1); return (url.indexOf(token) > -1 || title.indexOf(token) > -1);
})) }))
additionalCompletions.push(urls[i]); additionalCompletions.push(elem);
continue; continue;
} }
@@ -594,7 +585,7 @@ liberator.Completion = function () //{{{
}); });
} }
filtered.push(urls[i]); filtered.push(elem);
} }
return filtered.concat(additionalCompletions); return filtered.concat(additionalCompletions);

View File

@@ -60,18 +60,20 @@ function loadPref(name, store, type)
if (store) if (store)
var pref = getCharPref(prefName(name)); var pref = getCharPref(prefName(name));
if (pref) if (pref)
var obj = json.decode(pref); var result = json.decode(pref);
if (obj instanceof type) if (result instanceof type)
return obj; return result;
}
function savePref(obj)
{
if (obj.store)
prefService.setCharPref(prefName(obj.name), obj.serial)
} }
var prototype = { var prototype = {
fireEvent: function (event, arg) { storage.fireEvent(this.name, event, arg) }, fireEvent: function (event, arg) { storage.fireEvent(this.name, event, arg) },
save: function () save: function () { savePref(this) },
{
if (this.store)
prefService.setCharPref(prefName(this.name), this.serial)
},
}; };
function ObjectStore(name, store) function ObjectStore(name, store)
@@ -207,6 +209,13 @@ var storage = {
return this[key]; return this[key];
}, },
newObject: function newObject(key, constructor, store)
{
if(!(key in keys))
this._addKey(key, new constructor(key, store, loadPref(key, store, Object)));
return this[key];
},
addObserver: function addObserver(key, callback) addObserver: function addObserver(key, callback)
{ {
if (!(key in observers)) if (!(key in observers))
@@ -227,15 +236,20 @@ var storage = {
fireEvent: function fireEvent(key, event, arg) fireEvent: function fireEvent(key, event, arg)
{ {
for each(callback in observers[key]) for each (callback in observers[key])
callback(key, event, arg); callback(key, event, arg);
}, },
save: function save(key)
{
savePref(keys[key]);
},
saveAll: function storeAll() saveAll: function storeAll()
{ {
for each(key in keys) for each (obj in keys)
key.save(); savePref(obj);
} },
}; };
// vim: set fdm=marker sw=4 sts=4 et ft=javascript: // vim: set fdm=marker sw=4 sts=4 et ft=javascript:

View File

@@ -1402,7 +1402,7 @@ liberator.StatusLine = function () //{{{
modified += "+"; modified += "+";
if (sh.index < sh.count -1) if (sh.index < sh.count -1)
modified += "-"; modified += "-";
if (liberator.bookmarks.isBookmarked(url)) if (liberator.bookmarks.isBookmarked(liberator.buffer.URL))
modified += "\u2764"; // a heart symbol: ❤ modified += "\u2764"; // a heart symbol: ❤
//modified += "\u2665"; // a heart symbol: ♥ //modified += "\u2665"; // a heart symbol: ♥

View File

@@ -28,6 +28,11 @@ the terms of any one of the MPL, the GPL or the LGPL.
liberator.util = { //{{{ liberator.util = { //{{{
clip: function (str, length)
{
return str.length <= length ? str : str.substr(0, length - 3) + "...";
},
// TODO: use :highlight color groups // TODO: use :highlight color groups
// if "processStrings" is true, any passed strings will be surrounded by " and // if "processStrings" is true, any passed strings will be surrounded by " and
// any line breaks are displayed as \n // any line breaks are displayed as \n