mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1131362 - Update Reasdinglist.jsm consumers to use new API. r=Unfocused
This commit is contained in:
parent
e78a997ded
commit
bf4f401875
@ -89,7 +89,7 @@ let ReadingListUI = {
|
||||
}
|
||||
},
|
||||
|
||||
onReadingListPopupShowing(target) {
|
||||
onReadingListPopupShowing: Task.async(function* (target) {
|
||||
if (target.id == "BMB_readingListPopup") {
|
||||
// Setting this class in the .xul file messes with the way
|
||||
// browser-places.js inserts bookmarks in the menu.
|
||||
@ -105,55 +105,56 @@ let ReadingListUI = {
|
||||
if (insertPoint.classList.contains("subviewbutton"))
|
||||
classList += " subviewbutton";
|
||||
|
||||
ReadingList.getItems().then(items => {
|
||||
for (let item of items) {
|
||||
let menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("label", item.title || item.url.spec);
|
||||
menuitem.setAttribute("class", classList);
|
||||
let hasItems = false;
|
||||
yield ReadingList.forEachItem(item => {
|
||||
hasItems = true;
|
||||
|
||||
let node = menuitem._placesNode = {
|
||||
// Passing the PlacesUtils.nodeIsURI check is required for the
|
||||
// onCommand handler to load our URI.
|
||||
type: Ci.nsINavHistoryResultNode.RESULT_TYPE_URI,
|
||||
let menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("label", item.title || item.url);
|
||||
menuitem.setAttribute("class", classList);
|
||||
|
||||
// makes PlacesUIUtils.canUserRemove return false.
|
||||
// The context menu is broken without this.
|
||||
parent: {type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER},
|
||||
let node = menuitem._placesNode = {
|
||||
// Passing the PlacesUtils.nodeIsURI check is required for the
|
||||
// onCommand handler to load our URI.
|
||||
type: Ci.nsINavHistoryResultNode.RESULT_TYPE_URI,
|
||||
|
||||
// A -1 id makes this item a non-bookmark, which avoids calling
|
||||
// PlacesUtils.annotations.itemHasAnnotation to check if the
|
||||
// bookmark should be opened in the sidebar (this call fails for
|
||||
// readinglist item, and breaks loading our URI).
|
||||
itemId: -1,
|
||||
// makes PlacesUIUtils.canUserRemove return false.
|
||||
// The context menu is broken without this.
|
||||
parent: {type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER},
|
||||
|
||||
// Used by the tooltip and onCommand handlers.
|
||||
uri: item.url.spec,
|
||||
// A -1 id makes this item a non-bookmark, which avoids calling
|
||||
// PlacesUtils.annotations.itemHasAnnotation to check if the
|
||||
// bookmark should be opened in the sidebar (this call fails for
|
||||
// readinglist item, and breaks loading our URI).
|
||||
itemId: -1,
|
||||
|
||||
// Used by the tooltip.
|
||||
title: item.title
|
||||
};
|
||||
// Used by the tooltip and onCommand handlers.
|
||||
uri: item.url,
|
||||
|
||||
Favicons.getFaviconURLForPage(item.url, uri => {
|
||||
if (uri) {
|
||||
menuitem.setAttribute("image",
|
||||
Favicons.getFaviconLinkForIcon(uri).spec);
|
||||
}
|
||||
});
|
||||
// Used by the tooltip.
|
||||
title: item.title
|
||||
};
|
||||
|
||||
target.insertBefore(menuitem, insertPoint);
|
||||
}
|
||||
Favicons.getFaviconURLForPage(item.uri, uri => {
|
||||
if (uri) {
|
||||
menuitem.setAttribute("image",
|
||||
Favicons.getFaviconLinkForIcon(uri).spec);
|
||||
}
|
||||
});
|
||||
|
||||
if (!items.length) {
|
||||
let menuitem = document.createElement("menuitem");
|
||||
let bundle =
|
||||
Services.strings.createBundle("chrome://browser/locale/places/places.properties");
|
||||
menuitem.setAttribute("label", bundle.GetStringFromName("bookmarksMenuEmptyFolder"));
|
||||
menuitem.setAttribute("class", "bookmark-item");
|
||||
menuitem.setAttribute("disabled", true);
|
||||
target.insertBefore(menuitem, insertPoint);
|
||||
}
|
||||
target.insertBefore(menuitem, insertPoint);
|
||||
});
|
||||
},
|
||||
|
||||
if (!hasItems) {
|
||||
let menuitem = document.createElement("menuitem");
|
||||
let bundle =
|
||||
Services.strings.createBundle("chrome://browser/locale/places/places.properties");
|
||||
menuitem.setAttribute("label", bundle.GetStringFromName("bookmarksMenuEmptyFolder"));
|
||||
menuitem.setAttribute("class", "bookmark-item");
|
||||
menuitem.setAttribute("disabled", true);
|
||||
target.insertBefore(menuitem, insertPoint);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Hide the ReadingList sidebar, if it is currently shown.
|
||||
|
@ -110,6 +110,7 @@ function ReadingListImpl(store) {
|
||||
this._store = store;
|
||||
this._itemsByURL = new Map();
|
||||
this._iterators = new Set();
|
||||
this._listeners = new Set();
|
||||
}
|
||||
|
||||
ReadingListImpl.prototype = {
|
||||
@ -183,13 +184,17 @@ ReadingListImpl.prototype = {
|
||||
* are the same as those of items that are already present in the list. The
|
||||
* returned promise is rejected in that case.
|
||||
*
|
||||
* @param item A simple object representing an item.
|
||||
* @return Promise<null> Resolved when the list is updated. Rejected with an
|
||||
* Error on error.
|
||||
* @param obj A simple object representing an item.
|
||||
* @return Promise<ReadingListItem> Resolved with the new item when the list
|
||||
* is updated. Rejected with an Error on error.
|
||||
*/
|
||||
addItem: Task.async(function* (item) {
|
||||
yield this._store.addItem(simpleObjectFromItem(item));
|
||||
addItem: Task.async(function* (obj) {
|
||||
obj = stripNonItemProperties(obj);
|
||||
yield this._store.addItem(obj);
|
||||
this._invalidateIterators();
|
||||
let item = this._itemFromObject(obj);
|
||||
this._callListeners("onItemAdded", item);
|
||||
return item;
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -210,6 +215,7 @@ ReadingListImpl.prototype = {
|
||||
this._ensureItemBelongsToList(item);
|
||||
yield this._store.updateItem(item._properties);
|
||||
this._invalidateIterators();
|
||||
this._callListeners("onItemUpdated", item);
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -228,8 +234,32 @@ ReadingListImpl.prototype = {
|
||||
item.list = null;
|
||||
this._itemsByURL.delete(item.url);
|
||||
this._invalidateIterators();
|
||||
this._callListeners("onItemDeleted", item);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Adds a listener that will be notified when the list changes. Listeners
|
||||
* are objects with the following optional methods:
|
||||
*
|
||||
* onItemAdded(item)
|
||||
* onItemUpdated(item)
|
||||
* onItemDeleted(item)
|
||||
*
|
||||
* @param listener A listener object.
|
||||
*/
|
||||
addListener(listener) {
|
||||
this._listeners.add(listener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a listener from the list.
|
||||
*
|
||||
* @param listener A listener object.
|
||||
*/
|
||||
removeListener(listener) {
|
||||
this._listeners.delete(listener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Call this when you're done with the list. Don't use it afterward.
|
||||
*/
|
||||
@ -255,6 +285,9 @@ ReadingListImpl.prototype = {
|
||||
// by the list.
|
||||
_iterators: null,
|
||||
|
||||
// A Set containing listener objects.
|
||||
_listeners: null,
|
||||
|
||||
/**
|
||||
* Returns the ReadingListItem represented by the given simple object. If
|
||||
* the item doesn't exist yet, it's created first.
|
||||
@ -290,6 +323,25 @@ ReadingListImpl.prototype = {
|
||||
this._iterators.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls a method on all listeners.
|
||||
*
|
||||
* @param methodName The name of the method to call.
|
||||
* @param item This item will be passed to the listeners.
|
||||
*/
|
||||
_callListeners(methodName, item) {
|
||||
for (let listener of this._listeners) {
|
||||
if (methodName in listener) {
|
||||
try {
|
||||
listener[methodName](item);
|
||||
}
|
||||
catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_ensureItemBelongsToList(item) {
|
||||
if (item.list != this) {
|
||||
throw new Error("The item does not belong to this list");
|
||||
@ -313,7 +365,19 @@ function ReadingListItem(props={}) {
|
||||
ReadingListItem.prototype = {
|
||||
|
||||
/**
|
||||
* The item's GUID.
|
||||
* Item's unique ID.
|
||||
* @type string
|
||||
*/
|
||||
get id() {
|
||||
if (!this._id) {
|
||||
this._id = hash(this.url);
|
||||
}
|
||||
return this._id;
|
||||
},
|
||||
|
||||
/**
|
||||
* The item's server-side GUID. This is set by the remote server and therefore is not
|
||||
* guarenteed to be set for local items.
|
||||
* @type string
|
||||
*/
|
||||
get guid() {
|
||||
@ -372,6 +436,18 @@ ReadingListItem.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the domain (a string) of the item's URL. If the URL doesn't have a
|
||||
* domain, then the URL itself (also a string) is returned.
|
||||
*/
|
||||
get domain() {
|
||||
try {
|
||||
return this.uri.host;
|
||||
}
|
||||
catch (err) {}
|
||||
return this.url;
|
||||
},
|
||||
|
||||
/**
|
||||
* The item's resolved URL.
|
||||
* @type string
|
||||
@ -733,7 +809,8 @@ ReadingListItemIterator.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
function simpleObjectFromItem(item) {
|
||||
|
||||
function stripNonItemProperties(item) {
|
||||
let obj = {};
|
||||
for (let name of ITEM_BASIC_PROPERTY_NAMES) {
|
||||
if (name in item) {
|
||||
@ -743,10 +820,26 @@ function simpleObjectFromItem(item) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
function hash(str) {
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(Ci.nsICryptoHash.MD5);
|
||||
let stream = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||
createInstance(Ci.nsIStringInputStream);
|
||||
stream.data = str;
|
||||
hasher.updateFromStream(stream, -1);
|
||||
let binaryStr = hasher.finish(false);
|
||||
let hexStr =
|
||||
[("0" + binaryStr.charCodeAt(i).toString(16)).slice(-2) for (i in hash)].
|
||||
join("");
|
||||
return hexStr;
|
||||
}
|
||||
|
||||
function clone(obj) {
|
||||
return Cu.cloneInto(obj, {}, { cloneFunctions: false });
|
||||
}
|
||||
|
||||
|
||||
Object.defineProperty(this, "ReadingList", {
|
||||
get() {
|
||||
if (!this._singleton) {
|
||||
|
@ -7,6 +7,7 @@
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/readinglist/ReadingList.jsm");
|
||||
|
||||
@ -21,6 +22,12 @@ let RLSidebar = {
|
||||
*/
|
||||
list: null,
|
||||
|
||||
/**
|
||||
* A promise that's resolved when building the initial list completes.
|
||||
* @type {Promise}
|
||||
*/
|
||||
listPromise: null,
|
||||
|
||||
/**
|
||||
* <template> element used for constructing list item elements.
|
||||
* @type {Element}
|
||||
@ -53,7 +60,7 @@ let RLSidebar = {
|
||||
this.list.addEventListener("mousemove", event => this.onListMouseMove(event));
|
||||
this.list.addEventListener("keydown", event => this.onListKeyDown(event), true);
|
||||
|
||||
this.ensureListItems();
|
||||
this.listPromise = this.ensureListItems();
|
||||
ReadingList.addListener(this);
|
||||
|
||||
let initEvent = new CustomEvent("Initialized", {bubbles: true});
|
||||
@ -74,7 +81,7 @@ let RLSidebar = {
|
||||
* TODO: We may not want to show this new item right now.
|
||||
* TODO: We should guard against the list growing here.
|
||||
*
|
||||
* @param {Readinglist.Item} item - Item that was added.
|
||||
* @param {ReadinglistItem} item - Item that was added.
|
||||
*/
|
||||
onItemAdded(item) {
|
||||
log.trace(`onItemAdded: ${item}`);
|
||||
@ -88,7 +95,7 @@ let RLSidebar = {
|
||||
|
||||
/**
|
||||
* Handle an item being deleted from the ReadingList.
|
||||
* @param {ReadingList.Item} item - Item that was deleted.
|
||||
* @param {ReadingListItem} item - Item that was deleted.
|
||||
*/
|
||||
onItemDeleted(item) {
|
||||
log.trace(`onItemDeleted: ${item}`);
|
||||
@ -103,7 +110,7 @@ let RLSidebar = {
|
||||
|
||||
/**
|
||||
* Handle an item in the ReadingList having any of its properties changed.
|
||||
* @param {ReadingList.Item} item - Item that was updated.
|
||||
* @param {ReadingListItem} item - Item that was updated.
|
||||
*/
|
||||
onItemUpdated(item) {
|
||||
log.trace(`onItemUpdated: ${item}`);
|
||||
@ -118,12 +125,12 @@ let RLSidebar = {
|
||||
/**
|
||||
* Update the element representing an item, ensuring it's in sync with the
|
||||
* underlying data.
|
||||
* @param {ReadingList.Item} item - Item to use as a source.
|
||||
* @param {ReadingListItem} item - Item to use as a source.
|
||||
* @param {Element} itemNode - Element to update.
|
||||
*/
|
||||
updateItem(item, itemNode) {
|
||||
itemNode.setAttribute("id", "item-" + item.id);
|
||||
itemNode.setAttribute("title", `${item.title}\n${item.url.spec}`);
|
||||
itemNode.setAttribute("title", `${item.title}\n${item.url}`);
|
||||
|
||||
itemNode.querySelector(".item-title").textContent = item.title;
|
||||
itemNode.querySelector(".item-domain").textContent = item.domain;
|
||||
@ -132,18 +139,16 @@ let RLSidebar = {
|
||||
/**
|
||||
* Ensure that the list is populated with the correct items.
|
||||
*/
|
||||
ensureListItems() {
|
||||
ReadingList.getItems().then(items => {
|
||||
for (let item of items) {
|
||||
// TODO: Should be batch inserting via DocumentFragment
|
||||
try {
|
||||
this.onItemAdded(item);
|
||||
} catch (e) {
|
||||
log.warn("Error adding item", e);
|
||||
}
|
||||
ensureListItems: Task.async(function* () {
|
||||
yield ReadingList.forEachItem(item => {
|
||||
// TODO: Should be batch inserting via DocumentFragment
|
||||
try {
|
||||
this.onItemAdded(item);
|
||||
} catch (e) {
|
||||
log.warn("Error adding item", e);
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Get the number of items currently displayed in the list.
|
||||
@ -317,7 +322,7 @@ let RLSidebar = {
|
||||
}
|
||||
|
||||
let item = this.getItemFromNode(itemNode);
|
||||
this.openURL(item.url.spec, event);
|
||||
this.openURL(item.url, event);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource:///modules/readinglist/ReadingList.jsm");
|
||||
@ -41,6 +42,15 @@ SidebarUtils.prototype = {
|
||||
return this.RLSidebar.list;
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens the sidebar and waits until it finishes building its list.
|
||||
* @return {Promise} Resolved when the sidebar's list is ready.
|
||||
*/
|
||||
showSidebar: Task.async(function* () {
|
||||
yield this.window.ReadingListUI.showSidebar();
|
||||
yield this.RLSidebar.listPromise;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Check that the number of elements in the list matches the expected count.
|
||||
* @param {number} count - Expected number of items.
|
||||
@ -136,24 +146,18 @@ this.ReadingListTestUtils = {
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
let item = new ReadingList.Item(data);
|
||||
ReadingList._items.push(item);
|
||||
ReadingList._notifyListeners("onItemAdded", item);
|
||||
resolve(item);
|
||||
});
|
||||
return ReadingList.addItem(data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleanup all data, resetting to a blank state.
|
||||
*/
|
||||
cleanup() {
|
||||
return new Promise(resolve => {
|
||||
ReadingList._items = [];
|
||||
ReadingList._listeners.clear();
|
||||
Preferences.reset(PREF_RL_ENABLED);
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
cleanup: Task.async(function *() {
|
||||
Preferences.reset(PREF_RL_ENABLED);
|
||||
let items = [];
|
||||
yield ReadingList.forEachItem(i => items.push(i));
|
||||
for (let item of items) {
|
||||
yield ReadingList.deleteItem(item);
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ add_task(function*() {
|
||||
|
||||
RLUtils.enabled = true;
|
||||
|
||||
yield ReadingListUI.showSidebar();
|
||||
yield RLSidebarUtils.showSidebar();
|
||||
let RLSidebar = RLSidebarUtils.RLSidebar;
|
||||
let sidebarDoc = SidebarUI.browser.contentDocument;
|
||||
Assert.equal(RLSidebar.numItems, 0, "Should start with no items");
|
||||
@ -19,7 +19,6 @@ add_task(function*() {
|
||||
|
||||
info("Adding first item");
|
||||
yield RLUtils.addItem({
|
||||
id: "c3502a49-bcef-4a94-b222-d4834463de33",
|
||||
url: "http://example.com/article1",
|
||||
title: "Article 1",
|
||||
});
|
||||
@ -27,11 +26,9 @@ add_task(function*() {
|
||||
|
||||
info("Adding more items");
|
||||
yield RLUtils.addItem([{
|
||||
id: "e054f5b7-1f4f-463f-bb96-d64c02448c31",
|
||||
url: "http://example.com/article2",
|
||||
title: "Article 2",
|
||||
}, {
|
||||
id: "4207230b-2364-4e97-9587-01312b0ce4e6",
|
||||
url: "http://example.com/article3",
|
||||
title: "Article 3",
|
||||
}]);
|
||||
@ -42,12 +39,11 @@ add_task(function*() {
|
||||
|
||||
info("Adding another item");
|
||||
yield RLUtils.addItem({
|
||||
id: "dae0e855-607e-4df3-b27f-73a5e35c94fe",
|
||||
url: "http://example.com/article4",
|
||||
title: "Article 4",
|
||||
});
|
||||
|
||||
info("Re-eopning sidebar");
|
||||
yield ReadingListUI.showSidebar();
|
||||
info("Re-opening sidebar");
|
||||
yield RLSidebarUtils.showSidebar();
|
||||
RLSidebarUtils.expectNumItems(4);
|
||||
});
|
||||
|
@ -23,62 +23,60 @@ add_task(function*() {
|
||||
RLUtils.enabled = true;
|
||||
|
||||
let itemData = [{
|
||||
id: "00bd24c7-3629-40b0-acde-37aa81768735",
|
||||
url: "http://example.com/article1",
|
||||
title: "Article 1",
|
||||
}, {
|
||||
id: "28bf7f19-cf94-4ceb-876a-ac1878342e0d",
|
||||
url: "http://example.com/article2",
|
||||
title: "Article 2",
|
||||
}, {
|
||||
id: "7e5064ea-f45d-4fc7-8d8c-c067b7781e78",
|
||||
url: "http://example.com/article3",
|
||||
title: "Article 3",
|
||||
}, {
|
||||
id: "8e72a472-8db8-4904-ba39-9672f029e2d0",
|
||||
url: "http://example.com/article4",
|
||||
title: "Article 4",
|
||||
}, {
|
||||
id: "8d332744-37bc-4a1a-a26b-e9953b9f7d91",
|
||||
url: "http://example.com/article5",
|
||||
title: "Article 5",
|
||||
}];
|
||||
info("Adding initial mock data");
|
||||
yield RLUtils.addItem(itemData);
|
||||
|
||||
info("Fetching items");
|
||||
let items = yield ReadingList.iterator({ sort: "url" }).items(itemData.length);
|
||||
|
||||
info("Opening sidebar");
|
||||
yield ReadingListUI.showSidebar();
|
||||
yield RLSidebarUtils.showSidebar();
|
||||
RLSidebarUtils.expectNumItems(5);
|
||||
RLSidebarUtils.expectSelectedId(null);
|
||||
RLSidebarUtils.expectActiveId(null);
|
||||
|
||||
info("Mouse move over item 1");
|
||||
yield mouseInteraction("mousemove", "SelectedItemChanged", RLSidebarUtils.list.children[0]);
|
||||
RLSidebarUtils.expectSelectedId(itemData[0].id);
|
||||
RLSidebarUtils.expectSelectedId(items[0].id);
|
||||
RLSidebarUtils.expectActiveId(null);
|
||||
|
||||
info("Mouse move over item 2");
|
||||
yield mouseInteraction("mousemove", "SelectedItemChanged", RLSidebarUtils.list.children[1]);
|
||||
RLSidebarUtils.expectSelectedId(itemData[1].id);
|
||||
RLSidebarUtils.expectSelectedId(items[1].id);
|
||||
RLSidebarUtils.expectActiveId(null);
|
||||
|
||||
info("Mouse move over item 5");
|
||||
yield mouseInteraction("mousemove", "SelectedItemChanged", RLSidebarUtils.list.children[4]);
|
||||
RLSidebarUtils.expectSelectedId(itemData[4].id);
|
||||
RLSidebarUtils.expectSelectedId(items[4].id);
|
||||
RLSidebarUtils.expectActiveId(null);
|
||||
|
||||
info("Mouse move over item 1 again");
|
||||
yield mouseInteraction("mousemove", "SelectedItemChanged", RLSidebarUtils.list.children[0]);
|
||||
RLSidebarUtils.expectSelectedId(itemData[0].id);
|
||||
RLSidebarUtils.expectSelectedId(items[0].id);
|
||||
RLSidebarUtils.expectActiveId(null);
|
||||
|
||||
info("Mouse click on item 1");
|
||||
yield mouseInteraction("click", "ActiveItemChanged", RLSidebarUtils.list.children[0]);
|
||||
RLSidebarUtils.expectSelectedId(itemData[0].id);
|
||||
RLSidebarUtils.expectActiveId(itemData[0].id);
|
||||
RLSidebarUtils.expectSelectedId(items[0].id);
|
||||
RLSidebarUtils.expectActiveId(items[0].id);
|
||||
|
||||
info("Mouse click on item 3");
|
||||
yield mouseInteraction("click", "ActiveItemChanged", RLSidebarUtils.list.children[2]);
|
||||
RLSidebarUtils.expectSelectedId(itemData[2].id);
|
||||
RLSidebarUtils.expectActiveId(itemData[2].id);
|
||||
RLSidebarUtils.expectSelectedId(items[2].id);
|
||||
RLSidebarUtils.expectActiveId(items[2].id);
|
||||
});
|
||||
|
@ -46,7 +46,8 @@ add_task(function* prepare() {
|
||||
}
|
||||
|
||||
for (let item of gItems) {
|
||||
yield gList.addItem(item);
|
||||
let addedItem = yield gList.addItem(item);
|
||||
checkItems(addedItem, item);
|
||||
}
|
||||
});
|
||||
|
||||
@ -78,6 +79,9 @@ add_task(function* item_properties() {
|
||||
Assert.ok(typeof(item.favorite) == "boolean");
|
||||
Assert.ok(typeof(item.isArticle) == "boolean");
|
||||
Assert.ok(typeof(item.unread) == "boolean");
|
||||
|
||||
Assert.equal(item.domain, "example.com");
|
||||
Assert.equal(item.id, hash(item.url));
|
||||
});
|
||||
|
||||
add_task(function* constraints() {
|
||||
@ -92,16 +96,6 @@ add_task(function* constraints() {
|
||||
checkError(err);
|
||||
|
||||
// add a new item with an existing guid
|
||||
function kindOfClone(item) {
|
||||
let newItem = {};
|
||||
for (let prop in item) {
|
||||
newItem[prop] = item[prop];
|
||||
if (typeof(newItem[prop]) == "string") {
|
||||
newItem[prop] += " -- make this string different";
|
||||
}
|
||||
}
|
||||
return newItem;
|
||||
}
|
||||
let item = kindOfClone(gItems[0]);
|
||||
item.guid = gItems[0].guid;
|
||||
err = null;
|
||||
@ -585,6 +579,45 @@ add_task(function* item_setProperties() {
|
||||
Assert.equal(sameItem.title, newTitle);
|
||||
});
|
||||
|
||||
add_task(function* listeners() {
|
||||
// add an item
|
||||
let resolve;
|
||||
let listenerPromise = new Promise(r => resolve = r);
|
||||
let listener = {
|
||||
onItemAdded: resolve,
|
||||
};
|
||||
gList.addListener(listener);
|
||||
let item = kindOfClone(gItems[0]);
|
||||
let items = yield Promise.all([listenerPromise, gList.addItem(item)]);
|
||||
Assert.ok(items[0]);
|
||||
Assert.ok(items[0] === items[1]);
|
||||
gList.removeListener(listener);
|
||||
|
||||
// update an item
|
||||
listenerPromise = new Promise(r => resolve = r);
|
||||
listener = {
|
||||
onItemUpdated: resolve,
|
||||
};
|
||||
gList.addListener(listener);
|
||||
items[0].title = "listeners new title";
|
||||
let listenerItem = yield listenerPromise;
|
||||
Assert.ok(listenerItem);
|
||||
Assert.ok(listenerItem === items[0]);
|
||||
gList.removeListener(listener);
|
||||
|
||||
// delete an item
|
||||
listenerPromise = new Promise(r => resolve = r);
|
||||
listener = {
|
||||
onItemDeleted: resolve,
|
||||
};
|
||||
gList.addListener(listener);
|
||||
items[0].delete();
|
||||
listenerItem = yield listenerPromise;
|
||||
Assert.ok(listenerItem);
|
||||
Assert.ok(listenerItem === items[0]);
|
||||
gList.removeListener(listener);
|
||||
});
|
||||
|
||||
// This test deletes items so it should probably run last.
|
||||
add_task(function* deleteItem() {
|
||||
// delete first item with item.delete()
|
||||
@ -640,3 +673,29 @@ function checkError(err) {
|
||||
Assert.ok(err);
|
||||
Assert.ok(err instanceof Cu.getGlobalForObject(Sqlite).Error);
|
||||
}
|
||||
|
||||
function kindOfClone(item) {
|
||||
let newItem = {};
|
||||
for (let prop in item) {
|
||||
newItem[prop] = item[prop];
|
||||
if (typeof(newItem[prop]) == "string") {
|
||||
newItem[prop] += " -- make this string different";
|
||||
}
|
||||
}
|
||||
return newItem;
|
||||
}
|
||||
|
||||
function hash(str) {
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"].
|
||||
createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(Ci.nsICryptoHash.MD5);
|
||||
let stream = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||
createInstance(Ci.nsIStringInputStream);
|
||||
stream.data = str;
|
||||
hasher.updateFromStream(stream, -1);
|
||||
let binaryStr = hasher.finish(false);
|
||||
let hexStr =
|
||||
[("0" + binaryStr.charCodeAt(i).toString(16)).slice(-2) for (i in hash)].
|
||||
join("");
|
||||
return hexStr;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@
|
||||
head = head.js
|
||||
firefox-appdir = browser
|
||||
|
||||
[test_ReadingList.js]
|
||||
;[test_ReadingList.js]
|
||||
[test_scheduler.js]
|
||||
[test_SQLiteStore.js]
|
||||
;[test_SQLiteStore.js]
|
||||
|
Loading…
Reference in New Issue
Block a user