Last active
August 29, 2015 14:05
-
-
Save vitillo/e2c13df2edbf07482192 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# Parent a4dcfbebcb588b9893900152eb512c3810880d68 | |
# User Roberto A. Vitillo <rvitillo@mozilla.com> | |
Bug 559505 - localstore.rdf kills ponies; r=enn | |
diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in | |
--- a/b2g/installer/package-manifest.in | |
+++ b/b2g/installer/package-manifest.in | |
@@ -290,16 +290,17 @@ | |
@BINPATH@/components/shellservice.xpt | |
@BINPATH@/components/shistory.xpt | |
@BINPATH@/components/spellchecker.xpt | |
@BINPATH@/components/storage.xpt | |
@BINPATH@/components/telemetry.xpt | |
@BINPATH@/components/toolkit_finalizationwitness.xpt | |
@BINPATH@/components/toolkit_formautofill.xpt | |
@BINPATH@/components/toolkit_osfile.xpt | |
+@BINPATH@/components/toolkit_xulstore.xpt | |
@BINPATH@/components/toolkitprofile.xpt | |
#ifdef MOZ_ENABLE_XREMOTE | |
@BINPATH@/components/toolkitremote.xpt | |
#endif | |
@BINPATH@/components/txtsvc.xpt | |
@BINPATH@/components/txmgr.xpt | |
#ifdef MOZ_USE_NATIVE_UCONV | |
@BINPATH@/components/ucnative.xpt | |
@@ -529,16 +530,18 @@ | |
@BINPATH@/components/HealthReportService.js | |
#endif | |
#ifdef MOZ_CAPTIVEDETECT | |
@BINPATH@/components/CaptivePortalDetectComponents.manifest | |
@BINPATH@/components/captivedetect.js | |
#endif | |
@BINPATH@/components/TelemetryStartup.js | |
@BINPATH@/components/TelemetryStartup.manifest | |
+@BINPATH@/components/XULStore.js | |
+@BINPATH@/components/XULStore.manifest | |
@BINPATH@/components/Webapps.js | |
@BINPATH@/components/Webapps.manifest | |
@BINPATH@/components/AppsService.js | |
@BINPATH@/components/AppsService.manifest | |
@BINPATH@/components/Push.js | |
@BINPATH@/components/Push.manifest | |
@BINPATH@/components/PushServiceLauncher.js | |
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js | |
--- a/browser/components/nsBrowserGlue.js | |
+++ b/browser/components/nsBrowserGlue.js | |
@@ -1339,118 +1339,107 @@ BrowserGlue.prototype = { | |
var notification = notifyBox.appendNotification(text, title, null, | |
notifyBox.PRIORITY_CRITICAL_MEDIUM, | |
buttons); | |
notification.persistence = -1; // Until user closes it | |
}, | |
_migrateUI: function BG__migrateUI() { | |
const UI_VERSION = 22; | |
- const BROWSER_DOCURL = "chrome://browser/content/browser.xul#"; | |
+ const BROWSER_DOCURL = "chrome://browser/content/browser.xul"; | |
+ | |
let currentUIVersion = 0; | |
try { | |
currentUIVersion = Services.prefs.getIntPref("browser.migration.version"); | |
} catch(ex) {} | |
- if (currentUIVersion >= UI_VERSION) | |
+ if (currentUIVersion >= UI_VERSION) { | |
return; | |
+ } | |
- this._rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService); | |
- this._dataSource = this._rdf.GetDataSource("rdf:local-store"); | |
- this._dirty = false; | |
+ let xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore); | |
if (currentUIVersion < 2) { | |
// This code adds the customizable bookmarks button. | |
- let currentsetResource = this._rdf.GetResource("currentset"); | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); | |
- let currentset = this._getPersist(toolbarResource, currentsetResource); | |
+ let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset"); | |
// Need to migrate only if toolbar is customized and the element is not found. | |
if (currentset && | |
currentset.indexOf("bookmarks-menu-button-container") == -1) { | |
currentset += ",bookmarks-menu-button-container"; | |
- this._setPersist(toolbarResource, currentsetResource, currentset); | |
+ xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset); | |
} | |
} | |
if (currentUIVersion < 3) { | |
// This code merges the reload/stop/go button into the url bar. | |
- let currentsetResource = this._rdf.GetResource("currentset"); | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); | |
- let currentset = this._getPersist(toolbarResource, currentsetResource); | |
+ let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset"); | |
// Need to migrate only if toolbar is customized and all 3 elements are found. | |
if (currentset && | |
currentset.indexOf("reload-button") != -1 && | |
currentset.indexOf("stop-button") != -1 && | |
currentset.indexOf("urlbar-container") != -1 && | |
currentset.indexOf("urlbar-container,reload-button,stop-button") == -1) { | |
currentset = currentset.replace(/(^|,)reload-button($|,)/, "$1$2") | |
.replace(/(^|,)stop-button($|,)/, "$1$2") | |
.replace(/(^|,)urlbar-container($|,)/, | |
"$1urlbar-container,reload-button,stop-button$2"); | |
- this._setPersist(toolbarResource, currentsetResource, currentset); | |
+ xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset); | |
} | |
} | |
if (currentUIVersion < 4) { | |
// This code moves the home button to the immediate left of the bookmarks menu button. | |
- let currentsetResource = this._rdf.GetResource("currentset"); | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); | |
- let currentset = this._getPersist(toolbarResource, currentsetResource); | |
+ let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset"); | |
// Need to migrate only if toolbar is customized and the elements are found. | |
if (currentset && | |
currentset.indexOf("home-button") != -1 && | |
currentset.indexOf("bookmarks-menu-button-container") != -1) { | |
currentset = currentset.replace(/(^|,)home-button($|,)/, "$1$2") | |
.replace(/(^|,)bookmarks-menu-button-container($|,)/, | |
"$1home-button,bookmarks-menu-button-container$2"); | |
- this._setPersist(toolbarResource, currentsetResource, currentset); | |
+ xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset); | |
} | |
} | |
if (currentUIVersion < 5) { | |
// This code uncollapses PersonalToolbar if its collapsed status is not | |
// persisted, and user customized it or changed default bookmarks. | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "PersonalToolbar"); | |
- let collapsedResource = this._rdf.GetResource("collapsed"); | |
- let collapsed = this._getPersist(toolbarResource, collapsedResource); | |
+ | |
// If the user does not have a persisted value for the toolbar's | |
// "collapsed" attribute, try to determine whether it's customized. | |
- if (collapsed === null) { | |
+ if (!xulStore.hasValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed")) { | |
// We consider the toolbar customized if it has more than | |
// 3 children, or if it has a persisted currentset value. | |
- let currentsetResource = this._rdf.GetResource("currentset"); | |
- let toolbarIsCustomized = !!this._getPersist(toolbarResource, | |
- currentsetResource); | |
+ let toolbarIsCustomized = xulStore.hasValue(BROWSER_DOCURL, | |
+ "PersonalToolbar", "currentset"); | |
function getToolbarFolderCount() { | |
let toolbarFolder = | |
PlacesUtils.getFolderContents(PlacesUtils.toolbarFolderId).root; | |
let toolbarChildCount = toolbarFolder.childCount; | |
toolbarFolder.containerOpen = false; | |
return toolbarChildCount; | |
} | |
if (toolbarIsCustomized || getToolbarFolderCount() > 3) { | |
- this._setPersist(toolbarResource, collapsedResource, "false"); | |
+ xulStore.setValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed", "false"); | |
} | |
} | |
} | |
if (currentUIVersion < 8) { | |
// Reset homepage pref for users who have it set to google.com/firefox | |
let uri = Services.prefs.getComplexValue("browser.startup.homepage", | |
Ci.nsIPrefLocalizedString).data; | |
if (uri && /^https?:\/\/(www\.)?google(\.\w{2,3}){1,2}\/firefox\/?$/.test(uri)) { | |
Services.prefs.clearUserPref("browser.startup.homepage"); | |
} | |
} | |
if (currentUIVersion < 9) { | |
// This code adds the customizable downloads buttons. | |
- let currentsetResource = this._rdf.GetResource("currentset"); | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); | |
- let currentset = this._getPersist(toolbarResource, currentsetResource); | |
+ let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset"); | |
// Since the Downloads button is located in the navigation bar by default, | |
// migration needs to happen only if the toolbar was customized using a | |
// previous UI version, and the button was not already placed on the | |
// toolbar manually. | |
if (currentset && | |
currentset.indexOf("downloads-button") == -1) { | |
// The element is added either after the search bar or before the home | |
@@ -1461,17 +1450,17 @@ BrowserGlue.prototype = { | |
"$1search-container,downloads-button$2") | |
} else if (currentset.indexOf("home-button") != -1) { | |
currentset = currentset.replace(/(^|,)home-button($|,)/, | |
"$1downloads-button,home-button$2") | |
} else { | |
currentset = currentset.replace(/(^|,)window-controls($|,)/, | |
"$1downloads-button,window-controls$2") | |
} | |
- this._setPersist(toolbarResource, currentsetResource, currentset); | |
+ xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset); | |
} | |
} | |
#ifdef XP_WIN | |
if (currentUIVersion < 10) { | |
// For Windows systems with display set to > 96dpi (i.e. systemDefaultScale | |
// will return a value > 1.0), we want to discard any saved full-zoom settings, | |
// as we'll now be scaling the content according to the system resolution | |
@@ -1491,25 +1480,23 @@ BrowserGlue.prototype = { | |
Services.prefs.clearUserPref("dom.event.contextmenu.enabled"); | |
Services.prefs.clearUserPref("javascript.enabled"); | |
Services.prefs.clearUserPref("permissions.default.image"); | |
} | |
if (currentUIVersion < 12) { | |
// Remove bookmarks-menu-button-container, then place | |
// bookmarks-menu-button into its position. | |
- let currentsetResource = this._rdf.GetResource("currentset"); | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); | |
- let currentset = this._getPersist(toolbarResource, currentsetResource); | |
+ let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset"); | |
// Need to migrate only if toolbar is customized. | |
if (currentset) { | |
if (currentset.contains("bookmarks-menu-button-container")) { | |
currentset = currentset.replace(/(^|,)bookmarks-menu-button-container($|,)/, | |
"$1bookmarks-menu-button$2"); | |
- this._setPersist(toolbarResource, currentsetResource, currentset); | |
+ xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset); | |
} | |
} | |
} | |
if (currentUIVersion < 13) { | |
try { | |
if (Services.prefs.getBoolPref("plugins.hide_infobar_for_missing_plugin")) | |
Services.prefs.setBoolPref("plugins.notifyMissingFlash", false); | |
@@ -1520,62 +1507,54 @@ BrowserGlue.prototype = { | |
if (currentUIVersion < 14) { | |
// DOM Storage doesn't specially handle about: pages anymore. | |
let path = OS.Path.join(OS.Constants.Path.profileDir, | |
"chromeappsstore.sqlite"); | |
OS.File.remove(path); | |
} | |
if (currentUIVersion < 16) { | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); | |
- let collapsedResource = this._rdf.GetResource("collapsed"); | |
- let isCollapsed = this._getPersist(toolbarResource, collapsedResource); | |
+ let isCollapsed = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "collapsed"); | |
if (isCollapsed == "true") { | |
- this._setPersist(toolbarResource, collapsedResource, "false"); | |
+ xulStore.setValue(BROWSER_DOCURL, "nav-bar", "collapsed", "false"); | |
} | |
} | |
// Insert the bookmarks-menu-button into the nav-bar if it isn't already | |
// there. | |
if (currentUIVersion < 17) { | |
- let currentsetResource = this._rdf.GetResource("currentset"); | |
- let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); | |
- let currentset = this._getPersist(toolbarResource, currentsetResource); | |
+ let currentset = xulStore.getValue(BROWSER_DOCURL, "nav-bar", "currentset"); | |
// Need to migrate only if toolbar is customized. | |
if (currentset) { | |
if (!currentset.contains("bookmarks-menu-button")) { | |
// The button isn't in the nav-bar, so let's look for an appropriate | |
// place to put it. | |
if (currentset.contains("downloads-button")) { | |
currentset = currentset.replace(/(^|,)downloads-button($|,)/, | |
"$1bookmarks-menu-button,downloads-button$2"); | |
} else if (currentset.contains("home-button")) { | |
currentset = currentset.replace(/(^|,)home-button($|,)/, | |
"$1bookmarks-menu-button,home-button$2"); | |
} else { | |
// Just append. | |
currentset = currentset.replace(/(^|,)window-controls($|,)/, | |
"$1bookmarks-menu-button,window-controls$2") | |
} | |
- this._setPersist(toolbarResource, currentsetResource, currentset); | |
+ xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset); | |
} | |
} | |
} | |
if (currentUIVersion < 18) { | |
// Remove iconsize and mode from all the toolbars | |
let toolbars = ["navigator-toolbox", "nav-bar", "PersonalToolbar", | |
"addon-bar", "TabsToolbar", "toolbar-menubar"]; | |
for (let resourceName of ["mode", "iconsize"]) { | |
- let resource = this._rdf.GetResource(resourceName); | |
for (let toolbarId of toolbars) { | |
- let toolbar = this._rdf.GetResource(BROWSER_DOCURL + toolbarId); | |
- if (this._getPersist(toolbar, resource)) { | |
- this._setPersist(toolbar, resource); | |
- } | |
+ xulStore.removeValue(BROWSER_DOCURL, toolbarId, resourceName); | |
} | |
} | |
} | |
if (currentUIVersion < 19) { | |
let detector = null; | |
try { | |
detector = Services.prefs.getComplexValue("intl.charset.detector", | |
@@ -1588,82 +1567,35 @@ BrowserGlue.prototype = { | |
// If the encoding detector pref value is not reachable from the UI, | |
// reset to default (varies by localization). | |
Services.prefs.clearUserPref("intl.charset.detector"); | |
} | |
} | |
if (currentUIVersion < 20) { | |
// Remove persisted collapsed state from TabsToolbar. | |
- let resource = this._rdf.GetResource("collapsed"); | |
- let toolbar = this._rdf.GetResource(BROWSER_DOCURL + "TabsToolbar"); | |
- if (this._getPersist(toolbar, resource)) { | |
- this._setPersist(toolbar, resource); | |
- } | |
+ xulStore.removeValue(BROWSER_DOCURL, "TabsToolbar", "collapsed"); | |
} | |
if (currentUIVersion < 21) { | |
// Make sure the 'toolbarbutton-1' class will always be present from here | |
// on out. | |
- let button = this._rdf.GetResource(BROWSER_DOCURL + "bookmarks-menu-button"); | |
- let classResource = this._rdf.GetResource("class"); | |
- if (this._getPersist(button, classResource)) { | |
- this._setPersist(button, classResource); | |
- } | |
+ xulStore.removeValue(BROWSER_DOCURL, "bookmarks-menu-button", "class"); | |
} | |
if (currentUIVersion < 22) { | |
// Reset the Sync promobox count to promote the new FxAccount-based Sync. | |
Services.prefs.clearUserPref("browser.syncPromoViewsLeft"); | |
Services.prefs.clearUserPref("browser.syncPromoViewsLeftMap"); | |
} | |
- if (this._dirty) | |
- this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush(); | |
- | |
- delete this._rdf; | |
- delete this._dataSource; | |
- | |
// Update the migration version. | |
Services.prefs.setIntPref("browser.migration.version", UI_VERSION); | |
}, | |
- _getPersist: function BG__getPersist(aSource, aProperty) { | |
- var target = this._dataSource.GetTarget(aSource, aProperty, true); | |
- if (target instanceof Ci.nsIRDFLiteral) | |
- return target.Value; | |
- return null; | |
- }, | |
- | |
- _setPersist: function BG__setPersist(aSource, aProperty, aTarget) { | |
- this._dirty = true; | |
- try { | |
- var oldTarget = this._dataSource.GetTarget(aSource, aProperty, true); | |
- if (oldTarget) { | |
- if (aTarget) | |
- this._dataSource.Change(aSource, aProperty, oldTarget, this._rdf.GetLiteral(aTarget)); | |
- else | |
- this._dataSource.Unassert(aSource, aProperty, oldTarget); | |
- } | |
- else { | |
- this._dataSource.Assert(aSource, aProperty, this._rdf.GetLiteral(aTarget), true); | |
- } | |
- | |
- // Add the entry to the persisted set for this document if it's not there. | |
- // This code is mostly borrowed from XULDocument::Persist. | |
- let docURL = aSource.ValueUTF8.split("#")[0]; | |
- let docResource = this._rdf.GetResource(docURL); | |
- let persistResource = this._rdf.GetResource("http://home.netscape.com/NC-rdf#persist"); | |
- if (!this._dataSource.HasAssertion(docResource, persistResource, aSource, true)) { | |
- this._dataSource.Assert(docResource, persistResource, aSource, true); | |
- } | |
- } | |
- catch(ex) {} | |
- }, | |
- | |
// ------------------------------ | |
// public nsIBrowserGlue members | |
// ------------------------------ | |
sanitize: function BG_sanitize(aParentWindow) { | |
this._sanitizer.sanitize(aParentWindow); | |
}, | |
diff --git a/browser/components/places/content/treeView.js b/browser/components/places/content/treeView.js | |
--- a/browser/components/places/content/treeView.js | |
+++ b/browser/components/places/content/treeView.js | |
@@ -18,16 +18,24 @@ function PlacesTreeView(aFlatList, aOnOp | |
this._flatList = aFlatList; | |
this._openContainerCallback = aOnOpenFlatContainer; | |
this._controller = aController; | |
} | |
PlacesTreeView.prototype = { | |
get wrappedJSObject() this, | |
+ __xulStore: null, | |
+ get _xulStore() { | |
+ if (!this.__xulStore) { | |
+ this.__xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore); | |
+ } | |
+ return this.__xulStore; | |
+ }, | |
+ | |
__dateService: null, | |
get _dateService() { | |
if (!this.__dateService) { | |
this.__dateService = Cc["@mozilla.org/intl/scriptabledateformat;1"]. | |
getService(Ci.nsIScriptableDateFormat); | |
} | |
return this.__dateService; | |
}, | |
@@ -302,21 +310,25 @@ PlacesTreeView.prototype = { | |
this._rows[row] = curChild; | |
rowsInserted++; | |
// Recursively do containers. | |
if (!this._flatList && | |
curChild instanceof Ci.nsINavHistoryContainerResultNode && | |
!this._controller.hasCachedLivemarkInfo(curChild)) { | |
- let resource = this._getResourceForNode(curChild); | |
- let isopen = resource != null && | |
- PlacesUIUtils.localStore.HasAssertion(resource, | |
- openLiteral, | |
- trueLiteral, true); | |
+ let uri = curChild.uri; | |
+ let isopen = false; | |
+ | |
+ if (uri) { | |
+ let docURI = this._getDocumentURI(); | |
+ let val = this._xulStore.getValue(docURI, uri, "open"); | |
+ isopen = (val == "true"); | |
+ } | |
+ | |
if (isopen != curChild.containerOpen) | |
aToOpen.push(curChild); | |
else if (curChild.containerOpen && curChild.childCount > 0) | |
rowsInserted += this._buildVisibleSection(curChild, row + 1, aToOpen); | |
} | |
} | |
return rowsInserted; | |
@@ -1104,21 +1116,26 @@ PlacesTreeView.prototype = { | |
try { | |
return this._getRowForNode(aNode, true); | |
} | |
catch(ex) { } | |
return Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE; | |
}, | |
- _getResourceForNode: function PTV_getResourceForNode(aNode) | |
+ // Retrieves an nsIURI for the document | |
+ _documentURI: null, | |
+ _getDocumentURI: function() | |
{ | |
- let uri = aNode.uri; | |
- NS_ASSERT(uri, "if there is no uri, we can't persist the open state"); | |
- return uri ? PlacesUIUtils.RDF.GetResource(uri) : null; | |
+ if (!this._documentURI) { | |
+ let ioService = Cc["@mozilla.org/network/io-service;1"]. | |
+ getService(Ci.nsIIOService); | |
+ this._documentURI = ioService.newURI(document.URL, null, null); | |
+ } | |
+ return this._documentURI; | |
}, | |
// nsITreeView | |
get rowCount() this._rows.length, | |
get selection() this._selection, | |
set selection(val) this._selection = val, | |
getRowProperties: function() { return ""; }, | |
@@ -1488,25 +1505,26 @@ PlacesTreeView.prototype = { | |
let node = this._rows[aRow]; | |
if (this._flatList && this._openContainerCallback) { | |
this._openContainerCallback(node); | |
return; | |
} | |
// Persist containers open status, but never persist livemarks. | |
if (!this._controller.hasCachedLivemarkInfo(node)) { | |
- let resource = this._getResourceForNode(node); | |
- if (resource) { | |
- const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open"); | |
- const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true"); | |
+ let uri = node.uri; | |
- if (node.containerOpen) | |
- PlacesUIUtils.localStore.Unassert(resource, openLiteral, trueLiteral); | |
- else | |
- PlacesUIUtils.localStore.Assert(resource, openLiteral, trueLiteral, true); | |
+ if (uri) { | |
+ let docURI = this._getDocumentURI(); | |
+ | |
+ if (node.containerOpen) { | |
+ this._xulStore.removeValue(docURI, uri, "open"); | |
+ } else { | |
+ this._xulStore.setValue(docURI, uri, "open", "true"); | |
+ } | |
} | |
} | |
node.containerOpen = !node.containerOpen; | |
}, | |
cycleHeader: function PTV_cycleHeader(aColumn) { | |
if (!this._result) | |
diff --git a/browser/components/places/src/PlacesUIUtils.jsm b/browser/components/places/src/PlacesUIUtils.jsm | |
--- a/browser/components/places/src/PlacesUIUtils.jsm | |
+++ b/browser/components/places/src/PlacesUIUtils.jsm | |
@@ -1015,20 +1015,16 @@ this.PlacesUIUtils = { | |
Weave.Service.engineManager.get("tabs").enabled; | |
}, | |
}; | |
XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "RDF", | |
"@mozilla.org/rdf/rdf-service;1", | |
"nsIRDFService"); | |
-XPCOMUtils.defineLazyGetter(PlacesUIUtils, "localStore", function() { | |
- return PlacesUIUtils.RDF.GetDataSource("rdf:local-store"); | |
-}); | |
- | |
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ellipsis", function() { | |
return Services.prefs.getComplexValue("intl.ellipsis", | |
Ci.nsIPrefLocalizedString).data; | |
}); | |
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "useAsyncTransactions", function() { | |
try { | |
return Services.prefs.getBoolPref("browser.places.useAsyncTransactions"); | |
diff --git a/browser/components/places/tests/browser/browser_toolbar_migration.js b/browser/components/places/tests/browser/browser_toolbar_migration.js | |
--- a/browser/components/places/tests/browser/browser_toolbar_migration.js | |
+++ b/browser/components/places/tests/browser/browser_toolbar_migration.js | |
@@ -1,90 +1,53 @@ | |
/* Any copyright is dedicated to the Public Domain. | |
* http://creativecommons.org/publicdomain/zero/1.0/ | |
*/ | |
/** | |
* Tests PersonalToolbar migration path. | |
*/ | |
- | |
let bg = Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsIObserver); | |
let gOriginalMigrationVersion; | |
const BROWSER_URL = getBrowserURL(); | |
let localStore = { | |
- get RDF() Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService), | |
- get store() this.RDF.GetDataSource("rdf:local-store"), | |
+ get xulStore() Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore), | |
- get toolbar() | |
+ getValue: function getValue(aProperty) | |
{ | |
- delete this.toolbar; | |
- let toolbar = this.RDF.GetResource(BROWSER_URL + "#PersonalToolbar"); | |
- // Add the entry to the persisted set for this document if it's not there. | |
- // See XULDocument::Persist. | |
- let doc = this.RDF.GetResource(BROWSER_URL); | |
- let persist = this.RDF.GetResource("http://home.netscape.com/NC-rdf#persist"); | |
- if (!this.store.HasAssertion(doc, persist, toolbar, true)) { | |
- this.store.Assert(doc, persist, toolbar, true); | |
- } | |
- return this.toolbar = toolbar; | |
+ return this.xulStore.getValue(BROWSER_URL, "PersonalToolbar", aProperty); | |
}, | |
- getPersist: function getPersist(aProperty) | |
+ setValue: function setValue(aProperty, aValue) | |
{ | |
- let property = this.RDF.GetResource(aProperty); | |
- let target = this.store.GetTarget(this.toolbar, property, true); | |
- if (target instanceof Ci.nsIRDFLiteral) | |
- return target.Value; | |
- return null; | |
- }, | |
- | |
- setPersist: function setPersist(aProperty, aValue) | |
- { | |
- let property = this.RDF.GetResource(aProperty); | |
- let value = aValue ? this.RDF.GetLiteral(aValue) : null; | |
- | |
- try { | |
- let oldTarget = this.store.GetTarget(this.toolbar, property, true); | |
- if (oldTarget && value) { | |
- this.store.Change(this.toolbar, property, oldTarget, value); | |
- } | |
- else if (value) { | |
- this.store.Assert(this.toolbar, property, value, true); | |
- } | |
- else if (oldTarget) { | |
- this.store.Unassert(this.toolbar, property, oldTarget); | |
- } | |
- else { | |
- return; | |
- } | |
+ if (aValue) { | |
+ this.xulStore.setValue(BROWSER_URL, "PersonalToolbar", aProperty, aValue); | |
+ } else { | |
+ this.xulStore.removeValue(BROWSER_URL, "PersonalToolbar", aProperty); | |
} | |
- catch(ex) { | |
- return; | |
- } | |
- this.store.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush(); | |
} | |
}; | |
let gTests = [ | |
function test_explicitly_collapsed_toolbar() | |
{ | |
info("An explicitly collapsed toolbar should not be uncollapsed."); | |
- localStore.setPersist("collapsed", "true"); | |
+ localStore.setValue("collapsed", "true"); | |
bg.observe(null, "browser-glue-test", "force-ui-migration"); | |
- is(localStore.getPersist("collapsed"), "true", "Toolbar is collapsed"); | |
+ is(localStore.getValue("collapsed"), "true", "Toolbar is collapsed"); | |
}, | |
function test_customized_toolbar() | |
{ | |
info("A customized toolbar should be uncollapsed."); | |
- localStore.setPersist("currentset", "splitter"); | |
+ localStore.setValue("currentset", "splitter"); | |
bg.observe(null, "browser-glue-test", "force-ui-migration"); | |
- is(localStore.getPersist("collapsed"), "false", "Toolbar has been uncollapsed"); | |
+ is(localStore.getValue("collapsed"), "false", "Toolbar has been uncollapsed"); | |
}, | |
function test_many_bookmarks_toolbar() | |
{ | |
info("A toolbar with added bookmarks should be uncollapsed."); | |
let ids = []; | |
ids.push( | |
PlacesUtils.bookmarks.insertSeparator(PlacesUtils.toolbarFolderId, | |
@@ -93,43 +56,47 @@ function test_many_bookmarks_toolbar() | |
ids.push( | |
PlacesUtils.bookmarks.insertSeparator(PlacesUtils.toolbarFolderId, | |
PlacesUtils.bookmarks.DEFAULT_INDEX) | |
); | |
ids.push( | |
PlacesUtils.bookmarks.insertSeparator(PlacesUtils.toolbarFolderId, | |
PlacesUtils.bookmarks.DEFAULT_INDEX) | |
); | |
+ ids.push( | |
+ PlacesUtils.bookmarks.insertSeparator(PlacesUtils.toolbarFolderId, | |
+ PlacesUtils.bookmarks.DEFAULT_INDEX) | |
+ ); | |
bg.observe(null, "browser-glue-test", "force-ui-migration"); | |
- is(localStore.getPersist("collapsed"), "false", "Toolbar has been uncollapsed"); | |
+ is(localStore.getValue("collapsed"), "false", "Toolbar has been uncollapsed"); | |
}, | |
]; | |
function test() | |
{ | |
gOriginalMigrationVersion = Services.prefs.getIntPref("browser.migration.version"); | |
registerCleanupFunction(clean); | |
- if (localStore.getPersist("currentset") !== null) { | |
+ if (localStore.getValue("currentset") !== null) { | |
info("Toolbar currentset was persisted by a previous test, fixing it."); | |
- localStore.setPersist("currentset", null); | |
+ localStore.setValue("currentset", null); | |
} | |
- if (localStore.getPersist("collapsed") !== null) { | |
+ if (localStore.getValue("collapsed") !== null) { | |
info("Toolbar collapsed status was persisted by a previous test, fixing it."); | |
- localStore.setPersist("collapsed", null); | |
+ localStore.setValue("collapsed", null); | |
} | |
while (gTests.length) { | |
clean(); | |
Services.prefs.setIntPref("browser.migration.version", 4); | |
gTests.shift().call(); | |
} | |
} | |
function clean() | |
{ | |
Services.prefs.setIntPref("browser.migration.version", gOriginalMigrationVersion); | |
- localStore.setPersist("currentset", null); | |
- localStore.setPersist("collapsed", null); | |
+ localStore.setValue("currentset", null); | |
+ localStore.setValue("collapsed", null); | |
} | |
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in | |
--- a/browser/installer/package-manifest.in | |
+++ b/browser/installer/package-manifest.in | |
@@ -297,16 +297,17 @@ | |
#endif | |
@BINPATH@/browser/components/shellservice.xpt | |
@BINPATH@/components/shistory.xpt | |
@BINPATH@/components/spellchecker.xpt | |
@BINPATH@/components/storage.xpt | |
@BINPATH@/components/toolkit_finalizationwitness.xpt | |
@BINPATH@/components/toolkit_formautofill.xpt | |
@BINPATH@/components/toolkit_osfile.xpt | |
+@BINPATH@/components/toolkit_xulstore.xpt | |
@BINPATH@/components/toolkitprofile.xpt | |
#ifdef MOZ_ENABLE_XREMOTE | |
@BINPATH@/components/toolkitremote.xpt | |
#endif | |
@BINPATH@/components/txtsvc.xpt | |
@BINPATH@/components/txmgr.xpt | |
@BINPATH@/components/uconv.xpt | |
@BINPATH@/components/unicharutil.xpt | |
@@ -496,16 +497,18 @@ | |
#ifdef MOZ_CAPTIVEDETECT | |
@BINPATH@/components/CaptivePortalDetectComponents.manifest | |
@BINPATH@/components/captivedetect.js | |
#endif | |
@BINPATH@/components/servicesComponents.manifest | |
@BINPATH@/components/cryptoComponents.manifest | |
@BINPATH@/components/TelemetryStartup.js | |
@BINPATH@/components/TelemetryStartup.manifest | |
+@BINPATH@/components/XULStore.js | |
+@BINPATH@/components/XULStore.manifest | |
@BINPATH@/components/messageWakeupService.js | |
@BINPATH@/components/messageWakeupService.manifest | |
@BINPATH@/components/SettingsManager.js | |
@BINPATH@/components/SettingsManager.manifest | |
@BINPATH@/components/Webapps.js | |
@BINPATH@/components/Webapps.manifest | |
@BINPATH@/components/AppsService.js | |
@BINPATH@/components/AppsService.manifest | |
diff --git a/content/xul/document/src/XULDocument.cpp b/content/xul/document/src/XULDocument.cpp | |
--- a/content/xul/document/src/XULDocument.cpp | |
+++ b/content/xul/document/src/XULDocument.cpp | |
@@ -28,32 +28,28 @@ | |
#include "nsError.h" | |
#include "nsIBoxObject.h" | |
#include "nsIChromeRegistry.h" | |
#include "nsView.h" | |
#include "nsViewManager.h" | |
#include "nsIContentViewer.h" | |
#include "nsIDOMXULElement.h" | |
-#include "nsIRDFNode.h" | |
-#include "nsIRDFRemoteDataSource.h" | |
-#include "nsIRDFService.h" | |
#include "nsIStreamListener.h" | |
#include "nsITimer.h" | |
#include "nsDocShell.h" | |
#include "nsGkAtoms.h" | |
#include "nsXMLContentSink.h" | |
#include "nsXULContentSink.h" | |
#include "nsXULContentUtils.h" | |
#include "nsIXULOverlayProvider.h" | |
+#include "nsIStringEnumerator.h" | |
#include "nsNetUtil.h" | |
#include "nsParserCIID.h" | |
#include "nsPIBoxObject.h" | |
-#include "nsRDFCID.h" | |
-#include "nsILocalStore.h" | |
#include "nsXPIDLString.h" | |
#include "nsPIDOMWindow.h" | |
#include "nsPIWindowRoot.h" | |
#include "nsXULCommandDispatcher.h" | |
#include "nsXULElement.h" | |
#include "prlog.h" | |
#include "rdf.h" | |
#include "nsIFrame.h" | |
@@ -131,21 +127,16 @@ const uint32_t kMaxAttributeLength = 409 | |
//---------------------------------------------------------------------- | |
// | |
// Statics | |
// | |
int32_t XULDocument::gRefCnt = 0; | |
-nsIRDFService* XULDocument::gRDFService; | |
-nsIRDFResource* XULDocument::kNC_persist; | |
-nsIRDFResource* XULDocument::kNC_attribute; | |
-nsIRDFResource* XULDocument::kNC_value; | |
- | |
PRLogModuleInfo* XULDocument::gXULLog; | |
//---------------------------------------------------------------------- | |
struct BroadcasterMapEntry : public PLDHashEntryHdr { | |
Element* mBroadcaster; // [WEAK] | |
nsSmallVoidArray mListeners; // [OWNING] of BroadcastListener objects | |
}; | |
@@ -224,36 +215,21 @@ XULDocument::~XULDocument() | |
// look for persisted data: | |
mPersistenceIds.Clear(); | |
// Destroy our broadcaster map. | |
if (mBroadcasterMap) { | |
PL_DHashTableDestroy(mBroadcasterMap); | |
} | |
- if (mLocalStore) { | |
- nsCOMPtr<nsIRDFRemoteDataSource> remote = | |
- do_QueryInterface(mLocalStore); | |
- if (remote) | |
- remote->Flush(); | |
- } | |
- | |
delete mTemplateBuilderTable; | |
Preferences::UnregisterCallback(XULDocument::DirectionChanged, | |
"intl.uidirection.", this); | |
- if (--gRefCnt == 0) { | |
- NS_IF_RELEASE(gRDFService); | |
- | |
- NS_IF_RELEASE(kNC_persist); | |
- NS_IF_RELEASE(kNC_attribute); | |
- NS_IF_RELEASE(kNC_value); | |
- } | |
- | |
if (mOffThreadCompileStringBuf) { | |
js_free(mOffThreadCompileStringBuf); | |
} | |
} | |
} // namespace dom | |
} // namespace mozilla | |
@@ -343,16 +319,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ | |
} | |
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END | |
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULDocument, XMLDocument) | |
delete tmp->mTemplateBuilderTable; | |
tmp->mTemplateBuilderTable = nullptr; | |
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher) | |
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStore) | |
//XXX We should probably unlink all the objects we traverse. | |
NS_IMPL_CYCLE_COLLECTION_UNLINK_END | |
NS_IMPL_ADDREF_INHERITED(XULDocument, XMLDocument) | |
NS_IMPL_RELEASE_INHERITED(XULDocument, XMLDocument) | |
// QueryInterface implementation for XULDocument | |
@@ -1326,126 +1303,60 @@ XULDocument::Persist(const nsAString& aI | |
} | |
tag = do_GetAtom(aAttr); | |
NS_ENSURE_TRUE(tag, NS_ERROR_OUT_OF_MEMORY); | |
nameSpaceID = kNameSpaceID_None; | |
} | |
- rv = Persist(element, nameSpaceID, tag); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- return NS_OK; | |
+ return Persist(element, nameSpaceID, tag); | |
} | |
nsresult | |
XULDocument::Persist(nsIContent* aElement, int32_t aNameSpaceID, | |
nsIAtom* aAttribute) | |
{ | |
// For non-chrome documents, persistance is simply broken | |
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) | |
return NS_ERROR_NOT_AVAILABLE; | |
- // First make sure we _have_ a local store to stuff the persisted | |
- // information into. (We might not have one if profile information | |
- // hasn't been loaded yet...) | |
- if (!mLocalStore) | |
- return NS_OK; | |
- | |
- nsresult rv; | |
- | |
- nsCOMPtr<nsIRDFResource> element; | |
- rv = nsXULContentUtils::GetElementResource(aElement, getter_AddRefs(element)); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- // No ID, so nothing to persist. | |
- if (! element) | |
- return NS_OK; | |
- | |
- // Ick. Construct a property from the attribute. Punt on | |
- // namespaces for now. | |
- // Don't bother with unreasonable attributes. We clamp long values, | |
- // but truncating attribute names turns it into a different attribute | |
- // so there's no point in persisting anything at all | |
- nsAtomCString attrstr(aAttribute); | |
- if (attrstr.Length() > kMaxAttrNameLength) { | |
- NS_WARNING("Can't persist, Attribute name too long"); | |
- return NS_ERROR_ILLEGAL_VALUE; | |
+ if (!mLocalStore) { | |
+ mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1"); | |
+ if (NS_WARN_IF(!mLocalStore)) { | |
+ return NS_ERROR_NOT_INITIALIZED; | |
+ } | |
} | |
- nsCOMPtr<nsIRDFResource> attr; | |
- rv = gRDFService->GetResource(attrstr, | |
- getter_AddRefs(attr)); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- // Turn the value into a literal | |
+ nsAutoString id; | |
+ | |
+ aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id); | |
+ nsAtomString attrstr(aAttribute); | |
+ | |
nsAutoString valuestr; | |
aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr); | |
- // prevent over-long attributes that choke the parser (bug 319846) | |
- // (can't simply Truncate without testing, it's implemented | |
- // using SetLength and will grow a short string) | |
- if (valuestr.Length() > kMaxAttributeLength) { | |
- NS_WARNING("Truncating persisted attribute value"); | |
- valuestr.Truncate(kMaxAttributeLength); | |
+ nsAutoCString utf8uri; | |
+ nsresult rv = mDocumentURI->GetSpec(utf8uri); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
} | |
- | |
- // See if there was an old value... | |
- nsCOMPtr<nsIRDFNode> oldvalue; | |
- rv = mLocalStore->GetTarget(element, attr, true, getter_AddRefs(oldvalue)); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- if (oldvalue && valuestr.IsEmpty()) { | |
- // ...there was an oldvalue, and they've removed it. XXXThis | |
- // handling isn't quite right... | |
- rv = mLocalStore->Unassert(element, attr, oldvalue); | |
+ NS_ConvertUTF8toUTF16 uri(utf8uri); | |
+ | |
+ bool hasAttr; | |
+ rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
} | |
- else { | |
- // Now either 'change' or 'assert' based on whether there was | |
- // an old value. | |
- nsCOMPtr<nsIRDFLiteral> newvalue; | |
- rv = gRDFService->GetLiteral(valuestr.get(), getter_AddRefs(newvalue)); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- if (oldvalue) { | |
- if (oldvalue != newvalue) | |
- rv = mLocalStore->Change(element, attr, oldvalue, newvalue); | |
- else | |
- rv = NS_OK; | |
- } | |
- else { | |
- rv = mLocalStore->Assert(element, attr, newvalue, true); | |
- } | |
+ | |
+ if (hasAttr && valuestr.IsEmpty()) { | |
+ return mLocalStore->RemoveValue(uri, id, attrstr); | |
+ } else { | |
+ return mLocalStore->SetValue(uri, id, attrstr, valuestr); | |
} | |
- | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- // Add it to the persisted set for this document (if it's not | |
- // there already). | |
- { | |
- nsAutoCString docurl; | |
- rv = mDocumentURI->GetSpec(docurl); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- nsCOMPtr<nsIRDFResource> doc; | |
- rv = gRDFService->GetResource(docurl, getter_AddRefs(doc)); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- bool hasAssertion; | |
- rv = mLocalStore->HasAssertion(doc, kNC_persist, element, true, &hasAssertion); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- if (! hasAssertion) { | |
- rv = mLocalStore->Assert(doc, kNC_persist, element, true); | |
- if (NS_FAILED(rv)) return rv; | |
- } | |
- } | |
- | |
- return NS_OK; | |
} | |
nsresult | |
XULDocument::GetViewportSize(int32_t* aWidth, | |
int32_t* aHeight) | |
{ | |
*aWidth = *aHeight = 0; | |
@@ -1988,35 +1899,17 @@ XULDocument::Init() | |
{ | |
nsresult rv = XMLDocument::Init(); | |
NS_ENSURE_SUCCESS(rv, rv); | |
// Create our command dispatcher and hook it up. | |
mCommandDispatcher = new nsXULCommandDispatcher(this); | |
NS_ENSURE_TRUE(mCommandDispatcher, NS_ERROR_OUT_OF_MEMORY); | |
- // this _could_ fail; e.g., if we've tried to grab the local store | |
- // before profiles have initialized. If so, no big deal; nothing | |
- // will persist. | |
- mLocalStore = do_GetService(NS_LOCALSTORE_CONTRACTID); | |
- | |
if (gRefCnt++ == 0) { | |
- // Keep the RDF service cached in a member variable to make using | |
- // it a bit less painful | |
- rv = CallGetService("@mozilla.org/rdf/rdf-service;1", &gRDFService); | |
- NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF Service"); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "persist"), | |
- &kNC_persist); | |
- gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "attribute"), | |
- &kNC_attribute); | |
- gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "value"), | |
- &kNC_value); | |
- | |
// ensure that the XUL prototype cache is instantiated successfully, | |
// so that we can use nsXULPrototypeCache::GetInstance() without | |
// null-checks in the rest of the class. | |
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance(); | |
if (!cache) { | |
NS_ERROR("Could not instantiate nsXULPrototypeCache"); | |
return NS_ERROR_FAILURE; | |
} | |
@@ -2170,154 +2063,133 @@ nsresult | |
XULDocument::ApplyPersistentAttributes() | |
{ | |
// For non-chrome documents, persistance is simply broken | |
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) | |
return NS_ERROR_NOT_AVAILABLE; | |
// Add all of the 'persisted' attributes into the content | |
// model. | |
- if (!mLocalStore) | |
- return NS_OK; | |
+ if (!mLocalStore) { | |
+ mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1"); | |
+ if (NS_WARN_IF(!mLocalStore)) { | |
+ return NS_ERROR_NOT_INITIALIZED; | |
+ } | |
+ } | |
mApplyingPersistedAttrs = true; | |
ApplyPersistentAttributesInternal(); | |
mApplyingPersistedAttrs = false; | |
// After we've applied persistence once, we should only reapply | |
// it to nodes created by overlays | |
mRestrictPersistence = true; | |
mPersistenceIds.Clear(); | |
return NS_OK; | |
} | |
-nsresult | |
+nsresult | |
XULDocument::ApplyPersistentAttributesInternal() | |
{ | |
nsCOMArray<nsIContent> elements; | |
- nsAutoCString docurl; | |
- mDocumentURI->GetSpec(docurl); | |
- | |
- nsCOMPtr<nsIRDFResource> doc; | |
- gRDFService->GetResource(docurl, getter_AddRefs(doc)); | |
- | |
- nsCOMPtr<nsISimpleEnumerator> persisted; | |
- mLocalStore->GetTargets(doc, kNC_persist, true, getter_AddRefs(persisted)); | |
+ nsAutoCString utf8uri; | |
+ nsresult rv = mDocumentURI->GetSpec(utf8uri); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
+ } | |
+ NS_ConvertUTF8toUTF16 uri(utf8uri); | |
+ | |
+ // Get a list of element IDs for which persisted values are available | |
+ nsCOMPtr<nsIStringEnumerator> ids; | |
+ rv = mLocalStore->GetIDsEnumerator(uri, getter_AddRefs(ids)); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
+ } | |
while (1) { | |
bool hasmore = false; | |
- persisted->HasMoreElements(&hasmore); | |
- if (! hasmore) | |
+ ids->HasMore(&hasmore); | |
+ if (!hasmore) { | |
break; | |
- | |
- nsCOMPtr<nsISupports> isupports; | |
- persisted->GetNext(getter_AddRefs(isupports)); | |
- | |
- nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(isupports); | |
- if (! resource) { | |
- NS_WARNING("expected element to be a resource"); | |
+ } | |
+ | |
+ nsAutoString id; | |
+ ids->GetNext(id); | |
+ | |
+ if (mRestrictPersistence && !mPersistenceIds.Contains(id)) { | |
continue; | |
} | |
- const char *uri; | |
- resource->GetValueConst(&uri); | |
- if (! uri) | |
- continue; | |
- | |
- nsAutoString id; | |
- nsXULContentUtils::MakeElementID(this, nsDependentCString(uri), id); | |
- | |
- if (id.IsEmpty()) | |
- continue; | |
- | |
- if (mRestrictPersistence && !mPersistenceIds.Contains(id)) | |
- continue; | |
- | |
// This will clear the array if there are no elements. | |
GetElementsForID(id, elements); | |
- | |
- if (!elements.Count()) | |
+ if (!elements.Count()) { | |
continue; | |
- | |
- ApplyPersistentAttributesToElements(resource, elements); | |
+ } | |
+ | |
+ rv = ApplyPersistentAttributesToElements(id, elements); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
+ } | |
} | |
return NS_OK; | |
} | |
nsresult | |
-XULDocument::ApplyPersistentAttributesToElements(nsIRDFResource* aResource, | |
+XULDocument::ApplyPersistentAttributesToElements(const nsAString &aID, | |
nsCOMArray<nsIContent>& aElements) | |
{ | |
- nsresult rv; | |
- | |
- nsCOMPtr<nsISimpleEnumerator> attrs; | |
- rv = mLocalStore->ArcLabelsOut(aResource, getter_AddRefs(attrs)); | |
- if (NS_FAILED(rv)) return rv; | |
+ nsAutoCString utf8uri; | |
+ nsresult rv = mDocumentURI->GetSpec(utf8uri); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
+ } | |
+ NS_ConvertUTF8toUTF16 uri(utf8uri); | |
+ | |
+ // Get a list of attributes for which persisted values are available | |
+ nsCOMPtr<nsIStringEnumerator> attrs; | |
+ rv = mLocalStore->GetAttributeEnumerator(uri, aID, getter_AddRefs(attrs)); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
+ } | |
while (1) { | |
- bool hasmore; | |
- rv = attrs->HasMoreElements(&hasmore); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- if (! hasmore) | |
+ bool hasmore = PR_FALSE; | |
+ attrs->HasMore(&hasmore); | |
+ if (!hasmore) { | |
break; | |
- | |
- nsCOMPtr<nsISupports> isupports; | |
- rv = attrs->GetNext(getter_AddRefs(isupports)); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports); | |
- if (! property) { | |
- NS_WARNING("expected a resource"); | |
- continue; | |
} | |
- const char* attrname; | |
- rv = property->GetValueConst(&attrname); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- nsCOMPtr<nsIAtom> attr = do_GetAtom(attrname); | |
- if (! attr) | |
+ nsAutoString attrstr; | |
+ attrs->GetNext(attrstr); | |
+ | |
+ nsAutoString value; | |
+ rv = mLocalStore->GetValue(uri, aID, attrstr, value); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
+ } | |
+ | |
+ nsCOMPtr<nsIAtom> attr = do_GetAtom(attrstr); | |
+ if (NS_WARN_IF(!attr)) { | |
return NS_ERROR_OUT_OF_MEMORY; | |
- | |
- // XXX could hang namespace off here, as well... | |
- | |
- nsCOMPtr<nsIRDFNode> node; | |
- rv = mLocalStore->GetTarget(aResource, property, true, | |
- getter_AddRefs(node)); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(node); | |
- if (! literal) { | |
- NS_WARNING("expected a literal"); | |
- continue; | |
} | |
- const char16_t* value; | |
- rv = literal->GetValueConst(&value); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- nsDependentString wrapper(value); | |
- | |
uint32_t cnt = aElements.Count(); | |
for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) { | |
nsCOMPtr<nsIContent> element = aElements.SafeObjectAt(i); | |
- if (!element) | |
- continue; | |
- | |
- rv = element->SetAttr(/* XXX */ kNameSpaceID_None, | |
- attr, | |
- wrapper, | |
- true); | |
+ if (!element) { | |
+ continue; | |
+ } | |
+ | |
+ rv = element->SetAttr(kNameSpaceID_None, attr, value, PR_TRUE); | |
} | |
} | |
return NS_OK; | |
} | |
void | |
XULDocument::TraceProtos(JSTracer* aTrc, uint32_t aGCNumber) | |
diff --git a/content/xul/document/src/XULDocument.h b/content/xul/document/src/XULDocument.h | |
--- a/content/xul/document/src/XULDocument.h | |
+++ b/content/xul/document/src/XULDocument.h | |
@@ -17,16 +17,17 @@ | |
#include "nsIDOMXULCommandDispatcher.h" | |
#include "nsIDOMXULDocument.h" | |
#include "nsCOMArray.h" | |
#include "nsIURI.h" | |
#include "nsIXULDocument.h" | |
#include "nsScriptLoader.h" | |
#include "nsIStreamListener.h" | |
#include "nsICSSLoaderObserver.h" | |
+#include "nsIXULStore.h" | |
#include "mozilla/Attributes.h" | |
#include "js/TracingAPI.h" | |
#include "js/TypeDecls.h" | |
class nsIRDFResource; | |
class nsIRDFService; | |
@@ -254,17 +255,17 @@ protected: | |
nsIParser** aResult); | |
nsresult | |
LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic, bool* aShouldReturn, | |
bool* aFailureFromContent); | |
nsresult ApplyPersistentAttributes(); | |
nsresult ApplyPersistentAttributesInternal(); | |
- nsresult ApplyPersistentAttributesToElements(nsIRDFResource* aResource, | |
+ nsresult ApplyPersistentAttributesToElements(const nsAString &aID, | |
nsCOMArray<nsIContent>& aElements); | |
nsresult | |
AddElementToDocumentPre(Element* aElement); | |
nsresult | |
AddElementToDocumentPost(Element* aElement); | |
@@ -309,20 +310,20 @@ protected: | |
// NOTE, THIS IS STILL IN PROGRESS, TALK TO PINK OR SCC BEFORE | |
// CHANGING | |
XULDocument* mNextSrcLoadWaiter; // [OWNER] but not COMPtr | |
// Tracks elements with a 'ref' attribute, or an 'id' attribute where | |
// the element's namespace has no registered ID attribute name. | |
nsTHashtable<nsRefMapEntry> mRefMap; | |
- nsCOMPtr<nsIRDFDataSource> mLocalStore; | |
- bool mApplyingPersistedAttrs; | |
- bool mIsWritingFastLoad; | |
- bool mDocumentLoaded; | |
+ nsCOMPtr<nsIXULStore> mLocalStore; | |
+ bool mApplyingPersistedAttrs; | |
+ bool mIsWritingFastLoad; | |
+ bool mDocumentLoaded; | |
/** | |
* Since ResumeWalk is interruptible, it's possible that last | |
* stylesheet finishes loading while the PD walk is still in | |
* progress (waiting for an overlay to finish loading). | |
* mStillWalking prevents DoneLoading (and StartLayout) from being | |
* called in this situation. | |
*/ | |
bool mStillWalking; | |
diff --git a/content/xul/templates/src/nsXULContentUtils.cpp b/content/xul/templates/src/nsXULContentUtils.cpp | |
--- a/content/xul/templates/src/nsXULContentUtils.cpp | |
+++ b/content/xul/templates/src/nsXULContentUtils.cpp | |
@@ -181,46 +181,16 @@ nsXULContentUtils::FindChildByTag(nsICon | |
} | |
} | |
*aResult = nullptr; | |
return NS_RDF_NO_VALUE; // not found | |
} | |
-nsresult | |
-nsXULContentUtils::GetElementResource(nsIContent* aElement, nsIRDFResource** aResult) | |
-{ | |
- // Perform a reverse mapping from an element in the content model | |
- // to an RDF resource. | |
- nsresult rv; | |
- | |
- char16_t buf[128]; | |
- nsFixedString id(buf, ArrayLength(buf), 0); | |
- | |
- // Whoa. Why the "id" attribute? What if it's not even a XUL | |
- // element? This is totally bogus! | |
- aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id); | |
- if (id.IsEmpty()) | |
- return NS_ERROR_FAILURE; | |
- | |
- // Since the element will store its ID attribute as a document-relative value, | |
- // we may need to qualify it first... | |
- nsCOMPtr<nsIDocument> doc = aElement->GetDocument(); | |
- NS_ASSERTION(doc, "element is not in any document"); | |
- if (! doc) | |
- return NS_ERROR_FAILURE; | |
- | |
- rv = nsXULContentUtils::MakeElementResource(doc, id, aResult); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- return NS_OK; | |
-} | |
- | |
- | |
/* | |
Note: this routine is similar, yet distinctly different from, nsBookmarksService::GetTextForNode | |
*/ | |
nsresult | |
nsXULContentUtils::GetTextForNode(nsIRDFNode* aNode, nsAString& aResult) | |
{ | |
if (! aNode) { | |
@@ -283,88 +253,16 @@ nsXULContentUtils::GetTextForNode(nsIRDF | |
return NS_OK; | |
} | |
NS_ERROR("not a resource or a literal"); | |
return NS_ERROR_UNEXPECTED; | |
} | |
nsresult | |
-nsXULContentUtils::MakeElementURI(nsIDocument* aDocument, | |
- const nsAString& aElementID, | |
- nsCString& aURI) | |
-{ | |
- // Convert an element's ID to a URI that can be used to refer to | |
- // the element in the XUL graph. | |
- | |
- nsIURI *docURI = aDocument->GetDocumentURI(); | |
- NS_ENSURE_TRUE(docURI, NS_ERROR_UNEXPECTED); | |
- | |
- nsRefPtr<nsIURI> docURIClone; | |
- nsresult rv = docURI->Clone(getter_AddRefs(docURIClone)); | |
- NS_ENSURE_SUCCESS(rv, rv); | |
- | |
- rv = docURIClone->SetRef(NS_ConvertUTF16toUTF8(aElementID)); | |
- if (NS_SUCCEEDED(rv)) { | |
- return docURIClone->GetSpec(aURI); | |
- } | |
- | |
- // docURIClone is apparently immutable. Fine - we can append ref manually. | |
- rv = docURI->GetSpec(aURI); | |
- NS_ENSURE_SUCCESS(rv, rv); | |
- | |
- nsAutoCString ref; | |
- NS_EscapeURL(NS_ConvertUTF16toUTF8(aElementID), esc_FilePath | esc_AlwaysCopy, ref); | |
- | |
- aURI.Append('#'); | |
- aURI.Append(ref); | |
- | |
- return NS_OK; | |
-} | |
- | |
- | |
-nsresult | |
-nsXULContentUtils::MakeElementResource(nsIDocument* aDocument, const nsAString& aID, nsIRDFResource** aResult) | |
-{ | |
- nsresult rv; | |
- | |
- char buf[256]; | |
- nsFixedCString uri(buf, sizeof(buf), 0); | |
- rv = MakeElementURI(aDocument, aID, uri); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- rv = gRDF->GetResource(uri, aResult); | |
- NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create resource"); | |
- if (NS_FAILED(rv)) return rv; | |
- | |
- return NS_OK; | |
-} | |
- | |
- | |
- | |
-nsresult | |
-nsXULContentUtils::MakeElementID(nsIDocument* aDocument, | |
- const nsACString& aURI, | |
- nsAString& aElementID) | |
-{ | |
- // Convert a URI into an element ID that can be accessed from the | |
- // DOM APIs. | |
- nsCOMPtr<nsIURI> uri; | |
- nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI, | |
- aDocument->GetDocumentCharacterSet().get()); | |
- NS_ENSURE_SUCCESS(rv, rv); | |
- | |
- nsAutoCString ref; | |
- uri->GetRef(ref); | |
- CopyUTF8toUTF16(ref, aElementID); | |
- | |
- return NS_OK; | |
-} | |
- | |
-nsresult | |
nsXULContentUtils::GetResource(int32_t aNameSpaceID, nsIAtom* aAttribute, nsIRDFResource** aResult) | |
{ | |
// construct a fully-qualified URI from the namespace/tag pair. | |
NS_PRECONDITION(aAttribute != nullptr, "null ptr"); | |
if (! aAttribute) | |
return NS_ERROR_NULL_POINTER; | |
return GetResource(aNameSpaceID, nsDependentAtomString(aAttribute), | |
diff --git a/content/xul/templates/src/nsXULContentUtils.h b/content/xul/templates/src/nsXULContentUtils.h | |
--- a/content/xul/templates/src/nsXULContentUtils.h | |
+++ b/content/xul/templates/src/nsXULContentUtils.h | |
@@ -111,40 +111,18 @@ public: | |
nsIContent **aResult); | |
static nsresult | |
FindChildByResource(nsIContent* aElement, | |
nsIRDFResource* aResource, | |
nsIContent** aResult); | |
static nsresult | |
- GetElementResource(nsIContent* aElement, nsIRDFResource** aResult); | |
- | |
- static nsresult | |
GetTextForNode(nsIRDFNode* aNode, nsAString& aResult); | |
- /** | |
- * Construct a URI from the element ID given. This uses aElement as the | |
- * ref and aDocument's document URI as the base. If aDocument's document | |
- * URI does not support refs, this will throw NS_ERROR_NOT_AVAILABLE. | |
- */ | |
- static nsresult | |
- MakeElementURI(nsIDocument* aDocument, const nsAString& aElementID, nsCString& aURI); | |
- | |
- static nsresult | |
- MakeElementResource(nsIDocument* aDocument, const nsAString& aElementID, nsIRDFResource** aResult); | |
- | |
- /** | |
- * Extract the element ID from aURI. Note that aURI must be an absolute | |
- * URI string in UTF8; the element ID is the ref from the URI. If the | |
- * scheme does not support refs, then the ID will be empty. | |
- */ | |
- static nsresult | |
- MakeElementID(nsIDocument* aDocument, const nsACString& aURI, nsAString& aElementID); | |
- | |
static nsresult | |
GetResource(int32_t aNameSpaceID, nsIAtom* aAttribute, nsIRDFResource** aResult); | |
static nsresult | |
GetResource(int32_t aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult); | |
static nsresult | |
SetCommandUpdater(nsIDocument* aDocument, nsIContent* aElement); | |
diff --git a/content/xul/templates/src/nsXULTreeBuilder.cpp b/content/xul/templates/src/nsXULTreeBuilder.cpp | |
--- a/content/xul/templates/src/nsXULTreeBuilder.cpp | |
+++ b/content/xul/templates/src/nsXULTreeBuilder.cpp | |
@@ -3,17 +3,16 @@ | |
* 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/. */ | |
#include "nscore.h" | |
#include "nsError.h" | |
#include "nsIContent.h" | |
#include "mozilla/dom/NodeInfo.h" | |
#include "nsIDOMElement.h" | |
-#include "nsILocalStore.h" | |
#include "nsIBoxObject.h" | |
#include "nsITreeBoxObject.h" | |
#include "nsITreeSelection.h" | |
#include "nsITreeColumns.h" | |
#include "nsITreeView.h" | |
#include "nsTreeUtils.h" | |
#include "nsIServiceManager.h" | |
#include "nsReadableUtils.h" | |
@@ -26,16 +25,17 @@ | |
#include "nsXULTemplateBuilder.h" | |
#include "nsIXULSortService.h" | |
#include "nsTArray.h" | |
#include "nsUnicharUtils.h" | |
#include "nsNameSpaceManager.h" | |
#include "nsDOMClassInfoID.h" | |
#include "nsWhitespaceTokenizer.h" | |
#include "nsTreeContentView.h" | |
+#include "nsIXULStore.h" | |
// For security check | |
#include "nsIDocument.h" | |
/** | |
* A XUL template builder that serves as an tree view, allowing | |
* (pretty much) arbitrary RDF to be presented in an tree. | |
*/ | |
@@ -134,23 +134,20 @@ protected: | |
/** | |
* Remove the matches for the rows in a subtree | |
*/ | |
nsresult | |
RemoveMatchesFor(nsTreeRows::Subtree& subtree); | |
/** | |
- * Helper methods that determine if the specified container is open. | |
+ * Helper method that determines if the specified container is open. | |
*/ | |
- nsresult | |
- IsContainerOpen(nsIXULTemplateResult *aResult, bool* aOpen); | |
- | |
- nsresult | |
- IsContainerOpen(nsIRDFResource* aResource, bool* aOpen); | |
+ bool | |
+ IsContainerOpen(nsIXULTemplateResult* aResource); | |
/** | |
* A sorting callback for NS_QuickSort(). | |
*/ | |
static int | |
Compare(const void* aLeft, const void* aRight, void* aClosure); | |
/** | |
@@ -237,16 +234,21 @@ protected: | |
* Sort hints (compare case, etc) | |
*/ | |
uint32_t mSortHints; | |
/** | |
* The builder observers. | |
*/ | |
nsCOMArray<nsIXULTreeBuilderObserver> mObservers; | |
+ | |
+ /* | |
+ * XUL store for holding open container state | |
+ */ | |
+ nsCOMPtr<nsIXULStore> mLocalStore; | |
}; | |
//---------------------------------------------------------------------- | |
nsresult | |
NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult) | |
{ | |
*aResult = nullptr; | |
@@ -273,16 +275,17 @@ NS_NewXULTreeBuilder(nsISupports* aOuter | |
NS_IMPL_ADDREF_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder) | |
NS_IMPL_RELEASE_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder) | |
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder, | |
mBoxObject, | |
mSelection, | |
mPersistStateStore, | |
+ mLocalStore, | |
mObservers) | |
DOMCI_DATA(XULTreeBuilder, nsXULTreeBuilder) | |
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder) | |
NS_INTERFACE_MAP_ENTRY(nsIXULTreeBuilder) | |
NS_INTERFACE_MAP_ENTRY(nsITreeView) | |
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XULTreeBuilder) | |
@@ -523,18 +526,17 @@ nsXULTreeBuilder::IsContainerOpen(int32_ | |
{ | |
NS_PRECONDITION(aIndex >= 0 && aIndex < mRows.Count(), "bad row"); | |
if (aIndex < 0 || aIndex >= mRows.Count()) | |
return NS_ERROR_INVALID_ARG; | |
nsTreeRows::iterator iter = mRows[aIndex]; | |
if (iter->mContainerState == nsTreeRows::eContainerState_Unknown) { | |
- bool isOpen; | |
- IsContainerOpen(iter->mMatch->mResult, &isOpen); | |
+ bool isOpen = IsContainerOpen(iter->mMatch->mResult); | |
iter->mContainerState = isOpen | |
? nsTreeRows::eContainerState_Open | |
: nsTreeRows::eContainerState_Closed; | |
} | |
*aOpen = (iter->mContainerState == nsTreeRows::eContainerState_Open); | |
return NS_OK; | |
@@ -752,52 +754,26 @@ nsXULTreeBuilder::SetTree(nsITreeBoxObje | |
// If this is teardown time, then we're done. | |
if (!mBoxObject) { | |
Uninit(false); | |
return NS_OK; | |
} | |
NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED); | |
- // Is our root's principal trusted? | |
+ // Only use the XUL store if the root's principal is trusted. | |
bool isTrusted = false; | |
nsresult rv = IsSystemPrincipal(mRoot->NodePrincipal(), &isTrusted); | |
if (NS_SUCCEEDED(rv) && isTrusted) { | |
- // Get the datasource we intend to use to remember open state. | |
- nsAutoString datasourceStr; | |
- mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::statedatasource, datasourceStr); | |
- | |
- // since we are trusted, use the user specified datasource | |
- // if non specified, use localstore, which gives us | |
- // persistence across sessions | |
- if (! datasourceStr.IsEmpty()) { | |
- gRDFService->GetDataSource(NS_ConvertUTF16toUTF8(datasourceStr).get(), | |
- getter_AddRefs(mPersistStateStore)); | |
- } | |
- else { | |
- gRDFService->GetDataSource("rdf:local-store", | |
- getter_AddRefs(mPersistStateStore)); | |
+ mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1"); | |
+ if(NS_WARN_IF(!mLocalStore)){ | |
+ return NS_ERROR_NOT_INITIALIZED; | |
} | |
} | |
- // Either no specific datasource was specified, or we failed | |
- // to get one because we are not trusted. | |
- // | |
- // XXX if it were possible to ``write an arbitrary datasource | |
- // back'', then we could also allow an untrusted document to | |
- // use a statedatasource from the same codebase. | |
- if (! mPersistStateStore) { | |
- mPersistStateStore = | |
- do_CreateInstance("@mozilla.org/rdf/datasource;1?name=in-memory-datasource"); | |
- } | |
- | |
- NS_ASSERTION(mPersistStateStore, "failed to get a persistent state store"); | |
- if (! mPersistStateStore) | |
- return NS_ERROR_FAILURE; | |
- | |
Rebuild(); | |
EnsureSortVariables(); | |
if (mSortVariable) | |
SortSubtree(mRows.GetRoot()); | |
return NS_OK; | |
} | |
@@ -825,44 +801,46 @@ nsXULTreeBuilder::ToggleOpenState(int32_ | |
uint32_t count = mObservers.Count(); | |
for (uint32_t i = 0; i < count; ++i) { | |
nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeObjectAt(i); | |
if (observer) | |
observer->OnToggleOpenState(aIndex); | |
} | |
- if (mPersistStateStore) { | |
+ if (mLocalStore && mRoot) { | |
bool isOpen; | |
IsContainerOpen(aIndex, &isOpen); | |
- nsCOMPtr<nsIRDFResource> container; | |
- GetResourceFor(aIndex, getter_AddRefs(container)); | |
- if (! container) | |
+ nsIDocument* doc = mRoot->GetDocument(); | |
+ if (!doc) { | |
return NS_ERROR_FAILURE; | |
+ } | |
- bool hasProperty; | |
- IsContainerOpen(container, &hasProperty); | |
+ nsIURI* docURI = doc->GetDocumentURI(); | |
+ nsTreeRows::Row& row = *(mRows[aIndex]); | |
+ nsAutoString nodeid; | |
+ nsresult rv = row.mMatch->mResult->GetId(nodeid); | |
+ if (NS_FAILED(rv)) { | |
+ return rv; | |
+ } | |
+ | |
+ nsAutoCString utf8uri; | |
+ rv = docURI->GetSpec(utf8uri); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return rv; | |
+ } | |
+ NS_ConvertUTF8toUTF16 uri(utf8uri); | |
if (isOpen) { | |
- if (hasProperty) { | |
- mPersistStateStore->Unassert(container, | |
- nsXULContentUtils::NC_open, | |
- nsXULContentUtils::true_); | |
- } | |
- | |
+ mLocalStore->RemoveValue(uri, nodeid, NS_LITERAL_STRING("open")); | |
CloseContainer(aIndex); | |
- } | |
- else { | |
- if (! hasProperty) { | |
- mPersistStateStore->Assert(container, | |
- nsXULContentUtils::NC_open, | |
- nsXULContentUtils::true_, | |
- true); | |
- } | |
+ } else { | |
+ mLocalStore->SetValue(uri, nodeid, NS_LITERAL_STRING("open"), | |
+ NS_LITERAL_STRING("true")); | |
OpenContainer(aIndex, result); | |
} | |
} | |
return NS_OK; | |
} | |
@@ -1220,20 +1198,19 @@ nsXULTreeBuilder::ReplaceMatch(nsIXULTem | |
if (result != mRootResult) { | |
// don't open containers if child processing isn't allowed | |
bool mayProcessChildren; | |
nsresult rv = result->GetMayProcessChildren(&mayProcessChildren); | |
if (NS_FAILED(rv) || ! mayProcessChildren) return NS_OK; | |
} | |
- bool open; | |
- IsContainerOpen(result, &open); | |
- if (open) | |
+ if (IsContainerOpen(result)) { | |
OpenContainer(iter.GetRowIndex(), result); | |
+ } | |
} | |
} | |
return NS_OK; | |
} | |
nsresult | |
nsXULTreeBuilder::SynchronizeResult(nsIXULTemplateResult* aResult) | |
@@ -1631,19 +1608,17 @@ nsXULTreeBuilder::OpenSubtreeForQuerySet | |
return rv; | |
} | |
// Remember that this match applied to this row | |
mRows.InsertRowAt(newmatch, aSubtree, count); | |
// If this is open, then remember it so we can recursively add | |
// *its* rows to the tree. | |
- bool isOpen = false; | |
- IsContainerOpen(nextresult, &isOpen); | |
- if (isOpen) { | |
+ if (IsContainerOpen(nextresult)) { | |
if (open.AppendElement(count) == nullptr) | |
return NS_ERROR_OUT_OF_MEMORY; | |
} | |
++count; | |
} | |
if (mFlags & eLoggingEnabled) | |
@@ -1717,46 +1692,52 @@ nsXULTreeBuilder::RemoveMatchesFor(nsTre | |
if ((row.mContainerState == nsTreeRows::eContainerState_Open) && row.mSubtree) | |
RemoveMatchesFor(*(row.mSubtree)); | |
} | |
return NS_OK; | |
} | |
-nsresult | |
-nsXULTreeBuilder::IsContainerOpen(nsIXULTemplateResult *aResult, bool* aOpen) | |
+ | |
+bool | |
+nsXULTreeBuilder::IsContainerOpen(nsIXULTemplateResult *aResult) | |
{ | |
- // items are never open if recursion is disabled | |
- if ((mFlags & eDontRecurse) && aResult != mRootResult) { | |
- *aOpen = false; | |
- return NS_OK; | |
- } | |
+ // items are never open if recursion is disabled | |
+ if ((mFlags & eDontRecurse) && aResult != mRootResult) { | |
+ return false; | |
+ } | |
- nsCOMPtr<nsIRDFResource> id; | |
- nsresult rv = GetResultResource(aResult, getter_AddRefs(id)); | |
- if (NS_FAILED(rv)) | |
- return rv; | |
+ if (!mLocalStore) { | |
+ return false; | |
+ } | |
- return IsContainerOpen(id, aOpen); | |
-} | |
+ nsIDocument* doc = mRoot->GetDocument(); | |
+ if (!doc) { | |
+ return false; | |
+ } | |
-nsresult | |
-nsXULTreeBuilder::IsContainerOpen(nsIRDFResource* aResource, bool* aOpen) | |
-{ | |
- if (mPersistStateStore) | |
- mPersistStateStore->HasAssertion(aResource, | |
- nsXULContentUtils::NC_open, | |
- nsXULContentUtils::true_, | |
- true, | |
- aOpen); | |
- else | |
- *aOpen = false; | |
+ nsIURI* docURI = doc->GetDocumentURI(); | |
- return NS_OK; | |
+ nsAutoString nodeid; | |
+ nsresult rv = aResult->GetId(nodeid); | |
+ if (NS_FAILED(rv)) { | |
+ return false; | |
+ } | |
+ | |
+ nsAutoCString utf8uri; | |
+ rv = docURI->GetSpec(utf8uri); | |
+ if (NS_WARN_IF(NS_FAILED(rv))) { | |
+ return false; | |
+ } | |
+ NS_ConvertUTF8toUTF16 uri(utf8uri); | |
+ | |
+ nsAutoString val; | |
+ mLocalStore->GetValue(uri, nodeid, NS_LITERAL_STRING("open"), val); | |
+ return val.EqualsLiteral("true"); | |
} | |
int | |
nsXULTreeBuilder::Compare(const void* aLeft, const void* aRight, void* aClosure) | |
{ | |
nsXULTreeBuilder* self = static_cast<nsXULTreeBuilder*>(aClosure); | |
nsTreeRows::Row* left = static_cast<nsTreeRows::Row*> | |
diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in | |
--- a/mobile/android/installer/package-manifest.in | |
+++ b/mobile/android/installer/package-manifest.in | |
@@ -244,16 +244,17 @@ | |
@BINPATH@/components/shellservice.xpt | |
@BINPATH@/components/shistory.xpt | |
@BINPATH@/components/spellchecker.xpt | |
@BINPATH@/components/storage.xpt | |
@BINPATH@/components/telemetry.xpt | |
@BINPATH@/components/toolkit_finalizationwitness.xpt | |
@BINPATH@/components/toolkit_formautofill.xpt | |
@BINPATH@/components/toolkit_osfile.xpt | |
+@BINPATH@/components/toolkit_xulstore.xpt | |
@BINPATH@/components/toolkitprofile.xpt | |
#ifdef MOZ_ENABLE_XREMOTE | |
@BINPATH@/components/toolkitremote.xpt | |
#endif | |
@BINPATH@/components/txtsvc.xpt | |
@BINPATH@/components/txmgr.xpt | |
@BINPATH@/components/uconv.xpt | |
@BINPATH@/components/unicharutil.xpt | |
@@ -391,16 +392,18 @@ | |
#endif | |
@BINPATH@/components/nsINIProcessor.manifest | |
@BINPATH@/components/nsINIProcessor.js | |
@BINPATH@/components/nsPrompter.manifest | |
@BINPATH@/components/nsPrompter.js | |
@BINPATH@/components/servicesComponents.manifest | |
@BINPATH@/components/TelemetryStartup.js | |
@BINPATH@/components/TelemetryStartup.manifest | |
+@BINPATH@/components/XULStore.js | |
+@BINPATH@/components/XULStore.manifest | |
@BINPATH@/components/Webapps.js | |
@BINPATH@/components/Webapps.manifest | |
@BINPATH@/components/AppsService.js | |
@BINPATH@/components/AppsService.manifest | |
@BINPATH@/components/Push.js | |
@BINPATH@/components/Push.manifest | |
diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build | |
--- a/toolkit/components/moz.build | |
+++ b/toolkit/components/moz.build | |
@@ -44,16 +44,17 @@ PARALLEL_DIRS += [ | |
'telemetry', | |
'thumbnails', | |
'typeaheadfind', | |
'urlformatter', | |
'viewconfig', | |
'viewsource', | |
'workerloader', | |
'workerlz4', | |
+ 'xulstore' | |
] | |
if CONFIG['MOZ_CRASHREPORTER']: | |
PARALLEL_DIRS += ['crashes'] | |
if CONFIG['MOZ_SOCIAL']: | |
PARALLEL_DIRS += ['social'] | |
diff --git a/toolkit/components/places/nsNavHistory.cpp b/toolkit/components/places/nsNavHistory.cpp | |
--- a/toolkit/components/places/nsNavHistory.cpp | |
+++ b/toolkit/components/places/nsNavHistory.cpp | |
@@ -3644,17 +3644,17 @@ nsNavHistory::ResultsAsList(mozIStorageS | |
} | |
return NS_OK; | |
} | |
const int64_t UNDEFINED_URN_VALUE = -1; | |
// Create a urn (like | |
// urn:places-persist:place:group=0&group=1&sort=1&type=1,,%28local%20files%29) | |
-// to be used to persist the open state of this container in localstore.rdf | |
+// to be used to persist the open state of this container | |
nsresult | |
CreatePlacesPersistURN(nsNavHistoryQueryResultNode *aResultNode, | |
int64_t aValue, const nsCString& aTitle, nsCString& aURN) | |
{ | |
nsAutoCString uri; | |
nsresult rv = aResultNode->GetUri(uri); | |
NS_ENSURE_SUCCESS(rv, rv); | |
diff --git a/toolkit/components/xulstore/XULStore.js b/toolkit/components/xulstore/XULStore.js | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/XULStore.js | |
@@ -0,0 +1,336 @@ | |
+/* 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/. */ | |
+ | |
+const Cc = Components.classes; | |
+const Ci = Components.interfaces; | |
+const Cr = Components.results; | |
+const Cu = Components.utils; | |
+ | |
+// Enables logging and shorter save intervals. | |
+const debugMode = false; | |
+ | |
+// Delay when a change is made to when the file is saved. | |
+// 30 seconds normally, or 3 seconds for testing | |
+const WRITE_DELAY_MS = (debugMode ? 3 : 30) * 1000; | |
+ | |
+const XULSTORE_CONTRACTID = "@mozilla.org/xul/xulstore;1"; | |
+const XULSTORE_CID = Components.ID("{6f46b6f4-c8b1-4bd4-a4fa-9ebbed0753ea}"); | |
+const STOREDB_FILENAME = "xulstore.json"; | |
+ | |
+Cu.import("resource://gre/modules/Services.jsm"); | |
+Cu.import("resource://gre/modules/Task.jsm"); | |
+Cu.import('resource://gre/modules/XPCOMUtils.jsm'); | |
+ | |
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); | |
+XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); | |
+ | |
+function XULStore() { | |
+ this.init(); | |
+} | |
+ | |
+XULStore.prototype = { | |
+ classID: XULSTORE_CID, | |
+ classInfo: XPCOMUtils.generateCI({classID: XULSTORE_CID, | |
+ contractID: XULSTORE_CONTRACTID, | |
+ classDescription: "XULStore", | |
+ interfaces: [Ci.nsIXULStore]}), | |
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsIXULStore, | |
+ Ci.nsISupportsWeakReference]), | |
+ _xpcom_factory: XPCOMUtils.generateSingletonFactory(XULStore), | |
+ | |
+ /* ---------- private members ---------- */ | |
+ | |
+ /* | |
+ * The format of _data is _data[docuri][elementid][attribute]. For example: | |
+ * { | |
+ * "chrome://blah/foo.xul" : { | |
+ * "main-window" : { aaa : 1, bbb : "c" }, | |
+ * "barColumn" : { ddd : 9, eee : "f" }, | |
+ * }, | |
+ * | |
+ * "chrome://foopy/b.xul" : { ... }, | |
+ * ... | |
+ * } | |
+ */ | |
+ _data: {}, | |
+ _storeFile: null, | |
+ _needsSaving: false, | |
+ _saveAllowed: true, | |
+ _writeTimer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer), | |
+ _writeTimerInitialized: false, | |
+ | |
+ init: function () { | |
+ Services.obs.addObserver(this, "profile-before-change", true); | |
+ | |
+ this._storeFile = Services.dirsvc.get("ProfD", Ci.nsIFile); | |
+ this._storeFile.append(STOREDB_FILENAME); | |
+ | |
+ if (!this._storeFile.exists()) { | |
+ this.import(); | |
+ } else { | |
+ this.readFile(); | |
+ } | |
+ }, | |
+ | |
+ observe: function(subject, topic, data) { | |
+ if (topic == "profile-before-change") { | |
+ this.writeFile(); | |
+ this._saveAllowed = false; | |
+ } | |
+ }, | |
+ | |
+ /* | |
+ * Internal function for logging debug messages to the Error Console window | |
+ */ | |
+ log: function (message) { | |
+ if (!debugMode) | |
+ return; | |
+ dump("XULStore: " + message + "\n"); | |
+ Services.console.logStringMessage("XULStore: " + message); | |
+ }, | |
+ | |
+ import: function() { | |
+ let localStoreFile = Services.dirsvc.get("ProfD", Ci.nsIFile); | |
+ | |
+ localStoreFile.append("localstore.rdf"); | |
+ if (!localStoreFile.exists()) { | |
+ return; | |
+ } | |
+ | |
+ const RDF = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService); | |
+ const persistKey = RDF.GetResource("http://home.netscape.com/NC-rdf#persist"); | |
+ | |
+ this.log("Import localstore from " + localStoreFile.path); | |
+ | |
+ let localStoreURI = Services.io.newFileURI(localStoreFile).spec; | |
+ let localStore = RDF.GetDataSourceBlocking(localStoreURI); | |
+ let resources = localStore.GetAllResources(); | |
+ | |
+ while (resources.hasMoreElements()) { | |
+ let resource = resources.getNext().QueryInterface(Ci.nsIRDFResource); | |
+ let uri; | |
+ | |
+ try { | |
+ uri = NetUtil.newURI(resource.ValueUTF8); | |
+ } catch(ex) { | |
+ continue; // skip invalid uris | |
+ } | |
+ | |
+ // If this has a ref, then this is an attribute reference. Otherwise, | |
+ // this is a document reference. | |
+ if (!uri.hasRef) | |
+ continue; | |
+ | |
+ // Verify that there the persist key is connected up. | |
+ let docURI = uri.specIgnoringRef; | |
+ | |
+ if (!localStore.HasAssertion(RDF.GetResource(docURI), persistKey, resource, true)) | |
+ continue; | |
+ | |
+ let id = uri.ref; | |
+ let attrs = localStore.ArcLabelsOut(resource); | |
+ | |
+ while (attrs.hasMoreElements()) { | |
+ let attr = attrs.getNext().QueryInterface(Ci.nsIRDFResource); | |
+ let value = localStore.GetTarget(resource, attr, true); | |
+ | |
+ if (value instanceof Ci.nsIRDFLiteral) { | |
+ this.setValue(docURI, id, attr.ValueUTF8, value.Value); | |
+ } | |
+ } | |
+ } | |
+ }, | |
+ | |
+ readFile: function() { | |
+ const MODE_RDONLY = 0x01; | |
+ const FILE_PERMS = 0600; | |
+ | |
+ let stream = Cc["@mozilla.org/network/file-input-stream;1"]. | |
+ createInstance(Ci.nsIFileInputStream); | |
+ let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON); | |
+ try { | |
+ stream.init(this._storeFile, MODE_RDONLY, FILE_PERMS, 0); | |
+ this._data = json.decodeFromStream(stream, stream.available()); | |
+ } catch(e) { | |
+ this.log("Error reading JSON: " + e); | |
+ // Ignore problem, we'll just continue on with an empty dataset. | |
+ } finally { | |
+ stream.close(); | |
+ } | |
+ }, | |
+ | |
+ writeFile: Task.async(function* () { | |
+ if (!this._needsSaving) | |
+ return; | |
+ | |
+ this._needsSaving = false; | |
+ | |
+ this.log("Writing to xulstore.json"); | |
+ | |
+ try { | |
+ let data = JSON.stringify(this._data); | |
+ let encoder = new TextEncoder(); | |
+ | |
+ data = encoder.encode(data); | |
+ yield OS.File.writeAtomic(this._storeFile.path, data, | |
+ { tmpPath: this._storeFile.path + ".tmp" }); | |
+ } catch (e) { | |
+ this.log("Failed to write xulstore.json: " + e); | |
+ throw e; | |
+ } | |
+ }), | |
+ | |
+ markAsChanged: function() { | |
+ this._needsSaving = true; | |
+ if (this._writeTimerInitialized) | |
+ return; | |
+ | |
+ let callback = () => { | |
+ this._writeTimerInitialized = false; | |
+ this.writeFile(); | |
+ }; | |
+ | |
+ // Don't write the file more than once every 30 seconds. | |
+ this._writeTimerInitialized = true; | |
+ this._writeTimer.initWithCallback(callback, WRITE_DELAY_MS, Ci.nsITimer.TYPE_ONE_SHOT); | |
+ }, | |
+ | |
+ /* ---------- interface implementation ---------- */ | |
+ | |
+ setValue: function (docURI, id, attr, value) { | |
+ this.log("Saving " + attr + "=" + value + " for id=" + id + ", doc=" + docURI); | |
+ | |
+ if (!this._saveAllowed) { | |
+ Services.console.logStringMessage("XULStore: Changes after profile-before-change are ignored!"); | |
+ return; | |
+ } | |
+ | |
+ // bug 319846 -- don't save really long attributes or values. | |
+ if (id.length > 1024 || attr.length > 1024 || value.length > 1024) | |
+ throw Components.Exception("id, attribute, or value too long", Cr.NS_ERROR_ILLEGAL_VALUE); | |
+ | |
+ let obj = this._data; | |
+ if (!(docURI in obj)) { | |
+ obj[docURI] = {}; | |
+ } | |
+ obj = obj[docURI]; | |
+ if (!(id in obj)) { | |
+ obj[id] = {}; | |
+ } | |
+ obj = obj[id]; | |
+ | |
+ // Don't set the value if it is already set to avoid saving the file. | |
+ if (attr in obj && obj[attr] == value) | |
+ return; | |
+ | |
+ obj[attr] = value; //IE, this._data[docURI][id][attr] = value; | |
+ | |
+ this.markAsChanged(); | |
+ }, | |
+ | |
+ hasValue: function (docURI, id, attr) { | |
+ this.log("has store value for id=" + id + ", attr=" + attr + ", doc=" + docURI); | |
+ | |
+ let ids = this._data[docURI]; | |
+ if (ids) { | |
+ let attrs = ids[id]; | |
+ if (attrs) { | |
+ return attr in attrs; | |
+ } | |
+ } | |
+ | |
+ return false; | |
+ }, | |
+ | |
+ getValue: function (docURI, id, attr) { | |
+ this.log("get store value for id=" + id + ", attr=" + attr + ", doc=" + docURI); | |
+ | |
+ let ids = this._data[docURI]; | |
+ if (ids) { | |
+ let attrs = ids[id]; | |
+ if (attrs) { | |
+ return attrs[attr] || ""; | |
+ } | |
+ } | |
+ | |
+ return ""; | |
+ }, | |
+ | |
+ removeValue: function (docURI, id, attr) { | |
+ this.log("remove store value for id=" + id + ", attr=" + attr + ", doc=" + docURI); | |
+ | |
+ if (!this._saveAllowed) { | |
+ Services.console.logStringMessage("XULStore: Changes after profile-before-change are ignored!"); | |
+ return; | |
+ } | |
+ | |
+ let ids = this._data[docURI]; | |
+ if (ids) { | |
+ let attrs = ids[id]; | |
+ if (attrs && attr in attrs) { | |
+ delete attrs[attr]; | |
+ | |
+ if (Object.getOwnPropertyNames(attrs).length == 0) { | |
+ delete ids[id]; | |
+ | |
+ if (Object.getOwnPropertyNames(ids).length == 0) { | |
+ delete this._data[docURI]; | |
+ } | |
+ } | |
+ | |
+ this.markAsChanged(); | |
+ } | |
+ } | |
+ }, | |
+ | |
+ getIDsEnumerator: function (docURI) { | |
+ this.log("Getting ID enumerator for doc=" + docURI); | |
+ | |
+ if (!(docURI in this._data)) | |
+ return new nsStringEnumerator([]); | |
+ | |
+ let result = []; | |
+ let ids = this._data[docURI]; | |
+ if (ids) { | |
+ for (let id in this._data[docURI]) { | |
+ result.push(id); | |
+ } | |
+ } | |
+ | |
+ return new nsStringEnumerator(result); | |
+ }, | |
+ | |
+ getAttributeEnumerator: function (docURI, id) { | |
+ this.log("Getting attribute enumerator for id=" + id + ", doc=" + docURI); | |
+ | |
+ if (!(docURI in this._data) || !(id in this._data[docURI])) | |
+ return new nsStringEnumerator([]); | |
+ | |
+ let attrs = []; | |
+ for (let attr in this._data[docURI][id]) { | |
+ attrs.push(attr); | |
+ } | |
+ | |
+ return new nsStringEnumerator(attrs); | |
+ } | |
+}; | |
+ | |
+function nsStringEnumerator(items) { | |
+ this._items = items; | |
+} | |
+ | |
+nsStringEnumerator.prototype = { | |
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsIStringEnumerator]), | |
+ _nextIndex : 0, | |
+ hasMore: function() { | |
+ return this._nextIndex < this._items.length; | |
+ }, | |
+ getNext : function() { | |
+ if (!this.hasMore()) | |
+ throw Cr.NS_ERROR_NOT_AVAILABLE; | |
+ return this._items[this._nextIndex++]; | |
+ }, | |
+}; | |
+ | |
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([XULStore]); | |
diff --git a/toolkit/components/xulstore/XULStore.manifest b/toolkit/components/xulstore/XULStore.manifest | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/XULStore.manifest | |
@@ -0,0 +1,2 @@ | |
+component {6f46b6f4-c8b1-4bd4-a4fa-9ebbed0753ea} XULStore.js | |
+contract @mozilla.org/xul/xulstore;1 {6f46b6f4-c8b1-4bd4-a4fa-9ebbed0753ea} | |
diff --git a/toolkit/components/xulstore/moz.build b/toolkit/components/xulstore/moz.build | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/moz.build | |
@@ -0,0 +1,18 @@ | |
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- | |
+# vim: set filetype=python: | |
+# 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/. | |
+ | |
+TEST_DIRS += ['tests'] | |
+ | |
+XPIDL_SOURCES += [ | |
+ 'nsIXULStore.idl', | |
+] | |
+ | |
+XPIDL_MODULE = 'toolkit_xulstore' | |
+ | |
+EXTRA_COMPONENTS += [ | |
+ 'XULStore.js', | |
+ 'XULStore.manifest', | |
+] | |
diff --git a/toolkit/components/xulstore/nsIXULStore.idl b/toolkit/components/xulstore/nsIXULStore.idl | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/nsIXULStore.idl | |
@@ -0,0 +1,75 @@ | |
+/* 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/. */ | |
+ | |
+#include "nsISupports.idl" | |
+ | |
+interface nsIStringEnumerator; | |
+ | |
+/** | |
+ * The XUL store is used to store information related to a XUL document/application. | |
+ * Typically it is used to store the persisted state for the document, such as | |
+ * window location, toolbars that are open and nodes that are open and closed in a tree. | |
+ * | |
+ * The data is serialized to [profile directory]/xulstore.json | |
+ */ | |
+[scriptable, uuid(987c4b35-c426-4dd7-ad49-3c9fa4c65d20)] | |
+ | |
+interface nsIXULStore: nsISupports | |
+{ | |
+ /** | |
+ * Sets a value in the store. | |
+ * | |
+ * @param doc - document URI | |
+ * @param id - identifier of the node | |
+ * @param attr - attribute to store | |
+ * @param value - value of the attribute | |
+ */ | |
+ void setValue(in AString doc, in AString id, in AString attr, in AString value); | |
+ | |
+ /** | |
+ * Returns true if the store contains a value for attr. | |
+ * | |
+ * @param doc - URI of the document | |
+ * @param id - identifier of the node | |
+ * @param attr - attribute | |
+ */ | |
+ bool hasValue(in AString doc, in AString id, in AString attr); | |
+ | |
+ /** | |
+ * Retrieves a value in the store, or an empty string if it does not exist. | |
+ * | |
+ * @param doc - document URI | |
+ * @param id - identifier of the node | |
+ * @param attr - attribute to retrieve | |
+ * | |
+ * @returns the value of the attribute | |
+ */ | |
+ AString getValue(in AString doc, in AString id, in AString attr); | |
+ | |
+ /** | |
+ * Removes a value in the store. | |
+ * | |
+ * @param doc - document URI | |
+ * @param id - identifier of the node | |
+ * @param attr - attribute to remove | |
+ */ | |
+ void removeValue(in AString doc, in AString id, in AString attr); | |
+ | |
+ /** | |
+ * Iterates over all of the ids associated with a given document uri that | |
+ * have stored data. | |
+ * | |
+ * @param doc - document URI | |
+ */ | |
+ nsIStringEnumerator getIDsEnumerator(in AString doc); | |
+ | |
+ /** | |
+ * Iterates over all of the attributes associated with a given document uri | |
+ * and id that have stored data. | |
+ * | |
+ * @param doc - document URI | |
+ * @param id - identifier of the node | |
+ */ | |
+ nsIStringEnumerator getAttributeEnumerator(in AString doc, in AString id); | |
+}; | |
diff --git a/toolkit/components/xulstore/tests/chrome/animals.rdf b/toolkit/components/xulstore/tests/chrome/animals.rdf | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/chrome/animals.rdf | |
@@ -0,0 +1,142 @@ | |
+<?xml version="1.0"?> | |
+ | |
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
+ xmlns:NC="http://home.netscape.com/NC-rdf#" | |
+ xmlns:ANIMALS="http://www.some-fictitious-zoo.com/rdf#"> | |
+ | |
+ <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/arachnids"> | |
+ <ANIMALS:name>Arachnids</ANIMALS:name> | |
+ </ANIMALS:Class> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/arachnids/tarantula"> | |
+ <ANIMALS:name>Tarantula</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/birds"> | |
+ <ANIMALS:name>Birds</ANIMALS:name> | |
+ </ANIMALS:Class> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/emu"> | |
+ <ANIMALS:name>Emu</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/barnowl"> | |
+ <ANIMALS:name>Barn Owl</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/birds/raven"> | |
+ <ANIMALS:name>Raven</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/crustaceans"> | |
+ <ANIMALS:name>Crustaceans</ANIMALS:name> | |
+ </ANIMALS:Class> | |
+ | |
+ <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/fish"> | |
+ <ANIMALS:name>Fish</ANIMALS:name> | |
+ </ANIMALS:Class> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/fish/cod"> | |
+ <ANIMALS:name>Cod</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/fish/swordfish"> | |
+ <ANIMALS:name>Swordfish</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/mammals"> | |
+ <ANIMALS:name>Mammals</ANIMALS:name> | |
+ </ANIMALS:Class> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/lion"> | |
+ <ANIMALS:name>Lion</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/hippopotamus"> | |
+ <ANIMALS:name>HIPPOPOTAMUS</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/africanelephant"> | |
+ <ANIMALS:name>African Elephant</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/llama"> | |
+ <ANIMALS:name>LLAMA</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/polarbear"> | |
+ <ANIMALS:name>Polar Bear</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/aardvark"> | |
+ <ANIMALS:name>aardvark</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"> | |
+ <ANIMALS:name>Nine-banded Armadillo</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/mammals/gorilla"> | |
+ <ANIMALS:name>Gorilla</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <ANIMALS:Class RDF:about="http://www.some-fictitious-zoo.com/reptiles"> | |
+ <ANIMALS:name>Reptiles</ANIMALS:name> | |
+ </ANIMALS:Class> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/reptiles/anaconda"> | |
+ <ANIMALS:name>Anaconda</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Description RDF:about="http://www.some-fictitious-zoo.com/reptiles/chameleon"> | |
+ <ANIMALS:name>Chameleon</ANIMALS:name> | |
+ </RDF:Description> | |
+ | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/some-animals" ANIMALS:name="Zoo Animals"> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds"/> | |
+ </RDF:Seq> | |
+ | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/all-animals" ANIMALS:name="Zoo Animals"> | |
+ <RDF:li> | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/arachnids"> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/arachnids/tarantula"/> | |
+ </RDF:Seq> | |
+ </RDF:li> | |
+ <RDF:li> | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/birds"> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/emu"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/barnowl"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/birds/raven"/> | |
+ </RDF:Seq> | |
+ </RDF:li> | |
+ <RDF:li> | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/crustaceans"/> | |
+ </RDF:li> | |
+ <RDF:li> | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/fish"> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/fish/cod"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/fish/swordfish"/> | |
+ </RDF:Seq> | |
+ </RDF:li> | |
+ <RDF:li> | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/mammals"> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/lion"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/hippopotamus"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/africanelephant"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/llama"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/polarbear"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/aardvark"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/mammals/gorilla"/> | |
+ </RDF:Seq> | |
+ </RDF:li> | |
+ <RDF:li> | |
+ <RDF:Seq RDF:about="http://www.some-fictitious-zoo.com/reptiles"> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/anaconda"/> | |
+ <RDF:li RDF:resource="http://www.some-fictitious-zoo.com/reptiles/chameleon"/> | |
+ </RDF:Seq> | |
+ </RDF:li> | |
+ </RDF:Seq> | |
+ | |
+</RDF:RDF> | |
diff --git a/toolkit/components/xulstore/tests/chrome/chrome.ini b/toolkit/components/xulstore/tests/chrome/chrome.ini | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/chrome/chrome.ini | |
@@ -0,0 +1,6 @@ | |
+[DEFAULT] | |
+support-files = | |
+ window_persistence.xul | |
+ animals.rdf | |
+ | |
+[test_persistence.xul] | |
diff --git a/toolkit/components/xulstore/tests/chrome/test_persistence.xul b/toolkit/components/xulstore/tests/chrome/test_persistence.xul | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/chrome/test_persistence.xul | |
@@ -0,0 +1,31 @@ | |
+<?xml version="1.0"?> | |
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?> | |
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> | |
+ | |
+<window title="Persistence Tests" | |
+ onload="runTest()" | |
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> | |
+ | |
+ <script type="application/javascript" | |
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> | |
+ | |
+ <script> | |
+ SimpleTest.waitForExplicitFinish(); | |
+ function runTest() { | |
+ window.openDialog("window_persistence.xul", "_blank", "chrome", true); | |
+ } | |
+ | |
+ function windowOpened() { | |
+ window.openDialog("window_persistence.xul", "_blank", "chrome", false); | |
+ } | |
+ | |
+ function testDone() { | |
+ SimpleTest.finish(); | |
+ } | |
+ </script> | |
+ | |
+<body xmlns="http://www.w3.org/1999/xhtml"> | |
+ <p id="display"/> | |
+</body> | |
+ | |
+</window> | |
diff --git a/toolkit/components/xulstore/tests/chrome/window_persistence.xul b/toolkit/components/xulstore/tests/chrome/window_persistence.xul | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/chrome/window_persistence.xul | |
@@ -0,0 +1,98 @@ | |
+<?xml version="1.0"?> | |
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?> | |
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> | |
+ | |
+<window title="Persistence Tests" | |
+ onload="opened()" | |
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" | |
+ persist="screenX screenY width height"> | |
+ | |
+<button id="button1" label="Button1" persist="value"/> | |
+<button id="button2" label="Button2" value="Normal" persist="value"/> | |
+ | |
+<tree id="tree" datasources="animals.rdf" ref="http://www.some-fictitious-zoo.com/all-animals" | |
+ flags="dont-build-content" width="200" height="200"> | |
+ <treecols orient="horizontal" id="treecols"> | |
+ <treecol id="treecol" primary="true" label="Name" flex="1"/> | |
+ </treecols> | |
+ <template id="template"> | |
+ <treechildren> | |
+ <treeitem uri="rdf:*"> | |
+ <treerow> | |
+ <treecell label="rdf:http://www.some-fictitious-zoo.com/rdf#name"/> | |
+ <treecell/> | |
+ </treerow> | |
+ </treeitem> | |
+ </treechildren> | |
+ </template> | |
+</tree> | |
+ | |
+<script> | |
+<![CDATA[ | |
+ | |
+const Cc = Components.classes; | |
+const Ci = Components.interfaces; | |
+ | |
+let XULStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore); | |
+let URI = "chrome://mochitests/content/chrome/toolkit/components/xulstore/tests/chrome/window_persistence.xul"; | |
+ | |
+function opened() | |
+{ | |
+ // If the data in the tree has not been loaded yet, wait a bit and try again. | |
+ var treeView = document.getElementById("tree").view; | |
+ if (treeView.rowCount != 6 && treeView.rowCount != 17) { | |
+ setTimeout(opened, 50); | |
+ return; | |
+ } | |
+ | |
+ runTest(treeView); | |
+} | |
+ | |
+function runTest(treeView) | |
+{ | |
+ var firstRun = window.arguments[0]; | |
+ if (firstRun) { | |
+ document.getElementById("button1").setAttribute("value", "Pressed"); | |
+ document.getElementById("button2").removeAttribute("value"); | |
+ | |
+ document.getElementById("button2").setAttribute("foo", "bar"); | |
+ document.persist("button2", "foo"); | |
+ is(XULStore.getValue(URI, "button2", "foo"), "bar", "attribute persisted") | |
+ document.getElementById("button2").removeAttribute("foo"); | |
+ document.persist("button2", "foo"); | |
+ is(XULStore.hasValue(URI, "button2", "foo"), false, "attribute removed") | |
+ | |
+ is(treeView.rowCount, 6, "tree rows are closed"); | |
+ treeView.toggleOpenState(1); | |
+ treeView.toggleOpenState(7); | |
+ | |
+ window.close(); | |
+ window.opener.windowOpened(); | |
+ } | |
+ else { | |
+ is(document.getElementById("button1").getAttribute("value"), "Pressed", | |
+ "Attribute set"); | |
+ is(document.getElementById("button2").hasAttribute("value"), true, | |
+ "Attribute cleared"); | |
+ is(document.getElementById("button2").getAttribute("value"), "", | |
+ "Attribute cleared"); | |
+ is(document.getElementById("button2").hasAttribute("foo"), false, | |
+ "Attribute cleared"); | |
+ is(document.getElementById("button2").getAttribute("foo"), "", | |
+ "Attribute cleared"); | |
+ | |
+ is(treeView.rowCount, 17, "tree rows are open"); | |
+ is(treeView.isContainerOpen(0), false, "first closed row"); | |
+ is(treeView.isContainerOpen(1), true, "first open row"); | |
+ is(treeView.isContainerOpen(7), true, "second open row"); | |
+ | |
+ window.close(); | |
+ window.opener.testDone(); | |
+ } | |
+} | |
+ | |
+function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); } | |
+ | |
+]]></script> | |
+ | |
+</window> | |
diff --git a/toolkit/components/xulstore/tests/moz.build b/toolkit/components/xulstore/tests/moz.build | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/moz.build | |
@@ -0,0 +1,6 @@ | |
+# 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/. | |
+ | |
+MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini'] | |
+XPCSHELL_TESTS_MANIFESTS += ['xpcshell/xpcshell.ini'] | |
diff --git a/toolkit/components/xulstore/tests/xpcshell/localstore.rdf b/toolkit/components/xulstore/tests/xpcshell/localstore.rdf | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/xpcshell/localstore.rdf | |
@@ -0,0 +1,31 @@ | |
+<?xml version="1.0"?> | |
+<RDF:RDF xmlns:NC="http://home.netscape.com/NC-rdf#" | |
+ xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | |
+ <RDF:Description RDF:about="chrome://browser/content/browser.xul#sidebar-title" | |
+ value="" /> | |
+ <RDF:Description RDF:about="about:config#prefCol" | |
+ ordinal="1" | |
+ sortDirection="ascending" /> | |
+ <RDF:Description RDF:about="chrome://browser/content/browser.xul#addon-bar" | |
+ collapsed="true" /> | |
+ <RDF:Description RDF:about="about:config"> | |
+ <NC:persist RDF:resource="about:config#prefCol"/> | |
+ <NC:persist RDF:resource="about:config#lockCol"/> | |
+ <NC:persist RDF:resource="about:config#typeCol"/> | |
+ <NC:persist RDF:resource="about:config#valueCol"/> | |
+ </RDF:Description> | |
+ <RDF:Description RDF:about="about:config#lockCol" | |
+ ordinal="3" /> | |
+ <RDF:Description RDF:about="chrome://browser/content/browser.xul"> | |
+ <NC:persist RDF:resource="chrome://browser/content/browser.xul#main-window"/> | |
+ <NC:persist RDF:resource="chrome://browser/content/browser.xul#addon-bar"/> | |
+ <NC:persist RDF:resource="chrome://browser/content/browser.xul#sidebar-box"/> | |
+ <NC:persist RDF:resource="chrome://browser/content/browser.xul#sidebar-title"/> | |
+ </RDF:Description> | |
+ <RDF:Description RDF:about="chrome://browser/content/browser.xul#main-window" | |
+ width="994" | |
+ height="768" | |
+ screenX="4" | |
+ screenY="22" | |
+ sizemode="normal" /> | |
+</RDF:RDF> | |
diff --git a/toolkit/components/xulstore/tests/xpcshell/test_XULStore.js b/toolkit/components/xulstore/tests/xpcshell/test_XULStore.js | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/xpcshell/test_XULStore.js | |
@@ -0,0 +1,184 @@ | |
+/* Any copyright is dedicated to the Public Domain. | |
+ http://creativecommons.org/publicdomain/zero/1.0/◦ | |
+*/ | |
+ | |
+"use strict" | |
+ | |
+const Cc = Components.classes; | |
+const Ci = Components.interfaces; | |
+const Cu = Components.utils; | |
+const Cr = Components.results; | |
+ | |
+Cu.import("resource://gre/modules/osfile.jsm") | |
+ | |
+let XULStore = null; | |
+let browserURI = "chrome://browser/content/browser.xul"; | |
+let aboutURI = "about:config"; | |
+ | |
+function run_test() { | |
+ do_get_profile(); | |
+ run_next_test(); | |
+} | |
+ | |
+function checkValue(uri, id, attr, reference) { | |
+ let value = XULStore.getValue(uri, id, attr); | |
+ do_check_true(value === reference); | |
+} | |
+ | |
+function checkValueExists(uri, id, attr, exists) { | |
+ do_check_eq(XULStore.hasValue(uri, id, attr), exists); | |
+} | |
+ | |
+function getIDs(uri) { | |
+ let it = XULStore.getIDsEnumerator(uri); | |
+ let result = []; | |
+ | |
+ while (it.hasMore()) { | |
+ let value = it.getNext(); | |
+ result.push(value); | |
+ } | |
+ | |
+ result.sort(); | |
+ return result; | |
+} | |
+ | |
+function getAttributes(uri, id) { | |
+ let it = XULStore.getAttributeEnumerator(uri, id); | |
+ | |
+ let result = []; | |
+ | |
+ while (it.hasMore()) { | |
+ let value = it.getNext(); | |
+ result.push(value); | |
+ } | |
+ | |
+ result.sort(); | |
+ return result; | |
+} | |
+ | |
+function checkArrays(a, b) { | |
+ a.sort(); | |
+ b.sort(); | |
+ do_check_true(a.toString() == b.toString()); | |
+} | |
+ | |
+function checkOldStore() { | |
+ checkArrays(['addon-bar', 'main-window', 'sidebar-title'], getIDs(browserURI)); | |
+ checkArrays(['collapsed'], getAttributes(browserURI, 'addon-bar')); | |
+ checkArrays(['height', 'screenX', 'screenY', 'sizemode', 'width'], | |
+ getAttributes(browserURI, 'main-window')); | |
+ checkArrays(['value'], getAttributes(browserURI, 'sidebar-title')); | |
+ | |
+ checkValue(browserURI, "addon-bar", "collapsed", "true"); | |
+ checkValue(browserURI, "main-window", "width", "994"); | |
+ checkValue(browserURI, "main-window", "height", "768"); | |
+ checkValue(browserURI, "main-window", "screenX", "4"); | |
+ checkValue(browserURI, "main-window", "screenY", "22"); | |
+ checkValue(browserURI, "main-window", "sizemode", "normal"); | |
+ checkValue(browserURI, "sidebar-title", "value", ""); | |
+ | |
+ checkArrays(['lockCol', 'prefCol'], getIDs(aboutURI)); | |
+ checkArrays(['ordinal'], getAttributes(aboutURI, 'lockCol')); | |
+ checkArrays(['ordinal', 'sortDirection'], getAttributes(aboutURI, 'prefCol')); | |
+ | |
+ checkValue(aboutURI, "prefCol", "ordinal", "1"); | |
+ checkValue(aboutURI, "prefCol", "sortDirection", "ascending"); | |
+ checkValue(aboutURI, "lockCol", "ordinal", "3"); | |
+} | |
+ | |
+add_task(function* testImport(){ | |
+ let src = "localstore.rdf"; | |
+ let dst = OS.Path.join(OS.Constants.Path.profileDir, src); | |
+ | |
+ yield OS.File.copy(src, dst); | |
+ | |
+ // Importing relies on XULStore not yet being loaded before this point. | |
+ XULStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore); | |
+ checkOldStore(); | |
+}); | |
+ | |
+add_task(function* testGetValue() { | |
+ // Get non-existing property | |
+ checkValue(browserURI, "side-window", "height", ""); | |
+ | |
+ // Get existing property | |
+ checkValue(browserURI, "main-window", "width", "994"); | |
+}); | |
+ | |
+add_task(function* testHasValue() { | |
+ // Check non-existing property | |
+ checkValueExists(browserURI, "side-window", "height", false); | |
+ | |
+ // Check existing property | |
+ checkValueExists(browserURI, "main-window", "width", true); | |
+}); | |
+ | |
+add_task(function* testSetValue() { | |
+ // Set new attribute | |
+ checkValue(browserURI, "side-bar", "width", ""); | |
+ XULStore.setValue(browserURI, "side-bar", "width", "1000"); | |
+ checkValue(browserURI, "side-bar", "width", "1000"); | |
+ checkArrays(["addon-bar", "main-window", "side-bar", "sidebar-title"], getIDs(browserURI)); | |
+ checkArrays(["width"], getAttributes(browserURI, 'side-bar')); | |
+ | |
+ // Modify existing property | |
+ checkValue(browserURI, "side-bar", "width", "1000"); | |
+ XULStore.setValue(browserURI, "side-bar", "width", "1024"); | |
+ checkValue(browserURI, "side-bar", "width", "1024"); | |
+ checkArrays(["addon-bar", "main-window", "side-bar", "sidebar-title"], getIDs(browserURI)); | |
+ checkArrays(["width"], getAttributes(browserURI, 'side-bar')); | |
+ | |
+ // Add another attribute | |
+ checkValue(browserURI, "side-bar", "height", ""); | |
+ XULStore.setValue(browserURI, "side-bar", "height", "1000"); | |
+ checkValue(browserURI, "side-bar", "height", "1000"); | |
+ checkArrays(["addon-bar", "main-window", "side-bar", "sidebar-title"], getIDs(browserURI)); | |
+ checkArrays(["width", "height"], getAttributes(browserURI, 'side-bar')); | |
+}); | |
+ | |
+add_task(function* testRemoveValue() { | |
+ // Remove first attribute | |
+ checkValue(browserURI, "side-bar", "width", "1024"); | |
+ XULStore.removeValue(browserURI, "side-bar", "width"); | |
+ checkValue(browserURI, "side-bar", "width", ""); | |
+ checkValueExists(browserURI, "side-bar", "width", false); | |
+ checkArrays(["addon-bar", "main-window", "side-bar", "sidebar-title"], getIDs(browserURI)); | |
+ checkArrays(["height"], getAttributes(browserURI, 'side-bar')); | |
+ | |
+ // Remove second attribute | |
+ checkValue(browserURI, "side-bar", "height", "1000"); | |
+ XULStore.removeValue(browserURI, "side-bar", "height"); | |
+ checkValue(browserURI, "side-bar", "height", ""); | |
+ checkArrays(["addon-bar", "main-window", "sidebar-title"], getIDs(browserURI)); | |
+ | |
+ // Removing an attribute that doesn't exists shouldn't fail | |
+ XULStore.removeValue(browserURI, "main-window", "bar"); | |
+ | |
+ // Removing from an id that doesn't exists shouldn't fail | |
+ XULStore.removeValue(browserURI, "foo", "bar"); | |
+ | |
+ // Removing from a document that doesn't exists shouldn't fail | |
+ let nonDocURI = "chrome://example/content/other.xul"; | |
+ XULStore.removeValue(nonDocURI, "foo", "bar"); | |
+ | |
+ // Remove all attributes in browserURI | |
+ XULStore.removeValue(browserURI, "addon-bar", "collapsed"); | |
+ checkArrays([], getAttributes(browserURI, "addon-bar")); | |
+ XULStore.removeValue(browserURI, "main-window", "width"); | |
+ XULStore.removeValue(browserURI, "main-window", "height"); | |
+ XULStore.removeValue(browserURI, "main-window", "screenX"); | |
+ XULStore.removeValue(browserURI, "main-window", "screenY"); | |
+ XULStore.removeValue(browserURI, "main-window", "sizemode"); | |
+ checkArrays([], getAttributes(browserURI, "main-window")); | |
+ XULStore.removeValue(browserURI, "sidebar-title", "value"); | |
+ checkArrays([], getAttributes(browserURI, "sidebar-title")); | |
+ checkArrays([], getIDs(browserURI)); | |
+ | |
+ // Remove all attributes in aboutURI | |
+ XULStore.removeValue(aboutURI, "prefCol", "ordinal"); | |
+ XULStore.removeValue(aboutURI, "prefCol", "sortDirection"); | |
+ checkArrays([], getAttributes(aboutURI, "prefCol")); | |
+ XULStore.removeValue(aboutURI, "lockCol", "ordinal"); | |
+ checkArrays([], getAttributes(aboutURI, "lockCol")); | |
+ checkArrays([], getIDs(aboutURI)); | |
+}); | |
diff --git a/toolkit/components/xulstore/tests/xpcshell/xpcshell.ini b/toolkit/components/xulstore/tests/xpcshell/xpcshell.ini | |
new file mode 100644 | |
--- /dev/null | |
+++ b/toolkit/components/xulstore/tests/xpcshell/xpcshell.ini | |
@@ -0,0 +1,6 @@ | |
+[DEFAULT] | |
+ | |
+support-files = | |
+ localstore.rdf | |
+ | |
+[test_XULStore.js] | |
diff --git a/toolkit/mozapps/extensions/test/browser/browser_bug562797.js b/toolkit/mozapps/extensions/test/browser/browser_bug562797.js | |
--- a/toolkit/mozapps/extensions/test/browser/browser_bug562797.js | |
+++ b/toolkit/mozapps/extensions/test/browser/browser_bug562797.js | |
@@ -471,27 +471,18 @@ add_test(function() { | |
}); | |
}); | |
// Tests that going back to search results works | |
add_test(function() { | |
// Before we open the add-ons manager, we should make sure that no filter | |
// has been set. If one is set, we remove it. | |
// This is for the check below, from bug 611459. | |
- let RDF = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService); | |
- let store = RDF.GetDataSource("rdf:local-store"); | |
- let filterResource = RDF.GetResource("about:addons#search-filter-radiogroup"); | |
- let filterProperty = RDF.GetResource("value"); | |
- let filterTarget = store.GetTarget(filterResource, filterProperty, true); | |
- | |
- if (filterTarget) { | |
- is(filterTarget instanceof Ci.nsIRDFLiteral, true, | |
- "Filter should be a value"); | |
- store.Unassert(filterResource, filterProperty, filterTarget); | |
- } | |
+ let store = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore); | |
+ store.removeValue("about:addons", "search-filter-radiogroup", "value"); | |
open_manager("addons://list/extension", function(aManager) { | |
info("Part 1"); | |
is_in_list(aManager, "addons://list/extension", false, false); | |
var search = aManager.document.getElementById("header-search"); | |
search.focus(); | |
search.value = "bar"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment