--- a/suite/Makefile.in
+++ b/suite/Makefile.in
@@ -57,16 +57,17 @@ PARALLEL_DIRS += \
feeds/src \
locales \
modules \
themes/classic \
themes/modern \
profile \
security \
shell/public \
+ smile \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
PARALLEL_DIRS += shell/src
ifdef MOZ_INSTALLER
PARALLEL_DIRS += installer/windows
endif
endif
--- a/suite/installer/unix/packages
+++ b/suite/installer/unix/packages
@@ -216,16 +216,17 @@ bin/components/pref.xpt
bin/components/prefetch.xpt
bin/components/profile.xpt
bin/components/proxyObjInst.xpt
bin/components/rdf.xpt
bin/components/satchel.xpt
bin/components/saxparser.xpt
bin/components/shistory.xpt
bin/components/shellservice.xpt
+bin/components/smile.xpt
bin/components/spellchecker.xpt
bin/components/storage.xpt
bin/components/suitebrowser.xpt
bin/components/suitecommon.xpt
bin/components/suitefeeds.xpt
bin/components/suitemigration.xpt
bin/components/toolkitprofile.xpt
bin/components/toolkitremote.xpt
@@ -293,16 +294,17 @@ bin/components/nsSuiteDownloadManagerUI.
bin/components/nsSuiteGlue.js
bin/components/nsTaggingService.js
bin/components/nsTypeAheadFind.js
bin/components/nsTryToClose.js
bin/components/nsUpdateService.js
bin/components/nsURLFormatter.js
bin/components/nsWebHandlerApp.js
bin/components/pluginGlue.js
+bin/components/smileApplication.js
bin/components/storage-Legacy.js
bin/components/storage-mozStorage.js
bin/components/txEXSLTRegExFunctions.js
bin/components/WebContentConverter.js
; Modules
bin/modules/*
--- a/suite/installer/windows/packages
+++ b/suite/installer/windows/packages
@@ -216,16 +216,17 @@ bin\components\pref.xpt
bin\components\prefetch.xpt
bin\components\profile.xpt
bin\components\proxyObject.xpt
bin\components\rdf.xpt
bin\components\satchel.xpt
bin\components\saxparser.xpt
bin\components\shellservice.xpt
bin\components\shistory.xpt
+bin\components\smile.xpt
bin\components\spellchecker.xpt
bin\components\storage.xpt
bin\components\suitebrowser.xpt
bin\components\suitecommon.xpt
bin\components\suitefeeds.xpt
bin\components\suitemigration.xpt
bin\components\toolkitprofile.xpt
bin\components\txmgr.xpt
@@ -296,16 +297,17 @@ bin\components\nsSuiteDownloadManagerUI.
bin\components\nsSuiteGlue.js
bin\components\nsTaggingService.js
bin\components\nsTypeAheadFind.js
bin\components\nsTryToClose.js
bin\components\nsUpdateService.js
bin\components\nsURLFormatter.js
bin\components\nsWebHandlerApp.js
bin\components\pluginGlue.js
+bin\components\smileApplication.js
bin\components\storage-Legacy.js
bin\components\storage-mozStorage.js
bin\components\txEXSLTRegExFunctions.js
bin\components\WebContentConverter.js
; Modules
bin\modules\*
--- a/suite/makefiles.sh
+++ b/suite/makefiles.sh
@@ -58,12 +58,13 @@ add_makefiles "
suite/mailnews/Makefile
suite/modules/Makefile
suite/modules/test/Makefile
suite/profile/Makefile
suite/profile/migration/public/Makefile
suite/profile/migration/src/Makefile
suite/shell/public/Makefile
suite/shell/src/Makefile
+ suite/smile/Makefile
suite/themes/modern/Makefile
suite/themes/classic/Makefile
"
fi
new file mode 100644
--- /dev/null
+++ b/suite/smile/Makefile.in
@@ -0,0 +1,50 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is SMILE.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2006
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Jorge Villalobos <jorge.villalobos@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# 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 *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+PARALLEL_DIRS = public src
+
+ifdef ENABLE_TESTS
+PARALLEL_DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/suite/smile/public/Makefile.in
@@ -0,0 +1,49 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is SMILE.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2006
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Jorge Villalobos <jorge.villalobos@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# 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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = smile
+XPIDL_MODULE = smile
+
+XPIDLSRCS = smileIApplication.idl
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/suite/smile/public/smileIApplication.idl
@@ -0,0 +1,167 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FUEL.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mark Finkle <mfinkle@mozilla.com> (Original Author)
+ * John Resig <jresig@mozilla.com> (Original Author)
+ * Jorge Villalobos <jorge.villalobos@gmail.com> (SeaMonkey port)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * 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 ***** */
+
+#include "nsISupports.idl"
+#include "extIApplication.idl"
+
+interface nsIVariant;
+interface nsIURI;
+interface nsIDOMHTMLDocument;
+
+interface smileIBrowserTab;
+
+/**
+ * Interface representing a container for bookmark roots. Roots
+ * are the top level parents for the various types of bookmarks in the system.
+ * Empty as it is only used as the return type for Application.bookmarks. It
+ * will be supported once the Places bookmarks API is supported in SeaMonkey.
+ */
+[scriptable, uuid(1102eec4-f66b-4082-abad-c967ad7d5f76)]
+interface smileIBookmarkRoots : nsISupports
+{
+};
+
+/**
+ * Interface representing a browser window.
+ */
+[scriptable, uuid(1c3002ec-5aaf-4232-ab7d-835a348133fd)]
+interface smileIWindow : nsISupports
+{
+ /**
+ * A collection of browser tabs within the browser window.
+ */
+ readonly attribute nsIVariant tabs;
+
+ /**
+ * The currently-active tab within the browser window.
+ */
+ readonly attribute smileIBrowserTab activeTab;
+
+ /**
+ * Open a new browser tab, pointing to the specified URI.
+ * @param aURI
+ * The uri to open the browser tab to
+ */
+ smileIBrowserTab open(in nsIURI aURI);
+
+ /**
+ * The events object for the browser window.
+ * supports: "TabOpen", "TabClose", "TabMove", "TabSelect"
+ */
+ readonly attribute extIEvents events;
+};
+
+/**
+ * Interface representing a browser tab.
+ */
+[scriptable, uuid(9b06c55e-5377-4c71-8bda-8e8750c5a02a)]
+interface smileIBrowserTab : 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 smileIWindow window;
+
+ /**
+ * The content document of the browser tab.
+ */
+ readonly attribute nsIDOMHTMLDocument document;
+
+ /**
+ * The events object for the browser tab.
+ * supports: "load"
+ */
+ readonly attribute extIEvents 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 smileIBrowserTab aBefore);
+
+ /**
+ * Move this browser tab to the last tab within the window.
+ */
+ void moveToEnd();
+};
+
+/**
+ * Interface for managing and accessing the applications systems
+ */
+[scriptable, uuid(c9ba8f65-c936-4ac6-a859-8936832b0c12)]
+interface smileIApplication : extIApplication
+{
+ /**
+ * An array of browser windows within the application.
+ */
+ readonly attribute nsIVariant windows;
+
+ /**
+ * The currently active browser window.
+ */
+ readonly attribute smileIWindow activeWindow;
+};
new file mode 100644
--- /dev/null
+++ b/suite/smile/src/Makefile.in
@@ -0,0 +1,48 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is SMILE.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2006
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Jorge Villalobos <jorge.villalobos@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# 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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = smile
+
+EXTRA_PP_COMPONENTS = smileApplication.js
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/suite/smile/src/smileApplication.js
@@ -0,0 +1,386 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FUEL.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mark Finkle <mfinkle@mozilla.com> (Original Author)
+ * John Resig <jresig@mozilla.com> (Original Author)
+ * Jorge Villalobos <jorge.villalobos@gmail.com> (SeaMonkey port)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * 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 Ci = Components.interfaces;
+const Cc = Components.classes;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+//=================================================
+// Singleton that holds services and utilities
+var Utilities = {
+ _bookmarks : null,
+ get bookmarks() {
+ if (!this._bookmarks) {
+ this._bookmarks =
+ Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"]
+ .getService(Components.interfaces.nsINavBookmarksService);
+ }
+ return this._bookmarks;
+ },
+
+ _livemarks : null,
+ get livemarks() {
+ if (!this._livemarks) {
+ this._livemarks =
+ Components.classes["@mozilla.org/browser/livemark-service;2"]
+ .getService(Components.interfaces.nsILivemarkService);
+ }
+ return this._livemarks;
+ },
+
+ _annotations : null,
+ get annotations() {
+ if (!this._annotations) {
+ this._annotations =
+ Components.classes["@mozilla.org/browser/annotation-service;1"]
+ .getService(Components.interfaces.nsIAnnotationService);
+ }
+ return this._annotations;
+ },
+
+ _history : null,
+ get history() {
+ if (!this._history) {
+ this._history =
+ Components.classes["@mozilla.org/browser/nav-history-service;1"]
+ .getService(Components.interfaces.nsINavHistoryService);
+ }
+ return this._history;
+ },
+
+ _windowMediator : null,
+ get windowMediator() {
+ if (!this._windowMediator) {
+ this._windowMediator =
+ Components.classes["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Components.interfaces.nsIWindowMediator);
+ }
+ return this._windowMediator;
+ },
+
+ makeURI : function(aSpec) {
+ if (!aSpec)
+ return null;
+ var ios = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.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 win_watch(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 win_event(aEvent) {
+ this._events.dispatch(aEvent.type, new BrowserTab(this, aEvent.originalTarget));
+ },
+
+ get tabs() {
+ var tabs = [];
+ var mTabs = this._tabbrowser.mTabs;
+ for (var i = 0; i < mTabs.length; i++)
+ tabs.push(new BrowserTab(this, mTabs[i]));
+ return tabs;
+ },
+
+ get activeTab() {
+ return new BrowserTab(this, this._tabbrowser.selectedTab);
+ },
+
+ open : function win_open(aURI) {
+ return new BrowserTab(this, this._tabbrowser.addTab(aURI.spec));
+ },
+
+ _shutdown : function win_shutdown() {
+ for (var type in this._cleanup)
+ this._tabbrowser.removeEventListener(type, this._cleanup[type], true);
+ this._cleanup = null;
+
+ this._window = null;
+ this._tabbrowser = null;
+ this._events = null;
+ },
+
+ QueryInterface : XPCOMUtils.generateQI([Components.interfaces.smileIWindow])
+};
+
+
+//=================================================
+// BrowserTab implementation
+function BrowserTab(aSMILEWindow, aTab) {
+ this._window = aSMILEWindow;
+ this._tabbrowser = aSMILEWindow._tabbrowser;
+ this._browser = aTab.linkedBrowser;
+ this._tab = aTab;
+ 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() {
+ try {
+ return this._tabbrowser.getTabIndex(this._tab);
+ }
+ catch (e) {
+ 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 bt_watch(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 bt_event(aEvent) {
+ if (aEvent.type == "load") {
+ if (!(aEvent.originalTarget instanceof Components.interfaces.nsIDOMDocument))
+ return;
+
+ if (aEvent.originalTarget.defaultView instanceof Components.interfaces.nsIDOMWindowInternal &&
+ aEvent.originalTarget.defaultView.frameElement)
+ return;
+ }
+ this._events.dispatch(aEvent.type, this);
+ },
+
+ load : function bt_load(aURI) {
+ this._browser.loadURI(aURI.spec, null, null);
+ },
+
+ focus : function bt_focus() {
+ this._tabbrowser.selectedTab = this._tab;
+ this._tabbrowser.focus();
+ },
+
+ close : function bt_close() {
+ this._tabbrowser.removeTab(this._tab);
+ },
+
+ moveBefore : function bt_movebefore(aBefore) {
+ this._tabbrowser.moveTabTo(this._tab, aBefore.index);
+ },
+
+ moveToEnd : function bt_moveend() {
+ this._tabbrowser.moveTabTo(this._tab, this._tabbrowser.browsers.length);
+ },
+
+ _shutdown : function bt_shutdown() {
+ for (var type in this._cleanup)
+ this._browser.removeEventListener(type, this._cleanup[type], true);
+ this._cleanup = null;
+
+ this._window = null;
+ this._tabbrowser = null;
+ this._browser = null;
+ this._tab = null;
+ this._events = null;
+ },
+
+ QueryInterface : XPCOMUtils.generateQI([Components.interfaces.smileIBrowserTab])
+};
+
+
+//=================================================
+// Factory - Treat Application as a singleton
+// XXX This is required, because we're registered for the 'JavaScript global
+// privileged property' category, whose handler always calls createInstance.
+// See bug 386535.
+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);
+ }
+};
+
+
+
+//=================================================
+// Application constructor
+function Application() {
+ this.initToolkitHelpers();
+ this._bookmarks = null;
+}
+
+//=================================================
+// Application implementation
+Application.prototype = {
+ // for nsIClassInfo + XPCOMUtils
+ classDescription: "Application",
+ classID: Components.ID("c9ba8f65-c936-4ac6-a859-8936832b0c12"),
+ contractID: "@mozilla.org/smile/application;1",
+
+ // redefine the default factory for XPCOMUtils
+ _xpcom_factory: ApplicationFactory,
+
+ // for nsISupports
+ QueryInterface : XPCOMUtils.generateQI(
+ [Components.interfaces.smileIApplication,
+ Components.interfaces.extIApplication,
+ Components.interfaces.nsIObserver,
+ Components.interfaces.nsIClassInfo]),
+
+ getInterfaces : function app_gi(aCount) {
+ var interfaces = [Components.interfaces.smileIApplication,
+ Components.interfaces.extIApplication,
+ Components.interfaces.nsIObserver,
+ Components.interfaces.nsIClassInfo];
+ aCount.value = interfaces.length;
+ return interfaces;
+ },
+
+ // for nsIObserver
+ observe: function app_observe(aSubject, aTopic, aData) {
+ // Call the extApplication version of this function first
+ this.__proto__.__proto__.observe.call(this, aSubject, aTopic, aData);
+ if (aTopic == "xpcom-shutdown") {
+ this._bookmarks = null;
+ Utilities.free();
+ }
+ },
+
+ /*
+ Uncomment once Places Bookmarks migration is complete.
+ get bookmarks() {
+
+ if (this._bookmarks == null)
+ this._bookmarks = new BookmarkRoots();
+
+ 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"));
+ }
+};
+
+//module initialization
+function NSGetModule(aCompMgr, aFileSpec) {
+ // set the proto, defined in extApplication.js
+ Application.prototype.__proto__ = extApplication.prototype;
+ return XPCOMUtils.generateModule([Application]);
+}
+
+#include ../../../mozilla/toolkit/components/exthelper/extApplication.js
new file mode 100644
--- /dev/null
+++ b/suite/smile/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 SMILE Browser API</div>
+<div id="test1">A</div>
+<div id="test2">B</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/suite/smile/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 SMILE Browser API</div>
+<div id="test1">1</div>
+<div id="test2">2</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/ContentWithFrames.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 with Frames</title>
+</head>
+<body>
+<h1>Content Page with Frames</h1>
+<div id="desc">This is a simple framed content page used for testing SMILE Browser API</div>
+<iframe src="ContentA.html"></iframe>
+<iframe src="ContentB.html"></iframe>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/Makefile.in
@@ -0,0 +1,60 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is SMILE.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2006
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Mark Finkle <mfinkle@mozilla.com>
+# John Resig <jresig@mozilla.com>
+# Jorge Villalobos <jorge.villalobos@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# 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 *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = suite/smile/test
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_BROWSER_FILES =browser_Application.js \
+ browser_ApplicationPrefs.js \
+ browser_ApplicationStorage.js \
+ browser_ApplicationQuitting.js \
+ browser_Browser.js \
+ browser_Extensions.js \
+ ContentA.html \
+ ContentB.html \
+ ContentWithFrames.html \
+ $(NULL)
+
+libs:: $(_BROWSER_FILES)
+ $(INSTALL) $(foreach f,$^,"$f") $(MOZDEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/browser_Application.js
@@ -0,0 +1,86 @@
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+// This listens for the next opened window and checks it is of the right url.
+// opencallback is called when the new window is fully loaded
+// closecallback is called when the window is closed
+function WindowOpenListener(url, opencallback, closecallback) {
+ this.url = url;
+ this.opencallback = opencallback;
+ this.closecallback = closecallback;
+
+ var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
+ getService(Ci.nsIWindowMediator);
+ wm.addListener(this);
+}
+
+WindowOpenListener.prototype = {
+ url: null,
+ opencallback: null,
+ closecallback: null,
+ window: null,
+ domwindow: null,
+
+ handleEvent: function(event) {
+ is(this.domwindow.document.location.href, this.url, "Should have opened the correct window");
+
+ this.domwindow.removeEventListener("load", this, false);
+ // Allow any other load handlers to execute
+ var self = this;
+ executeSoon(function() { self.opencallback(self.domwindow); } );
+ },
+
+ onWindowTitleChange: function(window, title) {
+ },
+
+ onOpenWindow: function(window) {
+ if (this.window)
+ return;
+
+ this.window = window;
+ this.domwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowInternal);
+ this.domwindow.addEventListener("load", this, false);
+ },
+
+ onCloseWindow: function(window) {
+ if (this.window != window)
+ return;
+
+ var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
+ getService(Ci.nsIWindowMediator);
+ wm.removeListener(this);
+ this.opencallback = null;
+ this.window = null;
+ this.domwindow = null;
+
+ // Let the window close complete
+ executeSoon(this.closecallback);
+ this.closecallback = null;
+ }
+};
+
+function test() {
+ 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");
+
+ var wMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ var console = wMediator.getMostRecentWindow("global:console");
+ waitForExplicitFinish();
+ ok(!console, "Console should not already be open");
+
+ new WindowOpenListener("chrome://global/content/console.xul", consoleOpened, consoleClosed);
+ Application.console.open();
+}
+
+function consoleOpened(win) {
+ win.close();
+}
+
+function consoleClosed() {
+ finish();
+}
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/browser_ApplicationPrefs.js
@@ -0,0 +1,170 @@
+// The various properties that we'll be testing
+var testdata = {
+ missing: "smile.smile-test-missing",
+ dummy: "smile.smile-test",
+ string: "browser.active_color",
+ integer: "permissions.default.image",
+ boolean: "browser.blink_allowed"
+};
+
+function test() {
+ // test getting non-existing values
+ var itemValue = Application.prefs.getValue(testdata.missing, "default");
+ is(itemValue, "default", "Check 'Application.prefs.getValue' for non-existing item");
+
+ is(Application.prefs.get(testdata.missing), null, "Check 'Application.prefs.get' for non-existing item");
+
+ // test setting and getting a value
+ Application.prefs.setValue(testdata.dummy, "dummy");
+ itemValue = Application.prefs.getValue(testdata.dummy, "default");
+ is(itemValue, "dummy", "Check 'Application.prefs.getValue' for existing item");
+
+ // test for overwriting an existing value
+ Application.prefs.setValue(testdata.dummy, "smarty");
+ itemValue = Application.prefs.getValue(testdata.dummy, "default");
+ is(itemValue, "smarty", "Check 'Application.prefs.getValue' for overwritten item");
+
+ // test setting and getting a value
+ Application.prefs.get(testdata.dummy).value = "dummy2";
+ itemValue = Application.prefs.get(testdata.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(testdata.dummy).reset();
+ itemValue = Application.prefs.getValue(testdata.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(testdata.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(testdata.string), "Check existing string property for existance");
+
+ // test accessing a non-existant string property
+ var val = Application.prefs.getValue(testdata.dummy, "default");
+ is(val, "default", "Check non-existant string property for expected value");
+
+ // test accessing an existing string property
+ var val = Application.prefs.getValue(testdata.string, "default");
+ is(val, "#EE0000", "Check existing string property for expected value");
+
+ // test manipulating an existing string property
+ Application.prefs.setValue(testdata.string, "#EF0000");
+ var val = Application.prefs.getValue(testdata.string, "default");
+ is(val, "#EF0000", "Set existing string property");
+
+ // test getting the type of an existing string property
+ var type = Application.prefs.get(testdata.string).type;
+ is(type, "String", "Check 'Application.prefs.get().type' for string pref");
+
+ // test resetting an existing string property
+ Application.prefs.get(testdata.string).reset();
+ var val = Application.prefs.getValue(testdata.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(testdata.integer), "Check existing integer property for existance");
+
+ // test accessing a non-existant integer property
+ var val = Application.prefs.getValue(testdata.dummy, 0);
+ is(val, 0, "Check non-existant integer property for expected value");
+
+ // test accessing an existing integer property
+ var val = Application.prefs.getValue(testdata.integer, 0);
+ is(val, 1, "Check existing integer property for expected value");
+
+ // test manipulating an existing integer property
+ Application.prefs.setValue(testdata.integer, 0);
+ var val = Application.prefs.getValue(testdata.integer, 1);
+ is(val, 0, "Set existing integer property");
+
+ // test getting the type of an existing integer property
+ var type = Application.prefs.get(testdata.integer).type;
+ is(type, "Number", "Check 'Application.prefs.get().type' for integer pref");
+
+ // test resetting an existing integer property
+ Application.prefs.get(testdata.integer).reset();
+ var val = Application.prefs.getValue(testdata.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(testdata.boolean), "Check existing boolean property for existance");
+
+ // test accessing a non-existant boolean property
+ var val = Application.prefs.getValue(testdata.dummy, true);
+ ok(val, "Check non-existant boolean property for expected value");
+
+ // test accessing an existing boolean property
+ var val = Application.prefs.getValue(testdata.boolean, false);
+ ok(val, "Check existing boolean property for expected value");
+
+ // test manipulating an existing boolean property
+ Application.prefs.setValue(testdata.boolean, false);
+ var val = Application.prefs.getValue(testdata.boolean, true);
+ ok(!val, "Set existing boolean property");
+
+ // test getting the type of an existing boolean property
+ var type = Application.prefs.get(testdata.boolean).type;
+ is(type, "Boolean", "Check 'Application.prefs.get().type' for boolean pref");
+
+ // test resetting an existing boolean property
+ Application.prefs.get(testdata.boolean).reset();
+ var val = Application.prefs.getValue(testdata.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");
+ ok(allPrefs[0].name.length > 0, "Check 'Application.prefs.all' for a valid name in the 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(testdata.string).modified, "A single preference is marked as not modified.");
+
+ // test for a locked preference
+ var pref = Application.prefs.get(testdata.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
+ waitForExplicitFinish();
+ Application.prefs.events.addListener("change", onPrefChange);
+ Application.prefs.setValue("smile.smile-test", "change event");
+}
+
+function onPrefChange(evt) {
+ is(evt.data, testdata.dummy, "Check 'Application.prefs.set' fired a change event");
+ Application.prefs.events.removeListener("change", onPrefChange);
+
+ Application.prefs.get("smile.smile-test").events.addListener("change", onPrefChange2);
+ Application.prefs.setValue("smile.smile-test", "change event2");
+}
+
+function onPrefChange2(evt) {
+ is(evt.data, testdata.dummy, "Check 'Application.prefs.set' fired a change event for a single preference");
+ Application.prefs.events.removeListener("change", onPrefChange2);
+
+ finish();
+}
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/browser_ApplicationQuitting.js
@@ -0,0 +1,21 @@
+function test() {
+ let quitRequestObserver = {
+ observe: function(aSubject, aTopic, aData) {
+ ok(aTopic == "quit-application-requested" &&
+ aSubject instanceof Components.interfaces.nsISupportsPRBool,
+ "Received a quit request we're going to deny");
+ aSubject.data = true;
+ }
+ };
+
+ // ensure that we don't accidentally quit
+ let os = Components.classes["@mozilla.org/observer-service;1"]
+ .getService(Components.interfaces.nsIObserverService);
+ os.addObserver(quitRequestObserver, "quit-application-requested", false);
+
+ ok(!Application.quit(), "Tried to quit - and didn't succeed");
+ ok(!Application.restart(), "Tried to restart - and didn't succeed");
+
+ // clean up
+ os.removeObserver(quitRequestObserver, "quit-application-requested", false);
+}
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/browser_ApplicationStorage.js
@@ -0,0 +1,30 @@
+function test() {
+ // test for existence of values
+ var hasItem = Application.storage.has("smile-test-missing");
+ is(hasItem, false, "Check 'Application.storage.has' for non-existing item");
+ Application.storage.set("smile-test", "dummy");
+ hasItem = Application.storage.has("smile-test");
+ is(hasItem, true, "Check 'Application.storage.has' for existing item");
+
+ // test getting non-existing and existing values
+ var itemValue = Application.storage.get("smile-test-missing", "default");
+ is(itemValue, "default", "Check 'Application.storage.get' for non-existing item");
+ itemValue = Application.storage.get("smile-test", "default");
+ is(itemValue, "dummy", "Check 'Application.storage.get' for existing item");
+
+ // test for overwriting an existing value
+ Application.storage.set("smile-test", "smarty");
+ itemValue = Application.storage.get("smile-test", "default");
+ is(itemValue, "smarty", "Check 'Application.storage.get' for overwritten item");
+
+ // check for change event when setting a value
+ waitForExplicitFinish();
+ Application.storage.events.addListener("change", onStorageChange);
+ Application.storage.set("smile-test", "change event");
+}
+
+function onStorageChange(evt) {
+ is(evt.data, "smile-test", "Check 'Application.storage.set' fired a change event");
+ Application.storage.events.removeListener("change", onStorageChange);
+ finish();
+}
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/browser_Browser.js
@@ -0,0 +1,159 @@
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+function url(spec) {
+ var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ return ios.newURI(spec, null, null);
+}
+
+var gPageA = null;
+var gPageB = null;
+
+// cached data from events
+var gTabOpenPageA = null;
+var gTabOpenPageB = null;
+var gTabOpenCount = 0;
+var gTabCloseCount = 0;
+var gTabMoveCount = 0;
+var gPageLoadCount = 0;
+
+function test() {
+ 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);
+
+ gPageA = activeWin.open(url("chrome://mochikit/content/browser/suite/smile/test/ContentA.html"));
+ gPageA.events.addListener("load", onPageAFirstLoad);
+
+ is(activeWin.tabs.length, 2, "Checking length of 'Browser.tabs' after opening 1 additional tab");
+
+ waitForExplicitFinish();
+
+ function execAfterOpen() {
+ executeSoon(afterOpen);
+ }
+
+ function onPageAFirstLoad(event) {
+ gPageA.events.removeListener("load", onPageAFirstLoad);
+ is(gPageA.uri.spec, event.data.uri.spec, "Checking event browser tab is equal to page A");
+
+ gPageB = activeWin.open(url("chrome://mochikit/content/browser/suite/smile/test/ContentB.html"));
+ gPageB.events.addListener("load", execAfterOpen);
+ gPageB.focus();
+
+ is(activeWin.tabs.length, 3, "Checking length of 'Browser.tabs' after opening a second additional tab");
+ is(activeWin.activeTab.index, gPageB.index, "Checking 'Browser.activeTab' after setting focus");
+ }
+
+ // need to wait for the url's to be refreshed during the load
+ function afterOpen(event) {
+ gPageB.events.removeListener("load", execAfterOpen);
+ // check actuals
+ is(gPageA.uri.spec, "chrome://mochikit/content/browser/suite/smile/test/ContentA.html", "Checking 'BrowserTab.uri' after opening");
+ is(gPageB.uri.spec, "chrome://mochikit/content/browser/suite/smile/test/ContentB.html", "Checking 'BrowserTab.uri' after opening");
+
+ // check cached values from TabOpen event
+ is(gPageA.uri.spec, gTabOpenPageA.uri.spec, "Checking first browser tab open is equal to page A");
+ is(gPageB.uri.spec, gTabOpenPageB.uri.spec, "Checking second browser tab open is equal to page B");
+ // check event
+ is(gTabOpenCount, 2, "Checking event handler for tab open");
+
+ // test document access
+ var test1 = gPageA.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
+ gPageA.moveToEnd();
+ is(gPageA.index, 2, "Checking index after moving tab");
+
+ // check event
+ is(gTabMoveCount, 1, "Checking event handler for tab move");
+
+ let browser = gBrowser.getBrowserAtIndex(gPageB.index);
+ browser.addProgressListener({
+ onStateChange: function(webProgress, request, stateFlags, status) {
+ const complete = Ci.nsIWebProgressListener.STATE_IS_WINDOW +
+ Ci.nsIWebProgressListener.STATE_IS_NETWORK +
+ Ci.nsIWebProgressListener.STATE_STOP;
+ if ((stateFlags & complete) == complete) {
+ browser.removeProgressListener(this);
+ onPageBLoadComplete();
+ }
+ },
+
+ onLocationChange: function() { return 0; },
+ onProgressChange: function() { return 0; },
+ onStatusChange: function() { return 0; },
+ onSecurityChange: function() { return 0; },
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsISupportsWeakReference) ||
+ iid.equals(Ci.nsIWebProgressListener) ||
+ iid.equals(Ci.nsISupports))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ }
+ });
+
+ // test loading new content with a frame into a tab
+ // the event will be checked in afterClose
+ gPageB.events.addListener("load", onPageBLoadWithFrames);
+ gPageB.load(url("chrome://mochikit/content/browser/suite/smile/test/ContentWithFrames.html"));
+ }
+
+ function onPageBLoadWithFrames(event) {
+ gPageLoadCount++;
+ }
+
+ function onPageBLoadComplete() {
+ gPageB.events.removeListener("load", onPageBLoadWithFrames);
+ // check page load with frame event
+ is(gPageLoadCount, 1, "Checking load count after loading new content with a frame");
+
+ // test loading new content into a tab
+ // the event will be checked in onPageLoad
+ gPageA.events.addListener("load", onPageASecondLoad);
+ gPageA.load(url("chrome://mochikit/content/browser/suite/smile/test/ContentB.html"));
+ }
+
+ function onPageASecondLoad(event) {
+ gPageA.events.removeListener("load", onPageASecondLoad);
+ is(gPageA.uri.spec, "chrome://mochikit/content/browser/suite/smile/test/ContentB.html", "Checking 'BrowserTab.uri' after loading new content");
+
+ // start testing closing tabs
+ // the event will be checked in afterClose
+ // use executeSoon so the onPageASecondLoad
+ // has a chance to finish first
+ gPageA.close();
+ gPageB.close();
+
+ is(gTabCloseCount, 2, "Checking that tabs closed");
+ is(activeWin.tabs.length, 1, "Checking length of 'Browser.tabs' after closing 2 tabs");
+ finish();
+ }
+}
+
+function onTabOpen(event) {
+ gTabOpenCount++;
+
+ // cache these values so we can check them later (after loading completes)
+ if (gTabOpenCount == 1)
+ gTabOpenPageA = event.data;
+
+ if (gTabOpenCount == 2)
+ gTabOpenPageB = event.data;
+}
+
+function onTabClose(event) {
+ gTabCloseCount++;
+}
+
+function onTabMove(event) {
+ gTabMoveCount++;
+}
new file mode 100644
--- /dev/null
+++ b/suite/smile/test/browser_Extensions.js
@@ -0,0 +1,126 @@
+// The various pieces that we'll be testing
+var testdata = {
+ dummyid: "smile-dummy-extension@mozilla.org",
+ dummyname: "Dummy Extension",
+ inspectorid: "inspector@mozilla.org",
+ inspectorname: "DOM Inspector",
+ missing: "smile.smile-test-missing",
+ dummy: "smile.smile-test"
+};
+var gLastEvent = "";
+
+function test() {
+ // test to see if the extensions object is available
+ ok(Application.extensions, "Check for the 'Extensions' object");
+
+ // test to see if a non-existant extension exists
+ ok(!Application.extensions.has(testdata.dummyid), "Check non-existant extension for existance");
+
+ // BUG 420028: Must find a way to add a dummy extension for test suite
+ return;
+
+ // test to see if an extension exists
+ ok(Application.extensions.has(testdata.inspectorid), "Check extension for existance");
+
+ var inspector = Application.extensions.get(testdata.inspectorid);
+ is(inspector.id, testdata.inspectorid, "Check 'Extension.id' for known extension");
+ is(inspector.name, testdata.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");
+ ok(inspector.enabled, "Check 'Extension.enabled' for known extension");
+
+ // test to see if extension find works
+ is(Application.extensions.all.length, 1, "Check a find for all extensions");
+ // STORAGE TESTING
+ // Make sure the we are given the same extension (cached) so things like .storage work right
+ inspector.storage.set("test", "simple check");
+ ok(inspector.storage.has("test"), "Checking that extension storage worked");
+
+ var inspector2 = Application.extensions.get(testdata.inspectorid);
+ is(inspector2.id, testdata.inspectorid, "Check 'Extension.id' for known extension - from cache");
+ ok(inspector.storage.has("test"), "Checking that extension storage worked - from cache");
+ is(inspector2.storage.get("test", "cache"), inspector.storage.get("test", "original"), "Checking that the storage of same extension is correct - from cache");
+
+ inspector.events.addListener("disable", onGenericEvent);
+ inspector.events.addListener("enable", onGenericEvent);
+ inspector.events.addListener("uninstall", onGenericEvent);
+ inspector.events.addListener("cancel", onGenericEvent);
+
+ var extmgr = Components.classes["@mozilla.org/extensions/manager;1"]
+ .getService(Components.interfaces.nsIExtensionManager);
+
+ extmgr.disableItem(testdata.inspectorid);
+ is(gLastEvent, "disable", "Checking that disable event is fired");
+
+ // enabling after a disable will only fire a 'cancel' event
+ // see - http://mxr.mozilla.org/seamonkey/source/toolkit/mozapps/extensions/src/nsExtensionManager.js.in#5216
+ extmgr.enableItem(testdata.inspectorid);
+ is(gLastEvent, "cancel", "Checking that enable (cancel) event is fired");
+
+ extmgr.uninstallItem(testdata.inspectorid);
+ is(gLastEvent, "uninstall", "Checking that uninstall event is fired");
+
+ extmgr.cancelUninstallItem(testdata.inspectorid);
+ is(gLastEvent, "cancel", "Checking that cancel event is fired");
+
+ // PREF TESTING
+ // Reset the install event preference, so that we can test it again later
+ inspector.prefs.get("install-event-fired").reset();
+
+ // test the value of the preference root
+ is(Application.extensions.all[0].prefs.root, "extensions.inspector@mozilla.org.", "Check an extension preference root");
+
+ // test getting non-existing values
+ var itemValue = inspector.prefs.getValue(testdata.missing, "default");
+ is(itemValue, "default", "Check 'Extension.prefs.getValue' for non-existing item");
+
+ is(inspector.prefs.get(testdata.missing), null, "Check 'Extension.prefs.get' for non-existing item");
+
+ // test setting and getting a value
+ inspector.prefs.setValue(testdata.dummy, "dummy");
+ itemValue = inspector.prefs.getValue(testdata.dummy, "default");
+ is(itemValue, "dummy", "Check 'Extension.prefs.getValue' for existing item");
+
+ // test for overwriting an existing value
+ inspector.prefs.setValue(testdata.dummy, "smarty");
+ itemValue = inspector.prefs.getValue(testdata.dummy, "default");
+ is(itemValue, "smarty", "Check 'Extension.prefs.getValue' for overwritten item");
+
+ // test setting and getting a value
+ inspector.prefs.get(testdata.dummy).value = "dummy2";
+ itemValue = inspector.prefs.get(testdata.dummy).value;
+ is(itemValue, "dummy2", "Check 'Extension.prefs.get().value' for existing item");
+
+ // test resetting a pref [since there is no default value, the pref should disappear]
+ inspector.prefs.get(testdata.dummy).reset();
+ var itemValue = inspector.prefs.getValue(testdata.dummy, "default");
+ is(itemValue, "default", "Check 'Extension.prefs.getValue' for reset pref");
+
+ // test to see if a non-existant property exists
+ ok(!inspector.prefs.has(testdata.dummy), "Check non-existant property for existance");
+
+ waitForExplicitFinish();
+ inspector.prefs.events.addListener("change", onPrefChange);
+ inspector.prefs.setValue("smile.smile-test", "change event");
+}
+
+function onGenericEvent(event) {
+ gLastEvent = event.type;
+}
+
+function onPrefChange(evt) {
+ var inspector3 = Application.extensions.get(testdata.inspectorid);
+
+ is(evt.data, testdata.dummy, "Check 'Extension.prefs.set' fired a change event");
+ inspector3.prefs.events.removeListener("change", onPrefChange);
+
+ inspector3.prefs.get("smile.smile-test").events.addListener("change", onPrefChange2);
+ inspector3.prefs.setValue("smile.smile-test", "change event2");
+}
+
+function onPrefChange2(evt) {
+ is(evt.data, testdata.dummy, "Check 'Extension.prefs.set' fired a change event for a single preference");
+
+ finish();
+}