--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8895,24 +8895,26 @@ function toggleAddonBar() {
let addonBar = document.getElementById("addon-bar");
setToolbarVisibility(addonBar, addonBar.collapsed);
}
var Scratchpad = {
prefEnabledName: "devtools.scratchpad.enabled",
openScratchpad: function SP_openScratchpad() {
- const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/scratchpad.xul";
- const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
-
- return Services.ww.openWindow(null, SCRATCHPAD_WINDOW_URL, "_blank",
- SCRATCHPAD_WINDOW_FEATURES, null);
- },
+ return this.ScratchpadManager.openScratchpad();
+ }
};
+XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() {
+ let tmp = {};
+ Cu.import("resource:///modules/devtools/scratchpad-manager.jsm", tmp);
+ return tmp.ScratchpadManager;
+});
+
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
#ifdef XP_WIN
// Only show resizers on Windows 2000 and XP
let sysInfo = Components.classes["@mozilla.org/system-info;1"]
.getService(Components.interfaces.nsIPropertyBag2);
return parseFloat(sysInfo.getProperty("version")) < 6;
#else
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -135,16 +135,21 @@ Cu.import("resource://gre/modules/Servic
// debug.js adds NS_ASSERT. cf. bug 669196
Cu.import("resource://gre/modules/debug.js");
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
Cu.import("resource://gre/modules/NetUtil.jsm");
return NetUtil;
});
+XPCOMUtils.defineLazyGetter(this, "ScratchpadManager", function() {
+ Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
+ return ScratchpadManager;
+});
+
XPCOMUtils.defineLazyServiceGetter(this, "CookieSvc",
"@mozilla.org/cookiemanager;1", "nsICookieManager2");
#ifdef MOZ_CRASHREPORTER
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
"@mozilla.org/xre/app-info;1", "nsICrashReporter");
#endif
@@ -1577,16 +1582,20 @@ SessionStoreService.prototype = {
}
// Merge closed windows from this session with ones from last session
if (lastSessionState._closedWindows) {
this._closedWindows = this._closedWindows.concat(lastSessionState._closedWindows);
this._capClosedWindows();
}
+ if (lastSessionState.scratchpads) {
+ ScratchpadManager.restoreSession(lastSessionState.scratchpads);
+ }
+
// Set data that persists between sessions
this._recentCrashes = lastSessionState.session &&
lastSessionState.session.recentCrashes || 0;
this._sessionStartTime = lastSessionState.session &&
lastSessionState.session.startTime ||
this._sessionStartTime;
this._lastSessionState = null;
@@ -2482,22 +2491,26 @@ SessionStoreService.prototype = {
ix = -1;
let session = {
state: this._loadState == STATE_RUNNING ? STATE_RUNNING_STR : STATE_STOPPED_STR,
lastUpdate: Date.now(),
startTime: this._sessionStartTime,
recentCrashes: this._recentCrashes
};
+
+ // get open Scratchpad window states too
+ var scratchpads = ScratchpadManager.getSessionState();
return {
windows: total,
selectedWindow: ix + 1,
_closedWindows: lastClosedWindowsCopy,
- session: session
+ session: session,
+ scratchpads: scratchpads
};
},
/**
* serialize session data for a window
* @param aWindow
* Window reference
* @returns string
@@ -2695,16 +2708,20 @@ SessionStoreService.prototype = {
}
if (aOverwriteTabs || root._firstTabs) {
this._windows[aWindow.__SSi]._closedTabs = winData._closedTabs || [];
}
this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs,
(aOverwriteTabs ? (parseInt(winData.selected) || 1) : 0), 0, 0);
+ if (aState.scratchpads) {
+ ScratchpadManager.restoreSession(aState.scratchpads);
+ }
+
// This will force the keypress listener that Panorama has to attach if it
// isn't already. This will be the case if tab view wasn't entered or there
// were only visible tabs when TabView.init was first called.
aWindow.TabView.init();
// set smoothScroll back to the original value
tabstrip.smoothScroll = smoothScroll;
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -144,16 +144,17 @@ include $(topsrcdir)/config/rules.mk
browser_615394-SSWindowState_events.js \
browser_618151.js \
browser_623779.js \
browser_624727.js \
browser_625257.js \
browser_628270.js \
browser_635418.js \
browser_636279.js \
+ browser_644409-scratchpads.js \
browser_645428.js \
browser_659591.js \
browser_662812.js \
browser_665702-state_session.js \
browser_682507.js \
browser_694378.js \
$(NULL)
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_644409-scratchpads.js
@@ -0,0 +1,59 @@
+ /* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const testState = {
+ windows: [{
+ tabs: [
+ { entries: [{ url: "about:blank" }] },
+ ]
+ }],
+ scratchpads: [
+ { text: "text1", executionContext: 1 },
+ { text: "", executionContext: 2, filename: "test.js" }
+ ]
+};
+
+// only finish() when correct number of windows opened
+var restored = [];
+function addState(state) {
+ restored.push(state);
+
+ if (restored.length == testState.scratchpads.length) {
+ ok(statesMatch(restored, testState.scratchpads),
+ "Two scratchpad windows restored");
+
+ Services.ww.unregisterNotification(windowObserver);
+ finish();
+ }
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ Services.ww.registerNotification(windowObserver);
+
+ ss.setBrowserState(JSON.stringify(testState));
+}
+
+function windowObserver(aSubject, aTopic, aData) {
+ if (aTopic == "domwindowopened") {
+ let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
+ win.addEventListener("load", function() {
+ if (win.Scratchpad) {
+ let state = win.Scratchpad.getState();
+ win.close();
+ addState(state);
+ }
+ }, false);
+ }
+}
+
+function statesMatch(restored, states) {
+ return states.every(function(state) {
+ return restored.some(function(restoredState) {
+ return state.filename == restoredState.filename &&
+ state.text == restoredState.text &&
+ state.executionContext == restoredState.executionContext;
+ })
+ });
+}
\ No newline at end of file
--- a/browser/devtools/Makefile.in
+++ b/browser/devtools/Makefile.in
@@ -46,16 +46,13 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/config.mk
DIRS = \
highlighter \
webconsole \
sourceeditor \
styleinspector \
+ scratchpad \
shared \
$(NULL)
-ifdef ENABLE_TESTS
-DIRS += scratchpad/test
-endif
-
include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/Makefile.in
@@ -0,0 +1,53 @@
+#
+# ***** 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 Scratchpad Build Code.
+#
+# The Initial Developer of the Original Code is The Mozilla Foundation.
+#
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Rob Campbell <rcampbell@mozilla.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
+
+ifdef ENABLE_TESTS
+ DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+libs::
+ $(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/scratchpad-manager.jsm
@@ -0,0 +1,174 @@
+/* vim:set ts=2 sw=2 sts=2 et tw=80:
+ * ***** 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 Scratchpad
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Heather Arthur <fayearthur@gmail.com> (original author)
+ *
+ * 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 *****/
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["ScratchpadManager"];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/scratchpad.xul";
+const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+/**
+ * The ScratchpadManager object opens new Scratchpad windows and manages the state
+ * of open scratchpads for session restore. There's only one ScratchpadManager in
+ * the life of the browser.
+ */
+var ScratchpadManager = {
+
+ _scratchpads: [],
+
+ /**
+ * Get the saved states of open scratchpad windows. Called by
+ * session restore.
+ *
+ * @return array
+ * The array of scratchpad states.
+ */
+ getSessionState: function SPM_getSessionState()
+ {
+ return this._scratchpads;
+ },
+
+ /**
+ * Restore scratchpad windows from the scratchpad session store file.
+ * Called by session restore.
+ *
+ * @param function aSession
+ * The session object with scratchpad states.
+ *
+ * @return array
+ * The restored scratchpad windows.
+ */
+ restoreSession: function SPM_restoreSession(aSession)
+ {
+ if (!Array.isArray(aSession)) {
+ return [];
+ }
+
+ let wins = [];
+ aSession.forEach(function(state) {
+ let win = this.openScratchpad(state);
+ wins.push(win);
+ }, this);
+
+ return wins;
+ },
+
+ /**
+ * Iterate through open scratchpad windows and save their states.
+ */
+ saveOpenWindows: function SPM_saveOpenWindows() {
+ this._scratchpads = [];
+
+ let enumerator = Services.wm.getEnumerator("devtools:scratchpad");
+ while (enumerator.hasMoreElements()) {
+ let win = enumerator.getNext();
+ if (!win.closed) {
+ this._scratchpads.push(win.Scratchpad.getState());
+ }
+ }
+ },
+
+ /**
+ * Open a new scratchpad window with an optional initial state.
+ *
+ * @param object aState
+ * Optional. The initial state of the scratchpad, an object
+ * with properties filename, text, and executionContext.
+ *
+ * @return nsIDomWindow
+ * The opened scratchpad window.
+ */
+ openScratchpad: function SPM_openScratchpad(aState)
+ {
+ let params = null;
+ if (aState) {
+ if (typeof aState != 'object') {
+ return;
+ }
+ params = Cc["@mozilla.org/embedcomp/dialogparam;1"]
+ .createInstance(Ci.nsIDialogParamBlock);
+ params.SetNumberStrings(1);
+ params.SetString(0, JSON.stringify(aState));
+ }
+ let win = Services.ww.openWindow(null, SCRATCHPAD_WINDOW_URL, "_blank",
+ SCRATCHPAD_WINDOW_FEATURES, params);
+ // Only add shutdown observer if we've opened a scratchpad window
+ ShutdownObserver.init();
+
+ return win;
+ }
+};
+
+
+/**
+ * The ShutdownObserver listens for app shutdown and saves the current state
+ * of the scratchpads for session restore.
+ */
+var ShutdownObserver = {
+ _initialized: false,
+
+ init: function SDO_init()
+ {
+ if (this._initialized) {
+ return;
+ }
+
+ Services.obs.addObserver(this, "quit-application-granted", false);
+ this._initialized = true;
+ },
+
+ observe: function SDO_observe(aMessage, aTopic, aData)
+ {
+ if (aTopic == "quit-application-granted") {
+ ScratchpadManager.saveOpenWindows();
+ this.uninit();
+ }
+ },
+
+ uninit: function SDO_uninit()
+ {
+ Services.obs.removeObserver(this, "quit-application-granted");
+ }
+};
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -54,22 +54,22 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource:///modules/PropertyPanel.jsm");
Cu.import("resource:///modules/source-editor.jsm");
+Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
+
const SCRATCHPAD_CONTEXT_CONTENT = 1;
const SCRATCHPAD_CONTEXT_BROWSER = 2;
-const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/scratchpad.xul";
const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties";
-const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
/**
* The scratchpad object handles the Scratchpad window functionality.
*/
var Scratchpad = {
/**
* The script execution context. This tells Scratchpad in which context the
@@ -128,16 +128,65 @@ var Scratchpad = {
* replacing text in the editor.
*/
setText: function SP_setText(aText, aStart, aEnd)
{
this.editor.setText(aText, aStart, aEnd);
},
/**
+ * Set the filename in the scratchpad UI and object
+ *
+ * @param string aFilename
+ * The new filename
+ */
+ setFilename: function SP_setFilename(aFilename)
+ {
+ document.title = this.filename = aFilename;
+ },
+
+ /**
+ * Get the current state of the scratchpad. Called by the
+ * Scratchpad Manager for session storing.
+ *
+ * @return object
+ * An object with 3 properties: filename, text, and
+ * executionContext.
+ */
+ getState: function SP_getState()
+ {
+ return {
+ filename: this.filename,
+ text: this.getText(),
+ executionContext: this.executionContext
+ };
+ },
+
+ /**
+ * Set the filename and execution context using the given state. Called
+ * when scratchpad is being restored from a previous session.
+ *
+ * @param object aState
+ * An object with filename and executionContext properties.
+ */
+ setState: function SP_getState(aState)
+ {
+ if (aState.filename) {
+ this.setFilename(aState.filename);
+ }
+
+ if (aState.executionContext == SCRATCHPAD_CONTEXT_BROWSER) {
+ this.setBrowserContext();
+ }
+ else {
+ this.setContentContext();
+ }
+ },
+
+ /**
* Get the most recent chrome window of type navigator:browser.
*/
get browserWindow() Services.wm.getMostRecentWindow("navigator:browser"),
/**
* Reference to the last chrome window of type navigator:browser. We use this
* to check if the chrome window changed since the last code evaluation.
*/
@@ -437,18 +486,17 @@ var Scratchpad = {
// Menu Operations
/**
* Open a new Scratchpad window.
*/
openScratchpad: function SP_openScratchpad()
{
- Services.ww.openWindow(null, SCRATCHPAD_WINDOW_URL, "_blank",
- SCRATCHPAD_WINDOW_FEATURES, null);
+ ScratchpadManager.openScratchpad();
},
/**
* Export the textbox content to a file.
*
* @param nsILocalFile aFile
* The file where you want to save the textbox content.
* @param boolean aNoConfirmation
@@ -536,17 +584,17 @@ var Scratchpad = {
*/
openFile: function SP_openFile()
{
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, this.strings.GetStringFromName("openFile.title"),
Ci.nsIFilePicker.modeOpen);
fp.defaultString = "";
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
- document.title = this.filename = fp.file.path;
+ this.setFilename(fp.file.path);
this.importFromFile(fp.file);
}
},
/**
* Save the textbox content to the currently open file.
*/
saveFile: function SP_saveFile()
@@ -675,22 +723,30 @@ var Scratchpad = {
let environmentMenu = document.getElementById("sp-environment-menu");
let errorConsoleCommand = document.getElementById("sp-cmd-errorConsole");
let chromeContextCommand = document.getElementById("sp-cmd-browserContext");
environmentMenu.removeAttribute("hidden");
chromeContextCommand.removeAttribute("disabled");
errorConsoleCommand.removeAttribute("disabled");
}
+ let initialText = this.strings.GetStringFromName("scratchpadIntro");
+ if ("arguments" in window &&
+ window.arguments[0] instanceof Ci.nsIDialogParamBlock) {
+ let state = JSON.parse(window.arguments[0].GetString(0));
+ this.setState(state);
+ initialText = state.text;
+ }
+
this.editor = new SourceEditor();
let config = {
mode: SourceEditor.MODES.JAVASCRIPT,
showLineNumbers: true,
- placeholderText: this.strings.GetStringFromName("scratchpadIntro"),
+ placeholderText: initialText
};
let editorPlaceholder = document.getElementById("scratchpad-editor");
this.editor.init(editorPlaceholder, config, this.onEditorLoad.bind(this));
},
/**
* The load event handler for the source editor. This method does post-load
--- a/browser/devtools/scratchpad/test/Makefile.in
+++ b/browser/devtools/scratchpad/test/Makefile.in
@@ -48,11 +48,13 @@ include $(topsrcdir)/config/rules.mk
browser_scratchpad_contexts.js \
browser_scratchpad_tab_switch.js \
browser_scratchpad_execute_print.js \
browser_scratchpad_inspect.js \
browser_scratchpad_files.js \
browser_scratchpad_ui.js \
browser_scratchpad_bug_646070_chrome_context_pref.js \
browser_scratchpad_bug_660560_tab.js \
+ browser_scratchpad_open.js \
+ browser_scratchpad_restore.js \
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_open.js
@@ -0,0 +1,71 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var ScratchpadManager = Scratchpad.ScratchpadManager;
+
+// only finish() when correct number of tests are done
+const expected = 3;
+var count = 0;
+
+function done()
+{
+ if (++count == expected) {
+ finish();
+ }
+}
+
+
+function test()
+{
+ waitForExplicitFinish();
+ testOpen();
+ testOpenWithState();
+ testOpenInvalidState();
+}
+
+function testOpen()
+{
+ let win = ScratchpadManager.openScratchpad();
+
+ win.addEventListener("load", function() {
+ is(win.Scratchpad.filename, undefined, "Default filename is undefined");
+ is(win.Scratchpad.getText(),
+ win.Scratchpad.strings.GetStringFromName("scratchpadIntro"),
+ "Default text is loaded")
+ is(win.Scratchpad.executionContext, win.SCRATCHPAD_CONTEXT_CONTENT,
+ "Default execution context is content");
+
+ win.close();
+ done();
+ });
+}
+
+function testOpenWithState()
+{
+ let state = {
+ filename: "testfile",
+ executionContext: 2,
+ text: "test text"
+ };
+
+ let win = ScratchpadManager.openScratchpad(state);
+
+ win.addEventListener("load", function() {
+ is(win.Scratchpad.filename, state.filename, "Filename loaded from state");
+ is(win.Scratchpad.executionContext, state.executionContext, "Execution context loaded from state");
+ is(win.Scratchpad.getText(), state.text, "Content loaded from state");
+
+ win.close();
+ done();
+ });
+}
+
+function testOpenInvalidState()
+{
+ let state = 7;
+
+ let win = ScratchpadManager.openScratchpad(state);
+ ok(!win, "no scratchpad opened if state is not an object");
+ done();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_restore.js
@@ -0,0 +1,101 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var ScratchpadManager = Scratchpad.ScratchpadManager;
+
+/* Call the iterator for each item in the list,
+ calling the final callback with all the results
+ after every iterator call has sent its result */
+function asyncMap(items, iterator, callback)
+{
+ let expected = items.length;
+ let results = [];
+
+ items.forEach(function(item) {
+ iterator(item, function(result) {
+ results.push(result);
+ if (results.length == expected) {
+ callback(results);
+ }
+ });
+ });
+}
+
+function test()
+{
+ waitForExplicitFinish();
+ testRestore();
+}
+
+function testRestore()
+{
+ let states = [
+ {
+ filename: "testfile",
+ text: "test1",
+ executionContext: 2
+ },
+ {
+ text: "text2",
+ executionContext: 1
+ },
+ {
+ text: "text3",
+ executionContext: 1
+ }
+ ];
+
+ asyncMap(states, function(state, done) {
+ // Open some scratchpad windows
+ let win = ScratchpadManager.openScratchpad(state);
+ win.addEventListener("load", function() {
+ done(win);
+ })
+ }, function(wins) {
+ // Then save the windows to session store
+ ScratchpadManager.saveOpenWindows();
+
+ // Then get their states
+ let session = ScratchpadManager.getSessionState();
+
+ // Then close them
+ wins.forEach(function(win) {
+ win.close();
+ });
+
+ // Clear out session state for next tests
+ ScratchpadManager.saveOpenWindows();
+
+ // Then restore them
+ let restoredWins = ScratchpadManager.restoreSession(session);
+
+ is(restoredWins.length, 3, "Three scratchad windows restored");
+
+ asyncMap(restoredWins, function(restoredWin, done) {
+ restoredWin.addEventListener("load", function() {
+ let state = restoredWin.Scratchpad.getState();
+ restoredWin.close();
+ done(state);
+ });
+ }, function(restoredStates) {
+ // Then make sure they were restored with the right states
+ ok(statesMatch(restoredStates, states),
+ "All scratchpad window states restored correctly");
+
+ // Yay, we're done!
+ finish();
+ });
+ });
+}
+
+function statesMatch(restoredStates, states)
+{
+ return states.every(function(state) {
+ return restoredStates.some(function(restoredState) {
+ return state.filename == restoredState.filename
+ && state.text == restoredState.text
+ && state.executionContext == restoredState.executionContext;
+ })
+ });
+}