From 459dae23fa573605533b53b6bef3a31008f8c119 Mon Sep 17 00:00:00 2001 From: Daisuke Akatsuka Date: Thu, 6 May 2021 02:29:44 +0000 Subject: [PATCH] Bug 1511062: Apply bookmark-moved event. r=mak Depends on D102573 Differential Revision: https://phabricator.services.mozilla.com/D102574 --- browser/base/content/browser-places.js | 20 ++- .../extensions/parent/ext-bookmarks.js | 16 +- browser/components/places/PlacesUIUtils.jsm | 32 ++-- .../components/places/content/editBookmark.js | 38 +++++ .../browser_autoshow_bookmarks_toolbar.js | 11 +- ...ser_bookmarkProperties_remember_folders.js | 6 +- .../browser/browser_controller_onDrop.js | 9 +- .../browser_default_bookmark_location.js | 10 +- services/sync/modules/engines/bookmarks.js | 12 +- toolkit/components/places/Bookmarks.jsm | 45 +----- .../places/SyncedBookmarksMirror.jsm | 28 ---- toolkit/components/places/TaggingService.jsm | 13 +- .../components/places/nsNavHistoryResult.cpp | 37 ++++- .../places/tests/bookmarks/head_bookmarks.js | 16 ++ .../bookmarks/test_bookmarks_moveToFolder.js | 25 ++-- .../bookmarks/test_bookmarks_notifications.js | 140 +++++++++++------- .../bookmarks/test_nsINavBookmarkObserver.js | 24 +-- .../components/places/tests/sync/head_sync.js | 20 ++- .../sync/test_bookmark_observer_recorder.js | 14 +- .../sync/test_bookmark_structure_changes.js | 42 ++++-- .../tests/sync/test_bookmark_value_changes.js | 17 ++- .../tests/unit/test_async_transactions.js | 14 +- 22 files changed, 380 insertions(+), 209 deletions(-) diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index 044944d3a066..5026fd883c6a 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -1818,7 +1818,7 @@ var BookmarkingUI = { if (this._hasBookmarksObserver) { PlacesUtils.bookmarks.removeObserver(this); PlacesUtils.observers.removeListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], this.handlePlacesEvents ); } @@ -1869,7 +1869,7 @@ var BookmarkingUI = { PlacesUtils.bookmarks.addObserver(this); this.handlePlacesEvents = this.handlePlacesEvents.bind(this); PlacesUtils.observers.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], this.handlePlacesEvents ); this._hasBookmarksObserver = true; @@ -2221,6 +2221,22 @@ var BookmarkingUI = { isStarUpdateNeeded = true; } } + break; + case "bookmark-moved": + const hasMovedInOutOtherBookmarks = + ev.parentGuid === PlacesUtils.bookmarks.unfiledGuid || + ev.oldParentGuid === PlacesUtils.bookmarks.unfiledGuid; + if (hasMovedInOutOtherBookmarks) { + this.maybeShowOtherBookmarksFolder(); + } + + const hasMovedInOutToolbar = + ev.parentGuid === PlacesUtils.bookmarks.toolbarGuid || + ev.oldParentGuid === PlacesUtils.bookmarks.toolbarGuid; + if (hasMovedInOutToolbar) { + this.updateEmptyToolbarMessage(); + } + break; } diff --git a/browser/components/extensions/parent/ext-bookmarks.js b/browser/components/extensions/parent/ext-bookmarks.js index 02011aecbbdc..d4bdfc446c40 100644 --- a/browser/components/extensions/parent/ext-bookmarks.js +++ b/browser/components/extensions/parent/ext-bookmarks.js @@ -165,6 +165,18 @@ let observer = new (class extends EventEmitter { guid: event.guid, info: { parentId: event.parentGuid, index: event.index, node }, }); + break; + case "bookmark-moved": + this.emit("moved", { + guid: event.guid, + info: { + parentId: event.parentGuid, + index: event.index, + oldParentId: event.oldParentGuid, + oldIndex: event.oldIndex, + }, + }); + break; } } } @@ -220,7 +232,7 @@ const decrementListeners = () => { if (!listenerCount) { PlacesUtils.bookmarks.removeObserver(observer); PlacesUtils.observers.removeListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], observer.handlePlacesEvents ); } @@ -231,7 +243,7 @@ const incrementListeners = () => { if (listenerCount == 1) { PlacesUtils.bookmarks.addObserver(observer); PlacesUtils.observers.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], observer.handlePlacesEvents ); } diff --git a/browser/components/places/PlacesUIUtils.jsm b/browser/components/places/PlacesUIUtils.jsm index dca5d5135fe4..630b112c852d 100644 --- a/browser/components/places/PlacesUIUtils.jsm +++ b/browser/components/places/PlacesUIUtils.jsm @@ -1174,14 +1174,26 @@ var PlacesUIUtils = { // This listener is for counting new bookmarks let placesUtilsObserversListener = events => { for (let event of events) { - if ( - event.type == "bookmark-added" && - event.parentGuid == PlacesUtils.bookmarks.toolbarGuid - ) { - Services.telemetry.scalarAdd( - "browser.engagement.bookmarks_toolbar_bookmark_added", - 1 - ); + switch (event.type) { + case "bookmark-added": + if (event.parentGuid == PlacesUtils.bookmarks.toolbarGuid) { + Services.telemetry.scalarAdd( + "browser.engagement.bookmarks_toolbar_bookmark_added", + 1 + ); + } + break; + case "bookmark-moved": + let hasMovedToToolbar = + event.parentGuid == PlacesUtils.bookmarks.toolbarGuid && + event.oldParentGuid != PlacesUtils.bookmarks.toolbarGuid; + if (hasMovedToToolbar) { + Services.telemetry.scalarAdd( + "browser.engagement.bookmarks_toolbar_bookmark_added", + 1 + ); + } + break; } } }; @@ -1212,13 +1224,13 @@ var PlacesUIUtils = { this._bookmarkToolbarTelemetryListening = true; PlacesUtils.observers.addListener( - ["bookmark-added"], + ["bookmark-added", "bookmark-moved"], placesUtilsObserversListener ); PlacesUtils.bookmarks.addObserver(placesUtilsBookmarksObserver); PlacesUtils.registerShutdownFunction(() => { PlacesUtils.observers.removeListener( - ["bookmark-added"], + ["bookmark-added", "bookmark-moved"], placesUtilsObserversListener ); PlacesUtils.bookmarks.removeObserver(placesUtilsBookmarksObserver); diff --git a/browser/components/places/content/editBookmark.js b/browser/components/places/content/editBookmark.js index 36e1e4ca48b6..b2c61664332d 100644 --- a/browser/components/places/content/editBookmark.js +++ b/browser/components/places/content/editBookmark.js @@ -348,6 +348,11 @@ var gEditItemOverlay = { // Observe changes. if (!this._observersAdded) { PlacesUtils.bookmarks.addObserver(this); + this.handlePlacesEvents = this.handlePlacesEvents.bind(this); + PlacesUtils.observers.addListener( + ["bookmark-moved"], + this.handlePlacesEvents + ); window.addEventListener("unload", this); this._observersAdded = true; } @@ -566,6 +571,10 @@ var gEditItemOverlay = { if (this._observersAdded) { PlacesUtils.bookmarks.removeObserver(this); + PlacesUtils.observers.removeListener( + ["bookmark-moved"], + this.handlePlacesEvents + ); window.removeEventListener("unload", this); this._observersAdded = false; } @@ -1126,6 +1135,35 @@ var gEditItemOverlay = { } }, + async handlePlacesEvents(events) { + for (const event of events) { + switch (event.type) { + case "bookmark-moved": + if (!this._paneInfo.isItem || this._paneInfo.itemId != event.id) { + return; + } + + this._paneInfo.parentGuid = event.parentGuid; + + if ( + !this._paneInfo.visibleRows.has("folderRow") || + event.parentGuid === this._folderMenuList.selectedItem.folderGuid + ) { + return; + } + + // Just setting selectItem _does not_ trigger oncommand, so we don't + // recurse. + const bm = await PlacesUtils.bookmarks.fetch(event.parentGuid); + this._folderMenuList.selectedItem = this._getFolderMenuItem( + event.parentGuid, + bm.title + ); + break; + } + } + }, + toggleItemCheckbox(item) { // Update the tags field when items are checked/unchecked in the listbox let tags = this._getTagsArrayFromTagsInputField(); diff --git a/browser/components/places/tests/browser/browser_autoshow_bookmarks_toolbar.js b/browser/components/places/tests/browser/browser_autoshow_bookmarks_toolbar.js index d0b037135483..948c748f1499 100644 --- a/browser/components/places/tests/browser/browser_autoshow_bookmarks_toolbar.js +++ b/browser/components/places/tests/browser/browser_autoshow_bookmarks_toolbar.js @@ -165,9 +165,14 @@ add_task(async function test_move_existing_to_toolbar() { let menuList = win.document.getElementById("editBMPanel_folderMenuList"); let itemMovedPromise = PlacesTestUtils.waitForNotification( - "onItemMoved", - (id, oldIndex, newIndex, type, guid, oldParentGuid, newParentGuid) => - newParentGuid == PlacesUtils.bookmarks.toolbarGuid && guid == bm.guid + "bookmark-moved", + events => + events.some( + e => + e.parentGuid === PlacesUtils.bookmarks.toolbarGuid && + e.guid === bm.guid + ), + "places" ); let promisePopup = BrowserTestUtils.waitForEvent( menuList.menupopup, diff --git a/browser/components/places/tests/browser/browser_bookmarkProperties_remember_folders.js b/browser/components/places/tests/browser/browser_bookmarkProperties_remember_folders.js index b63d60d40fd8..82ffe56bdd8c 100644 --- a/browser/components/places/tests/browser/browser_bookmarkProperties_remember_folders.js +++ b/browser/components/places/tests/browser/browser_bookmarkProperties_remember_folders.js @@ -18,9 +18,9 @@ async function openPopupAndSelectFolder(guid, newBookmark = false) { let notificationPromise; if (!newBookmark) { notificationPromise = PlacesTestUtils.waitForNotification( - "onItemMoved", - (id, oldIndex, newIndex, type, itemGuid, oldParentGuid, newParentGuid) => - guid == newParentGuid + "bookmark-moved", + events => events.some(e => guid === e.parentGuid), + "places" ); } diff --git a/browser/components/places/tests/browser/browser_controller_onDrop.js b/browser/components/places/tests/browser/browser_controller_onDrop.js index 1aa585e16fff..6f51b670daf9 100644 --- a/browser/components/places/tests/browser/browser_controller_onDrop.js +++ b/browser/components/places/tests/browser/browser_controller_onDrop.js @@ -108,9 +108,12 @@ async function run_drag_test(startBookmarkIndex, insertionIndex) { add_task(async function test_simple_move_down() { let moveNotification = PlacesTestUtils.waitForNotification( - "onItemMoved", - (id, oldIndex, newIndex, itemType, guid, oldParentGuid, newParentGuid) => - guid == bookmarks[0].guid && oldIndex == 0 && newIndex == 1 + "bookmark-moved", + events => + events.some( + e => e.guid === bookmarks[0].guid && e.oldIndex == 0 && e.index == 1 + ), + "places" ); await run_drag_test(0, 2); diff --git a/browser/components/places/tests/browser/browser_default_bookmark_location.js b/browser/components/places/tests/browser/browser_default_bookmark_location.js index 1fea148a84e7..1b9dfb7e0573 100644 --- a/browser/components/places/tests/browser/browser_default_bookmark_location.js +++ b/browser/components/places/tests/browser/browser_default_bookmark_location.js @@ -176,9 +176,13 @@ add_task(async function test_change_location_panel() { let itemGuid = win.gEditItemOverlay._paneInfo.itemGuid; // Make sure we wait for the move to complete. let itemMovedPromise = PlacesTestUtils.waitForNotification( - "onItemMoved", - (id, oldIndex, newIndex, type, guid, oldParentGuid, newParentGuid) => - newParentGuid == PlacesUtils.bookmarks.menuGuid && guid == itemGuid + "bookmark-moved", + events => + events.some( + e => + e.guid === itemGuid && e.parentGuid === PlacesUtils.bookmarks.menuGuid + ), + "places" ); // Wait for the pref to change diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 96df9ae1a46d..92ff10e7133f 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -805,7 +805,7 @@ BookmarksTracker.prototype = { this.handlePlacesEvents.bind(this) ); PlacesUtils.observers.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], this._placesListener ); Svc.Obs.add("bookmarks-restore-begin", this); @@ -816,7 +816,7 @@ BookmarksTracker.prototype = { onStop() { PlacesUtils.bookmarks.removeObserver(this); PlacesUtils.observers.removeListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], this._placesListener ); Svc.Obs.remove("bookmarks-restore-begin", this); @@ -884,6 +884,14 @@ BookmarksTracker.prototype = { this._log.trace("'bookmark-removed': " + event.id); this._upScore(); break; + case "bookmark-moved": + if (IGNORED_SOURCES.includes(event.source)) { + return; + } + + this._log.trace("'bookmark-moved': " + event.id); + this._upScore(); + break; case "purge-caches": this._log.trace("purge-caches"); this._upScore(); diff --git a/toolkit/components/places/Bookmarks.jsm b/toolkit/components/places/Bookmarks.jsm index 73acafcfdf15..4b5d893760f1 100644 --- a/toolkit/components/places/Bookmarks.jsm +++ b/toolkit/components/places/Bookmarks.jsm @@ -49,7 +49,7 @@ * Each successful operation notifies through the nsINavBookmarksObserver * interface. To listen to such notifications you must register using * nsINavBookmarksService addObserver and removeObserver methods. - * Note that bookmark addition or order changes won't notify onItemMoved for + * Note that bookmark addition or order changes won't notify bookmark-moved for * items that have their indexes changed. * Similarly, lastModified changes not done explicitly (like changing another * property) won't fire an onItemChanged notification for the lastModified @@ -957,23 +957,11 @@ var Bookmarks = Object.freeze({ updatedItem.source, ]); } - // If the item was moved, notify onItemMoved. + // If the item was moved, notify bookmark-moved. if ( item.parentGuid != updatedItem.parentGuid || item.index != updatedItem.index ) { - notify(observers, "onItemMoved", [ - updatedItem._id, - item.index, - updatedItem.index, - updatedItem.type, - updatedItem.guid, - item.parentGuid, - updatedItem.parentGuid, - updatedItem.source, - updatedItem.url && updatedItem.url.href, - ]); - notifications.push( new PlacesBookmarkMoved({ id: updatedItem._id, @@ -1203,9 +1191,7 @@ var Bookmarks = Object.freeze({ // Updates complete, time to notify everyone. for (let { updatedItem, existingItem, newParent } of updateInfos) { - // Notify onItemChanged to listeners. - let observers = PlacesUtils.bookmarks.getObservers(); - // If the item was moved, notify onItemMoved. + // If the item was moved, notify bookmark-moved. // We use the updatedItem.index here, rather than currIndex, as the views // need to know where we inserted the item as opposed to where it ended // up. @@ -1213,18 +1199,6 @@ var Bookmarks = Object.freeze({ existingItem.parentGuid != updatedItem.parentGuid || existingItem.index != updatedItem.index ) { - notify(observers, "onItemMoved", [ - updatedItem._id, - existingItem.index, - updatedItem.index, - updatedItem.type, - updatedItem.guid, - existingItem.parentGuid, - updatedItem.parentGuid, - source, - existingItem.url, - ]); - notifications.push( new PlacesBookmarkMoved({ id: updatedItem._id, @@ -1791,22 +1765,9 @@ var Bookmarks = Object.freeze({ const notifications = []; - let observers = PlacesUtils.bookmarks.getObservers(); // Note that child.index is the old index. for (let i = 0; i < sortedChildren.length; ++i) { let child = sortedChildren[i]; - notify(observers, "onItemMoved", [ - child._id, - child.index, - i, - child.type, - child.guid, - child.parentGuid, - child.parentGuid, - options.source, - child.url && child.url.href, - ]); - notifications.push( new PlacesBookmarkMoved({ id: child._id, diff --git a/toolkit/components/places/SyncedBookmarksMirror.jsm b/toolkit/components/places/SyncedBookmarksMirror.jsm index a3774a8c2051..9570fda3dd68 100644 --- a/toolkit/components/places/SyncedBookmarksMirror.jsm +++ b/toolkit/components/places/SyncedBookmarksMirror.jsm @@ -2061,7 +2061,6 @@ class BookmarkObserverRecorder { this.signal = signal; this.placesEvents = []; this.guidChangedArgs = []; - this.itemMovedArgs = []; this.itemChangedArgs = []; this.shouldInvalidateKeywords = false; } @@ -2324,18 +2323,6 @@ class BookmarkObserverRecorder { } noteItemMoved(info) { - this.itemMovedArgs.push([ - info.id, - info.oldPosition, - info.newPosition, - info.type, - info.guid, - info.oldParentGuid, - info.newParentGuid, - PlacesUtils.bookmarks.SOURCES.SYNC, - info.urlHref, - ]); - this.placesEvents.push( new PlacesBookmarkMoved({ id: info.id, @@ -2432,21 +2419,6 @@ class BookmarkObserverRecorder { PlacesObservers.notifyListeners(this.placesEvents); } - await Async.yieldingForEach( - this.itemMovedArgs, - args => { - if (this.signal.aborted) { - throw new SyncedBookmarksMirror.InterruptedError( - "Interrupted before notifying observers for moved items" - ); - } - this.notifyObserversWithInfo(observers, "onItemMoved", { - isTagging: false, - args, - }); - }, - yieldState - ); await Async.yieldingForEach( this.itemChangedArgs, args => { diff --git a/toolkit/components/places/TaggingService.jsm b/toolkit/components/places/TaggingService.jsm index a5e2608a4d31..fec13666247e 100644 --- a/toolkit/components/places/TaggingService.jsm +++ b/toolkit/components/places/TaggingService.jsm @@ -22,7 +22,7 @@ function TaggingService() { // Observe bookmarks changes. PlacesUtils.bookmarks.addObserver(this); PlacesUtils.observers.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], this.handlePlacesEvents ); @@ -327,7 +327,7 @@ TaggingService.prototype = { if (aTopic == TOPIC_SHUTDOWN) { PlacesUtils.bookmarks.removeObserver(this); PlacesUtils.observers.removeListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], this.handlePlacesEvents ); Services.obs.removeObserver(this, TOPIC_SHUTDOWN); @@ -418,6 +418,15 @@ TaggingService.prototype = { } }); break; + case "bookmark-moved": + if ( + this._tagFolders[event.id] && + PlacesUtils.bookmarks.tagsGuid === event.oldParentGuid && + PlacesUtils.bookmarks.tagsGuid !== event.parentGuid + ) { + delete this._tagFolders[event.id]; + } + break; } } }, diff --git a/toolkit/components/places/nsNavHistoryResult.cpp b/toolkit/components/places/nsNavHistoryResult.cpp index 1172dc8da08f..04373dc9d36d 100644 --- a/toolkit/components/places/nsNavHistoryResult.cpp +++ b/toolkit/components/places/nsNavHistoryResult.cpp @@ -21,6 +21,7 @@ #include "mozilla/dom/PlacesVisit.h" #include "mozilla/dom/PlacesVisitRemoved.h" #include "mozilla/dom/PlacesVisitTitle.h" +#include "mozilla/dom/PlacesBookmarkMoved.h" #include "nsCycleCollectionParticipant.h" @@ -3488,7 +3489,7 @@ nsNavHistoryResult::~nsNavHistoryResult() { } void nsNavHistoryResult::StopObserving() { - AutoTArray events; + AutoTArray events; events.AppendElement(PlacesEventType::Favicon_changed); if (mIsBookmarksObserver) { nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); @@ -3498,6 +3499,7 @@ void nsNavHistoryResult::StopObserving() { } events.AppendElement(PlacesEventType::Bookmark_added); events.AppendElement(PlacesEventType::Bookmark_removed); + events.AppendElement(PlacesEventType::Bookmark_moved); } if (mIsMobilePrefObserver) { Preferences::UnregisterCallback(OnMobilePrefChangedCallback, @@ -3618,9 +3620,10 @@ void nsNavHistoryResult::EnsureIsObservingBookmarks() { return; } bookmarks->AddObserver(this, true); - AutoTArray events; + AutoTArray events; events.AppendElement(PlacesEventType::Bookmark_added); events.AppendElement(PlacesEventType::Bookmark_removed); + events.AppendElement(PlacesEventType::Bookmark_moved); // If we're not observing visits yet, also add a page-visited observer to // serve onItemVisited. if (!mIsHistoryObserver && !mIsHistoryDetailsObserver) { @@ -4186,6 +4189,36 @@ void nsNavHistoryResult::HandlePlacesEvent(const PlacesEventSequence& aEvents) { item->mGuid, item->mParentGuid, item->mSource)); break; } + case PlacesEventType::Bookmark_moved: { + const dom::PlacesBookmarkMoved* item = event->AsPlacesBookmarkMoved(); + if (NS_WARN_IF(!item)) { + continue; + } + + NS_ConvertUTF16toUTF8 url(item->mUrl); + + ENUMERATE_BOOKMARK_FOLDER_OBSERVERS( + item->mOldParentGuid, + OnItemMoved(item->mId, item->mOldIndex, item->mIndex, + item->mItemType, item->mGuid, item->mOldParentGuid, + item->mParentGuid, item->mSource, url)); + if (!item->mParentGuid.Equals(item->mOldParentGuid)) { + ENUMERATE_BOOKMARK_FOLDER_OBSERVERS( + item->mParentGuid, + OnItemMoved(item->mId, item->mOldIndex, item->mIndex, + item->mItemType, item->mGuid, item->mOldParentGuid, + item->mParentGuid, item->mSource, url)); + } + ENUMERATE_ALL_BOOKMARKS_OBSERVERS( + OnItemMoved(item->mId, item->mOldIndex, item->mIndex, + item->mItemType, item->mGuid, item->mOldParentGuid, + item->mParentGuid, item->mSource, url)); + ENUMERATE_HISTORY_OBSERVERS( + OnItemMoved(item->mId, item->mOldIndex, item->mIndex, + item->mItemType, item->mGuid, item->mOldParentGuid, + item->mParentGuid, item->mSource, url)); + break; + } case PlacesEventType::Page_title_changed: { const PlacesVisitTitle* titleEvent = event->AsPlacesVisitTitle(); if (NS_WARN_IF(!titleEvent)) { diff --git a/toolkit/components/places/tests/bookmarks/head_bookmarks.js b/toolkit/components/places/tests/bookmarks/head_bookmarks.js index ef43d23226bb..5a930e0f686b 100644 --- a/toolkit/components/places/tests/bookmarks/head_bookmarks.js +++ b/toolkit/components/places/tests/bookmarks/head_bookmarks.js @@ -107,6 +107,22 @@ function expectPlacesObserverNotifications( }); } } + break; + case "bookmark-moved": + notifications.push({ + type: event.type, + id: event.id, + itemType: event.itemType, + url: event.url, + guid: event.guid, + parentGuid: event.parentGuid, + source: event.source, + index: event.index, + oldParentGuid: event.oldParentGuid, + oldIndex: event.oldIndex, + isTagging: event.isTagging, + }); + break; } } }; diff --git a/toolkit/components/places/tests/bookmarks/test_bookmarks_moveToFolder.js b/toolkit/components/places/tests/bookmarks/test_bookmarks_moveToFolder.js index 472f3f54981c..7cc3eb091604 100644 --- a/toolkit/components/places/tests/bookmarks/test_bookmarks_moveToFolder.js +++ b/toolkit/components/places/tests/bookmarks/test_bookmarks_moveToFolder.js @@ -198,7 +198,7 @@ async function testMoveToFolder(details) { let observer; if (details.notifications) { - observer = expectNotifications(true); + observer = expectPlacesObserverNotifications(["bookmark-moved"]); } let movedItems = await PlacesUtils.bookmarks.moveToFolder( @@ -255,18 +255,17 @@ async function testMoveToFolder(details) { let newFolder = notification.newFolder == "folderA" ? folderA : folderB; expectedNotifications.push({ - name: "onItemMoved", - arguments: [ - await PlacesUtils.promiseItemId(origItem.guid), - notification.originalIndex, - notification.newIndex, - PlacesUtils.bookmarks.TYPE_BOOKMARK, - origItem.guid, - origItem.parentGuid, - newFolder.guid, - PlacesUtils.bookmarks.SOURCES.DEFAULT, - origItem.url, - ], + type: "bookmark-moved", + id: await PlacesUtils.promiseItemId(origItem.guid), + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + url: origItem.url, + guid: origItem.guid, + parentGuid: newFolder.guid, + source: PlacesUtils.bookmarks.SOURCES.DEFAULT, + index: notification.newIndex, + oldParentGuid: origItem.parentGuid, + oldIndex: notification.originalIndex, + isTagging: false, }); } observer.check(expectedNotifications); diff --git a/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js b/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js index 66190e2433b3..cef57cba9ba3 100644 --- a/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js +++ b/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js @@ -328,7 +328,8 @@ add_task(async function update_move_same_folder() { let bmItemId = await PlacesUtils.promiseItemId(bm.guid); let bmOldIndex = bm.index; - let observer = expectNotifications(); + let observer = expectPlacesObserverNotifications(["bookmark-moved"]); + bm = await PlacesUtils.bookmarks.update({ guid: bm.guid, parentGuid: PlacesUtils.bookmarks.unfiledGuid, @@ -337,24 +338,23 @@ add_task(async function update_move_same_folder() { Assert.equal(bm.index, 0); observer.check([ { - name: "onItemMoved", - arguments: [ - bmItemId, - bmOldIndex, - bm.index, - bm.type, - bm.guid, - bm.parentGuid, - bm.parentGuid, - Ci.nsINavBookmarksService.SOURCE_DEFAULT, - "http://move.example.com/", - ], + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: "http://move.example.com/", + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: bm.parentGuid, + oldIndex: bmOldIndex, + isTagging: false, }, ]); // Test that we get the right index for DEFAULT_INDEX input. bmOldIndex = 0; - observer = expectNotifications(); + observer = expectPlacesObserverNotifications(["bookmark-moved"]); bm = await PlacesUtils.bookmarks.update({ guid: bm.guid, parentGuid: PlacesUtils.bookmarks.unfiledGuid, @@ -363,18 +363,17 @@ add_task(async function update_move_same_folder() { Assert.ok(bm.index > 0); observer.check([ { - name: "onItemMoved", - arguments: [ - bmItemId, - bmOldIndex, - bm.index, - bm.type, - bm.guid, - bm.parentGuid, - bm.parentGuid, - Ci.nsINavBookmarksService.SOURCE_DEFAULT, - bm.url, - ], + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: bm.parentGuid, + oldIndex: bmOldIndex, + isTagging: false, }, ]); }); @@ -392,7 +391,7 @@ add_task(async function update_move_different_folder() { let bmItemId = await PlacesUtils.promiseItemId(bm.guid); let bmOldIndex = bm.index; - let observer = expectNotifications(); + const observer = expectPlacesObserverNotifications(["bookmark-moved"]); bm = await PlacesUtils.bookmarks.update({ guid: bm.guid, parentGuid: folder.guid, @@ -401,18 +400,55 @@ add_task(async function update_move_different_folder() { Assert.equal(bm.index, 0); observer.check([ { - name: "onItemMoved", - arguments: [ - bmItemId, - bmOldIndex, - bm.index, - bm.type, - bm.guid, - PlacesUtils.bookmarks.unfiledGuid, - bm.parentGuid, - Ci.nsINavBookmarksService.SOURCE_DEFAULT, - "http://move.example.com/", - ], + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: "http://move.example.com/", + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: PlacesUtils.bookmarks.unfiledGuid, + oldIndex: bmOldIndex, + isTagging: false, + }, + ]); +}); + +add_task(async function update_move_tag_folder() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://move.example.com/"), + }); + let folder = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.tagsGuid, + title: "tag", + }); + let bmItemId = await PlacesUtils.promiseItemId(bm.guid); + let bmOldIndex = bm.index; + + const observer = expectPlacesObserverNotifications(["bookmark-moved"]); + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + parentGuid: folder.guid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + }); + Assert.equal(bm.index, 0); + observer.check([ + { + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: "http://move.example.com/", + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: PlacesUtils.bookmarks.unfiledGuid, + oldIndex: bmOldIndex, + isTagging: true, }, ]); }); @@ -876,7 +912,7 @@ add_task(async function reorder_notification() { // Randomly reorder the array. sorted.sort(() => 0.5 - Math.random()); - let observer = expectNotifications(); + const observer = expectPlacesObserverNotifications(["bookmark-moved"]); await PlacesUtils.bookmarks.reorder( PlacesUtils.bookmarks.unfiledGuid, sorted.map(bm => bm.guid) @@ -887,20 +923,20 @@ add_task(async function reorder_notification() { let child = sorted[i]; let childId = await PlacesUtils.promiseItemId(child.guid); expectedNotifications.push({ - name: "onItemMoved", - arguments: [ - childId, - child.index, - i, - child.type, - child.guid, - child.parentGuid, - child.parentGuid, - Ci.nsINavBookmarksService.SOURCE_DEFAULT, - child.url, - ], + type: "bookmark-moved", + id: childId, + itemType: child.type, + url: child.url || "", + guid: child.guid, + parentGuid: child.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: i, + oldParentGuid: child.parentGuid, + oldIndex: child.index, + isTagging: false, }); } + observer.check(expectedNotifications); }); diff --git a/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js b/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js index 74ad712f4d0c..929c561d2854 100644 --- a/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js +++ b/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js @@ -127,11 +127,11 @@ add_task(async function setup() { gBookmarkSkipObserver ); PlacesUtils.observers.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], gBookmarksObserver.handlePlacesEvents ); PlacesUtils.observers.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], gBookmarkSkipObserver.handlePlacesEvents ); }); @@ -492,20 +492,20 @@ add_task(async function onItemChanged_tags_bookmark() { await promise; }); -add_task(async function onItemMoved_bookmark() { +add_task(async function bookmarkItemMoved_bookmark() { let bm = await PlacesUtils.bookmarks.fetch({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, index: 0, }); let promise = Promise.all([ - gBookmarkSkipObserver.setup(["onItemMoved", "onItemMoved"]), + gBookmarkSkipObserver.setup(["bookmark-moved", "bookmark-moved"]), gBookmarksObserver.setup([ { - name: "onItemMoved", + eventType: "bookmark-moved", args: [ - { name: "itemId", check: v => typeof v == "number" && v > 0 }, + { name: "id", check: v => typeof v == "number" && v > 0 }, { name: "oldIndex", check: v => v === 0 }, - { name: "newIndex", check: v => v === 0 }, + { name: "index", check: v => v === 0 }, { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK, @@ -519,7 +519,7 @@ add_task(async function onItemMoved_bookmark() { check: v => typeof v == "string" && PlacesUtils.isValidGuid(v), }, { - name: "newParentGuid", + name: "parentGuid", check: v => typeof v == "string" && PlacesUtils.isValidGuid(v), }, { @@ -531,11 +531,11 @@ add_task(async function onItemMoved_bookmark() { ], }, { - name: "onItemMoved", + eventType: "bookmark-moved", args: [ - { name: "itemId", check: v => typeof v == "number" && v > 0 }, + { name: "id", check: v => typeof v == "number" && v > 0 }, { name: "oldIndex", check: v => v === 0 }, - { name: "newIndex", check: v => v === 0 }, + { name: "index", check: v => v === 0 }, { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK, @@ -549,7 +549,7 @@ add_task(async function onItemMoved_bookmark() { check: v => typeof v == "string" && PlacesUtils.isValidGuid(v), }, { - name: "newParentGuid", + name: "parentGuid", check: v => typeof v == "string" && PlacesUtils.isValidGuid(v), }, { diff --git a/toolkit/components/places/tests/sync/head_sync.js b/toolkit/components/places/tests/sync/head_sync.js index dc4bc4462773..7bd9956ec458 100644 --- a/toolkit/components/places/tests/sync/head_sync.js +++ b/toolkit/components/places/tests/sync/head_sync.js @@ -344,6 +344,22 @@ BookmarkObserver.prototype = { this.notifications.push({ name: "bookmark-removed", params }); break; } + case "bookmark-moved": { + const params = { + itemId: event.id, + type: event.itemType, + urlHref: event.url, + source: event.source, + guid: event.guid, + newIndex: event.index, + newParentGuid: event.parentGuid, + oldIndex: event.oldIndex, + oldParentGuid: event.oldParentGuid, + isTagging: event.isTagging, + }; + this.notifications.push({ name: "bookmark-moved", params }); + break; + } } } }, @@ -409,7 +425,7 @@ BookmarkObserver.prototype = { check(expectedNotifications) { PlacesUtils.bookmarks.removeObserver(this); PlacesUtils.observers.removeListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], this.handlePlacesEvents ); if (!ObjectUtils.deepEqual(this.notifications, expectedNotifications)) { @@ -427,7 +443,7 @@ function expectBookmarkChangeNotifications(options) { let observer = new BookmarkObserver(options); PlacesUtils.bookmarks.addObserver(observer); PlacesUtils.observers.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], observer.handlePlacesEvents ); return observer; diff --git a/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js b/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js index e1943f132342..8ea1c8695555 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js +++ b/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js @@ -476,7 +476,7 @@ add_task(async function test_apply_then_revert() { }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkEEEE"), oldIndex: 2, @@ -487,10 +487,11 @@ add_task(async function test_apply_then_revert() { newParentGuid: PlacesUtils.bookmarks.menuGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/e", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("folderAAAAAA"), oldIndex: 0, @@ -500,11 +501,12 @@ add_task(async function test_apply_then_revert() { oldParentGuid: PlacesUtils.bookmarks.menuGuid, newParentGuid: PlacesUtils.bookmarks.toolbarGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, - urlHref: null, + urlHref: "", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkCCCC"), oldIndex: 1, @@ -515,10 +517,11 @@ add_task(async function test_apply_then_revert() { newParentGuid: "folderAAAAAA", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/c", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkBBBB"), oldIndex: 0, @@ -529,6 +532,7 @@ add_task(async function test_apply_then_revert() { newParentGuid: "folderAAAAAA", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/b-remote", + isTagging: false, }, }, { diff --git a/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js b/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js index 64f8159257cd..70559162fd0b 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js +++ b/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js @@ -149,7 +149,7 @@ add_task(async function test_value_structure_conflict() { ]); observer.check([ { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkEEEE"), oldIndex: 1, @@ -160,10 +160,11 @@ add_task(async function test_value_structure_conflict() { newParentGuid: "folderDDDDDD", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/e", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkBBBB"), oldIndex: 0, @@ -174,6 +175,7 @@ add_task(async function test_value_structure_conflict() { newParentGuid: "folderDDDDDD", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/b", + isTagging: false, }, }, { @@ -398,7 +400,7 @@ add_task(async function test_move() { ]); observer.check([ { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("devFolder___"), oldIndex: 0, @@ -408,11 +410,12 @@ add_task(async function test_move() { oldParentGuid: PlacesUtils.bookmarks.menuGuid, newParentGuid: PlacesUtils.bookmarks.toolbarGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, - urlHref: null, + urlHref: "", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("mozFolder___"), oldIndex: 1, @@ -422,11 +425,12 @@ add_task(async function test_move() { oldParentGuid: "devFolder___", newParentGuid: PlacesUtils.bookmarks.unfiledGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, - urlHref: null, + urlHref: "", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bzBmk_______"), oldIndex: 1, @@ -437,10 +441,11 @@ add_task(async function test_move() { newParentGuid: "devFolder___", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "https://bugzilla.mozilla.org/", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("wmBmk_______"), oldIndex: 2, @@ -451,10 +456,11 @@ add_task(async function test_move() { newParentGuid: "devFolder___", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "https://webmaker.org/", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("nightlyBmk__"), oldIndex: 1, @@ -465,10 +471,11 @@ add_task(async function test_move() { newParentGuid: "mozFolder___", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "https://nightly.mozilla.org/", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("mdnBmk______"), oldIndex: 0, @@ -479,10 +486,11 @@ add_task(async function test_move() { newParentGuid: "mozFolder___", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "https://developer.mozilla.org/", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("fxBmk_______"), oldIndex: 0, @@ -493,6 +501,7 @@ add_task(async function test_move() { newParentGuid: "mozFolder___", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://getfirefox.com/", + isTagging: false, }, }, ]); @@ -714,7 +723,7 @@ add_task(async function test_move_into_parent_sibling() { }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkBBBB"), oldIndex: 0, @@ -725,6 +734,7 @@ add_task(async function test_move_into_parent_sibling() { newParentGuid: "folderCCCCCC", source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/b", + isTagging: false, }, }, ]); @@ -931,7 +941,7 @@ add_task(async function test_complex_move_with_additions() { }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkCCCC"), oldIndex: 1, @@ -942,10 +952,11 @@ add_task(async function test_complex_move_with_additions() { newParentGuid: PlacesUtils.bookmarks.menuGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/c", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("folderAAAAAA"), oldIndex: 0, @@ -955,7 +966,8 @@ add_task(async function test_complex_move_with_additions() { oldParentGuid: PlacesUtils.bookmarks.menuGuid, newParentGuid: PlacesUtils.bookmarks.toolbarGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, - urlHref: null, + urlHref: "", + isTagging: false, }, }, ]); diff --git a/toolkit/components/places/tests/sync/test_bookmark_value_changes.js b/toolkit/components/places/tests/sync/test_bookmark_value_changes.js index 2379e8e71f8b..3f14ef8f7980 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_value_changes.js +++ b/toolkit/components/places/tests/sync/test_bookmark_value_changes.js @@ -218,7 +218,7 @@ add_task(async function test_value_combo() { }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bzBmk_______"), oldIndex: 0, @@ -229,6 +229,7 @@ add_task(async function test_value_combo() { newParentGuid: PlacesUtils.bookmarks.toolbarGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "https://bugzilla.mozilla.org/", + isTagging: false, }, }, { @@ -1364,12 +1365,12 @@ add_task(async function test_keywords_complex() { }, }, { - // These `onItemMoved` notifications aren't necessary: we only moved + // These `bookmark-moved` notifications aren't necessary: we only moved // (B C D E) to accomodate (A A1 B1), and Places doesn't usually fire move // notifications for repositioned siblings. However, detecting and filtering // these out complicates `noteObserverChanges`, so, for simplicity, we // record and fire the extra notifications. - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkBBBB"), oldIndex: 0, @@ -1380,10 +1381,11 @@ add_task(async function test_keywords_complex() { newParentGuid: PlacesUtils.bookmarks.menuGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/b", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkCCCC"), oldIndex: 1, @@ -1394,10 +1396,11 @@ add_task(async function test_keywords_complex() { newParentGuid: PlacesUtils.bookmarks.menuGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/c-remote", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkDDDD"), oldIndex: 2, @@ -1408,10 +1411,11 @@ add_task(async function test_keywords_complex() { newParentGuid: PlacesUtils.bookmarks.menuGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/d", + isTagging: false, }, }, { - name: "onItemMoved", + name: "bookmark-moved", params: { itemId: localItemIds.get("bookmarkEEEE"), oldIndex: 3, @@ -1422,6 +1426,7 @@ add_task(async function test_keywords_complex() { newParentGuid: PlacesUtils.bookmarks.menuGuid, source: PlacesUtils.bookmarks.SOURCES.SYNC, urlHref: "http://example.com/e", + isTagging: false, }, }, { diff --git a/toolkit/components/places/tests/unit/test_async_transactions.js b/toolkit/components/places/tests/unit/test_async_transactions.js index dbb2fc319615..10599ede62b0 100644 --- a/toolkit/components/places/tests/unit/test_async_transactions.js +++ b/toolkit/components/places/tests/unit/test_async_transactions.js @@ -58,6 +58,16 @@ var observer = { index: event.index, itemType: event.itemType, }); + break; + case "bookmark-moved": + this.itemsMoved.set(event.guid, { + oldParentGuid: event.oldParentGuid, + oldIndex: event.oldIndex, + newParentGuid: event.parentGuid, + newIndex: event.index, + itemType: event.itemType, + }); + break; } } }, @@ -118,13 +128,13 @@ function run_test() { bmsvc.addObserver(observer); observer.handlePlacesEvents = observer.handlePlacesEvents.bind(observer); obsvc.addListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], observer.handlePlacesEvents ); registerCleanupFunction(function() { bmsvc.removeObserver(observer); obsvc.removeListener( - ["bookmark-added", "bookmark-removed"], + ["bookmark-added", "bookmark-removed", "bookmark-moved"], observer.handlePlacesEvents ); });