Bug 1426245 - Replace OnItemAdded with bookmark-item-added r=mak

See https://docs.google.com/document/d/1G45vfd6RXFXwNz7i4FV40lDCU0ao-JX_bZdgJV4tLjk/edit#
for further info. This essentially follows the same philosophy as
the onVisits migration.

MozReview-Commit-ID: I4bOvFH0ZQR

Depends on D4605

Differential Revision: https://phabricator.services.mozilla.com/D4606

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Doug Thayer 2018-10-09 14:47:27 +00:00
Родитель 51b3a9348b
Коммит 218843ef6a
20 изменённых файлов: 508 добавлений и 218 удалений

Просмотреть файл

@ -1431,6 +1431,7 @@ var BookmarkingUI = {
if (this._hasBookmarksObserver) {
PlacesUtils.bookmarks.removeObserver(this);
PlacesUtils.observers.removeListener(["bookmark-added"], this.handlePlacesEvents);
}
if (this._pendingUpdate) {
@ -1476,6 +1477,8 @@ var BookmarkingUI = {
if (!this._hasBookmarksObserver) {
try {
PlacesUtils.bookmarks.addObserver(this);
this.handlePlacesEvents = this.handlePlacesEvents.bind(this);
PlacesUtils.observers.addListener(["bookmark-added"], this.handlePlacesEvents);
this._hasBookmarksObserver = true;
} catch (ex) {
Cu.reportError("BookmarkingUI failed adding a bookmarks observer: " + ex);
@ -1710,20 +1713,22 @@ var BookmarkingUI = {
updateToggleControlLabel(triggerNode);
},
// nsINavBookmarkObserver
onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle, aDateAdded, aGuid) {
if (aURI && aURI.equals(this._uri)) {
// If a new bookmark has been added to the tracked uri, register it.
if (!this._itemGuids.has(aGuid)) {
this._itemGuids.add(aGuid);
// Only need to update the UI if it wasn't marked as starred before:
if (this._itemGuids.size == 1) {
this._updateStar();
handlePlacesEvents(aEvents) {
// Only need to update the UI if it wasn't marked as starred before:
if (this._itemGuids.size == 0) {
for (let {url, guid} of aEvents) {
if (url && url == this._uri.spec) {
// If a new bookmark has been added to the tracked uri, register it.
if (!this._itemGuids.has(guid)) {
this._itemGuids.add(guid);
this._updateStar();
}
}
}
}
},
// nsINavBookmarkObserver
onItemRemoved(aItemId, aParentId, aIndex, aItemType, aURI, aGuid) {
// If one of the tracked bookmarks has been removed, unregister it.
if (this._itemGuids.has(aGuid)) {

Просмотреть файл

@ -107,27 +107,34 @@ let observer = new class extends EventEmitter {
this.skipTags = true;
this.skipDescendantsOnItemRemoval = true;
this.handlePlacesEvents = this.handlePlacesEvents.bind(this);
}
onBeginUpdateBatch() {}
onEndUpdateBatch() {}
onItemAdded(id, parentId, index, itemType, uri, title, dateAdded, guid, parentGuid, source) {
let bookmark = {
id: guid,
parentId: parentGuid,
index,
title,
dateAdded: dateAdded / 1000,
type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(itemType),
url: getUrl(itemType, uri && uri.spec),
};
handlePlacesEvents(events) {
for (let event of events) {
if (event.isTagging) {
continue;
}
let bookmark = {
id: event.guid,
parentId: event.parentGuid,
index: event.index,
title: event.title,
dateAdded: event.dateAdded,
type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(event.itemType),
url: getUrl(event.itemType, event.url),
};
if (itemType == TYPE_FOLDER) {
bookmark.dateGroupModified = bookmark.dateAdded;
if (event.itemType == TYPE_FOLDER) {
bookmark.dateGroupModified = bookmark.dateAdded;
}
this.emit("created", bookmark);
}
this.emit("created", bookmark);
}
onItemVisited() {}
@ -173,6 +180,7 @@ const decrementListeners = () => {
listenerCount -= 1;
if (!listenerCount) {
PlacesUtils.bookmarks.removeObserver(observer);
PlacesUtils.observers.removeListener(["bookmark-added"], observer.handlePlacesEvents);
}
};
@ -180,6 +188,7 @@ const incrementListeners = () => {
listenerCount++;
if (listenerCount == 1) {
PlacesUtils.bookmarks.addObserver(observer);
PlacesUtils.observers.addListener(["bookmark-added"], observer.handlePlacesEvents);
}
};

Просмотреть файл

@ -79,46 +79,6 @@ class BookmarksObserver extends Observer {
this.skipTags = true;
}
/**
* onItemAdded - Called when a bookmark is added
*
* @param {str} id
* @param {str} folderId
* @param {int} index
* @param {int} type Indicates if the bookmark is an actual bookmark,
* a folder, or a separator.
* @param {str} uri
* @param {str} title
* @param {int} dateAdded
* @param {str} guid The unique id of the bookmark
* @param {str} parent guid
* @param {int} source Used to distinguish bookmarks made by different
* actions: sync, bookmarks import, other.
*/
onItemAdded(id, folderId, index, type, uri, bookmarkTitle, dateAdded, bookmarkGuid, parentGuid, source) { // eslint-disable-line max-params
// Skips items that are not bookmarks (like folders), about:* pages or
// default bookmarks, added when the profile is created.
if (type !== PlacesUtils.bookmarks.TYPE_BOOKMARK ||
source === PlacesUtils.bookmarks.SOURCES.IMPORT ||
source === PlacesUtils.bookmarks.SOURCES.RESTORE ||
source === PlacesUtils.bookmarks.SOURCES.RESTORE_ON_STARTUP ||
source === PlacesUtils.bookmarks.SOURCES.SYNC ||
(uri.scheme !== "http" && uri.scheme !== "https")) {
return;
}
this.dispatch({type: at.PLACES_LINKS_CHANGED});
this.dispatch({
type: at.PLACES_BOOKMARK_ADDED,
data: {
bookmarkGuid,
bookmarkTitle,
dateAdded,
url: uri.spec,
},
});
}
/**
* onItemRemoved - Called when a bookmark is removed
*
@ -158,12 +118,50 @@ class BookmarksObserver extends Observer {
onItemChanged() {}
}
/**
* PlacesObserver - observes events from PlacesUtils.observers
*/
class PlacesObserver extends Observer {
constructor(dispatch) {
super(dispatch, Ci.nsINavBookmarkObserver);
this.handlePlacesEvent = this.handlePlacesEvent.bind(this);
}
handlePlacesEvent(events) {
for (let {itemType, source, dateAdded, guid, title, url, isTagging} of events) {
// Skips items that are not bookmarks (like folders), about:* pages or
// default bookmarks, added when the profile is created.
if (isTagging ||
itemType !== PlacesUtils.bookmarks.TYPE_BOOKMARK ||
source === PlacesUtils.bookmarks.SOURCES.IMPORT ||
source === PlacesUtils.bookmarks.SOURCES.RESTORE ||
source === PlacesUtils.bookmarks.SOURCES.RESTORE_ON_STARTUP ||
source === PlacesUtils.bookmarks.SOURCES.SYNC ||
(!url.startsWith("http://") && !url.startsWith("https://"))) {
return;
}
this.dispatch({type: at.PLACES_LINKS_CHANGED});
this.dispatch({
type: at.PLACES_BOOKMARK_ADDED,
data: {
bookmarkGuid: guid,
bookmarkTitle: title,
dateAdded: dateAdded * 1000,
url
}
});
}
}
}
class PlacesFeed {
constructor() {
this.placesChangedTimer = null;
this.customDispatch = this.customDispatch.bind(this);
this.historyObserver = new HistoryObserver(this.customDispatch);
this.bookmarksObserver = new BookmarksObserver(this.customDispatch);
this.placesObserver = new PlacesObserver(this.customDispatch);
}
addObservers() {
@ -174,6 +172,8 @@ class PlacesFeed {
Cc["@mozilla.org/browser/nav-bookmarks-service;1"]
.getService(Ci.nsINavBookmarksService)
.addObserver(this.bookmarksObserver, true);
PlacesUtils.observers.addListener(["bookmark-added"],
this.placesObserver.handlePlacesEvent);
Services.obs.addObserver(this, LINK_BLOCKED_EVENT);
}
@ -214,6 +214,8 @@ class PlacesFeed {
}
PlacesUtils.history.removeObserver(this.historyObserver);
PlacesUtils.bookmarks.removeObserver(this.bookmarksObserver);
PlacesUtils.observers.removeListener(["bookmark-added"],
this.placesObserver.handlePlacesEvent);
Services.obs.removeObserver(this, LINK_BLOCKED_EVENT);
}

Просмотреть файл

@ -1027,7 +1027,6 @@ var gEditItemOverlay = {
});
},
onItemAdded() {},
onItemRemoved() { },
onBeginUpdateBatch() { },
onEndUpdateBatch() { },

53
dom/base/PlacesBookmark.h Normal file
Просмотреть файл

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_PlacesBookmark_h
#define mozilla_dom_PlacesBookmark_h
#include "mozilla/dom/PlacesEvent.h"
namespace mozilla {
namespace dom {
class PlacesBookmark : public PlacesEvent
{
public:
explicit PlacesBookmark(PlacesEventType aEventType) : PlacesEvent(aEventType) {}
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{
return PlacesBookmark_Binding::Wrap(aCx, this, aGivenProto);
}
const PlacesBookmark* AsPlacesBookmark() const override { return this; }
unsigned short ItemType() { return mItemType; }
int64_t Id() { return mId; }
int64_t ParentId() { return mParentId; }
void GetUrl(nsString& aUrl) { aUrl = mUrl; }
void GetGuid(nsCString& aGuid) { aGuid = mGuid; }
void GetParentGuid(nsCString& aParentGuid) { aParentGuid = mParentGuid; }
uint16_t Source() { return mSource; }
bool IsTagging() { return mIsTagging; }
unsigned short mItemType;
int64_t mId;
int64_t mParentId;
nsString mUrl;
nsCString mGuid;
nsCString mParentGuid;
uint16_t mSource;
bool mIsTagging;
protected:
virtual ~PlacesBookmark() = default;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PlacesBookmark_h

Просмотреть файл

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_PlacesBookmarkAddition_h
#define mozilla_dom_PlacesBookmarkAddition_h
#include "mozilla/dom/PlacesBookmark.h"
namespace mozilla {
namespace dom {
class PlacesBookmarkAddition final : public PlacesBookmark
{
public:
explicit PlacesBookmarkAddition() : PlacesBookmark(PlacesEventType::Bookmark_added) {}
static already_AddRefed<PlacesBookmarkAddition>
Constructor(const GlobalObject& aGlobal,
const PlacesBookmarkAdditionInit& aInitDict,
ErrorResult& aRv) {
RefPtr<PlacesBookmarkAddition> event = new PlacesBookmarkAddition();
event->mItemType = aInitDict.mItemType;
event->mId = aInitDict.mId;
event->mParentId = aInitDict.mParentId;
event->mIndex = aInitDict.mIndex;
event->mUrl = aInitDict.mUrl;
event->mTitle = aInitDict.mTitle;
event->mDateAdded = aInitDict.mDateAdded;
event->mGuid = aInitDict.mGuid;
event->mParentGuid = aInitDict.mParentGuid;
event->mSource = aInitDict.mSource;
event->mIsTagging = aInitDict.mIsTagging;
return event.forget();
}
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{
return PlacesBookmarkAddition_Binding::Wrap(aCx, this, aGivenProto);
}
const PlacesBookmarkAddition* AsPlacesBookmarkAddition() const override { return this; }
int32_t Index() { return mIndex; }
void GetTitle(nsString& aTitle) { aTitle = mTitle; }
uint64_t DateAdded() { return mDateAdded; }
int32_t mIndex;
nsString mTitle;
uint64_t mDateAdded;
private:
~PlacesBookmarkAddition() = default;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PlacesBookmarkAddition_h

Просмотреть файл

@ -37,6 +37,8 @@ public:
PlacesEventType Type() const { return mType; }
virtual const PlacesVisit* AsPlacesVisit() const { return nullptr; }
virtual const PlacesBookmark* AsPlacesBookmark() const { return nullptr; }
virtual const PlacesBookmarkAddition* AsPlacesBookmarkAddition() const { return nullptr; }
protected:
virtual ~PlacesEvent() = default;
PlacesEventType mType;

Просмотреть файл

@ -205,6 +205,8 @@ EXPORTS.mozilla.dom += [
'NodeInfoInlines.h',
'NodeIterator.h',
'ParentProcessMessageManager.h',
'PlacesBookmark.h',
'PlacesBookmarkAddition.h',
'PlacesEvent.h',
'PlacesObservers.h',
'PlacesVisit.h',

Просмотреть файл

@ -5,6 +5,11 @@ enum PlacesEventType {
* data: PlacesVisit. Fired whenever a page is visited.
*/
"page-visited",
/**
* data: PlacesBookmarkAddition. Fired whenever a bookmark
* (or a bookmark folder/separator) is created.
*/
"bookmark-added",
};
[ChromeOnly, Exposed=(Window,System)]
@ -67,3 +72,83 @@ interface PlacesVisit : PlacesEvent {
*/
readonly attribute DOMString? lastKnownTitle;
};
/**
* Base class for properties that are common to all bookmark events.
*/
[ChromeOnly, Exposed=(Window,System)]
interface PlacesBookmark : PlacesEvent {
/**
* The id of the item.
*/
readonly attribute long long id;
/**
* The id of the folder to which the item belongs.
*/
readonly attribute long long parentId;
/**
* The type of the added item (see TYPE_* constants in nsINavBooksService.idl).
*/
readonly attribute unsigned short itemType;
/**
* The URI of the added item if it was TYPE_BOOKMARK, "" otherwise.
*/
readonly attribute DOMString url;
/**
* The unique ID associated with the item.
*/
readonly attribute ByteString guid;
/**
* The unique ID associated with the item's parent.
*/
readonly attribute ByteString parentGuid;
/**
* A change source constant from nsINavBookmarksService::SOURCE_*,
* passed to the method that notifies the observer.
*/
readonly attribute unsigned short source;
/**
* True if the item is a tag or a tag folder.
* NOTE: this will go away with bug 424160.
*/
readonly attribute boolean isTagging;
};
dictionary PlacesBookmarkAdditionInit {
required long long id;
required long long parentId;
required unsigned short itemType;
required DOMString url;
required ByteString guid;
required ByteString parentGuid;
required unsigned short source;
required long index;
required DOMString title;
required unsigned long long dateAdded;
required boolean isTagging;
};
[ChromeOnly, Exposed=(Window,System), Constructor(PlacesBookmarkAdditionInit initDict)]
interface PlacesBookmarkAddition : PlacesBookmark {
/**
* The item's index in the folder.
*/
readonly attribute long index;
/**
* The title of the added item.
*/
readonly attribute DOMString title;
/**
* The time that the item was added, in milliseconds from the epoch.
*/
readonly attribute unsigned long long dateAdded;
};

Просмотреть файл

@ -1289,6 +1289,8 @@ BookmarksTracker.prototype = {
onStart() {
PlacesUtils.bookmarks.addObserver(this, true);
this._placesListener = new PlacesWeakCallbackWrapper(this.handlePlacesEvents.bind(this));
PlacesUtils.observers.addListener(["bookmark-added"], this._placesListener);
Svc.Obs.add("bookmarks-restore-begin", this);
Svc.Obs.add("bookmarks-restore-success", this);
Svc.Obs.add("bookmarks-restore-failed", this);
@ -1296,6 +1298,7 @@ BookmarksTracker.prototype = {
onStop() {
PlacesUtils.bookmarks.removeObserver(this);
PlacesUtils.observers.removeListener(["bookmark-added"], this._placesListener);
Svc.Obs.remove("bookmarks-restore-begin", this);
Svc.Obs.remove("bookmarks-restore-success", this);
Svc.Obs.remove("bookmarks-restore-failed", this);
@ -1363,15 +1366,15 @@ BookmarksTracker.prototype = {
}
},
onItemAdded: function BMT_onItemAdded(itemId, folder, index,
itemType, uri, title, dateAdded,
guid, parentGuid, source) {
if (IGNORED_SOURCES.includes(source)) {
return;
}
handlePlacesEvents(events) {
for (let event of events) {
if (IGNORED_SOURCES.includes(event.source)) {
continue;
}
this._log.trace("onItemAdded: " + itemId);
this._upScore();
this._log.trace("'bookmark-added': " + event.id);
this._upScore();
}
},
onItemRemoved(itemId, parentId, index, type, uri,

Просмотреть файл

@ -279,24 +279,36 @@ var Bookmarks = Object.freeze({
let item = await insertBookmark(insertInfo, parent);
// Notify onItemAdded to listeners.
let observers = PlacesUtils.bookmarks.getObservers();
// We need the itemId to notify, though once the switch to guids is
// complete we may stop using it.
let uri = item.hasOwnProperty("url") ? PlacesUtils.toURI(item.url) : null;
let itemId = await PlacesUtils.promiseItemId(item.guid);
// Pass tagging information for the observers to skip over these notifications when needed.
let isTagging = parent._parentId == PlacesUtils.tagsFolderId;
let isTagsFolder = parent._id == PlacesUtils.tagsFolderId;
notify(observers, "onItemAdded", [ itemId, parent._id, item.index,
item.type, uri, item.title,
PlacesUtils.toPRTime(item.dateAdded), item.guid,
item.parentGuid, item.source ],
{ isTagging: isTagging || isTagsFolder });
let url = "";
if (item.type == Bookmarks.TYPE_BOOKMARK) {
url = item.url.href;
}
let notification = new PlacesBookmarkAddition({
id: itemId,
url,
itemType: item.type,
parentId: parent._id,
index: item.index,
title: item.title,
dateAdded: item.dateAdded,
guid: item.guid,
parentGuid: item.parentGuid,
source: item.source,
isTagging: isTagging || isTagsFolder,
});
PlacesObservers.notifyListeners([notification]);
// If it's a tag, notify OnItemChanged to all bookmarks for this URL.
if (isTagging) {
let observers = PlacesUtils.bookmarks.getObservers();
for (let entry of (await fetchBookmarksByURL(item, true))) {
notify(observers, "onItemChanged", [ entry._id, "tags", false, "",
PlacesUtils.toPRTime(entry.lastModified),
@ -554,12 +566,11 @@ var Bookmarks = Object.freeze({
// We need the itemIds to notify, though once the switch to guids is
// complete we may stop using them.
let itemIdMap = await PlacesUtils.promiseManyItemIds(insertInfos.map(info => info.guid));
// Notify onItemAdded to listeners.
let observers = PlacesUtils.bookmarks.getObservers();
let notifications = [];
for (let i = 0; i < insertInfos.length; i++) {
let item = insertInfos[i];
let itemId = itemIdMap.get(item.guid);
let uri = item.hasOwnProperty("url") ? PlacesUtils.toURI(item.url) : null;
// For sub-folders, we need to make sure their children have the correct parent ids.
let parentId;
if (item.parentGuid === treeParent.guid) {
@ -572,11 +583,25 @@ var Bookmarks = Object.freeze({
parentId = itemIdMap.get(item.parentGuid);
}
notify(observers, "onItemAdded", [ itemId, parentId, item.index,
item.type, uri, item.title,
PlacesUtils.toPRTime(item.dateAdded), item.guid,
item.parentGuid, item.source ],
{ isTagging: false });
let url = "";
if (item.type == Bookmarks.TYPE_BOOKMARK) {
url = (item.url instanceof URL) ? item.url.href : item.url;
}
notifications.push(new PlacesBookmarkAddition({
id: itemId,
url,
itemType: item.type,
parentId,
index: item.index,
title: item.title,
dateAdded: item.dateAdded,
guid: item.guid,
parentGuid: item.parentGuid,
source: item.source,
isTagging: false,
}));
// Note, annotations for livemark data are deleted from insertInfo
// within appendInsertionInfoForInfoArray, so we won't be duplicating
// the insertions here.
@ -593,6 +618,9 @@ var Bookmarks = Object.freeze({
insertInfos[i] = Object.assign({}, item);
}
PlacesObservers.notifyListeners(notifications);
return insertInfos;
})();
},

Просмотреть файл

@ -2676,12 +2676,13 @@ var GuidHelper = {
* So, for exmaple, when the NewBookmark needs the new GUID, we already
* have it cached.
*/
let listener = events => {
for (let event of events) {
this.updateCache(event.id, event.guid);
this.updateCache(event.parentId, event.parentGuid);
}
};
this.observer = {
onItemAdded: (aItemId, aParentId, aIndex, aItemType, aURI, aTitle,
aDateAdded, aGuid, aParentGuid) => {
this.updateCache(aItemId, aGuid);
this.updateCache(aParentId, aParentGuid);
},
onItemRemoved:
(aItemId, aParentId, aIndex, aItemTyep, aURI, aGuid, aParentGuid) => {
this.guidsForIds.delete(aItemId);
@ -2698,8 +2699,10 @@ var GuidHelper = {
onItemMoved() {},
};
PlacesUtils.bookmarks.addObserver(this.observer);
PlacesUtils.observers.addListener(["bookmark-added"], listener);
PlacesUtils.registerShutdownFunction(() => {
PlacesUtils.bookmarks.removeObserver(this.observer);
PlacesUtils.observers.removeListener(["bookmark-added"], listener);
});
}
},

Просмотреть файл

@ -4619,14 +4619,19 @@ class BookmarkObserverRecorder {
}
noteItemAdded(info) {
let uri = info.urlHref ? Services.io.newURI(info.urlHref) : null;
this.bookmarkObserverNotifications.push({
name: "onItemAdded",
this.bookmarkObserverNotifications.push(new PlacesBookmarkAddition({
id: info.id,
parentId: info.parentId,
index: info.position,
url: info.urlHref || "",
title: info.title,
dateAdded: info.dateAdded,
guid: info.guid,
parentGuid: info.parentGuid,
source: PlacesUtils.bookmarks.SOURCES.SYNC,
itemType: info.type,
isTagging: info.isTagging,
args: [info.id, info.parentId, info.position, info.type, uri, info.title,
info.dateAdded, info.guid, info.parentGuid,
PlacesUtils.bookmarks.SOURCES.SYNC],
});
}));
}
noteGuidChanged(info) {
@ -4703,12 +4708,20 @@ class BookmarkObserverRecorder {
let observers = PlacesUtils.bookmarks.getObservers();
for (let observer of observers) {
this.notifyObserver(observer, "onBeginUpdateBatch");
for await (let info of yieldingIterator(this.bookmarkObserverNotifications)) {
if (info.isTagging && observer.skipTags) {
continue;
}
for await (let info of yieldingIterator(this.bookmarkObserverNotifications)) {
if (info instanceof PlacesEvent) {
PlacesObservers.notifyListeners([info]);
} else {
for (let observer of observers) {
if (info.isTagging && observer.skipTags) {
continue;
}
this.notifyObserver(observer, info.name, info.args);
}
this.notifyObserver(observer, info.name, info.args);
}
}
for (let observer of observers) {
this.notifyObserver(observer, "onEndUpdateBatch");
}
}

Просмотреть файл

@ -42,46 +42,6 @@ interface nsINavBookmarkObserver : nsISupports
*/
void onEndUpdateBatch();
/**
* Notifies that an item (any type) was added. Called after the actual
* addition took place.
* When a new item is created, all the items following it in the same folder
* will have their index shifted down, but no additional notifications will
* be sent.
*
* @param aItemId
* The id of the item that was added.
* @param aParentId
* The id of the folder to which the item was added.
* @param aIndex
* The item's index in the folder.
* @param aItemType
* The type of the added item (see TYPE_* constants below).
* @param aURI
* The URI of the added item if it was TYPE_BOOKMARK, null otherwise.
* @param aTitle
* The title of the added item.
* @param aDateAdded
* The stored date added value, in microseconds from the epoch.
* @param aGuid
* The unique ID associated with the item.
* @param aParentGuid
* The unique ID associated with the item's parent.
* @param aSource
* A change source constant from nsINavBookmarksService::SOURCE_*,
* passed to the method that notifies the observer.
*/
void onItemAdded(in long long aItemId,
in long long aParentId,
in long aIndex,
in unsigned short aItemType,
in nsIURI aURI,
in AUTF8String aTitle,
in PRTime aDateAdded,
in ACString aGuid,
in ACString aParentGuid,
in unsigned short aSource);
/**
* Notifies that an item was removed. Called after the actual remove took
* place.

Просмотреть файл

@ -361,7 +361,6 @@ LivemarkService.prototype = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onItemVisited() {},
onItemAdded() {},
onItemChanged(id, property, isAnno, value, lastModified, itemType, parentId,
guid, parentGuid) {

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsQueryObject.h"
#include "mozilla/Preferences.h"
#include "mozilla/storage.h"
#include "mozilla/dom/PlacesBookmarkAddition.h"
#include "mozilla/dom/PlacesObservers.h"
#include "mozilla/dom/PlacesVisit.h"
@ -225,7 +226,7 @@ nsNavBookmarks::Init()
NS_ENSURE_STATE(history);
history->AddObserver(this, true);
AutoTArray<PlacesEventType, 1> events;
events.AppendElement(PlacesEventType::Page_visited);
events.AppendElement(PlacesEventType::Page_visited, fallible);
PlacesObservers::AddListener(events, this);
// DO NOT PUT STUFF HERE that can fail. See observer comment above.
@ -569,11 +570,28 @@ nsNavBookmarks::InsertBookmark(int64_t aFolder,
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers,
SKIP_TAGS(grandParentId == mDB->GetTagsFolderId()),
OnItemAdded(*aNewBookmarkId, aFolder, index,
TYPE_BOOKMARK, aURI, title, dateAdded,
guid, folderGuid, aSource));
if (mCanNotify) {
Sequence<OwningNonNull<PlacesEvent>> events;
nsAutoCString utf8spec;
aURI->GetSpec(utf8spec);
RefPtr<PlacesBookmarkAddition> bookmark = new PlacesBookmarkAddition();
bookmark->mItemType = TYPE_BOOKMARK;
bookmark->mId = *aNewBookmarkId;
bookmark->mParentId = aFolder;
bookmark->mIndex = index;
bookmark->mUrl.Assign(NS_ConvertUTF8toUTF16(utf8spec));
bookmark->mTitle.Assign(NS_ConvertUTF8toUTF16(title));
bookmark->mDateAdded = dateAdded / 1000;
bookmark->mGuid.Assign(guid);
bookmark->mParentGuid.Assign(folderGuid);
bookmark->mSource = aSource;
bookmark->mIsTagging = grandParentId == mDB->GetTagsFolderId();
bool success = !!events.AppendElement(bookmark.forget(), fallible);
MOZ_RELEASE_ASSERT(success);
PlacesObservers::NotifyListeners(events);
}
// If the bookmark has been added to a tag container, notify all
// bookmark-folder result nodes which contain a bookmark for the new
@ -781,11 +799,24 @@ nsNavBookmarks::CreateFolder(int64_t aParent, const nsACString& aTitle,
int64_t tagsRootId = TagsRootId();
NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers,
SKIP_TAGS(aParent == tagsRootId),
OnItemAdded(*aNewFolderId, aParent, index, FOLDER,
nullptr, title, dateAdded, guid,
folderGuid, aSource));
if (mCanNotify) {
Sequence<OwningNonNull<PlacesEvent>> events;
RefPtr<PlacesBookmarkAddition> folder = new PlacesBookmarkAddition();
folder->mItemType = TYPE_FOLDER;
folder->mId = *aNewFolderId;
folder->mParentId = aParent;
folder->mIndex = index;
folder->mTitle.Assign(NS_ConvertUTF8toUTF16(title));
folder->mDateAdded = dateAdded / 1000;
folder->mGuid.Assign(guid);
folder->mParentGuid.Assign(folderGuid);
folder->mSource = aSource;
folder->mIsTagging = aParent == tagsRootId;
bool success = !!events.AppendElement(folder.forget(), fallible);
MOZ_RELEASE_ASSERT(success);
PlacesObservers::NotifyListeners(events);
}
return NS_OK;
}

Просмотреть файл

@ -2696,13 +2696,12 @@ nsNavHistoryQueryResultNode::NotifyIfTagsChanged(nsIURI* aURI)
* for bookmark events and refresh the results if we have any dependence on
* the bookmark system.
*/
NS_IMETHODIMP
nsresult
nsNavHistoryQueryResultNode::OnItemAdded(int64_t aItemId,
int64_t aParentId,
int32_t aIndex,
uint16_t aItemType,
nsIURI* aURI,
const nsACString& aTitle,
PRTime aDateAdded,
const nsACString& aGUID,
const nsACString& aParentGUID,
@ -3409,13 +3408,12 @@ nsNavHistoryFolderResultNode::OnEndUpdateBatch()
}
NS_IMETHODIMP
nsresult
nsNavHistoryFolderResultNode::OnItemAdded(int64_t aItemId,
int64_t aParentFolder,
int32_t aIndex,
uint16_t aItemType,
nsIURI* aURI,
const nsACString& aTitle,
PRTime aDateAdded,
const nsACString& aGUID,
const nsACString& aParentGUID,
@ -3859,13 +3857,11 @@ nsNavHistoryFolderResultNode::OnItemMoved(int64_t aItemId,
} else {
// moving between two different folders, just do a remove and an add
nsCOMPtr<nsIURI> itemURI;
nsAutoCString itemTitle;
if (aItemType == nsINavBookmarksService::TYPE_BOOKMARK) {
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = bookmarks->GetBookmarkURI(aItemId, getter_AddRefs(itemURI));
NS_ENSURE_SUCCESS(rv, rv);
rv = bookmarks->GetItemTitle(aItemId, itemTitle);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aOldParent == mTargetFolderItemId) {
@ -3873,7 +3869,7 @@ nsNavHistoryFolderResultNode::OnItemMoved(int64_t aItemId,
aGUID, aOldParentGUID, aSource);
}
if (aNewParent == mTargetFolderItemId) {
OnItemAdded(aItemId, aNewParent, aNewIndex, aItemType, itemURI, itemTitle,
OnItemAdded(aItemId, aNewParent, aNewIndex, aItemType, itemURI,
RoundedPRNow(), // This is a dummy dateAdded, not the real value.
aGUID, aNewParentGUID, aSource);
}
@ -3971,6 +3967,7 @@ nsNavHistoryResult::~nsNavHistoryResult()
void
nsNavHistoryResult::StopObserving()
{
AutoTArray<PlacesEventType, 2> events;
if (mIsBookmarkFolderObserver || mIsAllBookmarksObserver) {
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
if (bookmarks) {
@ -3978,6 +3975,7 @@ nsNavHistoryResult::StopObserving()
mIsBookmarkFolderObserver = false;
mIsAllBookmarksObserver = false;
}
events.AppendElement(PlacesEventType::Bookmark_added);
}
if (mIsMobilePrefObserver) {
Preferences::UnregisterCallback(OnMobilePrefChangedCallback,
@ -3989,12 +3987,12 @@ nsNavHistoryResult::StopObserving()
nsNavHistory* history = nsNavHistory::GetHistoryService();
if (history) {
history->RemoveObserver(this);
AutoTArray<PlacesEventType, 1> events;
events.AppendElement(PlacesEventType::Page_visited);
PlacesObservers::RemoveListener(events, this);
mIsHistoryObserver = false;
}
}
PlacesObservers::RemoveListener(events, this);
}
void
@ -4028,6 +4026,9 @@ nsNavHistoryResult::AddAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode)
return;
}
bookmarks->AddObserver(this, true);
AutoTArray<PlacesEventType, 1> events;
events.AppendElement(PlacesEventType::Bookmark_added);
PlacesObservers::AddListener(events, this);
mIsAllBookmarksObserver = true;
}
// Don't add duplicate observers. In some case we don't unregister when
@ -4068,6 +4069,9 @@ nsNavHistoryResult::AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNod
return;
}
bookmarks->AddObserver(this, true);
AutoTArray<PlacesEventType, 1> events;
events.AppendElement(PlacesEventType::Bookmark_added);
PlacesObservers::AddListener(events, this);
mIsBookmarkFolderObserver = true;
}
// Don't add duplicate observers. In some case we don't unregister when
@ -4331,37 +4335,6 @@ nsNavHistoryResult::OnEndUpdateBatch()
}
NS_IMETHODIMP
nsNavHistoryResult::OnItemAdded(int64_t aItemId,
int64_t aParentId,
int32_t aIndex,
uint16_t aItemType,
nsIURI* aURI,
const nsACString& aTitle,
PRTime aDateAdded,
const nsACString& aGUID,
const nsACString& aParentGUID,
uint16_t aSource)
{
NS_ENSURE_ARG(aItemType != nsINavBookmarksService::TYPE_BOOKMARK ||
aURI);
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aParentId,
OnItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle, aDateAdded,
aGUID, aParentGUID, aSource)
);
ENUMERATE_HISTORY_OBSERVERS(
OnItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle, aDateAdded,
aGUID, aParentGUID, aSource)
);
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(
OnItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle, aDateAdded,
aGUID, aParentGUID, aSource)
);
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryResult::OnItemRemoved(int64_t aItemId,
int64_t aParentId,
@ -4593,23 +4566,58 @@ nsNavHistoryResult::OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
void
nsNavHistoryResult::HandlePlacesEvent(const PlacesEventSequence& aEvents) {
for (const auto& event : aEvents) {
if (NS_WARN_IF(event->Type() != PlacesEventType::Page_visited)) {
continue;
}
switch (event->Type()) {
case PlacesEventType::Page_visited: {
const dom::PlacesVisit* visit = event->AsPlacesVisit();
if (NS_WARN_IF(!visit)) {
continue;
}
const dom::PlacesVisit* visit = event->AsPlacesVisit();
if (NS_WARN_IF(!visit)) {
continue;
}
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), visit->mUrl));
if (!uri) {
continue;
}
OnVisit(uri, visit->mVisitId, visit->mVisitTime * 1000,
visit->mTransitionType, visit->mPageGuid,
visit->mHidden, visit->mVisitCount, visit->mLastKnownTitle);
break;
}
case PlacesEventType::Bookmark_added: {
const dom::PlacesBookmarkAddition* item = event->AsPlacesBookmarkAddition();
if (NS_WARN_IF(!item)) {
continue;
}
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), visit->mUrl));
if (!uri) {
return;
nsCOMPtr<nsIURI> uri;
if (item->mItemType == nsINavBookmarksService::TYPE_BOOKMARK) {
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), item->mUrl));
if (!uri) {
continue;
}
}
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(item->mParentId,
OnItemAdded(item->mId, item->mParentId, item->mIndex,
item->mItemType, uri, item->mDateAdded * 1000,
item->mGuid, item->mParentGuid, item->mSource)
);
ENUMERATE_HISTORY_OBSERVERS(
OnItemAdded(item->mId, item->mParentId,item->mIndex,
item->mItemType, uri, item->mDateAdded * 1000,
item->mGuid, item->mParentGuid, item->mSource)
);
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(
OnItemAdded(item->mId, item->mParentId,item->mIndex,
item->mItemType, uri, item->mDateAdded * 1000,
item->mGuid, item->mParentGuid, item->mSource)
);
break;
}
default: {
MOZ_ASSERT_UNREACHABLE("Receive notification of a type not subscribed to.");
}
}
OnVisit(uri, visit->mVisitId, visit->mVisitTime * 1000,
visit->mTransitionType, visit->mPageGuid,
visit->mHidden, visit->mVisitCount, visit->mLastKnownTitle);
}
}

Просмотреть файл

@ -628,6 +628,15 @@ public:
NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL
nsresult OnItemAdded(int64_t aItemId,
int64_t aParentId,
int32_t aIndex,
uint16_t aItemType,
nsIURI* aURI,
PRTime aDateAdded,
const nsACString& aGUID,
const nsACString& aParentGUID,
uint16_t aSource);
// The internal version has an output aAdded parameter, it is incremented by
// query nodes when the visited uri belongs to them. If no such query exists,
// the history result creates a new query node dynamically.
@ -706,6 +715,16 @@ public:
// result's actual observer and it knows all observers are FolderResultNodes
NS_DECL_NSINAVBOOKMARKOBSERVER
nsresult OnItemAdded(int64_t aItemId,
int64_t aParentId,
int32_t aIndex,
uint16_t aItemType,
nsIURI* aURI,
PRTime aDateAdded,
const nsACString& aGUID,
const nsACString& aParentGUID,
uint16_t aSource);
virtual void OnRemoving() override;
// this indicates whether the folder contents are valid, they don't go away

Просмотреть файл

@ -13,8 +13,11 @@ const TOPIC_SHUTDOWN = "places-shutdown";
* The Places Tagging Service
*/
function TaggingService() {
this.handlePlacesEvents = this.handlePlacesEvents.bind(this);
// Observe bookmarks changes.
PlacesUtils.bookmarks.addObserver(this);
PlacesUtils.observers.addListener(["bookmark-added"], this.handlePlacesEvents);
// Cleanup on shutdown.
Services.obs.addObserver(this, TOPIC_SHUTDOWN);
@ -293,6 +296,7 @@ TaggingService.prototype = {
observe: function TS_observe(aSubject, aTopic, aData) {
if (aTopic == TOPIC_SHUTDOWN) {
PlacesUtils.bookmarks.removeObserver(this);
PlacesUtils.observers.removeListener(["bookmark-added"], this.handlePlacesEvents);
Services.obs.removeObserver(this, TOPIC_SHUTDOWN);
}
},
@ -339,17 +343,18 @@ TaggingService.prototype = {
return isBookmarked ? [] : itemIds;
},
// nsINavBookmarkObserver
onItemAdded: function TS_onItemAdded(aItemId, aFolderId, aIndex, aItemType,
aURI, aTitle) {
// Nothing to do if this is not a tag.
if (aFolderId != PlacesUtils.tagsFolderId ||
aItemType != PlacesUtils.bookmarks.TYPE_FOLDER)
return;
handlePlacesEvents(events) {
for (let event of events) {
if (!event.isTagging ||
event.itemType != PlacesUtils.bookmarks.TYPE_FOLDER) {
continue;
}
this._tagFolders[aItemId] = aTitle;
this._tagFolders[event.id] = event.title;
}
},
// nsINavBookmarkObserver
onItemRemoved: function TS_onItemRemoved(aItemId, aFolderId, aIndex,
aItemType, aURI, aGuid, aParentGuid,
aSource) {

Просмотреть файл

@ -53,6 +53,8 @@ module.exports = {
"MatchPatternSet": false,
"MenuBoxObject": false,
// Specific to Firefox (Chrome code only).
"PlacesBookmarkAddition": false,
"PlacesEvent": false,
"PlacesObservers": false,
"PlacesWeakCallbackWrapper": false,
"PrioEncoder": false,