Skip to content

Instantly share code, notes, and snippets.

@johan
Created August 17, 2010 02:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johan/528134 to your computer and use it in GitHub Desktop.
Save johan/528134 to your computer and use it in GitHub Desktop.
Like the chrome.bookmarks.onRemoved.addListener call at http://code.google.com/chrome/extensions/bookmarks.html#event-onRemoved but guaranteed to fire even if the onremove event fired on a containing folder
// makes sure fn gets called when bm_id is removed, whether it was a direct kill
// or it got caught in collateral damage from a recursive bookmark removal spree
function addBookmarkRemoveListener(bm_id, fn) {
// as we won't get an onRemoved callback for bm_id when any of its parents got
// removed recursively, keep a list of all its parents to know when to fire fn
function indexParentsFor(bm_id, bookmarks) {
function bookmarkParents(id, bms, path) {
////console.log('bookmarkParents(', id, bms, path, ')');
for (var i = 0, bm, found; bm = bms[i]; i++) {
if (bm.id === id) return path;
if (bm.url) continue;
if ((found = bookmarkParents(id, bm.children, path.concat(bm.id)))) {
//console.info('found: ', found, ')');
return found;
}
}
return null;
}
///console.log('indexParentsFor(', bm_id, bookmarks, ')');
return parent_ids[bm_id] = bookmarkParents(bm_id, bookmarks, []);
}
function register(bm_id, fn) {
//console.log('addBookmarkRemoveListener.register(', bm_id, fn, ')');
var parents = parent_ids[bm_id];
if (parents) { // already indexed?
if (!parents.some(strictlyEquals(fn)))
callbacks[bm_id].push(fn);
}
else {
callbacks[bm_id] = (callbacks[bm_id] || []).concat(fn);
chrome.bookmarks.getTree(function(bms) { indexParentsFor(bm_id, bms); });
}
}
function strictlyEquals(x) { return function(y) { return x === y; }; }
// array of all bm_id:s we are tracking
function idsTracked() {
var ids = [];
for (var id in parent_ids)
if (Number(id) !== NaN)
ids.push(id);
return ids;
}
// refresh parent_id cache post-move
function onMove(bm_id, info) {
//console.log('onMove(', bm_id, info, ')');
function reindex(bookmarks) {
for (var i = 0, id, ids = idsTracked(); id = ids[i]; i++) {
indexParentsFor(bm_id, bookmarks);
}
}
chrome.bookmarks.getTree(reindex);
}
// when one or more of the bookmarks we track is removed, call their listeners
// and remove their associated data from our list of tracked ids and callbacks
function onRemove(bm_id, info) {
//console.log('onRemove(', bm_id, info, ')');
var is_bm_id = strictlyEquals(bm_id);
for (var i = 0, id, ids = idsTracked(); id = ids[i]; i++) {
if (id !== bm_id && !parent_ids[id].some(is_bm_id)) continue;
for (var j = 0, fn, fns = callbacks[id]; fn = fns[j]; j++)
fn(bm_id, Object.create(info));
delete parent_ids[id];
delete callbacks[id];
}
}
var self = addBookmarkRemoveListener,
callbacks = self.callbacks = self.callbacks || {}, // id => array<fn>
parent_ids = self.parent_ids = self.parent_ids || {}; // id => array<id>
self.onMove = self.onMove || // only add our listener for onMoved once
(onMove, chrome.bookmarks.onMoved.addListener(onMove)); // reindex bookmarks
self.onRemoved = self.onRemove || // only add our listener for onRemoved once
(onRemove, chrome.bookmarks.onRemoved.addListener(onRemove)); // real worker
register(bm_id, fn); // index the parents for this bm_id and register its fn
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment