Bug 730340 - Don't use expando properties for storing data on places nodes. Part 3 - cache livemark-info object in the controller for each view instead of setting _feedURI and _siteURI exapndos on livemark nodes. Also fix a bug I introduced in the previous check for this bug, in PVB_nodeHistoryDetailsChanged. r=mak

This commit is contained in:
Asaf Romano 2012-06-02 16:54:25 +03:00
parent d3be27c800
commit d17a36b7a7
4 changed files with 100 additions and 63 deletions

View File

@ -213,7 +213,7 @@ PlacesViewBase.prototype = {
if (!resultNode.containerOpen) if (!resultNode.containerOpen)
return; return;
if (resultNode._feedURI) { if (this.controller.hasCachedLivemarkInfo(resultNode)) {
this._setEmptyPopupStatus(aPopup, false); this._setEmptyPopupStatus(aPopup, false);
aPopup._built = true; aPopup._built = true;
this._populateLivemarkPopup(aPopup); this._populateLivemarkPopup(aPopup);
@ -315,10 +315,9 @@ PlacesViewBase.prototype = {
#endif #endif
// Set an expando on the node, controller will use it to build // Set an expando on the node, controller will use it to build
// its metadata. // its metadata.
aPlacesNode._feedURI = aLivemark.feedURI; this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
aPlacesNode._siteURI = aLivemark.siteURI;
} }
} }.bind(this)
); );
} }
@ -365,8 +364,9 @@ PlacesViewBase.prototype = {
_setLivemarkSiteURIMenuItem: _setLivemarkSiteURIMenuItem:
function PVB__setLivemarkSiteURIMenuItem(aPopup) { function PVB__setLivemarkSiteURIMenuItem(aPopup) {
let siteUrl = aPopup._placesNode._siteURI ? aPopup._placesNode._siteURI.spec let livemarkInfo = this.controller.getCachedLivemarkInfo(aPopup._placesNode);
: null; let siteUrl = livemarkInfo && livemarkInfo.siteURI ?
livemarkInfo.siteURI.spec : null;
if (!siteUrl && aPopup._siteURIMenuitem) { if (!siteUrl && aPopup._siteURIMenuitem) {
aPopup.removeChild(aPopup._siteURIMenuitem); aPopup.removeChild(aPopup._siteURIMenuitem);
aPopup._siteURIMenuitem = null; aPopup._siteURIMenuitem = null;
@ -493,15 +493,13 @@ PlacesViewBase.prototype = {
PlacesUtils.livemarks.getLivemark( PlacesUtils.livemarks.getLivemark(
{ id: aPlacesNode.itemId }, { id: aPlacesNode.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
if (Components.isSuccessCode(aStatus)) { if (Components.isSuccessCode(aStatus)) {
// Set an expando on the node, controller will use it to build // Controller will use this to build the meta data for the node.
// its metadata. this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
aPlacesNode._feedURI = aLivemark.feedURI;
aPlacesNode._siteURI = aLivemark.siteURI;
this.invalidateContainer(aPlacesNode); this.invalidateContainer(aPlacesNode);
} }
}).bind(this) }.bind(this)
); );
} }
}, },
@ -533,7 +531,6 @@ PlacesViewBase.prototype = {
nodeRemoved: nodeRemoved:
function PVB_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) { function PVB_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) {
let parentElt = this._getDOMNodeForPlacesNode(aPlacesNode); let parentElt = this._getDOMNodeForPlacesNode(aPlacesNode);
let elt = this._getDOMNodeForPlacesNode(aPlacesNode); let elt = this._getDOMNodeForPlacesNode(aPlacesNode);
// Here we need the <menu>. // Here we need the <menu>.
@ -573,9 +570,10 @@ PlacesViewBase.prototype = {
nodeHistoryDetailsChanged: nodeHistoryDetailsChanged:
function PVB_nodeHistoryDetailsChanged(aPlacesNode, aTime, aCount) { function PVB_nodeHistoryDetailsChanged(aPlacesNode, aTime, aCount) {
if (aPlacesNode.parent && aPlacesNode.parent._feedURI) { if (aPlacesNode.parent &&
this.controller.hasCachedLivemarkInfo(aPlacesNode.parent)) {
// Find the node in the parent. // Find the node in the parent.
let popup = this._getDOMNodeForPlacesNode(aPlacesNode); let popup = this._getDOMNodeForPlacesNode(aPlacesNode.parent);
for (let child = popup._startMarker.nextSibling; for (let child = popup._startMarker.nextSibling;
child != popup._endMarker; child != popup._endMarker;
child = child.nextSibling) { child = child.nextSibling) {
@ -652,11 +650,11 @@ PlacesViewBase.prototype = {
} }
PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId }, PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
if (Components.isSuccessCode(aStatus)) { if (Components.isSuccessCode(aStatus)) {
let shouldInvalidate = !aPlacesNode._feedURI; let shouldInvalidate =
aPlacesNode._feedURI = aLivemark.feedURI; !this.controller.hasCachedLivemarkInfo(aPlacesNode);
aPlacesNode._siteURI = aLivemark.siteURI; this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) { if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
aLivemark.registerForUpdates(aPlacesNode, this); aLivemark.registerForUpdates(aPlacesNode, this);
// Prioritize the current livemark. // Prioritize the current livemark.
@ -669,7 +667,7 @@ PlacesViewBase.prototype = {
aLivemark.unregisterForUpdates(aPlacesNode); aLivemark.unregisterForUpdates(aPlacesNode);
} }
} }
}).bind(this) }.bind(this)
); );
} }
} }
@ -683,7 +681,7 @@ PlacesViewBase.prototype = {
this._setLivemarkStatusMenuItem(aPopup, Ci.mozILivemark.STATUS_LOADING); this._setLivemarkStatusMenuItem(aPopup, Ci.mozILivemark.STATUS_LOADING);
PlacesUtils.livemarks.getLivemark({ id: aPopup._placesNode.itemId }, PlacesUtils.livemarks.getLivemark({ id: aPopup._placesNode.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
let placesNode = aPopup._placesNode; let placesNode = aPopup._placesNode;
if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen) if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen)
return; return;
@ -702,7 +700,7 @@ PlacesViewBase.prototype = {
else else
this._getDOMNodeForPlacesNode(child).removeAttribute("visited"); this._getDOMNodeForPlacesNode(child).removeAttribute("visited");
} }
}).bind(this) }.bind(this)
); );
}, },
@ -1004,10 +1002,9 @@ PlacesToolbar.prototype = {
button.setAttribute("livemark", "true"); button.setAttribute("livemark", "true");
// Set an expando on the node, controller will use it to build // Set an expando on the node, controller will use it to build
// its metadata. // its metadata.
aChild._feedURI = aLivemark.feedURI; this.controller.cacheLivemarkInfo(aChild, aLivemark);
aChild._siteURI = aLivemark.siteURI;
} }
} }.bind(this)
); );
} }
@ -1253,15 +1250,14 @@ PlacesToolbar.prototype = {
PlacesUtils.livemarks.getLivemark( PlacesUtils.livemarks.getLivemark(
{ id: aPlacesNode.itemId }, { id: aPlacesNode.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
if (Components.isSuccessCode(aStatus)) { if (Components.isSuccessCode(aStatus)) {
// Set an expando on the node, controller will use it to build // Set an expando on the node, controller will use it to build
// its metadata. // its metadata.
aPlacesNode._feedURI = aLivemark.feedURI; this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
aPlacesNode._siteURI = aLivemark.siteURI;
this.invalidateContainer(aPlacesNode); this.invalidateContainer(aPlacesNode);
} }
}).bind(this) }.bind(this)
); );
} }
} }
@ -1681,7 +1677,8 @@ PlacesToolbar.prototype = {
// so we don't rebuild its contents whenever the popup is reopened. // so we don't rebuild its contents whenever the popup is reopened.
// Though, we want to always close feed containers so their expiration // Though, we want to always close feed containers so their expiration
// status will be checked at next opening. // status will be checked at next opening.
if (!PlacesUtils.nodeIsFolder(placesNode) || placesNode._feedURI) { if (!PlacesUtils.nodeIsFolder(placesNode) ||
this.controller.hasCachedLivemarkInfo(placesNode)) {
placesNode.containerOpen = false; placesNode.containerOpen = false;
} }
} }
@ -1787,7 +1784,8 @@ PlacesMenu.prototype = {
// so we don't rebuild its contents whenever the popup is reopened. // so we don't rebuild its contents whenever the popup is reopened.
// Though, we want to always close feed containers so their expiration // Though, we want to always close feed containers so their expiration
// status will be checked at next opening. // status will be checked at next opening.
if (!PlacesUtils.nodeIsFolder(placesNode) || placesNode._feedURI) if (!PlacesUtils.nodeIsFolder(placesNode) ||
this.controller.hasCachedLivemarkInfo(placesNode))
placesNode.containerOpen = false; placesNode.containerOpen = false;
// The autoopened attribute is set for folders which have been // The autoopened attribute is set for folders which have been

View File

@ -79,6 +79,8 @@ function PlacesController(aView) {
XPCOMUtils.defineLazyGetter(this, "profileName", function () { XPCOMUtils.defineLazyGetter(this, "profileName", function () {
return Services.dirsvc.get("ProfD", Ci.nsIFile).leafName; return Services.dirsvc.get("ProfD", Ci.nsIFile).leafName;
}); });
this._cachedLivemarkInfoObjects = new WeakMap();
} }
PlacesController.prototype = { PlacesController.prototype = {
@ -176,7 +178,7 @@ PlacesController.prototype = {
case "placesCmd_reload": case "placesCmd_reload":
// Livemark containers // Livemark containers
var selectedNode = this._view.selectedNode; var selectedNode = this._view.selectedNode;
return selectedNode && !!selectedNode._feedURI; return selectedNode && this.hasCachedLivemarkInfo(selectedNode);
case "placesCmd_sortBy:name": case "placesCmd_sortBy:name":
var selectedNode = this._view.selectedNode; var selectedNode = this._view.selectedNode;
return selectedNode && return selectedNode &&
@ -469,7 +471,7 @@ PlacesController.prototype = {
if (parentNode) { if (parentNode) {
if (PlacesUtils.nodeIsTagQuery(parentNode)) if (PlacesUtils.nodeIsTagQuery(parentNode))
nodeData["tagChild"] = true; nodeData["tagChild"] = true;
else if (parentNode._feedURI) else if (this.hasCachedLivemarkInfo(parentNode))
nodeData["livemarkChild"] = true; nodeData["livemarkChild"] = true;
} }
} }
@ -1038,8 +1040,9 @@ PlacesController.prototype = {
addData(PlacesUtils.TYPE_X_MOZ_PLACE, i); addData(PlacesUtils.TYPE_X_MOZ_PLACE, i);
// Drop the feed uri for livemark containers // Drop the feed uri for livemark containers
if (node._feedURI) { let livemarkInfo = this.getCachedLivemarkInfo(node);
addURIData(i, node._feedURI.spec); if (livemarkInfo) {
addURIData(i, livemarkInfo.feedURI.spec);
} }
else if (node.uri) { else if (node.uri) {
addURIData(i); addURIData(i);
@ -1113,7 +1116,8 @@ PlacesController.prototype = {
if (PlacesUtils.nodeIsFolder(node)) if (PlacesUtils.nodeIsFolder(node))
copiedFolders.push(node); copiedFolders.push(node);
let overrideURI = node._feedURI ? node._feedURI.spec : null; let livemarkInfo = this.getCachedLivemarkInfo(node);
let overrideURI = livemarkInfo ? livemarkInfo.feedURI.spec : null;
let resolveShortcuts = !PlacesControllerDragHelper.canMoveNode(node); let resolveShortcuts = !PlacesControllerDragHelper.canMoveNode(node);
contents.forEach(function (content) { contents.forEach(function (content) {
@ -1281,7 +1285,39 @@ PlacesController.prototype = {
} }
if (insertedNodeIds.length > 0) if (insertedNodeIds.length > 0)
this._view.selectItems(insertedNodeIds, false); this._view.selectItems(insertedNodeIds, false);
} },
/**
* Cache the livemark info for a node. This allows the controller and the
* views to treat the given node as a livemark.
* @param aNode
* a places result node.
* @param aLivemarkInfo
* a mozILivemarkInfo object.
*/
cacheLivemarkInfo: function PC_cacheLivemarkInfo(aNode, aLivemarkInfo) {
this._cachedLivemarkInfoObjects.set(aNode, aLivemarkInfo);
},
/**
* Returns whether or not there's cached mozILivemarkInfo object for a node.
* @param aNode
* a places result node.
* @return true if there's a cached mozILivemarkInfo object for
* aNode, false otherwise.
*/
hasCachedLivemarkInfo: function PC_hasCachedLivemarkInfo(aNode)
this._cachedLivemarkInfoObjects.has(aNode),
/**
* Returns the cached livemark info for a node, if set by cacheLivemarkInfo,
* null otherwise.
* @param aNode
* a places result node.
* @return the mozILivemarkInfo object for aNode, if set, null otherwise.
*/
getCachedLivemarkInfo: function PC_getCachedLivemarkInfo(aNode)
this._cachedLivemarkInfoObjects.get(aNode, null)
}; };
/** /**

View File

@ -98,17 +98,18 @@
callback = new Function("aContainer", onOpenFlatContainer); callback = new Function("aContainer", onOpenFlatContainer);
} }
let treeView = new PlacesTreeView(this.flatList, callback); if (!this._controller) {
this._controller = new PlacesController(this);
this.controllers.appendController(this._controller);
}
let treeView = new PlacesTreeView(this.flatList, callback, this._controller);
// Observer removal is done within the view itself. When the tree // Observer removal is done within the view itself. When the tree
// goes away, treeboxobject calls view.setTree(null), which then // goes away, treeboxobject calls view.setTree(null), which then
// calls removeObserver. // calls removeObserver.
result.addObserver(treeView, false); result.addObserver(treeView, false);
this.view = treeView; this.view = treeView;
if (!this._controller) {
this._controller = new PlacesController(this);
this.controllers.appendController(this._controller);
}
this._cachedInsertionPoint = undefined; this._cachedInsertionPoint = undefined;
]]></body> ]]></body>
</method> </method>

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * 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/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
function PlacesTreeView(aFlatList, aOnOpenFlatContainer) { function PlacesTreeView(aFlatList, aOnOpenFlatContainer, aController) {
this._tree = null; this._tree = null;
this._result = null; this._result = null;
this._selection = null; this._selection = null;
@ -10,6 +10,7 @@ function PlacesTreeView(aFlatList, aOnOpenFlatContainer) {
this._rows = []; this._rows = [];
this._flatList = aFlatList; this._flatList = aFlatList;
this._openContainerCallback = aOnOpenFlatContainer; this._openContainerCallback = aOnOpenFlatContainer;
this._controller = aController;
} }
PlacesTreeView.prototype = { PlacesTreeView.prototype = {
@ -92,7 +93,7 @@ PlacesTreeView.prototype = {
*/ */
_isPlainContainer: function PTV__isPlainContainer(aContainer) { _isPlainContainer: function PTV__isPlainContainer(aContainer) {
// Livemarks are always plain containers. // Livemarks are always plain containers.
if (aContainer._feedURI) if (this._controller.hasCachedLivemarkInfo(aContainer))
return true; return true;
// We don't know enough about non-query containers. // We don't know enough about non-query containers.
@ -299,7 +300,7 @@ PlacesTreeView.prototype = {
// Recursively do containers. // Recursively do containers.
if (!this._flatList && if (!this._flatList &&
curChild instanceof Ci.nsINavHistoryContainerResultNode && curChild instanceof Ci.nsINavHistoryContainerResultNode &&
!curChild._feedURI) { !this._controller.hasCachedLivemarkInfo(curChild)) {
let resource = this._getResourceForNode(curChild); let resource = this._getResourceForNode(curChild);
let isopen = resource != null && let isopen = resource != null &&
PlacesUIUtils.localStore.HasAssertion(resource, PlacesUIUtils.localStore.HasAssertion(resource,
@ -789,7 +790,7 @@ PlacesTreeView.prototype = {
_populateLivemarkContainer: function PTV__populateLivemarkContainer(aNode) { _populateLivemarkContainer: function PTV__populateLivemarkContainer(aNode) {
PlacesUtils.livemarks.getLivemark({ id: aNode.itemId }, PlacesUtils.livemarks.getLivemark({ id: aNode.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
let placesNode = aNode; let placesNode = aNode;
// Need to check containerOpen since getLivemark is async. // Need to check containerOpen since getLivemark is async.
if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen) if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen)
@ -800,7 +801,7 @@ PlacesTreeView.prototype = {
let child = children[i]; let child = children[i];
this.nodeInserted(placesNode, child, i); this.nodeInserted(placesNode, child, i);
} }
}).bind(this)); }.bind(this));
}, },
nodeTitleChanged: function PTV_nodeTitleChanged(aNode, aNewTitle) { nodeTitleChanged: function PTV_nodeTitleChanged(aNode, aNewTitle) {
@ -818,7 +819,7 @@ PlacesTreeView.prototype = {
nodeHistoryDetailsChanged: nodeHistoryDetailsChanged:
function PTV_nodeHistoryDetailsChanged(aNode, aUpdatedVisitDate, function PTV_nodeHistoryDetailsChanged(aNode, aUpdatedVisitDate,
aUpdatedVisitCount) { aUpdatedVisitCount) {
if (aNode.parent && aNode.parent._feedURI) { if (aNode.parent && this._controller.hasCachedLivemarkInfo(aNode.parent)) {
// Find the node in the parent. // Find the node in the parent.
let parentRow = this._flatList ? 0 : this._getRowForNode(aNode.parent); let parentRow = this._flatList ? 0 : this._getRowForNode(aNode.parent);
for (let i = parentRow; i < this._rows.length; i++) { for (let i = parentRow; i < this._rows.length; i++) {
@ -851,9 +852,9 @@ PlacesTreeView.prototype = {
else if (aAnno == PlacesUtils.LMANNO_FEEDURI) { else if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
PlacesUtils.livemarks.getLivemark( PlacesUtils.livemarks.getLivemark(
{ id: aNode.itemId }, { id: aNode.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
if (Components.isSuccessCode(aStatus)) { if (Components.isSuccessCode(aStatus)) {
aNode._feedURI = aLivemark.feedURI; this._controller.cacheLivemarkInfo(aNode, aLivemark);
let properties = this._cellProperties.get(aNode, null); let properties = this._cellProperties.get(aNode, null);
if (properties) if (properties)
properties.push(this._getAtomFor("livemark")); properties.push(this._getAtomFor("livemark"));
@ -861,7 +862,7 @@ PlacesTreeView.prototype = {
// The livemark attribute is set as a cell property on the title cell. // The livemark attribute is set as a cell property on the title cell.
this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE); this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
} }
}).bind(this) }.bind(this)
); );
} }
}, },
@ -887,10 +888,11 @@ PlacesTreeView.prototype = {
} }
PlacesUtils.livemarks.getLivemark({ id: aNode.itemId }, PlacesUtils.livemarks.getLivemark({ id: aNode.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
if (Components.isSuccessCode(aStatus)) { if (Components.isSuccessCode(aStatus)) {
let shouldInvalidate = !aNode._feedURI; let shouldInvalidate =
aNode._feedURI = aLivemark.feedURI; !this._controller.hasCachedLivemarkInfo(aNode);
this._controller.cacheLivemarkInfo(aNode, aLivemark);
if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) { if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) {
aLivemark.registerForUpdates(aNode, this); aLivemark.registerForUpdates(aNode, this);
// Prioritize the current livemark. // Prioritize the current livemark.
@ -903,7 +905,7 @@ PlacesTreeView.prototype = {
aLivemark.unregisterForUpdates(aNode); aLivemark.unregisterForUpdates(aNode);
} }
} }
}).bind(this) }.bind(this)
); );
} }
}, },
@ -999,7 +1001,7 @@ PlacesTreeView.prototype = {
} }
} }
if (aContainer._feedURI) { if (this._controller.hasCachedLivemarkInfo(aContainer)) {
let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions; let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions;
if (!queryOptions.excludeItems) { if (!queryOptions.excludeItems) {
this._populateLivemarkContainer(aContainer); this._populateLivemarkContainer(aContainer);
@ -1169,20 +1171,20 @@ PlacesTreeView.prototype = {
} }
else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER || else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT) { nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT) {
if (node._feedURI) { if (this._controller.hasCachedLivemarkInfo(node)) {
properties.push(this._getAtomFor("livemark")); properties.push(this._getAtomFor("livemark"));
} }
else { else {
PlacesUtils.livemarks.getLivemark( PlacesUtils.livemarks.getLivemark(
{ id: node.itemId }, { id: node.itemId },
(function (aStatus, aLivemark) { function (aStatus, aLivemark) {
if (Components.isSuccessCode(aStatus)) { if (Components.isSuccessCode(aStatus)) {
node._feedURI = aLivemark.feedURI; this._controller.cacheLivemarkInfo(node, aLivemark);
properties.push(this._getAtomFor("livemark")); properties.push(this._getAtomFor("livemark"));
// The livemark attribute is set as a cell property on the title cell. // The livemark attribute is set as a cell property on the title cell.
this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE); this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE);
} }
}).bind(this) }.bind(this)
); );
} }
} }
@ -1198,7 +1200,7 @@ PlacesTreeView.prototype = {
else if (PlacesUtils.nodeIsURI(node)) { else if (PlacesUtils.nodeIsURI(node)) {
properties.push(this._getAtomFor(PlacesUIUtils.guessUrlSchemeForUI(node.uri))); properties.push(this._getAtomFor(PlacesUIUtils.guessUrlSchemeForUI(node.uri)));
if (node.parent._feedURI) { if (this._controller.hasCachedLivemarkInfo(node.parent)) {
properties.push(this._getAtomFor("livemarkItem")); properties.push(this._getAtomFor("livemarkItem"));
if (node.accessCount) { if (node.accessCount) {
properties.push(this._getAtomFor("visited")); properties.push(this._getAtomFor("visited"));
@ -1253,7 +1255,7 @@ PlacesTreeView.prototype = {
return true; return true;
let node = this._rows[aRow]; let node = this._rows[aRow];
if (node._feedURI) { if (this._controller.hasCachedLivemarkInfo(node)) {
let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions; let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions;
return queryOptions.excludeItems; return queryOptions.excludeItems;
} }
@ -1503,7 +1505,7 @@ PlacesTreeView.prototype = {
} }
// Persist containers open status, but never persist livemarks. // Persist containers open status, but never persist livemarks.
if (!node._feedURI) { if (!this._controller.hasCachedLivemarkInfo(node)) {
let resource = this._getResourceForNode(node); let resource = this._getResourceForNode(node);
if (resource) { if (resource) {
const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open"); const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");