--- a/browser/fuel/public/fuelIApplication.idl
+++ b/browser/fuel/public/fuelIApplication.idl
@@ -1,12 +1,17 @@
#include "nsISupports.idl"
-#include "nsIVariant.idl"
+
+interface nsIVariant;
+interface nsIURI;
+interface nsIDOMHTMLDocument;
interface fuelIPreference;
+interface fuelIBookmarkFolder;
+interface fuelIBrowserTab;
/**
* Interface that gives simplified access to the console
*/
[scriptable, uuid(ae8482e0-aa5a-11db-abbd-0800200c9a66)]
interface fuelIConsole : nsISupports
{
/**
@@ -258,19 +263,19 @@ interface fuelISessionStorage : nsISuppo
* The value to return if no item exists with the given name
* @returns value of the item or the given default value if no item
* exists with the given name.
*/
AString get(in AString aName, in AString aDefaultValue);
};
- /**
- * Interface representing an extension
- */
+/**
+ * Interface representing an extension
+ */
[scriptable, uuid(ea563b60-aa5a-11db-abbd-0800200c9a66)]
interface fuelIExtension : nsISupports
{
/**
* The id of the extension.
*/
readonly attribute AString id;
@@ -335,16 +340,301 @@ interface fuelIExtensions : nsISupports
* @returns An extension object or null if no extension exists
* with the given id.
*/
fuelIExtension get(in AString aId);
};
/**
+ * Interface representing a collection of annotations associated
+ * with a bookmark or bookmark folder.
+ */
+[scriptable, uuid(335c9292-91a1-4ca0-ad0b-07d5f63ed6cd)]
+interface fuelIAnnotations : nsISupports
+{
+ /**
+ * Array of the annotation names associated with the owning item
+ */
+ readonly attribute nsIVariant names;
+
+ /**
+ * Determines if an annotation exists with the given name.
+ * @param aName
+ * The name of the annotation
+ * @returns true if an annotation exists with the given name,
+ * false otherwise.
+ */
+ boolean has(in AString aName);
+
+ /**
+ * Gets the value of an annotation with the given name.
+ * @param aName
+ * The name of the annotation
+ * @returns A variant containing the value of the annotation. Supports
+ * string, boolean and number.
+ */
+ nsIVariant get(in AString aName);
+
+ /**
+ * Sets the value of an annotation with the given name.
+ * @param aName
+ * The name of the annotation
+ * @param aValue
+ * The new value of the annotation. Supports string, boolean
+ * and number
+ * @param aExpiration
+ * The expiration policy for the annotation.
+ * See nsIAnnotationService.
+ */
+ void set(in AString aName, in nsIVariant aValue, in PRInt32 aExpiration);
+
+ /**
+ * Removes the named annotation from the owner item.
+ * @param aName
+ * The name of annotation.
+ */
+ void remove(in AString aName);
+};
+
+
+/**
+ * Interface representing a bookmark item.
+ */
+[scriptable, uuid(808585b6-7568-4b26-8c62-545221bf2b8c)]
+interface fuelIBookmark : nsISupports
+{
+ /**
+ * The id of the bookmark.
+ */
+ readonly attribute long long id;
+
+ /**
+ * The title of the bookmark.
+ */
+ attribute AString title;
+
+ /**
+ * The uri of the bookmark.
+ */
+ attribute nsIURI uri;
+
+ /**
+ * The description of the bookmark.
+ */
+ attribute AString description;
+
+ /**
+ * The keyword associated with the bookmark.
+ */
+ attribute AString keyword;
+
+ /**
+ * The type of the bookmark.
+ * values: "bookmark", "separator"
+ */
+ readonly attribute AString type;
+
+ /**
+ * The parent folder of the bookmark.
+ */
+ attribute fuelIBookmarkFolder parent;
+
+ /**
+ * The annotations object for the bookmark.
+ */
+ readonly attribute fuelIAnnotations annotations;
+
+ /**
+ * The events object for the bookmark.
+ * supports: "remove", "change", "visit", "move"
+ */
+ readonly attribute fuelIEvents events;
+
+ /**
+ * Removes the item from the parent folder. Used to
+ * delete a bookmark or separator
+ */
+ void remove();
+};
+
+
+/**
+ * Interface representing a bookmark folder. Folders
+ * can hold bookmarks, separators and other folders.
+ */
+[scriptable, uuid(9f42fe20-52de-4a55-8632-a459c7716aa0)]
+interface fuelIBookmarkFolder : nsISupports
+{
+ /**
+ * The id of the folder.
+ */
+ readonly attribute long long id;
+
+ /**
+ * The title of the folder.
+ */
+ attribute AString title;
+
+ /**
+ * The description of the folder.
+ */
+ attribute AString description;
+
+ /**
+ * The type of the folder.
+ * values: "folder"
+ */
+ readonly attribute AString type;
+
+ /**
+ * The parent folder of the folder.
+ */
+ attribute fuelIBookmarkFolder parent;
+
+ /**
+ * The annotations object for the folder.
+ */
+ readonly attribute fuelIAnnotations annotations;
+
+ /**
+ * The events object for the folder.
+ * supports: "add", "addchild", "remove", "removechild", "change", "move"
+ */
+ readonly attribute fuelIEvents events;
+
+ /**
+ * Array of all bookmarks, separators and folders contained
+ * in this folder.
+ */
+ readonly attribute nsIVariant children;
+
+ /**
+ * Adds a new child bookmark to this folder.
+ * @param aTitle
+ * The title of bookmark.
+ * @param aURI
+ * The uri of bookmark.
+ */
+ fuelIBookmark addBookmark(in AString aTitle, in nsIURI aURI);
+
+ /**
+ * Adds a new child separator to this folder.
+ */
+ fuelIBookmark addSeparator();
+
+ /**
+ * Adds a new child folder to this folder.
+ * @param aTitle
+ * The title of folder.
+ */
+ fuelIBookmarkFolder addFolder(in AString aTitle);
+
+ /**
+ * Removes the folder from the parent folder.
+ */
+ void remove();
+};
+
+
+/**
+ * Interface representing a browser window.
+ */
+[scriptable, uuid(207edb28-eb5e-424e-a862-b0e97C8de866)]
+interface fuelIWindow : nsISupports
+{
+ /**
+ * A collection of browser tabs within the browser window.
+ */
+ readonly attribute nsIVariant tabs;
+
+ /**
+ * The currently-active tab within the browser window.
+ */
+ readonly attribute fuelIBrowserTab activeTab;
+
+ /**
+ * Open a new browser tab, pointing to the specified URI.
+ * @param aURI
+ * The uri to open the browser tab to
+ */
+ fuelIBrowserTab open(in nsIURI aURI);
+
+ /**
+ * The events object for the browser window.
+ * supports: "TabOpen", "TabClose", "TabMove", "TabSelect"
+ */
+ readonly attribute fuelIEvents events;
+};
+
+/**
+ * Interface representing a browser tab.
+ */
+[scriptable, uuid(3073ceff-777c-41ce-9ace-ab37268147c1)]
+interface fuelIBrowserTab : nsISupports
+{
+ /**
+ * The current uri of this tab.
+ */
+ readonly attribute nsIURI uri;
+
+ /**
+ * The current index of this tab in the browser window.
+ */
+ readonly attribute PRInt32 index;
+
+ /**
+ * The browser window that is holding the tab.
+ */
+ readonly attribute fuelIWindow window;
+
+ /**
+ * The content document of the browser tab.
+ */
+ readonly attribute nsIDOMHTMLDocument document;
+
+ /**
+ * The events object for the browser tab.
+ * supports: "load"
+ */
+ readonly attribute fuelIEvents events;
+
+ /**
+ * Load a new URI into this browser tab.
+ * @param aURI
+ * The uri to load into the browser tab
+ */
+ void load(in nsIURI aURI);
+
+ /**
+ * Give focus to this browser tab, and bring it to the front.
+ */
+ void focus();
+
+ /**
+ * Close the browser tab. This may not actually close the tab
+ * as script may abort the close operation.
+ */
+ void close();
+
+ /**
+ * Moves this browser tab before another browser tab within the window.
+ * @param aBefore
+ * The tab before which the target tab will be moved
+ */
+ void moveBefore(in fuelIBrowserTab aBefore);
+
+ /**
+ * Move this browser tab to the last tab within the window.
+ */
+ void moveToEnd();
+};
+
+
+/**
* Interface for managing and accessing the applications systems
*/
[scriptable, uuid(fe74cf80-aa2d-11db-abbd-0800200c9a66)]
interface fuelIApplication : nsISupports
{
/**
* The id of the application.
*/
@@ -382,9 +672,24 @@ interface fuelIApplication : nsISupports
*/
readonly attribute fuelISessionStorage storage;
/**
* The events object for the application.
* supports: "load", "ready", "quit", "unload"
*/
readonly attribute fuelIEvents events;
+
+ /**
+ * The root bookmarks object for the application.
+ */
+ readonly attribute fuelIBookmarkFolder bookmarks;
+
+ /**
+ * An array of browser windows within the application.
+ */
+ readonly attribute nsIVariant windows;
+
+ /**
+ * The currently active browser window.
+ */
+ readonly attribute fuelIWindow activeWindow;
};
--- a/browser/fuel/src/fuelApplication.js
+++ b/browser/fuel/src/fuelApplication.js
@@ -29,49 +29,46 @@
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-
-const nsISupports = Components.interfaces.nsISupports;
-const nsIClassInfo = Components.interfaces.nsIClassInfo;
-const nsIObserver = Components.interfaces.nsIObserver;
-const fuelIApplication = Components.interfaces.fuelIApplication;
+const Ci = Components.interfaces;
+const Cc = Components.classes;
//=================================================
// Shutdown - used to store cleanup functions which will
// be called on Application shutdown
var gShutdown = [];
//=================================================
// Console constructor
function Console() {
this._console = Components.classes["@mozilla.org/consoleservice;1"]
- .getService(Components.interfaces.nsIConsoleService);
+ .getService(Ci.nsIConsoleService);
}
//=================================================
// Console implementation
Console.prototype = {
log : function cs_log(aMsg) {
this._console.logStringMessage(aMsg);
},
open : function cs_open() {
var wMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
- .getService(Components.interfaces.nsIWindowMediator);
+ .getService(Ci.nsIWindowMediator);
var console = wMediator.getMostRecentWindow("global:console");
if (!console) {
var wWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
- .getService(Components.interfaces.nsIWindowWatcher);
+ .getService(Ci.nsIWindowWatcher);
wWatch.openWindow(null, "chrome://global/content/console.xul", "_blank",
"chrome,dialog=no,all", cmdLine);
} else {
// console was already open
console.focus();
}
}
};
@@ -144,37 +141,30 @@ Events.prototype = {
});
return !eventItem._cancel;
}
};
//=================================================
-// Preferences constants
-const nsIPrefService = Components.interfaces.nsIPrefService;
-const nsIPrefBranch = Components.interfaces.nsIPrefBranch;
-const nsIPrefBranch2 = Components.interfaces.nsIPrefBranch2;
-const nsISupportsString = Components.interfaces.nsISupportsString;
-
-//=================================================
// PreferenceBranch constructor
function PreferenceBranch(aBranch) {
if (!aBranch)
aBranch = "";
this._root = aBranch;
this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(nsIPrefService);
+ .getService(Ci.nsIPrefService);
if (aBranch)
this._prefs = this._prefs.getBranch(aBranch);
- this._prefs.QueryInterface(nsIPrefBranch);
- this._prefs.QueryInterface(nsIPrefBranch2);
+ this._prefs.QueryInterface(Ci.nsIPrefBranch);
+ this._prefs.QueryInterface(Ci.nsIPrefBranch2);
this._prefs.addObserver(this._root, this, false);
this._events = new Events();
var self = this;
gShutdown.push(function() { self._shutdown(); });
}
@@ -220,50 +210,50 @@ PreferenceBranch.prototype = {
for (var i = 0; i < items.length; i++) {
retVal.push(new Preference(items[i], this));
}
return retVal;
},
has : function prefs_has(aName) {
- return (this._prefs.getPrefType(aName) != nsIPrefBranch.PREF_INVALID);
+ return (this._prefs.getPrefType(aName) != Ci.nsIPrefBranch.PREF_INVALID);
},
get : function prefs_get(aName) {
return this.has(aName) ? new Preference(aName, this) : null;
},
getValue : function prefs_gv(aName, aValue) {
var type = this._prefs.getPrefType(aName);
switch (type) {
- case nsIPrefBranch2.PREF_STRING:
- aValue = this._prefs.getComplexValue(aName, nsISupportsString).data;
+ case Ci.nsIPrefBranch2.PREF_STRING:
+ aValue = this._prefs.getComplexValue(aName, Ci.nsISupportsString).data;
break;
- case nsIPrefBranch2.PREF_BOOL:
+ case Ci.nsIPrefBranch2.PREF_BOOL:
aValue = this._prefs.getBoolPref(aName);
break;
- case nsIPrefBranch2.PREF_INT:
+ case Ci.nsIPrefBranch2.PREF_INT:
aValue = this._prefs.getIntPref(aName);
break;
}
return aValue;
},
setValue : function prefs_sv(aName, aValue) {
var type = aValue != null ? aValue.constructor.name : "";
switch (type) {
case "String":
var str = Components.classes["@mozilla.org/supports-string;1"]
- .createInstance(nsISupportsString);
+ .createInstance(Ci.nsISupportsString);
str.data = aValue;
- this._prefs.setComplexValue(aName, nsISupportsString, str);
+ this._prefs.setComplexValue(aName, Ci.nsISupportsString, str);
break;
case "Boolean":
this._prefs.setBoolPref(aName, aValue);
break;
case "Number":
this._prefs.setIntPref(aName, aValue);
break;
default:
@@ -299,23 +289,23 @@ Preference.prototype = {
return this._name;
},
get type() {
var value = "";
var type = this._prefs.getPrefType(name);
switch (type) {
- case nsIPrefBranch2.PREF_STRING:
+ case Ci.nsIPrefBranch2.PREF_STRING:
value = "String";
break;
- case nsIPrefBranch2.PREF_BOOL:
+ case Ci.nsIPrefBranch2.PREF_BOOL:
value = "Boolean";
break;
- case nsIPrefBranch2.PREF_INT:
+ case Ci.nsIPrefBranch2.PREF_INT:
value = "Number";
break;
}
return value;
},
get value() {
@@ -377,61 +367,57 @@ SessionStorage.prototype = {
get : function ss_get(aName, aDefaultValue) {
return this.has(aName) ? this._storage[aName] : aDefaultValue;
}
};
//=================================================
-// Extension constants
-const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
-
-//=================================================
// Extension constructor
function Extension(aItem) {
this._item = aItem;
this._firstRun = false;
this._prefs = new PreferenceBranch("extensions." + this._item.id + ".");
this._storage = new SessionStorage();
this._events = new Events();
var installPref = "install-event-fired";
if (!this._prefs.has(installPref)) {
this._prefs.setValue(installPref, true);
this._firstRun = true;
}
var os = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
+ .getService(Ci.nsIObserverService);
os.addObserver(this, "em-action-requested", false);
var self = this;
gShutdown.push(function(){ self._shutdown(); });
}
//=================================================
-// Extensions implementation
+// Extension implementation
Extension.prototype = {
// cleanup observer so we don't leak
_shutdown: function ext_shutdown() {
var os = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
+ .getService(Ci.nsIObserverService);
os.removeObserver(this, "em-action-requested");
this._prefs = null;
this._storage = null;
this._events = null;
},
// for nsIObserver
observe: function ext_observe(aSubject, aTopic, aData)
{
if ((aData == "item-uninstalled") &&
- (aSubject instanceof nsIUpdateItem) &&
+ (aSubject instanceof Ci.nsIUpdateItem) &&
(aSubject.id == this._item.id))
{
this._events.dispatch("uninstall", this._item.id);
}
},
get id() {
return this._item.id;
@@ -462,17 +448,17 @@ Extension.prototype = {
}
};
//=================================================
// Extensions constructor
function Extensions() {
this._extmgr = Components.classes["@mozilla.org/extensions/manager;1"]
- .getService(Components.interfaces.nsIExtensionManager);
+ .getService(Ci.nsIExtensionManager);
var self = this;
gShutdown.push(function() { self._shutdown(); });
}
//=================================================
// Extensions implementation
Extensions.prototype = {
@@ -487,17 +473,17 @@ Extensions.prototype = {
// XXX: Disabled until we can figure out the wrapped object issues
// id: "some@id" or /id/
// name: "name" or /name/
// version: "1.0.1"
// minVersion: "1.0"
// maxVersion: "2.0"
find : function exts_find(aOptions) {
var retVal = [];
- var items = this._extmgr.getItemList(nsIUpdateItem.TYPE_EXTENSION, {});
+ var items = this._extmgr.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
for (var i = 0; i < items.length; i++) {
retVal.push(new Extension(items[i]));
}
return retVal;
},
@@ -508,34 +494,635 @@ Extensions.prototype = {
return !!(this._extmgr.getItemForID(aId).type);
},
get : function exts_get(aId) {
return this.has(aId) ? new Extension(this._extmgr.getItemForID(aId)) : null;
}
};
+//=================================================
+// Singleton that holds services and utilities
+var Utilities = {
+ _bookmarks : null,
+ get bookmarks() {
+ if (!this._bookmarks) {
+ this._bookmarks = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
+ getService(Ci.nsINavBookmarksService);
+ }
+ return this._bookmarks;
+ },
+
+ _livemarks : null,
+ get livemarks() {
+ if (!this._livemarks) {
+ this._livemarks = Cc["@mozilla.org/browser/livemark-service;2"].
+ getService(Ci.nsILivemarkService);
+ }
+ return this._livemarks;
+ },
+
+ _annotations : null,
+ get annotations() {
+ if (!this._annotations) {
+ this._annotations = Cc["@mozilla.org/browser/annotation-service;1"].
+ getService(Ci.nsIAnnotationService);
+ }
+ return this._annotations;
+ },
+
+ _history : null,
+ get history() {
+ if (!this._history) {
+ this._history = Cc["@mozilla.org/browser/nav-history-service;1"].
+ getService(Ci.nsINavHistoryService);
+ }
+ return this._history;
+ },
+
+ _windowMediator : null,
+ get windowMediator() {
+ if (!this._windowMediator) {
+ this._windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
+ getService(Ci.nsIWindowMediator);
+ }
+ return this._windowMediator;
+ },
+
+ makeURI : function(aSpec) {
+ if (!aSpec)
+ return null;
+ var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ return ios.newURI(aSpec, null, null);
+ },
+
+ free : function() {
+ this._bookmarks = null;
+ this._livemarks = null;
+ this._annotations = null;
+ this._history = null;
+ this._windowMediator = null;
+ }
+};
+
+
+//=================================================
+// Window implementation
+function Window(aWindow) {
+ this._window = aWindow;
+ this._tabbrowser = aWindow.getBrowser();
+ this._events = new Events();
+ this._cleanup = {};
+
+ this._watch("TabOpen");
+ this._watch("TabMove");
+ this._watch("TabClose");
+ this._watch("TabSelect");
+
+ var self = this;
+ gShutdown.push(function() { self._shutdown(); });
+}
+
+Window.prototype = {
+ get events() {
+ return this._events;
+ },
+
+ /*
+ * Helper used to setup event handlers on the XBL element. Note that the events
+ * are actually dispatched to tabs, so we capture them.
+ */
+ _watch : function(aType) {
+ var self = this;
+ this._tabbrowser.addEventListener(aType,
+ this._cleanup[aType] = function(e){ self._event(e); },
+ true);
+ },
+
+ /*
+ * Helper event callback used to redirect events made on the XBL element
+ */
+ _event : function(aEvent) {
+ this._events.dispatch(aEvent.type, "");
+ },
+
+ get tabs() {
+ var tabs = [];
+ var browsers = this._tabbrowser.browsers;
+
+ for (var i=0; i<browsers.length; i++)
+ tabs.push(new BrowserTab(this._window, browsers[i]));
+
+ return tabs;
+ },
+
+ get activeTab() {
+ return new BrowserTab(this._window, this._tabbrowser.selectedBrowser);
+ },
+
+ open : function(aURI) {
+ return new BrowserTab(this._window, this._tabbrowser.addTab(aURI.spec).linkedBrowser);
+ },
+
+ _shutdown : function() {
+ for (var type in this._cleanup)
+ this._tabbrowser.removeEventListener(type, this._cleanup[type]);
+ this._cleanup = null;
+
+ this._window = null;
+ this._tabbrowser = null;
+ this._events = null;
+ }
+};
+
+
+//=================================================
+// BrowserTab implementation
+function BrowserTab(aWindow, aBrowser) {
+ this._window = aWindow;
+ this._tabbrowser = aWindow.getBrowser();
+ this._browser = aBrowser;
+ this._events = new Events();
+ this._cleanup = {};
+
+ this._watch("load");
+
+ var self = this;
+ gShutdown.push(function() { self._shutdown(); });
+}
+
+BrowserTab.prototype = {
+ get uri() {
+ return this._browser.currentURI;
+ },
+
+ get index() {
+ var tabs = this._tabbrowser.mTabs;
+ for (var i=0; i<tabs.length; i++) {
+ if (tabs[i].linkedBrowser == this._browser)
+ return i;
+ }
+ return -1;
+ },
+
+ get events() {
+ return this._events;
+ },
+
+ get window() {
+ return this._window;
+ },
+
+ get document() {
+ return this._browser.contentDocument;
+ },
+
+ /*
+ * Helper used to setup event handlers on the XBL element
+ */
+ _watch : function(aType) {
+ var self = this;
+ this._browser.addEventListener(aType,
+ this._cleanup[aType] = function(e){ self._event(e); },
+ true);
+ },
+
+ /*
+ * Helper event callback used to redirect events made on the XBL element
+ */
+ _event : function(aEvent) {
+ if (aEvent.type == "load" && (!aEvent.originalTarget instanceof Ci.nsIDOMHTMLDocument ||
+ aEvent.originalTarget.defaultView.frameElement))
+ return;
+
+ this._events.dispatch(aEvent.type, "");
+ },
+
+ /*
+ * Helper used to determine the index offset of the browsertab
+ */
+ _getTab : function() {
+ var tabs = this._tabbrowser.mTabs;
+ return tabs[this.index] || null;
+ },
+
+ load : function(aURI) {
+ this._browser.loadURI(aURI.spec, null, null);
+ },
+
+ focus : function() {
+ this._tabbrowser.selectedTab = this._getTab();
+ this._tabbrowser.focus();
+ },
+
+ close : function() {
+ this._tabbrowser.removeTab(this._getTab());
+ },
+
+ moveBefore : function(aBefore) {
+ this._tabbrowser.moveTabTo(this._getTab(), aBefore.index);
+ },
+
+ moveToEnd : function() {
+ this._tabbrowser.moveTabTo(this._getTab(), this._tabbrowser.browsers.length);
+ },
+
+ _shutdown : function() {
+ for (var type in this._cleanup)
+ this._browser.removeEventListener(type, this._cleanup[type]);
+ this._cleanup = null;
+
+ this._window = null;
+ this._tabbrowser = null;
+ this._browser = null;
+ this._events = null;
+ }
+};
+
+
+//=================================================
+// Annotations implementation
+function Annotations(aId) {
+ this._id = aId;
+}
+
+Annotations.prototype = {
+ get names() {
+ return Utilities.annotations.getItemAnnotationNames(this._id, {});
+ },
+
+ has : function(aName) {
+ return Utilities.annotations.itemHasAnnotation(this._id, aName);
+ },
+
+ get : function(aName) {
+ var value = null;
+ var type = Utilities.annotations.getItemAnnotationType(this._id, aName);
+ switch (type) {
+ case Ci.nsIAnnotationService.TYPE_INT32:
+ value = Utilities.annotations.getItemAnnotationInt32(this._id, aName);
+ break;
+ case Ci.nsIAnnotationService.TYPE_INT64:
+ value = Utilities.annotations.getItemAnnotationInt64(this._id, aName);
+ break;
+ case Ci.nsIAnnotationService.TYPE_DOUBLE:
+ value = Utilities.annotations.getItemAnnotationDouble(this._id, aName);
+ break;
+ case Ci.nsIAnnotationService.TYPE_STRING:
+ value = Utilities.annotations.getItemAnnotationString(this._id, aName);
+ break;
+ default:
+ throw("Unknown annotation type specified.");
+ }
+ return value;
+ },
+
+ set : function(aName, aValue, aExpiration) {
+ var type = aValue != null ? aValue.constructor.name : "";
+
+ switch (type) {
+ case "String":
+ Utilities.annotations.setItemAnnotationString(this._id, aName, aValue, 0, aExpiration);
+ break;
+ case "Boolean":
+ Utilities.annotations.setItemAnnotationInt32(this._id, aName, aValue, 0, aExpiration);
+ break;
+ case "Number":
+ Utilities.annotations.setItemAnnotationDouble(this._id, aName, aValue, 0, aExpiration);
+ break;
+ default:
+ throw("Unknown annotation value specified.");
+ }
+ },
+
+ remove : function(aName) {
+ if (aName)
+ Utilities.annotations.removeItemAnnotation(this._id, aName);
+ }
+};
+
+
+//=================================================
+// Bookmark implementation
+function Bookmark(aId, aParent, aType) {
+ this._id = aId;
+ this._parent = aParent;
+ this._type = aType || "bookmark";
+ this._annotations = new Annotations(this._id);
+ this._events = new Events();
+
+ Utilities.bookmarks.addObserver(this, false);
+
+ var self = this;
+ gShutdown.push(function() { self._shutdown(); });
+}
+
+Bookmark.prototype = {
+ _shutdown : function() {
+ this._annotations = null;
+ this._events = null;
+
+ Utilities.bookmarks.removeObserver(this);
+ },
+
+ get id() {
+ return this._id;
+ },
+
+ get title() {
+ return Utilities.bookmarks.getItemTitle(this._id);
+ },
+
+ set title(aTitle) {
+ Utilities.bookmarks.setItemTitle(this._id, aTitle);
+ },
+
+ get uri() {
+ return Utilities.bookmarks.getBookmarkURI(this._id);
+ },
+
+ set uri(aURI) {
+ return Utilities.bookmarks.changeBookmarkURI(this._id, aURI);
+ },
+
+ get description() {
+ return this._annotations.get("bookmarkProperties/description");
+ },
+
+ set description(aDesc) {
+ this._annotations.set("bookmarkProperties/description", aDesc, Ci.nsIAnnotationService.EXPIRE_NEVER);
+ },
+
+ get keyword() {
+ return Utilities.bookmarks.getKeywordForBookmark(this._id);
+ },
+
+ set keyword(aKeyword) {
+ Utilities.bookmarks.setKeywordForBookmark(this._id, aKeyword);
+ },
+
+ get type() {
+ return this._type;
+ },
+
+ get parent() {
+ return this._parent;
+ },
+
+ set parent(aFolder) {
+ Utilities.bookmarks.moveItem(this._id, aFolder.id, Utilities.bookmarks.DEFAULT_INDEX);
+ // this._parent is updated in onItemMoved
+ },
+
+ get annotations() {
+ return this._annotations;
+ },
+
+ get events() {
+ return this._events;
+ },
+
+ remove : function() {
+ Utilities.bookmarks.removeItem(this._id);
+ },
+
+ // observer
+ onBeginUpdateBatch : function() {
+ },
+
+ onEndUpdateBatch : function() {
+ },
+
+ onItemAdded : function(aId, aFolder, aIndex) {
+ // bookmark object doesn't exist at this point
+ },
+
+ onItemRemoved : function(aId, aFolder, aIndex) {
+ if (this._id == aId)
+ this._events.dispatch("remove", aId);
+ },
+
+ onItemChanged : function(aId, aProperty, aIsAnnotationProperty, aValue) {
+ if (this._id == aId)
+ this._events.dispatch("change", aProperty);
+ },
+
+ onItemVisited: function(aId, aVisitID, aTime) {
+ },
+
+ onItemMoved: function(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
+ if (this._id == aId) {
+ this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
+ this._events.dispatch("move", aId);
+ }
+ },
+
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.fuelIBookmark) ||
+ aIID.equals(Ci.nsINavBookmarkObserver) ||
+ aIID.equals(Ci.nsISupports)) {
+ return this;
+ }
+ throw Component.result.NS_ERROR_NO_INTERFACE;
+ }
+};
+
+
+//=================================================
+// BookmarkFolder implementation
+function BookmarkFolder(aId, aParent) {
+ this._id = aId;
+ if (this._id == null)
+ this._id = Utilities.bookmarks.bookmarksRoot;
+
+ this._parent = aParent;
+
+ this._annotations = new Annotations(this._id);
+ this._events = new Events();
+
+ Utilities.bookmarks.addObserver(this, false);
+
+ var self = this;
+ gShutdown.push(function() { self._shutdown(); });
+}
+
+BookmarkFolder.prototype = {
+ _shutdown : function() {
+ this._annotations = null;
+ this._events = null;
+
+ Utilities.bookmarks.removeObserver(this);
+ },
+
+ get id() {
+ return this._id;
+ },
+
+ get title() {
+ return Utilities.bookmarks.getItemTitle(this._id);
+ },
+
+ set title(aTitle) {
+ Utilities.bookmarks.setItemTitle(this._id, aTitle);
+ },
+
+ get description() {
+ return this._annotations.get("bookmarkProperties/description");
+ },
+
+ set description(aDesc) {
+ this._annotations.set("bookmarkProperties/description", aDesc, Ci.nsIAnnotationService.EXPIRE_NEVER);
+ },
+
+ get type() {
+ return "folder";
+ },
+
+ get parent() {
+ return this._parent;
+ },
+
+ set parent(aFolder) {
+ Utilities.bookmarks.moveItem(this._id, aFolder.id, Utilities.bookmarks.DEFAULT_INDEX);
+ // this._parent is updated in onItemMoved
+ },
+
+ get annotations() {
+ return this._annotations;
+ },
+
+ get events() {
+ return this._events;
+ },
+
+ get children() {
+ var items = [];
+
+ var options = Utilities.history.getNewQueryOptions();
+ var query = Utilities.history.getNewQuery();
+ query.setFolders([this._id], 1);
+ var result = Utilities.history.executeQuery(query, options);
+ var rootNode = result.root;
+ rootNode.containerOpen = true;
+ var cc = rootNode.childCount;
+ for (var i=0; i<cc; ++i) {
+ var node = rootNode.getChild(i);
+ if (node.type == node.RESULT_TYPE_FOLDER) {
+ var folder = new BookmarkFolder(node.itemId, this._id);
+ items.push(folder);
+ }
+ else if (node.type == node.RESULT_TYPE_SEPARATOR) {
+ var separator = new Bookmark(node.itemId, this._id, "separator");
+ items.push(separator);
+ }
+ else {
+ var bookmark = new Bookmark(node.itemId, this._id, "bookmark");
+ items.push(bookmark);
+ }
+ }
+ rootNode.containerOpen = false;
+
+ return items;
+ },
+
+ addBookmark : function(aTitle, aUri) {
+ var newBookmarkID = Utilities.bookmarks.insertBookmark(this._id, aUri, Utilities.bookmarks.DEFAULT_INDEX, aTitle);
+ var newBookmark = new Bookmark(newBookmarkID, this, "bookmark");
+ return newBookmark;
+ },
+
+ addSeparator : function() {
+ var newBookmarkID = Utilities.bookmarks.insertSeparator(this._id, Utilities.bookmarks.DEFAULT_INDEX);
+ var newBookmark = new Bookmark(newBookmarkID, this, "separator");
+ return newBookmark;
+ },
+
+ addFolder : function(aTitle) {
+ var newFolderID = Utilities.bookmarks.createFolder(this._id, aTitle, Utilities.bookmarks.DEFAULT_INDEX);
+ var newFolder = new BookmarkFolder(newFolderID, this);
+ return newFolder;
+ },
+
+ remove : function() {
+ Utilities.bookmarks.removeFolder(this._id);
+ },
+
+ // observer
+ onBeginUpdateBatch : function() {
+ },
+
+ onEndUpdateBatch : function() {
+ },
+
+ onItemAdded : function(aId, aFolder, aIndex) {
+ // handle root folder events
+ if (!this._parent)
+ this._events.dispatch("add", aId);
+
+ // handle this folder events
+ if (this._id == aFolder)
+ this._events.dispatch("addchild", aId);
+ },
+
+ onItemRemoved : function(aId, aFolder, aIndex) {
+ // handle root folder events
+ if (!this._parent || this._id == aId)
+ this._events.dispatch("remove", aId);
+
+ // handle this folder events
+ if (this._id == aFolder)
+ this._events.dispatch("removechild", aId);
+ },
+
+ onItemChanged : function(aId, aProperty, aIsAnnotationProperty, aValue) {
+ // handle root folder and this folder events
+ if (!this._parent || this._id == aId)
+ this._events.dispatch("change", aProperty);
+ },
+
+ onItemVisited: function(aId, aVisitID, aTime) {
+ },
+
+ onItemMoved: function(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
+ // handle this folder event, root folder cannot be moved
+ if (this._id == aId) {
+ this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
+ this._events.dispatch("move", aId);
+ }
+ },
+
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.fuelIBookmarkFolder) ||
+ aIID.equals(Ci.nsINavBookmarkObserver) ||
+ aIID.equals(Ci.nsISupports)) {
+ return this;
+ }
+ throw Component.result.NS_ERROR_NO_INTERFACE;
+ }
+};
+
const CLASS_ID = Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66");
const CLASS_NAME = "Application wrapper";
const CONTRACT_ID = "@mozilla.org/fuel/application;1";
//=================================================
// Application constructor
function Application() {
this._console = null;
this._prefs = null;
this._storage = null;
this._events = null;
+ this._bookmarks = null;
this._info = Components.classes["@mozilla.org/xre/app-info;1"]
- .getService(Components.interfaces.nsIXULAppInfo);
+ .getService(Ci.nsIXULAppInfo);
var os = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
+ .getService(Ci.nsIObserverService);
os.addObserver(this, "final-ui-startup", false);
os.addObserver(this, "quit-application-requested", false);
os.addObserver(this, "quit-application-granted", false);
os.addObserver(this, "quit-application", false);
os.addObserver(this, "xpcom-shutdown", false);
}
@@ -573,59 +1160,62 @@ Application.prototype = {
// call the cleanup functions and empty the array
while (gShutdown.length) {
gShutdown.shift()();
}
// release our observers
var os = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
+ .getService(Ci.nsIObserverService);
os.removeObserver(this, "final-ui-startup");
os.removeObserver(this, "quit-application-requested");
os.removeObserver(this, "quit-application-granted");
os.removeObserver(this, "quit-application");
os.removeObserver(this, "xpcom-shutdown");
this._info = null;
this._console = null;
this._prefs = null;
this._storage = null;
this._events = null;
this._extensions = null;
+ this._bookmarks = null;
+
+ Utilities.free();
}
},
// for nsIClassInfo
classDescription : "Application",
classID : CLASS_ID,
contractID : CONTRACT_ID,
- flags : nsIClassInfo.SINGLETON,
- implementationLanguage : Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
+ flags : Ci.nsIClassInfo.SINGLETON,
+ implementationLanguage : Ci.nsIProgrammingLanguage.JAVASCRIPT,
getInterfaces : function app_gi(aCount) {
- var interfaces = [fuelIApplication, nsIObserver, nsIClassInfo];
+ var interfaces = [Ci.fuelIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
aCount.value = interfaces.length;
return interfaces;
},
getHelperForLanguage : function app_ghfl(aCount) {
return null;
},
// for nsISupports
QueryInterface: function app_qi(aIID) {
// add any other interfaces you support here
- if (aIID.equals(fuelIApplication) ||
- aIID.equals(nsIObserver) ||
- aIID.equals(nsIClassInfo) ||
- aIID.equals(nsISupports))
+ if (aIID.equals(Ci.fuelIApplication) ||
+ aIID.equals(Ci.nsIObserver) ||
+ aIID.equals(Ci.nsIClassInfo) ||
+ aIID.equals(Ci.nsISupports))
{
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
},
get console() {
if (this._console == null)
@@ -652,65 +1242,85 @@ Application.prototype = {
return this._extensions;
},
get events() {
if (this._events == null)
this._events = new Events();
return this._events;
+ },
+
+ get bookmarks() {
+ if (this._bookmarks == null)
+ this._bookmarks = new BookmarkFolder(null, null);
+
+ return this._bookmarks;
+ },
+
+ get windows() {
+ var win = [];
+ var enum = Utilities.windowMediator.getEnumerator("navigator:browser");
+
+ while (enum.hasMoreElements())
+ win.push(new Window(enum.getNext()));
+
+ return win;
+ },
+
+ get activeWindow() {
+ return new Window(Utilities.windowMediator.getMostRecentWindow("navigator:browser"));
}
-}
+};
//=================================================
// Factory - Treat Application as a singleton
var gSingleton = null;
var ApplicationFactory = {
-
createInstance: function af_ci(aOuter, aIID) {
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
if (gSingleton == null) {
gSingleton = new Application();
}
return gSingleton.QueryInterface(aIID);
}
};
//=================================================
// Module
var ApplicationModule = {
registerSelf: function am_rs(aCompMgr, aFileSpec, aLocation, aType) {
- aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+ aCompMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
var categoryManager = Components.classes["@mozilla.org/categorymanager;1"]
- .getService(Components.interfaces.nsICategoryManager);
+ .getService(Ci.nsICategoryManager);
// make Application a startup observer
categoryManager.addCategoryEntry("app-startup", CLASS_NAME, "service," + CONTRACT_ID, true, true);
// add Application as a global property for easy access
categoryManager.addCategoryEntry("JavaScript global property", "Application", CONTRACT_ID, true, true);
},
unregisterSelf: function am_us(aCompMgr, aLocation, aType) {
- aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+ aCompMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
// cleanup categories
var categoryManager = Components.classes["@mozilla.org/categorymanager;1"]
- .getService(Components.interfaces.nsICategoryManager);
+ .getService(Ci.nsICategoryManager);
categoryManager.deleteCategoryEntry("app-startup", "service," + CONTRACT_ID, true);
categoryManager.deleteCategoryEntry("JavaScript global property", CONTRACT_ID, true);
},
getClassObject: function am_gco(aCompMgr, aCID, aIID) {
- if (!aIID.equals(Components.interfaces.nsIFactory))
+ if (!aIID.equals(Ci.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
if (aCID.equals(CLASS_ID))
return ApplicationFactory;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
--- a/browser/fuel/test/Makefile.in
+++ b/browser/fuel/test/Makefile.in
@@ -39,16 +39,20 @@ DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/fuel/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
-_TEST_FILES = test_Application.html \
- test_ApplicationPrefs.html \
- test_ApplicationStorage.html \
- test_Extensions.html \
+_CHROME_FILES = test_Application.xul \
+ test_ApplicationPrefs.xul \
+ test_ApplicationStorage.xul \
+ test_Extensions.xul \
+ test_Bookmarks.xul \
+ test_Browser.xul \
+ test_ContentA.html \
+ test_ContentB.html \
$(NULL)
-libs:: $(_TEST_FILES)
- $(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+libs:: $(_CHROME_FILES)
+ $(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_Application.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="Testing Application"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" />
+
+<script type="application/javascript">
+<![CDATA[
+
+test_Application();
+
+function test_Application() {
+ ok(Application, "Check global access to Application");
+
+ // I'd test these against a specific value, but that is bound to flucuate
+ ok(Application.id, "Check to see if an ID exists for the Application");
+ ok(Application.name, "Check to see if a name exists for the Application");
+ ok(Application.version, "Check to see if a version exists for the Application");
+}
+
+]]>
+</script>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_ApplicationPrefs.xul
@@ -0,0 +1,181 @@
+<?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="Testing Application Prefs"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" />
+
+<script type="application/javascript">
+<![CDATA[
+
+// The various properties that we'll be testing
+var test = {
+ missing: "fuel.fuel-test-missing",
+ dummy: "fuel.fuel-test",
+ string: "browser.active_color",
+ integer: "permissions.default.image",
+ boolean: "browser.blink_allowed"
+};
+
+test_Preferences();
+
+function test_Preferences() {
+ // test getting non-existing values
+ var itemValue = Application.prefs.getValue(test.missing, "default");
+ is(itemValue, "default", "Check 'Application.prefs.getValue' for non-existing item");
+
+ is(Application.prefs.get(test.missing), null, "Check 'Application.prefs.get' for non-existing item");
+
+ // test setting and getting a value
+ Application.prefs.setValue(test.dummy, "dummy");
+ itemValue = Application.prefs.getValue(test.dummy, "default");
+ is(itemValue, "dummy", "Check 'Application.prefs.getValue' for existing item");
+
+ // test for overwriting an existing value
+ Application.prefs.setValue(test.dummy, "smarty");
+ itemValue = Application.prefs.getValue(test.dummy, "default");
+ is(itemValue, "smarty", "Check 'Application.prefs.getValue' for overwritten item");
+
+ // test setting and getting a value
+ Application.prefs.get(test.dummy).value = "dummy2";
+ itemValue = Application.prefs.get(test.dummy).value;
+ is(itemValue, "dummy2", "Check 'Application.prefs.get().value' for existing item");
+
+ // test resetting a pref [since there is no default value, the pref should disappear]
+ Application.prefs.get(test.dummy).reset();
+ var itemValue = Application.prefs.getValue(test.dummy, "default");
+ is(itemValue, "default", "Check 'Application.prefs.getValue' for reset pref");
+
+ // test to see if a non-existant property exists
+ ok(!Application.prefs.has(test.dummy), "Check non-existant property for existance");
+
+ // PREF: string browser.active_color == #EE0000
+
+ // test to see if an existing string property exists
+ ok(Application.prefs.has(test.string), "Check existing string property for existance");
+
+ // test accessing a non-existant string property
+ var val = Application.prefs.getValue(test.dummy, "default");
+ is(val, "default", "Check non-existant string property for expected value");
+
+ // test accessing an existing string property
+ var val = Application.prefs.getValue(test.string, "default");
+ is(val, "#EE0000", "Check existing string property for expected value");
+
+ // test manipulating an existing string property
+ Application.prefs.setValue(test.string, "#EF0000");
+ var val = Application.prefs.getValue(test.string, "default");
+ is(val, "#EF0000", "Set existing string property");
+
+ // test resetting an existing string property
+ Application.prefs.get(test.string).reset();
+ var val = Application.prefs.getValue(test.string, "default");
+ is(val, "#EE0000", "Reset existing string property");
+
+ // PREF: integer permissions.default.image == 1
+
+ // test to see if an existing integer property exists
+ ok(Application.prefs.has(test.integer), "Check existing integer property for existance");
+
+ // test accessing a non-existant integer property
+ var val = Application.prefs.getValue(test.dummy, 0);
+ is(val, 0, "Check non-existant integer property for expected value");
+
+ // test accessing an existing integer property
+ var val = Application.prefs.getValue(test.integer, 0);
+ is(val, 1, "Check existing integer property for expected value");
+
+ // test manipulating an existing integer property
+ Application.prefs.setValue(test.integer, 0);
+ var val = Application.prefs.getValue(test.integer, 1);
+ is(val, 0, "Set existing integer property");
+
+ // test resetting an existing integer property
+ Application.prefs.get(test.integer).reset();
+ var val = Application.prefs.getValue(test.integer, 0);
+ is(val, 1, "Reset existing integer property");
+
+ // PREF: boolean browser.blink_allowed == true
+
+ // test to see if an existing boolean property exists
+ ok(Application.prefs.has(test.boolean), "Check existing boolean property for existance");
+
+ // test accessing a non-existant boolean property
+ var val = Application.prefs.getValue(test.dummy, true);
+ ok(val, "Check non-existant boolean property for expected value");
+
+ // test accessing an existing boolean property
+ var val = Application.prefs.getValue(test.boolean, false);
+ ok(val, "Check existing boolean property for expected value");
+
+ // test manipulating an existing boolean property
+ Application.prefs.setValue(test.boolean, false);
+ var val = Application.prefs.getValue(test.boolean, true);
+ ok(!val, "Set existing boolean property");
+
+ // test resetting an existing boolean property
+ Application.prefs.get(test.boolean).reset();
+ var val = Application.prefs.getValue(test.boolean, false);
+ ok(val, "Reset existing string property for expected value");
+
+ // test getting all preferences
+ var allPrefs = Application.prefs.all;
+ ok(allPrefs.length >= 800, "Check 'Application.prefs.all' for the right number of preferences");
+ is(allPrefs[0].name, "capability.policy.default.Window.parent.get", "Check 'Application.prefs.all' for the right starting preference");
+
+ // test the value of the preference root
+ is(Application.prefs.root, "", "Check the Application preference root");
+
+ // test for user changed preferences
+ ok(Application.prefs.get("browser.shell.checkDefaultBrowser").modified, "A single preference is marked as modified.");
+ ok(!Application.prefs.get(test.string).modified, "A single preference is marked as not modified.");
+
+ // test for a locked preference
+ var pref = Application.prefs.get(test.string);
+ ok(!pref.locked, "A single preference should not be locked.");
+
+ pref.locked = true;
+ ok(pref.locked, "A single preference should be locked.");
+
+ try {
+ prev.value = "test value";
+
+ ok(false, "A locked preference should not be able to be modified.");
+ } catch(e){
+ ok(true, "A locked preference should not be able to be modified.");
+ }
+
+ pref.locked = false;
+ ok(!pref.locked, "A single preference should not be locked.");
+
+ // check for change event when setting a value
+ SimpleTest.waitForExplicitFinish();
+ Application.prefs.events.addListener("change", onPrefChange);
+ Application.prefs.setValue("fuel.fuel-test", "change event");
+}
+
+function onPrefChange(evt) {
+ is(evt.data, test.dummy, "Check 'Application.prefs.set' fired a change event");
+ Application.prefs.events.removeListener("change", onPrefChange);
+
+ Application.prefs.get("fuel.fuel-test").events.addListener("change", onPrefChange2);
+ Application.prefs.setValue("fuel.fuel-test", "change event2");
+}
+
+function onPrefChange2(evt) {
+ is(evt.data, test.dummy, "Check 'Application.prefs.set' fired a change event for a single preference");
+ Application.prefs.events.removeListener("change", onPrefChange2);
+
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_ApplicationStorage.xul
@@ -0,0 +1,53 @@
+<?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="Testing Application Storage"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" />
+
+<script type="application/javascript">
+<![CDATA[
+
+test_Storage();
+
+function test_Storage() {
+ // test for existence of values
+ var hasItem = Application.storage.has("fuel-test-missing");
+ is(hasItem, false, "Check 'Application.storage.has' for non-existing item");
+ Application.storage.set("fuel-test", "dummy");
+ hasItem = Application.storage.has("fuel-test");
+ is(hasItem, true, "Check 'Application.storage.has' for existing item");
+
+ // test getting non-existing and existing values
+ var itemValue = Application.storage.get("fuel-test-missing", "default");
+ is(itemValue, "default", "Check 'Application.storage.get' for non-existing item");
+ itemValue = Application.storage.get("fuel-test", "default");
+ is(itemValue, "dummy", "Check 'Application.storage.get' for existing item");
+
+ // test for overwriting an existing value
+ Application.storage.set("fuel-test", "smarty");
+ itemValue = Application.storage.get("fuel-test", "default");
+ is(itemValue, "smarty", "Check 'Application.storage.get' for overwritten item");
+
+ // check for change event when setting a value
+ SimpleTest.waitForExplicitFinish();
+ Application.storage.events.addListener("change", onStorageChange);
+ Application.storage.set("fuel-test", "change event");
+}
+
+function onStorageChange(evt) {
+ is(evt.data, "fuel-test", "Check 'Application.storage.set' fired a change event");
+ Application.storage.events.removeListener("change", onStorageChange);
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_Bookmarks.xul
@@ -0,0 +1,212 @@
+<?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="Testing Bookmarks"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" />
+
+<script type="application/javascript">
+<![CDATA[
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+var gLastFolderAction = "";
+var gLastBookmarkAction = "";
+
+test_Bookmarks();
+
+function url(spec) {
+ var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ return ios.newURI(spec, null, null);
+}
+
+function test_Bookmarks() {
+ var root = Application.bookmarks;
+ ok(root, "Check access to bookmark root");
+ ok(!root.parent, "Check root parent (should be null)");
+
+ var rootKidCount = root.children.length;
+
+ // test adding folders
+ var testFolder = root.addFolder("FUEL");
+ ok(testFolder, "Check folder creation");
+ is(testFolder.type, "folder", "Check 'folder.type' after creation");
+ ok(testFolder.parent, "Check parent after folder creation");
+
+ rootKidCount++;
+ is(root.children.length, rootKidCount, "Check root folder child count after adding a child folder");
+
+ // test modifying a folder
+ testFolder.events.addListener("change", onFolderChange);
+ testFolder.description = "FUEL folder";
+ is(testFolder.description, "FUEL folder", "Check setting 'folder.description'");
+ is(gLastFolderAction, "bookmarkProperties/description", "Check event handler for setting 'folder.description'");
+
+ testFolder.title = "fuel-is-cool";
+ is(testFolder.title, "fuel-is-cool", "Check setting 'folder.title'");
+ is(gLastFolderAction, "title", "Check event handler for setting 'folder.title'");
+
+ testFolder.annotations.set("testing/folder", "annotate-this", 0);
+ ok(testFolder.annotations.has("testing/folder"), "Checking existence of added annotation");
+ is(gLastFolderAction, "testing/folder", "Check event handler for setting annotation");
+ gLastFolderAction = "";
+ is(testFolder.annotations.get("testing/folder"), "annotate-this", "Checking existence of added annotation");
+ testFolder.annotations.remove("testing/folder");
+ ok(!testFolder.annotations.has("testing/folder"), "Checking existence of removed annotation");
+ is(gLastFolderAction, "testing/folder", "Check event handler for removing annotation");
+
+ testFolder.events.addListener("addchild", onFolderAddChild);
+ testFolder.events.addListener("removechild", onFolderRemoveChild);
+
+ // test adding a bookmark
+ var testBookmark = testFolder.addBookmark("Mozilla", url("http://www.mozilla.com/"));
+ ok(testBookmark, "Check bookmark creation");
+ ok(testBookmark.parent, "Check parent after bookmark creation");
+ is(gLastFolderAction, "addchild", "Check event handler for adding a child to a folder");
+ is(testBookmark.type, "bookmark", "Check 'bookmark.type' after creation");
+ is(testBookmark.title, "Mozilla", "Check 'bookmark.title' after creation");
+ is(testBookmark.uri.spec, "http://www.mozilla.com/", "Check 'bookmark.uri' after creation");
+
+ is(testFolder.children.length, 1, "Check test folder child count after adding a child bookmark");
+
+ // test modifying a bookmark
+ testBookmark.events.addListener("change", onBookmarkChange);
+ testBookmark.description = "mozcorp";
+ is(testBookmark.description, "mozcorp", "Check setting 'bookmark.description'");
+ is(gLastBookmarkAction, "bookmarkProperties/description", "Check event handler for setting 'bookmark.description'");
+
+ testBookmark.keyword = "moz"
+ is(testBookmark.keyword, "moz", "Check setting 'bookmark.keyword'");
+ is(gLastBookmarkAction, "keyword", "Check event handler for setting 'bookmark.keyword'");
+
+ testBookmark.title = "MozCorp"
+ is(testBookmark.title, "MozCorp", "Check setting 'bookmark.title'");
+ is(gLastBookmarkAction, "title", "Check event handler for setting 'bookmark.title'");
+
+ testBookmark.uri = url("http://www.mozilla.org/");
+ is(testBookmark.uri.spec, "http://www.mozilla.org/", "Check setting 'bookmark.uri'");
+ is(gLastBookmarkAction, "uri", "Check event handler for setting 'bookmark.uri'");
+
+ // test adding and removing a bookmark annotation
+ testBookmark.annotations.set("testing/bookmark", "annotate-this", 0);
+ ok(testBookmark.annotations.has("testing/bookmark"), "Checking existence of added annotation");
+ is(gLastBookmarkAction, "testing/bookmark", "Check event handler for setting annotation");
+ gLastBookmarkAction = "";
+ is(testBookmark.annotations.get("testing/bookmark"), "annotate-this", "Checking existence of added annotation");
+ testBookmark.annotations.remove("testing/bookmark");
+ ok(!testBookmark.annotations.has("testing/bookmark"), "Checking existence of removed annotation");
+ is(gLastBookmarkAction, "testing/bookmark", "Check event handler for removing annotation");
+
+ // quick annotation type tests
+ testBookmark.annotations.set("testing/bookmark/string", "annotate-this", 0);
+ ok(testBookmark.annotations.has("testing/bookmark/string"), "Checking existence of added string annotation");
+ is(testBookmark.annotations.get("testing/bookmark/string"), "annotate-this", "Checking value of added string annotation");
+ is(gLastBookmarkAction, "testing/bookmark/string", "Check event handler for setting annotation");
+ gLastBookmarkAction = "";
+ testBookmark.annotations.set("testing/bookmark/int", 100, 0);
+ ok(testBookmark.annotations.has("testing/bookmark/int"), "Checking existence of added integer annotation");
+ is(testBookmark.annotations.get("testing/bookmark/int"), 100, "Checking value of added integer annotation");
+ is(gLastBookmarkAction, "testing/bookmark/int", "Check event handler for setting annotation");
+ gLastBookmarkAction = "";
+ testBookmark.annotations.set("testing/bookmark/double", 3.333, 0);
+ ok(testBookmark.annotations.has("testing/bookmark/double"), "Checking existence of added double annotation");
+ is(testBookmark.annotations.get("testing/bookmark/double"), 3.333, "Checking value of added double annotation");
+ is(gLastBookmarkAction, "testing/bookmark/double", "Check event handler for setting annotation");
+ gLastBookmarkAction = "";
+
+ // test names array - NOTE: "bookmarkProperties/description" is an annotation too
+ var names = testBookmark.annotations.names;
+ is(names[1], "testing/bookmark/string", "Checking contents of annotation names array");
+ is(names.length, 4, "Checking the annotation names array after adding 3 annotations");
+
+ // test adding a separator
+ var testSeparator = testFolder.addSeparator();
+ ok(testSeparator, "Check bookmark creation");
+ ok(testSeparator.parent, "Check parent after separator creation");
+ is(gLastFolderAction, "addchild", "Check event handler for adding a child separator to a folder");
+ is(testSeparator.type, "separator", "Check 'bookmark.type' after separator creation");
+
+ is(testFolder.children.length, 2, "Check test folder child count after adding a child separator");
+
+ // test removing separator
+ testSeparator.events.addListener("remove", onBookmarkRemove);
+ testSeparator.remove();
+ is(gLastBookmarkAction, "remove", "Check event handler for removing separator");
+ is(gLastFolderAction, "removechild", "Check event handler for removing a child separator from a folder");
+ is(testFolder.children.length, 1, "Check test folder child count after removing a child separator");
+
+ // test removing bookmark
+ testBookmark.events.addListener("remove", onBookmarkRemove);
+ testBookmark.remove();
+ is(gLastBookmarkAction, "remove", "Check event handler for removing bookmark");
+ is(gLastFolderAction, "removechild", "Check event handler for removing a child from a folder");
+ is(testFolder.children.length, 0, "Check test folder child count after removing a child bookmark");
+
+ // test removing a folder
+ testFolder.events.addListener("remove", onFolderRemove);
+ testFolder.remove();
+ is(gLastFolderAction, "remove", "Check event handler for removing child folder");
+ rootKidCount--;
+ is(root.children.length, rootKidCount, "Check root folder child count after removing a child folder");
+
+ // test moving between folders
+ var testFolderA = root.addFolder("folder-a");
+ var testFolderB = root.addFolder("folder-b");
+
+ var testMove = testFolderA.addBookmark("Mozilla", url("http://www.mozilla.com/"));
+ testMove.events.addListener("move", onBookmarkMove);
+ is(testMove.parent.title, "folder-a", "Checking for new parent before moving bookmark");
+
+ testMove.parent = testFolderB;
+ is(testMove.parent.title, "folder-b", "Checking for new parent after moving bookmark");
+ is(gLastBookmarkAction, "move", "Checking for event handler after moving bookmark");
+
+ // test moving a folder
+ testFolderA.events.addListener("move", onFolderMove);
+ testFolderA.parent = testFolderB;
+ is(testFolderA.parent.title, "folder-b", "Checking for new parent after moving folder");
+ is(gLastFolderAction, "move", "Checking for event handler after moving folder");
+}
+
+function onFolderChange(evt) {
+ gLastFolderAction = evt.data;
+}
+
+function onFolderRemove(evt) {
+ gLastFolderAction = evt.type;
+}
+
+function onFolderAddChild(evt) {
+ gLastFolderAction = evt.type;
+}
+
+function onFolderRemoveChild(evt) {
+ gLastFolderAction = evt.type;
+}
+
+function onFolderMove(evt) {
+ gLastFolderAction = evt.type;
+}
+
+function onBookmarkChange(evt) {
+ gLastBookmarkAction = evt.data;
+}
+
+function onBookmarkRemove(evt) {
+ gLastBookmarkAction = evt.type;
+}
+
+function onBookmarkMove(evt) {
+ gLastBookmarkAction = evt.type;
+}
+
+]]>
+</script>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_Browser.xul
@@ -0,0 +1,110 @@
+<?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="Testing Browser"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" />
+
+<script type="application/javascript">
+<![CDATA[
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+test_Browser();
+
+function url(spec) {
+ var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ return ios.newURI(spec, null, null);
+}
+
+var gTabOpenCount = 0;
+var gTabCloseCount = 0;
+var gTabMoveCount = 0;
+
+function test_Browser() {
+ var windows = Application.windows;
+ ok(windows, "Check access to browser windows");
+ ok(windows.length, "There should be at least one browser window open");
+
+ var activeWin = Application.activeWindow;
+ activeWin.events.addListener("TabOpen", onTabOpen);
+ activeWin.events.addListener("TabClose", onTabClose);
+ activeWin.events.addListener("TabMove", onTabMove);
+
+ var pageA = activeWin.open(url("chrome://mochikit/content/chrome/browser/fuel/test/test_ContentA.html"));
+ var pageB = activeWin.open(url("chrome://mochikit/content/chrome/browser/fuel/test/test_ContentB.html"));
+ pageB.focus();
+
+ is(activeWin.tabs.length, 3, "Checking length of 'Browser.tabs' after opening 2 additional tabs");
+ is(activeWin.activeTab.index, pageB.index, "Checking 'Browser.activeTab' after setting focus");
+
+ SimpleTest.waitForExplicitFinish();
+ setTimeout(afterOpen, 1000);
+
+ // need to wait for the url's to be refreshed during the load
+ function afterOpen() {
+ is(pageA.uri.spec, "chrome://mochikit/content/chrome/browser/fuel/test/test_ContentA.html", "Checking 'BrowserTab.uri' after opening");
+ is(pageB.uri.spec, "chrome://mochikit/content/chrome/browser/fuel/test/test_ContentB.html", "Checking 'BrowserTab.uri' after opening");
+
+ // check event
+ todo_is(gTabOpenCount, 2, "Checking event handler for tab open");
+
+ // test document access
+ var test1 = pageA.document.getElementById("test1");
+ ok(test1, "Checking existence of element in content DOM");
+ is(test1.innerHTML, "A", "Checking content of element in content DOM");
+
+ // test moving tab
+ pageA.moveToEnd();
+ is(pageA.index, 2, "Checking index after moving tab");
+
+ // check event
+ is(gTabMoveCount, 1, "Checking event handler for tab move");
+
+ // test loading new content into a tab
+ // the event will be checked in afterClose
+ pageA.events.addListener("load", onPageLoad);
+ pageA.load(pageB.uri);
+ }
+
+ function onPageLoad(event) {
+ is(pageA.uri.spec, "chrome://mochikit/content/chrome/browser/fuel/test/test_ContentB.html", "Checking 'BrowserTab.uri' after loading new content");
+
+ // start testing closing tabs
+ pageA.close();
+ pageB.close();
+ setTimeout(afterClose, 1000);
+ }
+
+ function afterClose() {
+ // check event
+ is(gTabCloseCount, 2, "Checking event handler for tab close");
+
+ is(activeWin.tabs.length, 1, "Checking length of 'Browser.tabs' after closing 2 tabs");
+
+ SimpleTest.finish();
+ }
+}
+
+function onTabOpen(event) {
+ gTabOpenCount++;
+}
+
+function onTabClose(event) {
+ gTabCloseCount++;
+}
+
+function onTabMove(event) {
+ gTabMoveCount++;
+}
+
+]]>
+</script>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_ContentA.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" >
+<head>
+ <title>Content Page A</title>
+</head>
+<body>
+<h1>Content Page A</h1>
+<div id="desc">This is a simple content page used for testing FUEL Browser API</div>
+<div id="test1">A</div>
+<div id="test2">B</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_ContentB.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" >
+<head>
+ <title>Content Page B</title>
+</head>
+<body>
+<h1>Content Page B</h1>
+<div id="desc">This is a simple content page used for testing FUEL Browser API</div>
+<div id="test1">1</div>
+<div id="test2">2</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/fuel/test/test_Extensions.xul
@@ -0,0 +1,54 @@
+<?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="Testing Extensions"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" />
+
+<script type="application/javascript">
+<![CDATA[
+
+// The various pieces that we'll be testing
+var test = {
+ dummyid: "fuel-dummy-extension@mozilla.org",
+ dummyname: "Dummy Extension",
+ inspectorid: "inspector@mozilla.org",
+ inspectorname: "DOM Inspector"
+};
+
+test_Extensions();
+
+function test_Extensions() {
+ // test to see if a non-existant extension exists
+ ok(!Application.extensions.has(test.dummyid), "Check non-existant extension for existance");
+
+ // test to see if an extension exists
+ ok(Application.extensions.has(test.inspectorid), "Check extension for existance");
+
+ var inspector = Application.extensions.get(test.inspectorid);
+ is(inspector.id, test.inspectorid, "Check 'Extension.id' for known extension");
+ is(inspector.name, test.inspectorname, "Check 'Extension.name' for known extension");
+ // The known version number changes too frequently to hardcode in
+ ok(inspector.version, "Check 'Extension.version' for known extension");
+ ok(inspector.firstRun, "Check 'Extension.firstRun' for known extension");
+
+ // test to see if extension find works
+ is(Application.extensions.all.length, 1, "Check a find for all extensions");
+
+ // test the value of the preference root
+ is(Application.extensions.all[0].prefs.root, "extensions.inspector@mozilla.org.", "Check an extension preference root");
+
+ // Reset the install event preference, so that we can test it again later
+ inspector.prefs.get("install-event-fired").reset();
+}
+
+]]>
+</script>
+
+</window>