summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/chrome
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /toolkit/content/tests/chrome
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/content/tests/chrome')
-rw-r--r--toolkit/content/tests/chrome/.eslintrc.js7
-rw-r--r--toolkit/content/tests/chrome/RegisterUnregisterChrome.js161
-rw-r--r--toolkit/content/tests/chrome/bug263683_window.xul210
-rw-r--r--toolkit/content/tests/chrome/bug304188_window.xul94
-rw-r--r--toolkit/content/tests/chrome/bug331215_window.xul102
-rw-r--r--toolkit/content/tests/chrome/bug360437_window.xul120
-rw-r--r--toolkit/content/tests/chrome/bug366992_window.xul57
-rw-r--r--toolkit/content/tests/chrome/bug409624_window.xul98
-rw-r--r--toolkit/content/tests/chrome/bug429723_window.xul84
-rw-r--r--toolkit/content/tests/chrome/bug451540_window.xul248
-rw-r--r--toolkit/content/tests/chrome/bug624329_window.xul22
-rw-r--r--toolkit/content/tests/chrome/chrome.ini199
-rw-r--r--toolkit/content/tests/chrome/dialog_dialogfocus.xul57
-rw-r--r--toolkit/content/tests/chrome/file_about_networking_wsh.py9
-rw-r--r--toolkit/content/tests/chrome/file_autocomplete_with_composition.js540
-rw-r--r--toolkit/content/tests/chrome/findbar_entireword_window.xul275
-rw-r--r--toolkit/content/tests/chrome/findbar_events_window.xul173
-rw-r--r--toolkit/content/tests/chrome/findbar_window.xul756
-rw-r--r--toolkit/content/tests/chrome/frame_popup_anchor.xul82
-rw-r--r--toolkit/content/tests/chrome/frame_popupremoving_frame.xul75
-rw-r--r--toolkit/content/tests/chrome/frame_subframe_origin_subframe1.xul43
-rw-r--r--toolkit/content/tests/chrome/frame_subframe_origin_subframe2.xul39
-rw-r--r--toolkit/content/tests/chrome/popup_childframe_node.xul2
-rw-r--r--toolkit/content/tests/chrome/popup_trigger.js859
-rw-r--r--toolkit/content/tests/chrome/rtlchrome/rtl.css2
-rw-r--r--toolkit/content/tests/chrome/rtlchrome/rtl.dtd1
-rw-r--r--toolkit/content/tests/chrome/rtlchrome/rtl.manifest5
-rw-r--r--toolkit/content/tests/chrome/rtltest/content/dirtest.xul25
-rw-r--r--toolkit/content/tests/chrome/rtltest/righttoleft.manifest3
-rw-r--r--toolkit/content/tests/chrome/sample_entireword_latin1.html11
-rw-r--r--toolkit/content/tests/chrome/test_about_networking.html58
-rw-r--r--toolkit/content/tests/chrome/test_arrowpanel.xul327
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete2.xul197
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete3.xul188
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete4.xul280
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete5.xul152
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul128
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete_emphasis.xul175
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete_mac_caret.xul74
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xul309
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete_with_composition_on_input.html64
-rw-r--r--toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul124
-rw-r--r--toolkit/content/tests/chrome/test_browser_drop.xul38
-rw-r--r--toolkit/content/tests/chrome/test_bug1048178.xul86
-rw-r--r--toolkit/content/tests/chrome/test_bug253481.xul90
-rw-r--r--toolkit/content/tests/chrome/test_bug263683.xul39
-rw-r--r--toolkit/content/tests/chrome/test_bug304188.xul37
-rw-r--r--toolkit/content/tests/chrome/test_bug331215.xul38
-rw-r--r--toolkit/content/tests/chrome/test_bug360220.xul61
-rw-r--r--toolkit/content/tests/chrome/test_bug360437.xul40
-rw-r--r--toolkit/content/tests/chrome/test_bug365773.xul67
-rw-r--r--toolkit/content/tests/chrome/test_bug366992.xul40
-rw-r--r--toolkit/content/tests/chrome/test_bug382990.xul44
-rw-r--r--toolkit/content/tests/chrome/test_bug409624.xul39
-rw-r--r--toolkit/content/tests/chrome/test_bug418874.xul71
-rw-r--r--toolkit/content/tests/chrome/test_bug429723.xul38
-rw-r--r--toolkit/content/tests/chrome/test_bug437844.xul95
-rw-r--r--toolkit/content/tests/chrome/test_bug451540.xul39
-rw-r--r--toolkit/content/tests/chrome/test_bug457632.xul178
-rw-r--r--toolkit/content/tests/chrome/test_bug460942.xul42
-rw-r--r--toolkit/content/tests/chrome/test_bug471776.xul47
-rw-r--r--toolkit/content/tests/chrome/test_bug509732.xul53
-rw-r--r--toolkit/content/tests/chrome/test_bug554279.xul39
-rw-r--r--toolkit/content/tests/chrome/test_bug557987.xul76
-rw-r--r--toolkit/content/tests/chrome/test_bug562554.xul92
-rw-r--r--toolkit/content/tests/chrome/test_bug570192.xul53
-rw-r--r--toolkit/content/tests/chrome/test_bug585946.xul51
-rw-r--r--toolkit/content/tests/chrome/test_bug624329.xul160
-rw-r--r--toolkit/content/tests/chrome/test_bug792324.xul75
-rw-r--r--toolkit/content/tests/chrome/test_button.xul71
-rw-r--r--toolkit/content/tests/chrome/test_chromemargin.xul36
-rw-r--r--toolkit/content/tests/chrome/test_closemenu_attribute.xul96
-rw-r--r--toolkit/content/tests/chrome/test_colorpicker_popup.xul148
-rw-r--r--toolkit/content/tests/chrome/test_contextmenu_list.xul288
-rw-r--r--toolkit/content/tests/chrome/test_cursorsnap.xul127
-rw-r--r--toolkit/content/tests/chrome/test_datepicker.xul415
-rw-r--r--toolkit/content/tests/chrome/test_deck.xul133
-rw-r--r--toolkit/content/tests/chrome/test_dialogfocus.xul102
-rw-r--r--toolkit/content/tests/chrome/test_findbar.xul47
-rw-r--r--toolkit/content/tests/chrome/test_findbar_entireword.xul41
-rw-r--r--toolkit/content/tests/chrome/test_findbar_events.xul39
-rw-r--r--toolkit/content/tests/chrome/test_focus_anons.xul119
-rw-r--r--toolkit/content/tests/chrome/test_hiddenitems.xul89
-rw-r--r--toolkit/content/tests/chrome/test_hiddenpaging.xul161
-rw-r--r--toolkit/content/tests/chrome/test_keys.xul29
-rw-r--r--toolkit/content/tests/chrome/test_labelcontrol.xul44
-rw-r--r--toolkit/content/tests/chrome/test_largemenu.xul29
-rw-r--r--toolkit/content/tests/chrome/test_menu.xul85
-rw-r--r--toolkit/content/tests/chrome/test_menu_anchored.xul77
-rw-r--r--toolkit/content/tests/chrome/test_menu_hide.xul58
-rw-r--r--toolkit/content/tests/chrome/test_menuchecks.xul147
-rw-r--r--toolkit/content/tests/chrome/test_menuitem_blink.xul106
-rw-r--r--toolkit/content/tests/chrome/test_menuitem_commands.xul104
-rw-r--r--toolkit/content/tests/chrome/test_menulist.xul314
-rw-r--r--toolkit/content/tests/chrome/test_menulist_keynav.xul272
-rw-r--r--toolkit/content/tests/chrome/test_menulist_null_value.xul96
-rw-r--r--toolkit/content/tests/chrome/test_menulist_paging.xul163
-rw-r--r--toolkit/content/tests/chrome/test_menulist_position.xul97
-rw-r--r--toolkit/content/tests/chrome/test_mousescroll.xul274
-rw-r--r--toolkit/content/tests/chrome/test_notificationbox.xul522
-rw-r--r--toolkit/content/tests/chrome/test_panel.xul31
-rw-r--r--toolkit/content/tests/chrome/test_panel_focus.xul38
-rw-r--r--toolkit/content/tests/chrome/test_panelfrommenu.xul118
-rw-r--r--toolkit/content/tests/chrome/test_popup_anchor.xul30
-rw-r--r--toolkit/content/tests/chrome/test_popup_anchoratrect.xul28
-rw-r--r--toolkit/content/tests/chrome/test_popup_attribute.xul28
-rw-r--r--toolkit/content/tests/chrome/test_popup_button.xul28
-rw-r--r--toolkit/content/tests/chrome/test_popup_coords.xul91
-rw-r--r--toolkit/content/tests/chrome/test_popup_keys.xul148
-rw-r--r--toolkit/content/tests/chrome/test_popup_moveToAnchor.xul84
-rw-r--r--toolkit/content/tests/chrome/test_popup_preventdefault.xul76
-rw-r--r--toolkit/content/tests/chrome/test_popup_preventdefault_chrome.xul29
-rw-r--r--toolkit/content/tests/chrome/test_popup_recreate.xul83
-rw-r--r--toolkit/content/tests/chrome/test_popup_scaled.xul105
-rw-r--r--toolkit/content/tests/chrome/test_popup_tree.xul72
-rw-r--r--toolkit/content/tests/chrome/test_popuphidden.xul74
-rw-r--r--toolkit/content/tests/chrome/test_popupincontent.xul131
-rw-r--r--toolkit/content/tests/chrome/test_popupremoving.xul165
-rw-r--r--toolkit/content/tests/chrome/test_popupremoving_frame.xul80
-rw-r--r--toolkit/content/tests/chrome/test_position.xul136
-rw-r--r--toolkit/content/tests/chrome/test_preferences.xul533
-rw-r--r--toolkit/content/tests/chrome/test_preferences_beforeaccept.xul55
-rw-r--r--toolkit/content/tests/chrome/test_preferences_onsyncfrompreference.xul62
-rw-r--r--toolkit/content/tests/chrome/test_progressmeter.xul74
-rw-r--r--toolkit/content/tests/chrome/test_props.xul91
-rw-r--r--toolkit/content/tests/chrome/test_radio.xul66
-rw-r--r--toolkit/content/tests/chrome/test_richlist_direction.xul138
-rw-r--r--toolkit/content/tests/chrome/test_righttoleft.xul126
-rw-r--r--toolkit/content/tests/chrome/test_scale.xul277
-rw-r--r--toolkit/content/tests/chrome/test_scaledrag.xul197
-rw-r--r--toolkit/content/tests/chrome/test_screenPersistence.xul63
-rw-r--r--toolkit/content/tests/chrome/test_scrollbar.xul137
-rw-r--r--toolkit/content/tests/chrome/test_showcaret.xul101
-rw-r--r--toolkit/content/tests/chrome/test_sorttemplate.xul89
-rw-r--r--toolkit/content/tests/chrome/test_statusbar.xul42
-rw-r--r--toolkit/content/tests/chrome/test_subframe_origin.xul37
-rw-r--r--toolkit/content/tests/chrome/test_tabbox.xul224
-rw-r--r--toolkit/content/tests/chrome/test_tabindex.xul120
-rw-r--r--toolkit/content/tests/chrome/test_textbox_dictionary.xul98
-rw-r--r--toolkit/content/tests/chrome/test_textbox_emptytext.xul48
-rw-r--r--toolkit/content/tests/chrome/test_textbox_number.xul353
-rw-r--r--toolkit/content/tests/chrome/test_textbox_search.xul170
-rw-r--r--toolkit/content/tests/chrome/test_timepicker.xul207
-rw-r--r--toolkit/content/tests/chrome/test_titlebar.xul35
-rw-r--r--toolkit/content/tests/chrome/test_toolbar.xul227
-rw-r--r--toolkit/content/tests/chrome/test_tooltip.xul28
-rw-r--r--toolkit/content/tests/chrome/test_tooltip_noautohide.xul57
-rw-r--r--toolkit/content/tests/chrome/test_tree.xul84
-rw-r--r--toolkit/content/tests/chrome/test_tree_hier.xul136
-rw-r--r--toolkit/content/tests/chrome/test_tree_hier_cell.xul136
-rw-r--r--toolkit/content/tests/chrome/test_tree_single.xul110
-rw-r--r--toolkit/content/tests/chrome/test_tree_view.xul118
-rw-r--r--toolkit/content/tests/chrome/window_browser_drop.xul254
-rw-r--r--toolkit/content/tests/chrome/window_chromemargin.xul73
-rw-r--r--toolkit/content/tests/chrome/window_cursorsnap_dialog.xul104
-rw-r--r--toolkit/content/tests/chrome/window_cursorsnap_wizard.xul111
-rw-r--r--toolkit/content/tests/chrome/window_keys.xul202
-rw-r--r--toolkit/content/tests/chrome/window_largemenu.xul425
-rw-r--r--toolkit/content/tests/chrome/window_panel.xul312
-rw-r--r--toolkit/content/tests/chrome/window_panel_focus.xul132
-rw-r--r--toolkit/content/tests/chrome/window_popup_anchor.xul28
-rw-r--r--toolkit/content/tests/chrome/window_popup_anchoratrect.xul117
-rw-r--r--toolkit/content/tests/chrome/window_popup_attribute.xul40
-rw-r--r--toolkit/content/tests/chrome/window_popup_button.xul41
-rw-r--r--toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xul113
-rw-r--r--toolkit/content/tests/chrome/window_preferences.xul73
-rw-r--r--toolkit/content/tests/chrome/window_preferences2.xul25
-rw-r--r--toolkit/content/tests/chrome/window_preferences3.xul74
-rw-r--r--toolkit/content/tests/chrome/window_preferences_beforeaccept.xul45
-rw-r--r--toolkit/content/tests/chrome/window_preferences_commandretarget.xul36
-rw-r--r--toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul42
-rw-r--r--toolkit/content/tests/chrome/window_screenPosSize.xul17
-rw-r--r--toolkit/content/tests/chrome/window_showcaret.xul10
-rw-r--r--toolkit/content/tests/chrome/window_subframe_origin.xul42
-rw-r--r--toolkit/content/tests/chrome/window_titlebar.xul223
-rw-r--r--toolkit/content/tests/chrome/window_tooltip.xul311
-rw-r--r--toolkit/content/tests/chrome/xul_selectcontrol.js390
177 files changed, 21546 insertions, 0 deletions
diff --git a/toolkit/content/tests/chrome/.eslintrc.js b/toolkit/content/tests/chrome/.eslintrc.js
new file mode 100644
index 000000000..2c669d844
--- /dev/null
+++ b/toolkit/content/tests/chrome/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../testing/mochitest/chrome.eslintrc.js"
+ ]
+};
diff --git a/toolkit/content/tests/chrome/RegisterUnregisterChrome.js b/toolkit/content/tests/chrome/RegisterUnregisterChrome.js
new file mode 100644
index 000000000..34f25d2f8
--- /dev/null
+++ b/toolkit/content/tests/chrome/RegisterUnregisterChrome.js
@@ -0,0 +1,161 @@
+/* This code is mostly copied from chrome/test/unit/head_crtestutils.js */
+
+const NS_CHROME_MANIFESTS_FILE_LIST = "ChromeML";
+const XUL_CACHE_PREF = "nglayout.debug.disable_xul_cache";
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+
+var gDirSvc = Cc["@mozilla.org/file/directory_service;1"].
+ getService(Ci.nsIDirectoryService).QueryInterface(Ci.nsIProperties);
+var gChromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIXULChromeRegistry);
+var gPrefs = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+
+// Create the temporary file in the profile, instead of in TmpD, because
+// we know the mochitest harness kills off the profile when it's done.
+function copyToTemporaryFile(f)
+{
+ let tmpd = gDirSvc.get("ProfD", Ci.nsIFile);
+ tmpf = tmpd.clone();
+ tmpf.append("temp.manifest");
+ tmpf.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
+ tmpf.remove(false);
+ f.copyTo(tmpd, tmpf.leafName);
+ return tmpf;
+}
+
+function* dirIter(directory)
+{
+ var ioSvc = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ var testsDir = ioSvc.newURI(directory, null, null)
+ .QueryInterface(Ci.nsIFileURL).file;
+
+ let en = testsDir.directoryEntries;
+ while (en.hasMoreElements()) {
+ let file = en.getNext();
+ yield file.QueryInterface(Ci.nsIFile);
+ }
+}
+
+function getParent(path) {
+ let lastSlash = path.lastIndexOf("/");
+ if (lastSlash == -1) {
+ lastSlash = path.lastIndexOf("\\");
+ if (lastSlash == -1) {
+ return "";
+ }
+ return '/' + path.substring(0, lastSlash).replace(/\\/g, '/');
+ }
+ return path.substring(0, lastSlash);
+}
+
+function copyDirToTempProfile(path, subdirname) {
+
+ if (subdirname === undefined) {
+ subdirname = "mochikit-tmp";
+ }
+
+ let tmpdir = gDirSvc.get("ProfD", Ci.nsIFile);
+ tmpdir.append(subdirname);
+ tmpdir.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o777);
+
+ let rootDir = getParent(path);
+ if (rootDir == "") {
+ return tmpdir;
+ }
+
+ // The SimpleTest directory is hidden
+ var files = Array.from(dirIter('file://' + rootDir));
+ for (f in files) {
+ files[f].copyTo(tmpdir, "");
+ }
+ return tmpdir;
+
+}
+
+function convertChromeURI(chromeURI)
+{
+ let uri = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService).newURI(chromeURI, null, null);
+ return gChromeReg.convertChromeURL(uri);
+}
+
+function chromeURIToFile(chromeURI)
+{
+ var jar = getJar(chromeURI);
+ if (jar) {
+ var tmpDir = extractJarToTmp(jar);
+ let parts = chromeURI.split('/');
+ if (parts[parts.length - 1] != '') {
+ tmpDir.append(parts[parts.length - 1]);
+ }
+ return tmpDir;
+ }
+
+ return convertChromeURI(chromeURI).
+ QueryInterface(Ci.nsIFileURL).file;
+}
+
+// Register a chrome manifest temporarily and return a function which un-does
+// the registrarion when no longer needed.
+function createManifestTemporarily(tempDir, manifestText)
+{
+ gPrefs.setBoolPref(XUL_CACHE_PREF, true);
+
+ tempDir.append("temp.manifest");
+
+ let foStream = Cc["@mozilla.org/network/file-output-stream;1"]
+ .createInstance(Ci.nsIFileOutputStream);
+ foStream.init(tempDir,
+ 0x02 | 0x08 | 0x20, 0o664, 0); // write, create, truncate
+ foStream.write(manifestText, manifestText.length);
+ foStream.close();
+ let tempfile = copyToTemporaryFile(tempDir);
+
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar).
+ autoRegister(tempfile);
+
+ gChromeReg.refreshSkins();
+
+ return function() {
+ tempfile.fileSize = 0; // truncate the manifest
+ gChromeReg.checkForNewChrome();
+ gChromeReg.refreshSkins();
+ gPrefs.clearUserPref(XUL_CACHE_PREF);
+ }
+}
+
+// Register a chrome manifest temporarily and return a function which un-does
+// the registrarion when no longer needed.
+function registerManifestTemporarily(manifestURI)
+{
+ gPrefs.setBoolPref(XUL_CACHE_PREF, true);
+
+ let file = chromeURIToFile(manifestURI);
+
+ let tempfile = copyToTemporaryFile(file);
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar).
+ autoRegister(tempfile);
+
+ gChromeReg.refreshSkins();
+
+ return function() {
+ tempfile.fileSize = 0; // truncate the manifest
+ gChromeReg.checkForNewChrome();
+ gChromeReg.refreshSkins();
+ gPrefs.clearUserPref(XUL_CACHE_PREF);
+ }
+}
+
+function registerManifestPermanently(manifestURI)
+{
+ var chromepath = chromeURIToFile(manifestURI);
+
+ Components.manager.QueryInterface(Ci.nsIComponentRegistrar).
+ autoRegister(chromepath);
+ return chromepath;
+}
diff --git a/toolkit/content/tests/chrome/bug263683_window.xul b/toolkit/content/tests/chrome/bug263683_window.xul
new file mode 100644
index 000000000..46985a7ad
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug263683_window.xul
@@ -0,0 +1,210 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window id="263683test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="SimpleTest.executeSoon(startTest);"
+ title="263683 test">
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/AppConstants.jsm");
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+
+ var gPrefsvc = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ var gFindBar = null;
+ var gBrowser;
+
+ var imports = ["SimpleTest", "ok", "info", "is"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+
+ function startTest() {
+ Task.spawn(function* () {
+ gFindBar = document.getElementById("FindToolbar");
+ for (let browserId of ["content", "content-remote"]) {
+ yield startTestWithBrowser(browserId);
+ }
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ function* startTestWithBrowser(browserId) {
+ // We're bailing out when testing a remote browser on OSX 10.6, because it
+ // fails permanently.
+ if (browserId.endsWith("remote") && AppConstants.isPlatformAndVersionAtMost("macosx", 11)) {
+ return;
+ }
+
+ info("Starting test with browser '" + browserId + "'");
+ gBrowser = document.getElementById(browserId);
+ gFindBar.browser = gBrowser;
+ let promise = BrowserTestUtils.browserLoaded(gBrowser);
+ gBrowser.loadURI('data:text/html,<h2>Text mozilla</h2><input id="inp" type="text" />');
+ yield promise;
+ yield onDocumentLoaded();
+ }
+
+ function toggleHighlightAndWait(highlight) {
+ return new Promise(resolve => {
+ let listener = {
+ onHighlightFinished: function() {
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ gFindBar.toggleHighlight(highlight);
+ });
+ }
+
+ function* onDocumentLoaded() {
+ gFindBar.open();
+ var search = "mozilla";
+ gFindBar._findField.focus();
+ gFindBar._findField.value = search;
+ var matchCase = gFindBar.getElement("find-case-sensitive");
+ if (matchCase.checked) {
+ matchCase.doCommand();
+ }
+
+ yield toggleHighlightAndWait(true);
+ gFindBar._find();
+
+ yield ContentTask.spawn(gBrowser, { search }, function* (args) {
+ let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ Assert.ok("SELECTION_FIND" in controller, "Correctly detects new selection type");
+ let selection = controller.getSelection(controller.SELECTION_FIND);
+
+ Assert.equal(selection.rangeCount, 1,
+ "Correctly added a match to the selection type");
+ Assert.equal(selection.getRangeAt(0).toString().toLowerCase(),
+ args.search, "Added the correct match");
+ });
+
+ yield toggleHighlightAndWait(false);
+
+ yield ContentTask.spawn(gBrowser, { search }, function* (args) {
+ let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ let selection = controller.getSelection(controller.SELECTION_FIND);
+ Assert.equal(selection.rangeCount, 0, "Correctly removed the range");
+
+ let input = content.document.getElementById("inp");
+ input.value = args.search;
+ });
+
+ yield toggleHighlightAndWait(true);
+
+ yield ContentTask.spawn(gBrowser, { search }, function* (args) {
+ let input = content.document.getElementById("inp");
+ let inputController = input.editor.selectionController;
+ let inputSelection = inputController.getSelection(inputController.SELECTION_FIND);
+
+ Assert.equal(inputSelection.rangeCount, 1,
+ "Correctly added a match from input to the selection type");
+ Assert.equal(inputSelection.getRangeAt(0).toString().toLowerCase(),
+ args.search, "Added the correct match");
+ });
+
+ yield toggleHighlightAndWait(false);
+
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ let input = content.document.getElementById("inp");
+ let inputController = input.editor.selectionController;
+ let inputSelection = inputController.getSelection(inputController.SELECTION_FIND);
+
+ Assert.equal(inputSelection.rangeCount, 0, "Correctly removed the range");
+ });
+
+ // For posterity, test iframes too.
+
+ let promise = BrowserTestUtils.browserLoaded(gBrowser);
+ gBrowser.loadURI('data:text/html,<h2>Text mozilla</h2><iframe id="leframe" ' +
+ 'src="data:text/html,Text mozilla"></iframe>');
+ yield promise;
+
+ yield toggleHighlightAndWait(true);
+
+ yield ContentTask.spawn(gBrowser, { search }, function* (args) {
+ function getSelection(docShell) {
+ let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ return controller.getSelection(controller.SELECTION_FIND);
+ }
+
+ let selection = getSelection(docShell);
+ Assert.equal(selection.rangeCount, 1,
+ "Correctly added a match to the selection type");
+ Assert.equal(selection.getRangeAt(0).toString().toLowerCase(),
+ args.search, "Added the correct match");
+
+ // Check the iframe too:
+ let frame = content.document.getElementById("leframe");
+ // Hoops! Get the docShell first, then the selection.
+ selection = getSelection(frame.contentWindow
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell));
+ Assert.equal(selection.rangeCount, 1,
+ "Correctly added a match to the selection type");
+ Assert.equal(selection.getRangeAt(0).toString().toLowerCase(),
+ args.search, "Added the correct match");
+ });
+
+ yield toggleHighlightAndWait(false);
+
+ let matches = gFindBar._foundMatches.value.match(/([\d]*)\sof\s([\d]*)/);
+ is(matches[1], "2", "Found correct amount of matches")
+
+ yield ContentTask.spawn(gBrowser, null, function* (args) {
+ function getSelection(docShell) {
+ let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ return controller.getSelection(controller.SELECTION_FIND);
+ }
+
+ let selection = getSelection(docShell);
+ Assert.equal(selection.rangeCount, 0, "Correctly removed the range");
+
+ // Check the iframe too:
+ let frame = content.document.getElementById("leframe");
+ // Hoops! Get the docShell first, then the selection.
+ selection = getSelection(frame.contentWindow
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell));
+ Assert.equal(selection.rangeCount, 0, "Correctly removed the range");
+
+ content.document.documentElement.focus();
+ });
+
+ gFindBar.close(true);
+ }
+ ]]></script>
+
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug304188_window.xul b/toolkit/content/tests/chrome/bug304188_window.xul
new file mode 100644
index 000000000..931fd5c73
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug304188_window.xul
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="onLoad();"
+ title="FindbarTest for bug 304188 -
+find-menu appears in editor element which has had makeEditable() called but designMode not set">
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+
+ var gFindBar = null;
+ var gBrowser;
+
+ var imports = ["SimpleTest", "ok", "info"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+
+ function onLoad() {
+ Task.spawn(function* () {
+ gFindBar = document.getElementById("FindToolbar");
+ for (let browserId of ["content", "content-remote"]) {
+ yield startTestWithBrowser(browserId);
+ }
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ function* startTestWithBrowser(browserId) {
+ info("Starting test with browser '" + browserId + "'");
+ gBrowser = document.getElementById(browserId);
+ gFindBar.browser = gBrowser;
+ let promise = ContentTask.spawn(gBrowser, null, function* () {
+ return new Promise(resolve => {
+ addEventListener("DOMContentLoaded", function listener() {
+ removeEventListener("DOMContentLoaded", listener);
+ resolve();
+ });
+ });
+ });
+ gBrowser.loadURI("data:text/html;charset=utf-8,some%20random%20text");
+ yield promise;
+ yield onDocumentLoaded();
+ }
+
+ function* onDocumentLoaded() {
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ var edsession = content.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIEditingSession);
+ edsession.makeWindowEditable(content, "html", false, true, false);
+ content.focus();
+ });
+
+ yield enterStringIntoEditor("'");
+ yield enterStringIntoEditor("/");
+
+ ok(gFindBar.hidden,
+ "Findfield should have stayed hidden after entering editor test");
+ }
+
+ function* enterStringIntoEditor(aString) {
+ for (let i = 0; i < aString.length; i++) {
+ yield ContentTask.spawn(gBrowser, { charCode: aString.charCodeAt(i) }, function* (args) {
+ let event = content.document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, args.charCode);
+ content.document.body.dispatchEvent(event);
+ });
+ }
+ }
+ ]]></script>
+
+ <browser id="content" flex="1" src="about:blank" type="content-primary"/>
+ <browser id="content-remote" remote="true" flex="1" src="about:blank" type="content-primary"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug331215_window.xul b/toolkit/content/tests/chrome/bug331215_window.xul
new file mode 100644
index 000000000..757ce61b8
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug331215_window.xul
@@ -0,0 +1,102 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window id="331215test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="SimpleTest.executeSoon(startTest);"
+ title="331215 test">
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+
+ var gFindBar = null;
+ var gBrowser;
+
+ var imports = ["SimpleTest", "ok", "info"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+ SimpleTest.requestLongerTimeout(2);
+
+ function startTest() {
+ Task.spawn(function* () {
+ gFindBar = document.getElementById("FindToolbar");
+ for (let browserId of ["content", "content-remote"]) {
+ yield startTestWithBrowser(browserId);
+ }
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ function* startTestWithBrowser(browserId) {
+ info("Starting test with browser '" + browserId + "'");
+ gBrowser = document.getElementById(browserId);
+ gFindBar.browser = gBrowser;
+ let promise = BrowserTestUtils.browserLoaded(gBrowser);
+ gBrowser.loadURI("data:text/plain,latest");
+ yield promise;
+ yield onDocumentLoaded();
+ }
+
+ function* onDocumentLoaded() {
+ document.getElementById("cmd_find").doCommand();
+ yield promiseEnterStringIntoFindField("test");
+ document.commandDispatcher
+ .getControllerForCommand("cmd_moveTop")
+ .doCommand("cmd_moveTop");
+ yield promiseEnterStringIntoFindField("l");
+ ok(gFindBar._findField.getAttribute("status") == "notfound",
+ "Findfield status attribute should have been 'notfound' after entering test");
+ yield promiseEnterStringIntoFindField("a");
+ ok(gFindBar._findField.getAttribute("status") != "notfound",
+ "Findfield status attribute should not have been 'notfound' after entering latest");
+ }
+
+ function promiseEnterStringIntoFindField(aString) {
+ return new Promise(resolve => {
+ let listener = {
+ onFindResult: function(result) {
+ if (result.result == Ci.nsITypeAheadFind.FIND_FOUND && result.searchString != aString)
+ return;
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+
+ for (let c of aString) {
+ let code = c.charCodeAt(0);
+ let ev = new KeyboardEvent("keypress", {
+ keyCode: code,
+ charCode: code,
+ bubbles: true
+ });
+ gFindBar._findField.inputField.dispatchEvent(ev);
+ }
+ });
+ }
+ ]]></script>
+
+ <commandset>
+ <command id="cmd_find" oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
+ </commandset>
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug360437_window.xul b/toolkit/content/tests/chrome/bug360437_window.xul
new file mode 100644
index 000000000..08498b58b
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug360437_window.xul
@@ -0,0 +1,120 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window id="360437Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="startTest();"
+ title="360437 test">
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+
+ var gFindBar = null;
+ var gBrowser;
+
+ var imports = ["SimpleTest", "ok", "is", "info"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+
+ function startTest() {
+ Task.spawn(function* () {
+ gFindBar = document.getElementById("FindToolbar");
+ for (let browserId of ["content", "content-remote"]) {
+ yield startTestWithBrowser(browserId);
+ }
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ function* startTestWithBrowser(browserId) {
+ info("Starting test with browser '" + browserId + "'");
+ gBrowser = document.getElementById(browserId);
+ gFindBar.browser = gBrowser;
+ let promise = ContentTask.spawn(gBrowser, null, function* () {
+ return new Promise(resolve => {
+ addEventListener("DOMContentLoaded", function listener() {
+ removeEventListener("DOMContentLoaded", listener);
+ resolve();
+ });
+ });
+ });
+ gBrowser.loadURI("data:text/html,<form><input id='input' type='text' value='text inside an input element'></form>");
+ yield promise;
+ yield onDocumentLoaded();
+ }
+
+ function* onDocumentLoaded() {
+ gFindBar.onFindCommand();
+
+ // Make sure the findfield is correctly focused on open
+ var searchStr = "text inside an input element";
+ yield promiseEnterStringIntoFindField(searchStr);
+ is(document.commandDispatcher.focusedElement,
+ gFindBar._findField.inputField, "Find field isn't focused");
+
+ // Make sure "find again" correctly transfers focus to the content element
+ // when the find bar is closed.
+ gFindBar.close();
+ gFindBar.onFindAgainCommand(false);
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ Assert.equal(content.document.activeElement,
+ content.document.getElementById("input"), "Input Element isn't focused");
+ });
+
+ // Make sure "find again" doesn't focus the content element if focus
+ // isn't in the content document.
+ var textbox = document.getElementById("textbox");
+ textbox.focus();
+ gFindBar.close();
+ gFindBar.onFindAgainCommand(false);
+ ok(textbox.hasAttribute("focused"),
+ "Focus was stolen from a chrome element");
+ }
+
+ function promiseFindResult(str = null) {
+ return new Promise(resolve => {
+ let listener = {
+ onFindResult: function({ searchString }) {
+ if (str !== null && str != searchString) {
+ return;
+ }
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ });
+ }
+
+ function promiseEnterStringIntoFindField(str) {
+ let promise = promiseFindResult(str);
+ for (let i = 0; i < str.length; i++) {
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, str.charCodeAt(i));
+ gFindBar._findField.inputField.dispatchEvent(event);
+ }
+ return promise;
+ }
+ ]]></script>
+ <textbox id="textbox"/>
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug366992_window.xul b/toolkit/content/tests/chrome/bug366992_window.xul
new file mode 100644
index 000000000..a1e2ae1af
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug366992_window.xul
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
+
+<window id="366992 test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="onLoad();"
+ width="600"
+ height="600"
+ title="366992 test">
+
+ <commandset id="editMenuCommands"/>
+
+ <script type="application/javascript"
+ src="chrome://global/content/globalOverlay.js"/>
+ <script type="application/javascript"><![CDATA[
+ // Without the fix for bug 366992, the delete command would be enabled
+ // for the textbox even though the textbox's controller for this command
+ // disables it.
+ var gShouldNotBeReachedController = {
+ supportsCommand: function(aCommand) {
+ return aCommand == "cmd_delete";
+ },
+ isCommandEnabled: function(aCommand) {
+ return aCommand == "cmd_delete";
+ },
+ doCommand: function(aCommand) { }
+ }
+
+ function ok(condition, message) {
+ window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+ }
+ function finish() {
+ window.controllers.removeController(gShouldNotBeReachedController);
+ window.close();
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ }
+
+ function onLoad() {
+ document.getElementById("textbox").focus();
+ var deleteDisabled = document.getElementById("cmd_delete")
+ .getAttribute("disabled") == "true";
+ ok(deleteDisabled,
+ "cmd_delete should be disabled when the empty textbox is focused");
+ finish();
+ }
+
+ window.controllers.appendController(gShouldNotBeReachedController);
+ ]]></script>
+
+ <textbox id="textbox"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug409624_window.xul b/toolkit/content/tests/chrome/bug409624_window.xul
new file mode 100644
index 000000000..002cbe042
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug409624_window.xul
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window id="409624test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ title="409624 test">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <script type="application/javascript"><![CDATA[
+ var gFindBar = null;
+ var gBrowser;
+
+ var imports = ["SimpleTest", "ok", "is"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+
+ function finish() {
+ window.close();
+ SimpleTest.finish();
+ }
+
+ function startTest() {
+ gFindBar = document.getElementById("FindToolbar");
+ gBrowser = document.getElementById("content");
+ gBrowser.addEventListener("pageshow", onPageShow, false);
+ gBrowser.loadURI('data:text/html,<h2>Text mozilla</h2><input id="inp" type="text" />');
+ }
+
+ function onPageShow() {
+ gBrowser.removeEventListener("pageshow", onPageShow, false);
+ gFindBar.clear();
+ let textbox = gFindBar.getElement("findbar-textbox");
+
+ // Clear should work regardless of whether the editor has been lazily
+ // initialised yet
+ ok(!gFindBar.hasTransactions, "No transactions when findbar empty");
+ textbox.value = "mozilla";
+ ok(gFindBar.hasTransactions, "Has transactions when findbar value set without editor init");
+ gFindBar.clear();
+ is(textbox.value, '', "findbar input value cleared after clear() call without editor init");
+ ok(!gFindBar.hasTransactions, "No transactions after clear() call");
+
+ gFindBar.open();
+ let matchCaseCheckbox = gFindBar.getElement("find-case-sensitive");
+ if (!matchCaseCheckbox.hidden && matchCaseCheckbox.checked)
+ matchCaseCheckbox.click();
+ ok(!matchCaseCheckbox.checked, "case-insensitivity correctly set");
+
+ // Simulate typical input
+ textbox.focus();
+ gFindBar.clear();
+ sendChar("m");
+ ok(gFindBar.hasTransactions, "Has transactions after input");
+ let preSelection = gBrowser.contentWindow.getSelection();
+ ok(!preSelection.isCollapsed, "Found item and selected range");
+ gFindBar.clear();
+ is(textbox.value, '', "findbar input value cleared after clear() call");
+ let postSelection = gBrowser.contentWindow.getSelection();
+ ok(postSelection.isCollapsed, "item found deselected after clear() call");
+ let fp = gFindBar.getElement("find-previous");
+ ok(fp.disabled, "find-previous button disabled after clear() call");
+ let fn = gFindBar.getElement("find-next");
+ ok(fn.disabled, "find-next button disabled after clear() call");
+
+ // Test status updated after a search for text not in page
+ textbox.focus();
+ sendChar("x");
+ gFindBar.clear();
+ let ftext = gFindBar.getElement("find-status");
+ is(ftext.textContent, "", "status text disabled after clear() call");
+
+ // Test input empty with undo stack non-empty
+ textbox.focus();
+ sendChar("m");
+ sendKey("BACK_SPACE");
+ ok(gFindBar.hasTransactions, "Has transactions when undo available");
+ gFindBar.clear();
+ gFindBar.close();
+
+ finish();
+ }
+
+ SimpleTest.waitForFocus(startTest, window);
+ ]]></script>
+
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug429723_window.xul b/toolkit/content/tests/chrome/bug429723_window.xul
new file mode 100644
index 000000000..28439ae8e
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug429723_window.xul
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window id="429723Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="onLoad();"
+ title="429723 test">
+
+ <script type="application/javascript"><![CDATA[
+ var gFindBar = null;
+ var gBrowser;
+
+ function ok(condition, message) {
+ window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+ }
+
+ function finish() {
+ window.close();
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ }
+
+ function onLoad() {
+ var _delayedOnLoad = function() {
+ gFindBar = document.getElementById("FindToolbar");
+ gBrowser = document.getElementById("content");
+ gBrowser.addEventListener("pageshow", onPageShow, false);
+ gBrowser.loadURI("data:text/html,<h2 id='h2'>mozilla</h2>");
+ }
+ setTimeout(_delayedOnLoad, 1000);
+ }
+
+ function enterStringIntoFindField(aString) {
+ for (var i=0; i < aString.length; i++) {
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, aString.charCodeAt(i));
+ gFindBar._findField.inputField.dispatchEvent(event);
+ }
+ }
+
+ function onPageShow() {
+ gBrowser.removeEventListener("pageshow", onPageShow, false);
+ var findField = gFindBar._findField;
+ document.getElementById("cmd_find").doCommand();
+
+ var matchCaseCheckbox = gFindBar.getElement("find-case-sensitive");
+ if (!matchCaseCheckbox.hidden & matchCaseCheckbox.checked)
+ matchCaseCheckbox.click();
+
+ // Perform search
+ var searchStr = "z";
+ enterStringIntoFindField(searchStr);
+
+ // Highlight search term
+ var highlight = gFindBar.getElement("highlight");
+ if (!highlight.checked)
+ highlight.click();
+
+ // Delete search term
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, KeyEvent.DOM_VK_BACK_SPACE, 0);
+ gFindBar._findField.inputField.dispatchEvent(event);
+
+ var notRed = !findField.hasAttribute("status") ||
+ (findField.getAttribute("status") != "notfound");
+ ok(notRed, "Find Bar textbox is correct colour");
+ finish();
+ }
+ ]]></script>
+
+ <commandset>
+ <command id="cmd_find" oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
+ </commandset>
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug451540_window.xul b/toolkit/content/tests/chrome/bug451540_window.xul
new file mode 100644
index 000000000..3c08c95c9
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug451540_window.xul
@@ -0,0 +1,248 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+
+<window id="451540test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ title="451540 test">
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+ const SEARCH_TEXT = "minefield";
+
+ let gFindBar = null;
+ let gPrefsvc = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ let gBrowser;
+
+ let sendCtrl = true;
+ let sendMeta = false;
+ if (navigator.platform.indexOf("Mac") >= 0) {
+ sendCtrl = false;
+ sendMeta = true;
+ }
+
+ let imports = [ "SimpleTest", "ok", "is", "info"];
+ for (let name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+
+ SimpleTest.requestLongerTimeout(2);
+
+ function startTest() {
+ gFindBar = document.getElementById("FindToolbar");
+ gBrowser = document.getElementById("content");
+ gBrowser.addEventListener("pageshow", onPageShow, false);
+ let data = `data:text/html,<input id="inp" type="text" />
+ <textarea id="tarea"/>`;
+ gBrowser.loadURI(data);
+ }
+
+ function promiseHighlightFinished() {
+ return new Promise(resolve => {
+ let listener = {
+ onHighlightFinished() {
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ });
+ }
+
+ function* resetForNextTest(elementId, aText) {
+ if (!aText)
+ aText = SEARCH_TEXT;
+
+ // Turn off highlighting
+ let highlightButton = gFindBar.getElement("highlight");
+ if (highlightButton.checked) {
+ highlightButton.click();
+ }
+
+ // Initialise input
+ info(`setting element value to ${aText}`);
+ yield ContentTask.spawn(gBrowser, {elementId, aText}, function*(args) {
+ let {elementId, aText} = args;
+ let doc = content.document;
+ let element = doc.getElementById(elementId);
+ element.value = aText;
+ element.focus();
+ });
+ info(`just set element value to ${aText}`);
+ gFindBar._findField.value = SEARCH_TEXT;
+
+ // Perform search and turn on highlighting
+ gFindBar._find();
+ highlightButton.click();
+ yield promiseHighlightFinished();
+
+ // Move caret to start of element
+ info(`focusing element`);
+ yield ContentTask.spawn(gBrowser, elementId, function*(elementId) {
+ let doc = content.document;
+ let element = doc.getElementById(elementId);
+ element.focus();
+ });
+ info(`focused element`);
+ if (navigator.platform.indexOf("Mac") >= 0) {
+ yield BrowserTestUtils.synthesizeKey("VK_LEFT", { metaKey: true }, gBrowser);
+ } else {
+ yield BrowserTestUtils.synthesizeKey("VK_HOME", {}, gBrowser);
+ }
+ }
+
+ function* testSelection(elementId, expectedRangeCount, message) {
+ yield ContentTask.spawn(gBrowser, {elementId, expectedRangeCount, message}, function*(args) {
+ let {elementId, expectedRangeCount, message} = args;
+ let doc = content.document;
+ let element = doc.getElementById(elementId);
+ let controller = element.editor.selectionController;
+ let selection = controller.getSelection(controller.SELECTION_FIND);
+ Assert.equal(selection.rangeCount, expectedRangeCount, message);
+ });
+ }
+
+ function* testInput(elementId, testTypeText) {
+ let isEditableElement = yield ContentTask.spawn(gBrowser, elementId, function*(elementId) {
+ let doc = content.document;
+ let element = doc.getElementById(elementId);
+ return element instanceof Ci.nsIDOMNSEditableElement;
+ });
+ if (!isEditableElement) {
+ return;
+ }
+
+ // Initialize the findbar
+ let matchCase = gFindBar.getElement("find-case-sensitive");
+ if (matchCase.checked) {
+ matchCase.doCommand();
+ }
+
+ // First check match has been correctly highlighted
+ yield resetForNextTest(elementId);
+
+ yield testSelection(elementId, 1, testTypeText + " correctly highlighted match");
+
+ // Test 2: check highlight removed when text added within the highlight
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", {}, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("a", {}, gBrowser);
+
+ yield testSelection(elementId, 0, testTypeText + " correctly removed highlight on text insertion");
+
+ // Test 3: check highlighting remains when text added before highlight
+ yield resetForNextTest(elementId);
+ yield BrowserTestUtils.synthesizeKey("a", {}, gBrowser);
+ yield testSelection(elementId, 1, testTypeText + " highlight correctly remained on text insertion at start");
+
+ // Test 4: check highlighting remains when text added after highlight
+ yield resetForNextTest(elementId);
+ for (let x = 0; x < SEARCH_TEXT.length; x++) {
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", {}, gBrowser);
+ }
+ yield BrowserTestUtils.synthesizeKey("a", {}, gBrowser);
+ yield testSelection(elementId, 1, testTypeText + " highlight correctly remained on text insertion at end");
+
+ // Test 5: deleting text within the highlight
+ yield resetForNextTest(elementId);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", {}, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_BACK_SPACE", {}, gBrowser);
+ yield testSelection(elementId, 0, testTypeText + " correctly removed highlight on text deletion");
+
+ // Test 6: deleting text at end of highlight
+ yield resetForNextTest(elementId, SEARCH_TEXT + "A");
+ for (let x = 0; x < (SEARCH_TEXT + "A").length; x++) {
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", {}, gBrowser);
+ }
+ yield BrowserTestUtils.synthesizeKey("VK_BACK_SPACE", {}, gBrowser);
+ yield testSelection(elementId, 1, testTypeText + " highlight correctly remained on text deletion at end");
+
+ // Test 7: deleting text at start of highlight
+ yield resetForNextTest(elementId, "A" + SEARCH_TEXT);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", {}, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_BACK_SPACE", {}, gBrowser);
+ yield testSelection(elementId, 1, testTypeText + " highlight correctly remained on text deletion at start");
+
+ // Test 8: deleting selection
+ yield resetForNextTest(elementId);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { shiftKey: true }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { shiftKey: true }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("x", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield testSelection(elementId, 0, testTypeText + " correctly removed highlight on selection deletion");
+
+ // Test 9: Multiple matches within one editor (part 1)
+ // Check second match remains highlighted after inserting text into
+ // first match, and that its highlighting gets removed when the
+ // second match is edited
+ yield resetForNextTest(elementId, SEARCH_TEXT + " " + SEARCH_TEXT);
+ yield testSelection(elementId, 2, testTypeText + " correctly highlighted both matches");
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", {}, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("a", {}, gBrowser);
+ yield testSelection(elementId, 1, testTypeText + " correctly removed only the first highlight on text insertion");
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_LEFT", {}, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("a", {}, gBrowser);
+ yield testSelection(elementId, 0, testTypeText + " correctly removed second highlight on text insertion");
+
+ // Test 10: Multiple matches within one editor (part 2)
+ // Check second match remains highlighted after deleting text in
+ // first match, and that its highlighting gets removed when the
+ // second match is edited
+ yield resetForNextTest(elementId, SEARCH_TEXT + " " + SEARCH_TEXT);
+ yield testSelection(elementId, 2, testTypeText + " correctly highlighted both matches");
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", {}, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_BACK_SPACE", {}, gBrowser);
+ yield testSelection(elementId, 1, testTypeText + " correctly removed only the first highlight on text deletion");
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_LEFT", {}, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_BACK_SPACE", {}, gBrowser);
+ yield testSelection(elementId, 0, testTypeText + " correctly removed second highlight on text deletion");
+
+ // Test 11: Multiple matches within one editor (part 3)
+ // Check second match remains highlighted after deleting selection
+ // in first match, and that second match highlighting gets correctly
+ // removed when it has a selection deleted from it
+ yield resetForNextTest(elementId, SEARCH_TEXT + " " + SEARCH_TEXT);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { shiftKey: true }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { shiftKey: true }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("x", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield testSelection(elementId, 1, testTypeText + " correctly removed only first highlight on selection deletion");
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_RIGHT", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_LEFT", { shiftKey: true }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("VK_LEFT", { shiftKey: true }, gBrowser);
+ yield BrowserTestUtils.synthesizeKey("x", { ctrlKey: sendCtrl, metaKey: sendMeta }, gBrowser);
+ yield testSelection(elementId, 0, testTypeText + " correctly removed second highlight on selection deletion");
+ }
+
+ function onPageShow() {
+ gBrowser.removeEventListener("load", onPageShow, true);
+ Task.spawn(function*() {
+ gFindBar.open();
+ yield testInput("inp", "Input:");
+ yield testInput("tarea", "Textarea:");
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ SimpleTest.waitForFocus(startTest, window);
+ ]]></script>
+
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/bug624329_window.xul b/toolkit/content/tests/chrome/bug624329_window.xul
new file mode 100644
index 000000000..efca39d3b
--- /dev/null
+++ b/toolkit/content/tests/chrome/bug624329_window.xul
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Test for bug 624329 context menu position"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ context="menu">
+
+ <script>
+ opener.SimpleTest.waitForFocus(opener.childFocused, window);
+ </script>
+
+ <menupopup id="menu">
+ <!-- The bug demonstrated only when the accesskey was presented separately
+ from the label.
+ e.g. because the accesskey is not a letter in the label.
+
+ The bug demonstrates only on the first show of the context menu
+ unless menu items are removed/added each time the menu is
+ constructed. -->
+ <menuitem label="Long label to ensure the popup would hit the right of the screen" accesskey="1"/>
+ </menupopup>
+</window>
diff --git a/toolkit/content/tests/chrome/chrome.ini b/toolkit/content/tests/chrome/chrome.ini
new file mode 100644
index 000000000..2b9be4c8e
--- /dev/null
+++ b/toolkit/content/tests/chrome/chrome.ini
@@ -0,0 +1,199 @@
+[DEFAULT]
+skip-if = os == 'android'
+support-files =
+ ../widgets/popup_shared.js
+ ../widgets/tree_shared.js
+ RegisterUnregisterChrome.js
+ bug263683_window.xul
+ bug304188_window.xul
+ bug331215_window.xul
+ bug360437_window.xul
+ bug366992_window.xul
+ bug409624_window.xul
+ bug429723_window.xul
+ bug624329_window.xul
+ dialog_dialogfocus.xul
+ file_about_networking_wsh.py
+ file_autocomplete_with_composition.js
+ findbar_entireword_window.xul
+ findbar_events_window.xul
+ findbar_window.xul
+ frame_popup_anchor.xul
+ frame_popupremoving_frame.xul
+ frame_subframe_origin_subframe1.xul
+ frame_subframe_origin_subframe2.xul
+ popup_childframe_node.xul
+ popup_trigger.js
+ sample_entireword_latin1.html
+ window_browser_drop.xul
+ window_keys.xul
+ window_largemenu.xul
+ window_panel.xul
+ window_popup_anchor.xul
+ window_popup_anchoratrect.xul
+ window_popup_attribute.xul
+ window_popup_button.xul
+ window_popup_preventdefault_chrome.xul
+ window_preferences.xul
+ window_preferences2.xul
+ window_preferences3.xul
+ window_preferences_commandretarget.xul
+ window_screenPosSize.xul
+ window_showcaret.xul
+ window_subframe_origin.xul
+ window_titlebar.xul
+ window_tooltip.xul
+ xul_selectcontrol.js
+ rtlchrome/rtl.css
+ rtlchrome/rtl.dtd
+ rtlchrome/rtl.manifest
+ rtltest/righttoleft.manifest
+ rtltest/content/dirtest.xul
+
+[test_about_networking.html]
+[test_arrowpanel.xul]
+[test_autocomplete2.xul]
+[test_autocomplete3.xul]
+[test_autocomplete4.xul]
+[test_autocomplete5.xul]
+[test_autocomplete_delayOnPaste.xul]
+subsuite = clipboard
+[test_autocomplete_emphasis.xul]
+[test_autocomplete_with_composition_on_input.html]
+[test_autocomplete_with_composition_on_textbox.xul]
+[test_autocomplete_placehold_last_complete.xul]
+[test_browser_drop.xul]
+[test_bug253481.xul]
+subsuite = clipboard
+[test_bug263683.xul]
+[test_bug304188.xul]
+[test_bug331215.xul]
+[test_bug360220.xul]
+[test_bug360437.xul]
+skip-if = os == 'linux' # Bug 1264604
+[test_bug365773.xul]
+[test_bug366992.xul]
+[test_bug382990.xul]
+[test_bug409624.xul]
+[test_bug418874.xul]
+[test_bug429723.xul]
+[test_bug437844.xul]
+[test_bug457632.xul]
+[test_bug460942.xul]
+[test_bug471776.xul]
+[test_bug509732.xul]
+[test_bug554279.xul]
+[test_bug557987.xul]
+[test_bug562554.xul]
+[test_bug570192.xul]
+[test_bug585946.xul]
+[test_bug624329.xul]
+skip-if = (os == 'mac' && os_version == '10.10') # Unexpectedly perma-passes on OSX 10.10
+[test_bug792324.xul]
+[test_bug1048178.xul]
+skip-if = toolkit == "cocoa"
+[test_button.xul]
+[test_closemenu_attribute.xul]
+[test_colorpicker_popup.xul]
+[test_contextmenu_list.xul]
+[test_datepicker.xul]
+[test_deck.xul]
+[test_dialogfocus.xul]
+[test_findbar.xul]
+subsuite = clipboard
+[test_findbar_entireword.xul]
+[test_findbar_events.xul]
+[test_focus_anons.xul]
+[test_hiddenitems.xul]
+[test_hiddenpaging.xul]
+[test_keys.xul]
+[test_labelcontrol.xul]
+[test_largemenu.xul]
+skip-if = os == 'linux' && !debug #Bug 1207174
+[test_menu.xul]
+[test_menu_anchored.xul]
+[test_menu_hide.xul]
+[test_menuchecks.xul]
+[test_menuitem_blink.xul]
+[test_menuitem_commands.xul]
+[test_menulist.xul]
+[test_menulist_keynav.xul]
+[test_menulist_null_value.xul]
+[test_menulist_paging.xul]
+[test_menulist_position.xul]
+[test_mousescroll.xul]
+[test_notificationbox.xul]
+[test_panel.xul]
+[test_panelfrommenu.xul]
+[test_popup_anchor.xul]
+[test_popup_anchoratrect.xul]
+skip-if = os == 'linux' # 1167694
+[test_popup_attribute.xul]
+skip-if = os == 'linux' && asan #Bug 1131634
+[test_popup_button.xul]
+skip-if = os == 'linux' && asan # Bug 1281360
+[test_popup_coords.xul]
+[test_popup_keys.xul]
+[test_popup_moveToAnchor.xul]
+[test_popup_preventdefault.xul]
+[test_popup_preventdefault_chrome.xul]
+[test_popup_recreate.xul]
+[test_popup_scaled.xul]
+[test_popup_tree.xul]
+[test_popuphidden.xul]
+[test_popupincontent.xul]
+[test_popupremoving.xul]
+[test_popupremoving_frame.xul]
+[test_position.xul]
+[test_preferences.xul]
+[test_preferences_beforeaccept.xul]
+support-files = window_preferences_beforeaccept.xul
+[test_preferences_onsyncfrompreference.xul]
+support-files = window_preferences_onsyncfrompreference.xul
+[test_progressmeter.xul]
+[test_props.xul]
+[test_radio.xul]
+[test_richlist_direction.xul]
+[test_righttoleft.xul]
+[test_scale.xul]
+[test_scaledrag.xul]
+[test_screenPersistence.xul]
+[test_scrollbar.xul]
+[test_showcaret.xul]
+[test_sorttemplate.xul]
+[test_statusbar.xul]
+[test_subframe_origin.xul]
+[test_tabbox.xul]
+[test_tabindex.xul]
+[test_textbox_dictionary.xul]
+[test_textbox_emptytext.xul]
+[test_textbox_number.xul]
+[test_textbox_search.xul]
+[test_timepicker.xul]
+[test_titlebar.xul]
+skip-if = os == "linux"
+[test_toolbar.xul]
+[test_tooltip.xul]
+skip-if = (os == 'mac' && os_version == '10.10') # Bug 1141245, frequent timeouts on OSX 10.10
+[test_tooltip_noautohide.xul]
+[test_tree.xul]
+[test_tree_hier.xul]
+[test_tree_hier_cell.xul]
+[test_tree_single.xul]
+[test_tree_view.xul]
+# test_panel_focus.xul won't work if the Full Keyboard Access preference is set to
+# textboxes and lists only, so skip this test on Mac
+[test_panel_focus.xul]
+support-files = window_panel_focus.xul
+skip-if = toolkit == "cocoa"
+[test_chromemargin.xul]
+support-files = window_chromemargin.xul
+skip-if = toolkit == "cocoa"
+[test_bug451540.xul]
+support-files = bug451540_window.xul
+[test_autocomplete_mac_caret.xul]
+skip-if = toolkit != "cocoa"
+[test_cursorsnap.xul]
+disabled =
+#skip-if = os != "win"
+support-files = window_cursorsnap_dialog.xul window_cursorsnap_wizard.xul
diff --git a/toolkit/content/tests/chrome/dialog_dialogfocus.xul b/toolkit/content/tests/chrome/dialog_dialogfocus.xul
new file mode 100644
index 000000000..770695ed3
--- /dev/null
+++ b/toolkit/content/tests/chrome/dialog_dialogfocus.xul
@@ -0,0 +1,57 @@
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<dialog buttons="extra2,accept,cancel" onload="loaded()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<tabbox id="tabbox" hidden="true">
+ <tabs>
+ <tab id="tab" label="Tab"/>
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <button id="tabbutton" label="Tab Button"/>
+ <button id="tabbutton2" label="Tab Button 2"/>
+ </tabpanel>
+ </tabpanels>
+</tabbox>
+
+<textbox id="textbox-yes" value="textbox-yes" hidden="true"/>
+<textbox id="textbox-no" value="textbox-no" noinitialfocus="true" hidden="true"/>
+<button id="one" label="One"/>
+<button id="two" label="Two" hidden="true"/>
+
+<script>
+function loaded()
+{
+ if (window.arguments) {
+ var step = window.arguments[0];
+ switch (step) {
+ case 2:
+ document.getElementById("one").setAttribute("noinitialfocus", "true");
+ break;
+ case 3:
+ document.getElementById("one").hidden = true;
+ case 4:
+ document.getElementById("tabbutton2").setAttribute("noinitialfocus", "true");
+ case 5:
+ document.getElementById("tabbutton").setAttribute("noinitialfocus", "true");
+ case 6:
+ document.getElementById("tabbox").hidden = false;
+ break;
+ case 7:
+ var two = document.getElementById("two");
+ two.hidden = false;
+ two.focus();
+ break;
+ case 8:
+ document.getElementById("textbox-yes").hidden = false;
+ break;
+ case 9:
+ document.getElementById("textbox-no").hidden = false;
+ break;
+ }
+ }
+}
+</script>
+
+</dialog>
diff --git a/toolkit/content/tests/chrome/file_about_networking_wsh.py b/toolkit/content/tests/chrome/file_about_networking_wsh.py
new file mode 100644
index 000000000..17ad250e5
--- /dev/null
+++ b/toolkit/content/tests/chrome/file_about_networking_wsh.py
@@ -0,0 +1,9 @@
+from mod_pywebsocket import msgutil
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+def web_socket_transfer_data(request):
+ while not request.client_terminated:
+ msgutil.receive_message(request)
+
diff --git a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js
new file mode 100644
index 000000000..881e772ad
--- /dev/null
+++ b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js
@@ -0,0 +1,540 @@
+// nsDoTestsForAutoCompleteWithComposition tests autocomplete with composition.
+// Users must include SimpleTest.js and EventUtils.js.
+
+function waitForCondition(condition, nextTest) {
+ var tries = 0;
+ var interval = setInterval(function() {
+ if (condition() || tries >= 30) {
+ moveOn();
+ }
+ tries++;
+ }, 100);
+ var moveOn = function() { clearInterval(interval); nextTest(); };
+}
+
+function nsDoTestsForAutoCompleteWithComposition(aDescription,
+ aWindow,
+ aTarget,
+ aAutoCompleteController,
+ aIsFunc,
+ aGetTargetValueFunc,
+ aOnFinishFunc)
+{
+ this._description = aDescription;
+ this._window = aWindow;
+ this._target = aTarget;
+ this._controller = aAutoCompleteController;
+
+ this._is = aIsFunc;
+ this._getTargetValue = aGetTargetValueFunc;
+ this._onFinish = aOnFinishFunc;
+
+ this._target.focus();
+
+ this._DefaultCompleteDefaultIndex =
+ this._controller.input.completeDefaultIndex;
+
+ this._doTests();
+}
+
+nsDoTestsForAutoCompleteWithComposition.prototype = {
+ _window: null,
+ _target: null,
+ _controller: null,
+ _DefaultCompleteDefaultIndex: false,
+ _description: "",
+
+ _is: null,
+ _getTargetValue: function () { return "not initialized"; },
+ _onFinish: null,
+
+ _doTests: function ()
+ {
+ if (++this._testingIndex == this._tests.length) {
+ this._controller.input.completeDefaultIndex =
+ this._DefaultCompleteDefaultIndex;
+ this._onFinish();
+ return;
+ }
+
+ var test = this._tests[this._testingIndex];
+ if (this._controller.input.completeDefaultIndex != test.completeDefaultIndex) {
+ this._controller.input.completeDefaultIndex = test.completeDefaultIndex;
+ }
+ test.execute(this._window);
+
+ waitForCondition(() => {
+ return this._controller.searchStatus >=
+ Components.interfaces.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
+ },
+ this._checkResult.bind(this));
+ },
+
+ _checkResult: function ()
+ {
+ var test = this._tests[this._testingIndex];
+ this._is(this._getTargetValue(), test.value,
+ this._description + ", " + test.description + ": value");
+ this._is(this._controller.searchString, test.searchString,
+ this._description + ", " + test.description +": searchString");
+ this._is(this._controller.input.popupOpen, test.popup,
+ this._description + ", " + test.description + ": popupOpen");
+ this._doTests();
+ },
+
+ _testingIndex: -1,
+ _tests: [
+ // Simple composition when popup hasn't been shown.
+ // The autocomplete popup should not be shown during composition, but
+ // after compositionend, the popup should be shown.
+ { description: "compositionstart shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "M",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
+ shiftKey: true },
+ }, aWindow);
+ }, popup: false, value: "M", searchString: ""
+ },
+ { description: "modifying composition string shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "Mo",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ }, aWindow);
+ }, popup: false, value: "Mo", searchString: ""
+ },
+ { description: "compositionend should open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommitasis",
+ key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
+ }, popup: true, value: "Mo", searchString: "Mo"
+ },
+ // If composition starts when popup is shown, the compositionstart event
+ // should cause closing the popup.
+ { description: "compositionstart should close the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "z",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
+ }, aWindow);
+ }, popup: false, value: "Moz", searchString: "Mo"
+ },
+ { description: "modifying composition string shouldn't reopen the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "zi",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
+ }, aWindow);
+ }, popup: false, value: "Mozi", searchString: "Mo"
+ },
+ { description: "compositionend should research the result and open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommitasis",
+ key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
+ }, popup: true, value: "Mozi", searchString: "Mozi"
+ },
+ // If composition is cancelled, the value shouldn't be changed.
+ { description: "compositionstart should reclose the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "l",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "l", code: "KeyL", keyCode: KeyboardEvent.DOM_VK_L },
+ }, aWindow);
+ }, popup: false, value: "Mozil", searchString: "Mozi"
+ },
+ { description: "modifying composition string shouldn't reopen the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "ll",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "l", code: "KeyL", keyCode: KeyboardEvent.DOM_VK_L },
+ }, aWindow);
+ }, popup: false, value: "Mozill", searchString: "Mozi"
+ },
+ { description: "modifying composition string to empty string shouldn't reopen the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "",
+ "clauses":
+ [
+ { "length": 0, "attr": 0 }
+ ]
+ },
+ "caret": { "start": 0, "length": 0 }
+ }, aWindow);
+ }, popup: false, value: "Mozi", searchString: "Mozi"
+ },
+ { description: "cancled compositionend should reopen the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommit", data: "",
+ key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ }, popup: true, value: "Mozi", searchString: "Mozi"
+ },
+ // But if composition replaces some characters and canceled, the search
+ // string should be the latest value.
+ { description: "compositionstart with selected string should close the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeKey("VK_LEFT", { shiftKey: true }, aWindow);
+ synthesizeKey("VK_LEFT", { shiftKey: true }, aWindow);
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "z",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
+ }, aWindow);
+ }, popup: false, value: "Moz", searchString: "Mozi"
+ },
+ { description: "modifying composition string shouldn't reopen the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "zi",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
+ }, aWindow);
+ }, popup: false, value: "Mozi", searchString: "Mozi"
+ },
+ { description: "modifying composition string to empty string shouldn't reopen the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "",
+ "clauses":
+ [
+ { "length": 0, "attr": 0 }
+ ]
+ },
+ "caret": { "start": 0, "length": 0 }
+ }, aWindow);
+ }, popup: false, value: "Mo", searchString: "Mozi"
+ },
+ { description: "canceled compositionend should search the result with the latest value",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommitasis",
+ key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ }, popup: true, value: "Mo", searchString: "Mo"
+ },
+ // If all characters are removed, the popup should be closed.
+ { description: "the value becomes empty by backspace, the popup should be closed",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ }, popup: false, value: "", searchString: ""
+ },
+ // composition which is canceled shouldn't cause opening the popup.
+ { description: "compositionstart shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "M",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "m", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
+ shiftKey: true },
+ }, aWindow);
+ }, popup: false, value: "M", searchString: ""
+ },
+ { description: "modifying composition string shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "Mo",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ }, aWindow);
+ }, popup: false, value: "Mo", searchString: ""
+ },
+ { description: "modifying composition string to empty string shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "",
+ "clauses":
+ [
+ { "length": 0, "attr": 0 }
+ ]
+ },
+ "caret": { "start": 0, "length": 0 }
+ }, aWindow);
+ }, popup: false, value: "", searchString: ""
+ },
+ { description: "canceled compositionend shouldn't open the popup if it was closed",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommitasis",
+ key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ }, popup: false, value: "", searchString: ""
+ },
+ // Down key should open the popup even if the editor is empty.
+ { description: "DOWN key should open the popup even if the value is empty",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeKey("VK_DOWN", {}, aWindow);
+ }, popup: true, value: "", searchString: ""
+ },
+ // If popup is open at starting composition, the popup should be reopened
+ // after composition anyway.
+ { description: "compositionstart shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "M",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
+ shiftKey: true },
+ }, aWindow);
+ }, popup: false, value: "M", searchString: ""
+ },
+ { description: "modifying composition string shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "Mo",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ }, aWindow);
+ }, popup: false, value: "Mo", searchString: ""
+ },
+ { description: "modifying composition string to empty string shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "",
+ "clauses":
+ [
+ { "length": 0, "attr": 0 }
+ ]
+ },
+ "caret": { "start": 0, "length": 0 }
+ }, aWindow);
+ }, popup: false, value: "", searchString: ""
+ },
+ { description: "canceled compositionend should open the popup if it was opened",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommitasis",
+ key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ }, popup: true, value: "", searchString: ""
+ },
+ // Type normally, and hit escape, the popup should be closed.
+ { description: "ESCAPE should close the popup after typing something",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeKey("M", { shiftKey: true }, aWindow);
+ synthesizeKey("o", { shiftKey: true }, aWindow);
+ synthesizeKey("VK_ESCAPE", {}, aWindow);
+ }, popup: false, value: "Mo", searchString: "Mo"
+ },
+ // Even if the popup is closed, composition which is canceled should open
+ // the popup if the value isn't empty.
+ // XXX This might not be good behavior, but anyway, this is minor issue...
+ { description: "compositionstart shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "z",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "z", code: "KeyZ", keyCode: KeyboardEvent.DOM_VK_Z },
+ }, aWindow);
+ }, popup: false, value: "Moz", searchString: "Mo"
+ },
+ { description: "modifying composition string shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "zi",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "i", code: "KeyI", keyCode: KeyboardEvent.DOM_VK_I },
+ }, aWindow);
+ }, popup: false, value: "Mozi", searchString: "Mo"
+ },
+ { description: "modifying composition string to empty string shouldn't open the popup",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "",
+ "clauses":
+ [
+ { "length": 0, "attr": 0 }
+ ]
+ },
+ "caret": { "start": 0, "length": 0 }
+ }, aWindow);
+ }, popup: false, value: "Mo", searchString: "Mo"
+ },
+ { description: "canceled compositionend shouldn't open the popup if the popup was closed",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommitasis",
+ key: { key: "KEY_Escape", code: "Escape" } }, aWindow);
+ }, popup: true, value: "Mo", searchString: "Mo"
+ },
+ // House keeping...
+ { description: "house keeping for next tests",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ }, popup: false, value: "", searchString: ""
+ },
+ // Testing for nsIAutoCompleteInput.completeDefaultIndex being true.
+ { description: "compositionstart shouldn't open the popup (completeDefaultIndex is true)",
+ completeDefaultIndex: true,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "M",
+ "clauses":
+ [
+ { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 1, "length": 0 },
+ "key": { key: "M", code: "KeyM", keyCode: KeyboardEvent.DOM_VK_M,
+ shiftKey: true },
+ }, aWindow);
+ }, popup: false, value: "M", searchString: ""
+ },
+ { description: "modifying composition string shouldn't open the popup (completeDefaultIndex is true)",
+ completeDefaultIndex: true,
+ execute: function (aWindow) {
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": "Mo",
+ "clauses":
+ [
+ { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": 2, "length": 0 },
+ "key": { key: "o", code: "KeyO", keyCode: KeyboardEvent.DOM_VK_O },
+ }, aWindow);
+ }, popup: false, value: "Mo", searchString: ""
+ },
+ { description: "compositionend should open the popup (completeDefaultIndex is true)",
+ completeDefaultIndex: true,
+ execute: function (aWindow) {
+ synthesizeComposition({ type: "compositioncommitasis",
+ key: { key: "KEY_Enter", code: "Enter" } }, aWindow);
+ }, popup: true, value: "Mozilla", searchString: "Mo"
+ },
+ // House keeping...
+ { description: "house keeping for next tests",
+ completeDefaultIndex: false,
+ execute: function (aWindow) {
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ synthesizeKey("VK_BACK_SPACE", {}, aWindow);
+ }, popup: false, value: "", searchString: ""
+ }
+ ]
+};
diff --git a/toolkit/content/tests/chrome/findbar_entireword_window.xul b/toolkit/content/tests/chrome/findbar_entireword_window.xul
new file mode 100644
index 000000000..f0da61081
--- /dev/null
+++ b/toolkit/content/tests/chrome/findbar_entireword_window.xul
@@ -0,0 +1,275 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+
+<window id="FindbarEntireWordTest"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="onLoad();"
+ title="findbar test - entire words only">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"/>
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+
+ var gFindBar = null;
+ var gBrowser;
+
+ var imports = ["SimpleTest", "SpecialPowers", "ok", "is", "isnot", "info"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+ SimpleTest.requestLongerTimeout(2);
+
+ const kBaseURL = "chrome://mochitests/content/chrome/toolkit/content/tests/chrome";
+ const kTests = {
+ latin1: {
+ testSimpleEntireWord: {
+ "and": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'and' should've been found");
+ is(results.matches.total, 6, "should've found 6 matches");
+ },
+ "an": results => {
+ is(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'an' shouldn't have been found");
+ is(results.matches.total, 0, "should've found 0 matches");
+ },
+ "darkness": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'darkness' should've been found");
+ is(results.matches.total, 3, "should've found 3 matches");
+ },
+ "mammon": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'mammon' should've been found");
+ is(results.matches.total, 1, "should've found 1 match");
+ }
+ },
+ testCaseSensitive: {
+ "And": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'And' should've been found");
+ is(results.matches.total, 1, "should've found 1 match");
+ },
+ "and": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'and' should've been found");
+ is(results.matches.total, 5, "should've found 5 matches");
+ },
+ "Mammon": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'mammon' should've been found");
+ is(results.matches.total, 1, "should've found 1 match");
+ }
+ },
+ testWordBreakChars: {
+ "a": results => {
+ // 'a' is a common charactar, but there should only be one occurrence
+ // separated by word boundaries.
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'a' should've been found");
+ is(results.matches.total, 1, "should've found 1 match");
+ },
+ "quarrelled": results => {
+ // 'quarrelled' is denoted as a word by a period char.
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'quarrelled' should've been found");
+ is(results.matches.total, 1, "should've found 1 match");
+ }
+ },
+ testQuickfind: {
+ "and": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'and' should've been found");
+ is(results.matches.total, 6, "should've found 6 matches");
+ },
+ "an": results => {
+ is(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'an' shouldn't have been found");
+ is(results.matches.total, 0, "should've found 0 matches");
+ },
+ "darkness": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'darkness' should've been found");
+ is(results.matches.total, 3, "should've found 3 matches");
+ },
+ "mammon": results => {
+ isnot(results.find.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "'mammon' should've been found");
+ is(results.matches.total, 1, "should've found 1 match");
+ }
+ }
+ }
+ };
+
+ function onLoad() {
+ Task.spawn(function* () {
+ yield new Promise(resolve => {
+ SpecialPowers.pushPrefEnv(
+ { set: [["findbar.entireword", true]] }, resolve);
+ });
+
+ gFindBar = document.getElementById("FindToolbar");
+ for (let browserId of ["content", "content-remote"]) {
+ // XXXmikedeboer: when multiple test samples are available, make this
+ // a nested loop that iterates over them. For now, only
+ // latin is available.
+ yield startTestWithBrowser("latin1", browserId);
+ }
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ function* startTestWithBrowser(testName, browserId) {
+ info("Starting test with browser '" + browserId + "'");
+ gBrowser = document.getElementById(browserId);
+ gFindBar.browser = gBrowser;
+
+ let promise = ContentTask.spawn(gBrowser, null, function* () {
+ return new Promise(resolve => {
+ addEventListener("DOMContentLoaded", function listener() {
+ removeEventListener("DOMContentLoaded", listener);
+ resolve();
+ });
+ });
+ });
+ gBrowser.loadURI(kBaseURL + "/sample_entireword_" + testName + ".html");
+ yield promise;
+ yield onDocumentLoaded(testName);
+ }
+
+ function* onDocumentLoaded(testName) {
+ let suite = kTests[testName];
+ yield testSimpleEntireWord(suite.testSimpleEntireWord);
+ yield testCaseSensitive(suite.testCaseSensitive);
+ yield testWordBreakChars(suite.testWordBreakChars);
+ yield testQuickfind(suite.testQuickfind);
+ }
+
+ var enterStringIntoFindField = Task.async(function* (str, waitForResult = true) {
+ for (let promise, i = 0; i < str.length; i++) {
+ if (waitForResult) {
+ promise = promiseFindResult();
+ }
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, str.charCodeAt(i));
+ gFindBar._findField.inputField.dispatchEvent(event);
+ if (waitForResult) {
+ yield promise;
+ }
+ }
+ });
+
+ function openFindbar() {
+ document.getElementById("cmd_find").doCommand();
+ return gFindBar._startFindDeferred && gFindBar._startFindDeferred.promise;
+ }
+
+ function promiseFindResult(searchString) {
+ return new Promise(resolve => {
+ let data = {};
+ let listener = {
+ onFindResult: res => {
+ if (searchString && res.searchString != searchString)
+ return;
+
+ gFindBar.browser.finder.removeResultListener(listener);
+ data.find = res;
+ if (res.result == Ci.nsITypeAheadFind.FIND_NOTFOUND) {
+ data.matches = { total: 0, current: 0 };
+ resolve(data);
+ return;
+ }
+ listener = {
+ onMatchesCountResult: res => {
+ gFindBar.browser.finder.removeResultListener(listener);
+ data.matches = res;
+ resolve(data);
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ }
+ };
+
+ gFindBar.browser.finder.addResultListener(listener);
+ });
+ }
+
+ function* testIterator(tests) {
+ for (let searchString of Object.getOwnPropertyNames(tests)) {
+ gFindBar.clear();
+
+ let promise = promiseFindResult(searchString);
+
+ yield enterStringIntoFindField(searchString, false);
+
+ let result = yield promise;
+ tests[searchString](result);
+ }
+ }
+
+ function* testSimpleEntireWord(tests) {
+ yield openFindbar();
+ ok(!gFindBar.hidden, "testSimpleEntireWord: findbar should be open");
+
+ yield* testIterator(tests);
+
+ gFindBar.close();
+ }
+
+ function* testCaseSensitive(tests) {
+ yield openFindbar();
+ ok(!gFindBar.hidden, "testCaseSensitive: findbar should be open");
+
+ let matchCaseCheckbox = gFindBar.getElement("find-case-sensitive");
+ if (!matchCaseCheckbox.hidden && !matchCaseCheckbox.checked)
+ matchCaseCheckbox.click();
+
+ yield* testIterator(tests);
+
+ if (!matchCaseCheckbox.hidden)
+ matchCaseCheckbox.click();
+ gFindBar.close();
+ }
+
+ function* testWordBreakChars(tests) {
+ yield openFindbar();
+ ok(!gFindBar.hidden, "testWordBreakChars: findbar should be open");
+
+ yield* testIterator(tests);
+
+ gFindBar.close();
+ }
+
+ function* testQuickfind(tests) {
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ let document = content.document;
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, "/".charCodeAt(0));
+ document.documentElement.dispatchEvent(event);
+ });
+
+ ok(!gFindBar.hidden, "testQuickfind: failed to open findbar");
+ ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
+ "testQuickfind: find field is not focused");
+ ok(!gFindBar.getElement("entire-word-status").hidden,
+ "testQuickfind: entire word mode status text should be visible");
+
+ yield* testIterator(tests);
+
+ gFindBar.close();
+ }
+ ]]></script>
+
+ <commandset>
+ <command id="cmd_find" oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
+ </commandset>
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/findbar_events_window.xul b/toolkit/content/tests/chrome/findbar_events_window.xul
new file mode 100644
index 000000000..2bfc52c14
--- /dev/null
+++ b/toolkit/content/tests/chrome/findbar_events_window.xul
@@ -0,0 +1,173 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window id="FindbarTest"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="SimpleTest.executeSoon(startTest);"
+ title="findbar events test">
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+
+ var gFindBar = null;
+ var gBrowser;
+ const kTimeout = 5000; // 5 seconds.
+
+ var imports = ["SimpleTest", "ok", "is", "info"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+ SimpleTest.requestLongerTimeout(2);
+
+ function startTest() {
+ Task.spawn(function* () {
+ gFindBar = document.getElementById("FindToolbar");
+ for (let browserId of ["content", "content-remote"]) {
+ yield startTestWithBrowser(browserId);
+ }
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ function* startTestWithBrowser(browserId) {
+ info("Starting test with browser '" + browserId + "'");
+ gBrowser = document.getElementById(browserId);
+ gFindBar.browser = gBrowser;
+ let promise = BrowserTestUtils.browserLoaded(gBrowser);
+ gBrowser.loadURI("data:text/html,hello there");
+ yield promise;
+ yield onDocumentLoaded();
+ }
+
+ function* onDocumentLoaded() {
+ gFindBar.open();
+ gFindBar.onFindCommand();
+
+ yield testFind();
+ yield testFindAgain();
+ yield testCaseSensitivity();
+ yield testHighlight();
+ }
+
+ function checkSelection() {
+ return new Promise(resolve => {
+ SimpleTest.executeSoon(() => {
+ ContentTask.spawn(gBrowser, null, function* () {
+ let selected = content.getSelection();
+ Assert.equal(String(selected), "", "No text is selected");
+
+ let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ let selection = controller.getSelection(controller.SELECTION_FIND);
+ Assert.equal(selection.rangeCount, 0, "No text is highlighted");
+ }).then(resolve);
+ });
+ });
+ }
+
+ function once(node, eventName, preventDefault = true) {
+ return new Promise((resolve, reject) => {
+ let timeout = window.setTimeout(() => {
+ reject("Event wasn't fired within " + kTimeout + "ms for event '" +
+ eventName + "'.");
+ }, kTimeout);
+
+ node.addEventListener(eventName, function clb(e) {
+ window.clearTimeout(timeout);
+ node.removeEventListener(eventName, clb);
+ if (preventDefault)
+ e.preventDefault();
+ resolve(e);
+ });
+ });
+ }
+
+ function* testFind() {
+ info("Testing normal find.");
+ let query = "t";
+ let promise = once(gFindBar, "find");
+
+ // Put some text in the find box.
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, query.charCodeAt(0));
+ gFindBar._findField.inputField.dispatchEvent(event);
+
+ let e = yield promise;
+ ok(e.detail.query === query, "find event query should match '" + query + "'");
+ // Since we're preventing the default make sure nothing was selected.
+ yield checkSelection();
+ }
+
+ function testFindAgain() {
+ info("Testing repeating normal find.");
+ let promise = once(gFindBar, "findagain");
+
+ gFindBar.onFindAgainCommand();
+
+ yield promise;
+ // Since we're preventing the default make sure nothing was selected.
+ yield checkSelection();
+ }
+
+ function* testCaseSensitivity() {
+ info("Testing normal case sensitivity.");
+ let promise = once(gFindBar, "findcasesensitivitychange", false);
+
+ let matchCaseCheckbox = gFindBar.getElement("find-case-sensitive");
+ matchCaseCheckbox.click();
+
+ let e = yield promise;
+ ok(e.detail.caseSensitive, "find should be case sensitive");
+
+ // Toggle it back to the original setting.
+ matchCaseCheckbox.click();
+
+ // Changing case sensitivity does the search so clear the selected text
+ // before the next test.
+ yield ContentTask.spawn(gBrowser, null, () => content.getSelection().removeAllRanges());
+ }
+
+ function* testHighlight() {
+ info("Testing find with highlight all.");
+ // Update the find state so the highlight button is clickable.
+ gFindBar.updateControlState(Ci.nsITypeAheadFind.FIND_FOUND, false);
+
+ let promise = once(gFindBar, "findhighlightallchange");
+
+ let highlightButton = gFindBar.getElement("highlight");
+ if (!highlightButton.checked)
+ highlightButton.click();
+
+ let e = yield promise;
+ ok(e.detail.highlightAll, "find event should have highlight all set");
+ // Since we're preventing the default make sure nothing was highlighted.
+ yield checkSelection();
+
+ // Toggle it back to the original setting.
+ if (highlightButton.checked)
+ highlightButton.click();
+ }
+ ]]></script>
+
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/findbar_window.xul b/toolkit/content/tests/chrome/findbar_window.xul
new file mode 100644
index 000000000..f17f760fe
--- /dev/null
+++ b/toolkit/content/tests/chrome/findbar_window.xul
@@ -0,0 +1,756 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window id="FindbarTest"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="600"
+ height="600"
+ onload="onLoad();"
+ title="findbar test">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <script type="application/javascript"><![CDATA[
+ const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+ Cu.import("resource://gre/modules/AppConstants.jsm");
+ Cu.import("resource://gre/modules/Task.jsm");
+ Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ ContentTask.setTestScope(window.opener.wrappedJSObject);
+
+ var gPrefsvc = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+
+ const SAMPLE_URL = "http://www.mozilla.org/";
+ const SAMPLE_TEXT = "Some text in a text field.";
+ const SEARCH_TEXT = "Text Test";
+ const NOT_FOUND_TEXT = "This text is not on the page."
+ const ITERATOR_TIMEOUT = gPrefsvc.getIntPref("findbar.iteratorTimeout");
+
+ var gFindBar = null;
+ var gBrowser;
+
+ var gClipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+ var gHasFindClipboard = gClipboard.supportsFindClipboard();
+
+ var gStatusText;
+ var gXULBrowserWindow = {
+ QueryInterface: function(aIID) {
+ if (aIID.Equals(Ci.nsIXULBrowserWindow) ||
+ aIID.Equals(Ci.nsISupports))
+ return this;
+
+ throw Cr.NS_NOINTERFACE;
+ },
+
+ setJSStatus: function() { },
+
+ setOverLink: function(aStatusText, aLink) {
+ gStatusText = aStatusText;
+ },
+
+ onBeforeLinkTraversal: function() { }
+ };
+
+ var imports = ["SimpleTest", "ok", "is", "info"];
+ for (var name of imports) {
+ window[name] = window.opener.wrappedJSObject[name];
+ }
+ SimpleTest.requestLongerTimeout(2);
+
+ function onLoad() {
+ Task.spawn(function* () {
+ window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .treeOwner
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIXULWindow)
+ .XULBrowserWindow = gXULBrowserWindow;
+
+ gFindBar = document.getElementById("FindToolbar");
+ for (let browserId of ["content", "content-remote"]) {
+ yield startTestWithBrowser(browserId);
+ }
+ }).then(() => {
+ window.close();
+ SimpleTest.finish();
+ });
+ }
+
+ function* startTestWithBrowser(browserId) {
+ info("Starting test with browser '" + browserId + "'");
+ gBrowser = document.getElementById(browserId);
+ gFindBar.browser = gBrowser;
+
+ // Tests delays the loading of a document for one second.
+ yield new Promise(resolve => setTimeout(resolve, 1000));
+
+ let promise = BrowserTestUtils.browserLoaded(gBrowser);
+ gBrowser.loadURI("data:text/html,<h2 id='h2'>" + SEARCH_TEXT +
+ "</h2><h2><a href='" + SAMPLE_URL + "'>Link Test</a></h2><input id='text' type='text' value='" +
+ SAMPLE_TEXT + "'></input><input id='button' type='button'></input><img id='img' width='50' height='50'/>");
+ yield promise;
+ yield onDocumentLoaded();
+ }
+
+ function* onDocumentLoaded() {
+ yield testNormalFind();
+ gFindBar.close();
+ ok(gFindBar.hidden, "Failed to close findbar after testNormalFind");
+ yield openFindbar();
+ yield testNormalFindWithComposition();
+ gFindBar.close();
+ ok(gFindBar.hidden, "findbar should be hidden after testNormalFindWithComposition");
+ yield openFindbar();
+ yield testAutoCaseSensitivityUI();
+ yield testQuickFindText();
+ gFindBar.close();
+ ok(gFindBar.hidden, "Failed to close findbar after testQuickFindText");
+ // TODO: `testFindWithHighlight` tests fastFind integrity, which can not
+ // be accessed with RemoteFinder. We're skipping it for now.
+ if (gFindBar._browser.finder._fastFind) {
+ yield testFindWithHighlight();
+ gFindBar.close();
+ ok(gFindBar.hidden, "Failed to close findbar after testFindWithHighlight");
+ }
+ yield testFindbarSelection();
+ ok(gFindBar.hidden, "Failed to close findbar after testFindbarSelection");
+ // TODO: I don't know how to drop a content element on a chrome input.
+ if (!gBrowser.hasAttribute("remote"))
+ testDrop();
+ yield testQuickFindLink();
+ if (gHasFindClipboard) {
+ yield testStatusText();
+ }
+
+ if (!AppConstants.DEBUG) {
+ yield testFindCountUI();
+ gFindBar.close();
+ ok(gFindBar.hidden, "Failed to close findbar after testFindCountUI");
+ yield testFindCountUI(true);
+ gFindBar.close();
+ ok(gFindBar.hidden, "Failed to close findbar after testFindCountUI - linksOnly");
+ }
+
+ yield openFindbar();
+ yield testFindAfterCaseChanged();
+ gFindBar.close();
+ yield openFindbar();
+ yield testFailedStringReset();
+ gFindBar.close();
+ yield testQuickFindClose();
+ // TODO: This doesn't seem to work when the findbar is connected to a
+ // remote browser element.
+ if (!gBrowser.hasAttribute("remote"))
+ yield testFindAgainNotFound();
+ yield testToggleEntireWord();
+ }
+
+ function* testFindbarSelection() {
+ function checkFindbarState(aTestName, aExpSelection) {
+ ok(!gFindBar.hidden, "testFindbarSelection: failed to open findbar: " + aTestName);
+ ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
+ "testFindbarSelection: find field is not focused: " + aTestName);
+ if (!gHasFindClipboard) {
+ ok(gFindBar._findField.value == aExpSelection,
+ "Incorrect selection in testFindbarSelection: " + aTestName +
+ ". Selection: " + gFindBar._findField.value);
+ }
+
+ // Clear the value, close the findbar.
+ gFindBar._findField.value = "";
+ gFindBar.close();
+ }
+
+ // Test normal selected text.
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ let document = content.document;
+ let cH2 = document.getElementById("h2");
+ let cSelection = content.getSelection();
+ let cRange = document.createRange();
+ cRange.setStart(cH2, 0);
+ cRange.setEnd(cH2, 1);
+ cSelection.removeAllRanges();
+ cSelection.addRange(cRange);
+ });
+ yield openFindbar();
+ checkFindbarState("plain text", SEARCH_TEXT);
+
+ // Test nsIDOMNSEditableElement with selection.
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ let textInput = content.document.getElementById("text");
+ textInput.focus();
+ textInput.select();
+ });
+ yield openFindbar();
+ checkFindbarState("text input", SAMPLE_TEXT);
+
+ // Test non-editable nsIDOMNSEditableElement (button).
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ content.document.getElementById("button").focus();
+ });
+ yield openFindbar();
+ checkFindbarState("button", "");
+ }
+
+ function testDrop() {
+ gFindBar.open();
+ // use an dummy image to start the drag so it doesn't get interrupted by a selection
+ var img = gBrowser.contentDocument.getElementById("img");
+ synthesizeDrop(img, gFindBar._findField, [[ {type: "text/plain", data: "Rabbits" } ]], "copy", window);
+ is(gFindBar._findField.inputField.value, "Rabbits", "drop on findbar");
+ gFindBar.close();
+ }
+
+ function testQuickFindClose() {
+ return new Promise(resolve => {
+ var _isClosedCallback = function() {
+ ok(gFindBar.hidden,
+ "_isClosedCallback: Failed to auto-close quick find bar after " +
+ gFindBar._quickFindTimeoutLength + "ms");
+ resolve();
+ };
+ setTimeout(_isClosedCallback, gFindBar._quickFindTimeoutLength + 100);
+ });
+ }
+
+ function testStatusText() {
+ return new Promise(resolve => {
+ var _delayedCheckStatusText = function() {
+ ok(gStatusText == SAMPLE_URL, "testStatusText: Failed to set status text of found link");
+ resolve();
+ };
+ setTimeout(_delayedCheckStatusText, 100);
+ });
+ }
+
+ function promiseFindResult() {
+ return new Promise(resolve => {
+ let listener = {
+ onFindResult: function(result) {
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve(result);
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ });
+ }
+
+ function promiseMatchesCountResult() {
+ return new Promise(resolve => {
+ let listener = {
+ onMatchesCountResult: function() {
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ // Make sure we resolve _at least_ after five times the find iterator timeout.
+ setTimeout(resolve, (ITERATOR_TIMEOUT * 5) + 20);
+ });
+ }
+
+ function promiseHighlightFinished() {
+ return new Promise(resolve => {
+ let listener = {
+ onHighlightFinished() {
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ }
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ });
+ }
+
+ var enterStringIntoFindField = Task.async(function* (str, waitForResult = true) {
+ for (let promise, i = 0; i < str.length; i++) {
+ if (waitForResult) {
+ promise = promiseFindResult();
+ }
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, str.charCodeAt(i));
+ gFindBar._findField.inputField.dispatchEvent(event);
+ if (waitForResult) {
+ yield promise;
+ }
+ }
+ });
+
+ function promiseExpectRangeCount(rangeCount) {
+ return ContentTask.spawn(gBrowser, { rangeCount }, function* (args) {
+ let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+ let sel = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
+ Assert.equal(sel.rangeCount, args.rangeCount,
+ "Expected the correct amount of ranges inside the Find selection");
+ });
+ }
+
+ // also test match-case
+ function* testNormalFind() {
+ document.getElementById("cmd_find").doCommand();
+
+ ok(!gFindBar.hidden, "testNormalFind: failed to open findbar");
+ ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
+ "testNormalFind: find field is not focused");
+
+ let promise;
+ let matchCaseCheckbox = gFindBar.getElement("find-case-sensitive");
+ if (!matchCaseCheckbox.hidden && matchCaseCheckbox.checked) {
+ promise = promiseFindResult();
+ matchCaseCheckbox.click();
+ yield promise;
+ }
+
+ var searchStr = "text tes";
+ yield enterStringIntoFindField(searchStr);
+
+ let sel = yield ContentTask.spawn(gBrowser, { searchStr }, function* (args) {
+ let sel = content.getSelection().toString();
+ Assert.equal(sel.toLowerCase(), args.searchStr,
+ "testNormalFind: failed to find '" + args.searchStr + "'");
+ return sel;
+ });
+ testClipboardSearchString(sel);
+
+ if (!matchCaseCheckbox.hidden) {
+ promise = promiseFindResult();
+ matchCaseCheckbox.click();
+ yield promise;
+ enterStringIntoFindField("t");
+ yield ContentTask.spawn(gBrowser, { searchStr }, function* (args) {
+ Assert.notEqual(content.getSelection().toString(), args.searchStr,
+ "testNormalFind: Case-sensitivy is broken '" + args.searchStr + "'");
+ });
+ promise = promiseFindResult();
+ matchCaseCheckbox.click();
+ yield promise;
+ }
+ }
+
+ function openFindbar() {
+ document.getElementById("cmd_find").doCommand();
+ return gFindBar._startFindDeferred && gFindBar._startFindDeferred.promise;
+ }
+
+ function* testNormalFindWithComposition() {
+ ok(!gFindBar.hidden, "testNormalFindWithComposition: findbar should be open");
+ ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
+ "testNormalFindWithComposition: find field should be focused");
+
+ var matchCaseCheckbox = gFindBar.getElement("find-case-sensitive");
+ var clicked = false;
+ if (!matchCaseCheckbox.hidden & matchCaseCheckbox.checked) {
+ matchCaseCheckbox.click();
+ clicked = true;
+ }
+
+ gFindBar._findField.inputField.focus();
+
+ var searchStr = "text";
+
+ synthesizeCompositionChange(
+ { "composition":
+ { "string": searchStr,
+ "clauses":
+ [
+ { "length": searchStr.length, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ "caret": { "start": searchStr.length, "length": 0 }
+ });
+
+ yield ContentTask.spawn(gBrowser, { searchStr }, function* (args) {
+ Assert.notEqual(content.getSelection().toString().toLowerCase(), args.searchStr,
+ "testNormalFindWithComposition: text shouldn't be found during composition");
+ });
+
+ synthesizeComposition({ type: "compositioncommitasis" });
+
+ let sel = yield ContentTask.spawn(gBrowser, { searchStr }, function* (args) {
+ let sel = content.getSelection().toString();
+ Assert.equal(sel.toLowerCase(), args.searchStr,
+ "testNormalFindWithComposition: text should be found after committing composition");
+ return sel;
+ });
+ testClipboardSearchString(sel);
+
+ if (clicked) {
+ matchCaseCheckbox.click();
+ }
+ }
+
+ function* testAutoCaseSensitivityUI() {
+ var matchCaseCheckbox = gFindBar.getElement("find-case-sensitive");
+ var matchCaseLabel = gFindBar.getElement("match-case-status");
+ ok(!matchCaseCheckbox.hidden, "match case box is hidden in manual mode");
+ ok(matchCaseLabel.hidden, "match case label is visible in manual mode");
+
+ gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 2);
+
+ ok(matchCaseCheckbox.hidden,
+ "match case box is visible in automatic mode");
+ ok(!matchCaseLabel.hidden,
+ "match case label is hidden in automatic mode");
+
+ yield enterStringIntoFindField("a");
+ var insensitiveLabel = matchCaseLabel.value;
+ yield enterStringIntoFindField("A");
+ var sensitiveLabel = matchCaseLabel.value;
+ ok(insensitiveLabel != sensitiveLabel,
+ "Case Sensitive label was not correctly updated");
+
+ // bug 365551
+ gFindBar.onFindAgainCommand();
+ ok(matchCaseCheckbox.hidden && !matchCaseLabel.hidden,
+ "bug 365551: case sensitivity UI is broken after find-again");
+ gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
+ gFindBar.close();
+ }
+
+ function* clearFocus() {
+ document.commandDispatcher.focusedElement = null;
+ document.commandDispatcher.focusedWindow = null;
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ content.focus();
+ });
+ }
+
+ function* testQuickFindLink() {
+ yield clearFocus();
+
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ let document = content.document;
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, "'".charCodeAt(0));
+ document.documentElement.dispatchEvent(event);
+ });
+
+ ok(!gFindBar.hidden, "testQuickFindLink: failed to open findbar");
+ ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
+ "testQuickFindLink: find field is not focused");
+
+ var searchStr = "Link Test";
+ yield enterStringIntoFindField(searchStr);
+ yield ContentTask.spawn(gBrowser, { searchStr }, function* (args) {
+ Assert.equal(content.getSelection().toString(), args.searchStr,
+ "testQuickFindLink: failed to find sample link");
+ });
+ testClipboardSearchString(searchStr);
+ }
+
+ // See bug 963925 for more details on this test.
+ function* testFindWithHighlight() {
+ gFindBar._findField.value = "";
+
+ // For this test, we want to closely control the selection. The easiest
+ // way to do so is to replace the implementation of
+ // Finder.getInitialSelection with a no-op and call the findbar's callback
+ // (onCurrentSelection(..., true)) ourselves with our hand-picked
+ // selection.
+ let oldGetInitialSelection = gFindBar.browser.finder.getInitialSelection;
+ let searchStr;
+ gFindBar.browser.finder.getInitialSelection = function(){};
+
+ let findCommand = document.getElementById("cmd_find");
+ findCommand.doCommand();
+
+ gFindBar.onCurrentSelection("", true);
+
+ searchStr = "e";
+ yield enterStringIntoFindField(searchStr);
+
+ let a = gFindBar._findField.value;
+ let b = gFindBar._browser.finder._fastFind.searchString;
+ let c = gFindBar._browser.finder.searchString;
+ ok(a == b && b == c, "testFindWithHighlight 1: " + a + ", " + b + ", " + c + ".");
+
+ searchStr = "t";
+ findCommand.doCommand();
+
+ gFindBar.onCurrentSelection(searchStr, true);
+ gFindBar.browser.finder.getInitialSelection = oldGetInitialSelection;
+
+ a = gFindBar._findField.value;
+ b = gFindBar._browser.finder._fastFind.searchString;
+ c = gFindBar._browser.finder.searchString;
+ ok(a == searchStr && b == c, "testFindWithHighlight 2: " + searchStr +
+ ", " + a + ", " + b + ", " + c + ".");
+
+ let highlightButton = gFindBar.getElement("highlight");
+ highlightButton.click();
+ ok(highlightButton.checked, "testFindWithHighlight 3: Highlight All should be checked.");
+
+ a = gFindBar._findField.value;
+ b = gFindBar._browser.finder._fastFind.searchString;
+ c = gFindBar._browser.finder.searchString;
+ ok(a == searchStr && b == c, "testFindWithHighlight 4: " + a + ", " + b + ", " + c + ".");
+
+ gFindBar.onFindAgainCommand();
+ a = gFindBar._findField.value;
+ b = gFindBar._browser.finder._fastFind.searchString;
+ c = gFindBar._browser.finder.searchString;
+ ok(a == b && b == c, "testFindWithHighlight 5: " + a + ", " + b + ", " + c + ".");
+
+ highlightButton.click();
+ ok(!highlightButton.checked, "testFindWithHighlight: Highlight All should be unchecked.");
+
+ // Regression test for bug 1316515.
+ searchStr = "e";
+ gFindBar.clear();
+ yield enterStringIntoFindField(searchStr);
+ yield promiseExpectRangeCount(0);
+
+ highlightButton.click();
+ ok(highlightButton.checked, "testFindWithHighlight: Highlight All should be checked.");
+ yield promiseHighlightFinished();
+ yield promiseExpectRangeCount(3);
+
+ synthesizeKey("VK_BACK_SPACE", {});
+ yield promiseExpectRangeCount(0);
+
+ // Regression test for bug 1316513.
+ highlightButton.click();
+ ok(!highlightButton.checked, "testFindWithHighlight - 1316513: Highlight All should be unchecked.");
+ yield enterStringIntoFindField(searchStr);
+
+ highlightButton.click();
+ ok(highlightButton.checked, "testFindWithHighlight - 1316513: Highlight All should be checked.");
+ yield promiseHighlightFinished();
+ yield promiseExpectRangeCount(3);
+
+ let promise = BrowserTestUtils.browserLoaded(gBrowser);
+ gBrowser.reload();
+ yield promise;
+
+ ok(highlightButton.checked, "testFindWithHighlight - 1316513: Highlight All " +
+ "should still be checked after a reload.");
+ synthesizeKey("VK_RETURN", {});
+ yield promiseHighlightFinished();
+ yield promiseExpectRangeCount(3);
+
+ // Uncheck at test end to not interfere with other test functions that are
+ // run after this one.
+ highlightButton.click();
+ }
+
+ function* testQuickFindText() {
+ yield clearFocus();
+
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ let document = content.document;
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, "/".charCodeAt(0));
+ document.documentElement.dispatchEvent(event);
+ });
+
+ ok(!gFindBar.hidden, "testQuickFindText: failed to open findbar");
+ ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
+ "testQuickFindText: find field is not focused");
+
+ yield enterStringIntoFindField(SEARCH_TEXT);
+ yield ContentTask.spawn(gBrowser, { SEARCH_TEXT }, function* (args) {
+ Assert.equal(content.getSelection().toString(), args.SEARCH_TEXT,
+ "testQuickFindText: failed to find '" + args.SEARCH_TEXT + "'");
+ });
+ testClipboardSearchString(SEARCH_TEXT);
+ }
+
+ function* testFindCountUI(linksOnly = false) {
+ yield clearFocus();
+
+ if (linksOnly) {
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ let document = content.document;
+ let event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, null, false, false,
+ false, false, 0, "'".charCodeAt(0));
+ document.documentElement.dispatchEvent(event);
+ });
+ } else {
+ document.getElementById("cmd_find").doCommand();
+ }
+
+ ok(!gFindBar.hidden, "testFindCountUI: failed to open findbar");
+ ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
+ "testFindCountUI: find field is not focused");
+
+ let promise;
+ let matchCase = gFindBar.getElement("find-case-sensitive");
+ if (matchCase.checked) {
+ promise = promiseFindResult();
+ matchCase.click();
+ yield new Promise(resolve => setTimeout(resolve, ITERATOR_TIMEOUT + 20));
+ yield promise;
+ }
+
+ let foundMatches = gFindBar._foundMatches;
+ let tests = [{
+ text: "t",
+ current: linksOnly ? 1 : 5,
+ total: linksOnly ? 2 : 10,
+ }, {
+ text: "te",
+ current: linksOnly ? 1 : 3,
+ total: linksOnly ? 1 : 5,
+ }, {
+ text: "tes",
+ current: 1,
+ total: linksOnly ? 1 : 2,
+ }, {
+ text: "texxx",
+ current: 0,
+ total: 0
+ }];
+ let regex = /([\d]*)\sof\s([\d]*)/;
+
+ function assertMatches(aTest, aMatches) {
+ is(aMatches[1], String(aTest.current),
+ `${linksOnly ? "[Links-only] " : ""}Currently highlighted match should be at ${aTest.current} for '${aTest.text}'`);
+ is(aMatches[2], String(aTest.total),
+ `${linksOnly ? "[Links-only] " : ""}Total amount of matches should be ${aTest.total} for '${aTest.text}'`);
+ }
+
+ for (let test of tests) {
+ gFindBar._findField.select();
+ gFindBar._findField.focus();
+
+ let timeout = ITERATOR_TIMEOUT;
+ if (test.text.length == 1)
+ timeout *= 4;
+ else if (test.text.length == 2)
+ timeout *= 2;
+ timeout += 20;
+ yield new Promise(resolve => setTimeout(resolve, timeout));
+ yield enterStringIntoFindField(test.text, false);
+ yield promiseMatchesCountResult();
+ let matches = foundMatches.value.match(regex);
+ if (!test.total) {
+ ok(!matches, "No message should be shown when 0 matches are expected");
+ } else {
+ assertMatches(test, matches);
+ for (let i = 1; i < test.total; i++) {
+ yield new Promise(resolve => setTimeout(resolve, timeout));
+ gFindBar.onFindAgainCommand();
+ yield promiseMatchesCountResult();
+ // test.current + 1, test.current + 2, ..., test.total, 1, ..., test.current
+ let current = (test.current + i - 1) % test.total + 1;
+ assertMatches({
+ text: test.text,
+ current: current,
+ total: test.total
+ }, foundMatches.value.match(regex));
+ }
+ }
+ }
+ }
+
+ // See bug 1051187.
+ function* testFindAfterCaseChanged() {
+ // Search to set focus on "Text Test" so that searching for "t" selects first
+ // (upper case!) "T".
+ yield enterStringIntoFindField(SEARCH_TEXT);
+ gFindBar.clear();
+
+ gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
+
+ yield enterStringIntoFindField("t");
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ Assert.equal(content.getSelection().toString(), "T", "First T should be selected.");
+ });
+
+ gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 1);
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ Assert.equal(content.getSelection().toString(), "t", "First t should be selected.");
+ });
+ }
+
+ // Make sure that _findFailedString is cleared:
+ // 1. Do a search that fails with case sensitivity but matches with no case sensitivity.
+ // 2. Uncheck case sensitivity button to match the string.
+ function* testFailedStringReset() {
+ gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 1);
+
+ yield enterStringIntoFindField(SEARCH_TEXT.toUpperCase(), false);
+ yield ContentTask.spawn(gBrowser, null, function* () {
+ Assert.equal(content.getSelection().toString(), "", "Not found.");
+ });
+
+ gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
+ yield ContentTask.spawn(gBrowser, { SEARCH_TEXT }, function* (args) {
+ Assert.equal(content.getSelection().toString(), args.SEARCH_TEXT,
+ "Search text should be selected.");
+ });
+ }
+
+ function testClipboardSearchString(aExpected) {
+ if (!gHasFindClipboard)
+ return;
+
+ if (!aExpected)
+ aExpected = "";
+ var searchStr = gFindBar.browser.finder.clipboardSearchString;
+ ok(searchStr.toLowerCase() == aExpected.toLowerCase(),
+ "testClipboardSearchString: search string not set to '" + aExpected +
+ "', instead found '" + searchStr + "'");
+ }
+
+ // See bug 967982.
+ function* testFindAgainNotFound() {
+ yield openFindbar();
+ yield enterStringIntoFindField(NOT_FOUND_TEXT, false);
+ gFindBar.close();
+ ok(gFindBar.hidden, "The findbar is closed.");
+ let promise = promiseFindResult();
+ gFindBar.onFindAgainCommand();
+ yield promise;
+ ok(!gFindBar.hidden, "Unsuccessful Find Again opens the find bar.");
+
+ yield enterStringIntoFindField(SEARCH_TEXT);
+ gFindBar.close();
+ ok(gFindBar.hidden, "The findbar is closed.");
+ promise = promiseFindResult();
+ gFindBar.onFindAgainCommand();
+ yield promise;
+ ok(gFindBar.hidden, "Successful Find Again leaves the find bar closed.");
+ }
+
+ function* testToggleEntireWord() {
+ yield openFindbar();
+ let promise = promiseFindResult();
+ yield enterStringIntoFindField("Tex", false);
+ let result = yield promise;
+ is(result.result, Ci.nsITypeAheadFind.FIND_FOUND, "Text should be found");
+
+ yield new Promise(resolve => setTimeout(resolve, ITERATOR_TIMEOUT + 20));
+ promise = promiseFindResult();
+ let check = gFindBar.getElement("find-entire-word");
+ check.click();
+ result = yield promise;
+ is(result.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "Text should NOT be found");
+
+ check.click();
+ gFindBar.close(true);
+ }
+ ]]></script>
+
+ <commandset>
+ <command id="cmd_find" oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
+ </commandset>
+ <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+ <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
+ <findbar id="FindToolbar" browserid="content"/>
+</window>
diff --git a/toolkit/content/tests/chrome/frame_popup_anchor.xul b/toolkit/content/tests/chrome/frame_popup_anchor.xul
new file mode 100644
index 000000000..be6254ce0
--- /dev/null
+++ b/toolkit/content/tests/chrome/frame_popup_anchor.xul
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<menupopup id="popup" onpopupshowing="if (isSecondTest) popupShowing(event)" onpopupshown="popupShown()"
+ onpopuphidden="nextTest()">
+ <menuitem label="One"/>
+ <menuitem label="Two"/>
+</menupopup>
+
+<button id="button" label="OK" popup="popup"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+var isSecondTest = false;
+
+function openPopup()
+{
+ document.getElementById("popup").openPopup(parent.document.getElementById("outerbutton"), "after_start", 3, 1);
+}
+
+function popupShowing(event)
+{
+ var buttonrect = document.getElementById("button").getBoundingClientRect();
+ parent.opener.wrappedJSObject.SimpleTest.is(event.clientX, buttonrect.left + 6, "popup clientX with mouse");
+ parent.opener.wrappedJSObject.SimpleTest.is(event.clientY, buttonrect.top + 6, "popup clientY with mouse");
+}
+
+function popupShown()
+{
+ var left, top;
+ var popuprect = document.getElementById("popup").getBoundingClientRect();
+ if (isSecondTest) {
+ var buttonrect = document.getElementById("button").getBoundingClientRect();
+ left = buttonrect.left + 6;
+ top = buttonrect.top + 6;
+ }
+ else {
+ var iframerect = parent.document.getElementById("frame").getBoundingClientRect();
+ var buttonrect = parent.document.getElementById("outerbutton").getBoundingClientRect();
+
+ // The popup should appear anchored on the bottom left edge of the button, however
+ // the client rectangle is relative to the iframe's document. Thus the coordinates
+ // are:
+ // left = iframe's left - anchor button's left - 3 pixel offset passed to openPopup +
+ // iframe border (17px) + iframe padding (0)
+ // top = iframe's top - anchor button's bottom - 1 pixel offset passed to openPopup +
+ // iframe border (0) + iframe padding (3px);
+ left = -(Math.round(iframerect.left) - Math.round(buttonrect.left) + 14);
+ top = -(Math.round(iframerect.top) - Math.round(buttonrect.bottom) + 2);
+ }
+
+ var testid = isSecondTest ? "with mouse" : "anchored to parent frame";
+ parent.opener.wrappedJSObject.SimpleTest.is(Math.round(popuprect.left), left, "popup left " + testid);
+ parent.opener.wrappedJSObject.SimpleTest.is(Math.round(popuprect.top), top, "popup top " + testid);
+
+ document.getElementById("popup").hidePopup();
+}
+
+function nextTest()
+{
+ if (isSecondTest) {
+ parent.opener.wrappedJSObject.SimpleTest.finish();
+ parent.close();
+ }
+ else {
+ // this second test ensures that the popupshowing coordinates when a popup in
+ // a frame is opened are correct
+ isSecondTest = true;
+ synthesizeMouse(document.getElementById("button"), 6, 6, { });
+ }
+}
+
+]]>
+</script>
+
+</page>
diff --git a/toolkit/content/tests/chrome/frame_popupremoving_frame.xul b/toolkit/content/tests/chrome/frame_popupremoving_frame.xul
new file mode 100644
index 000000000..e8f00ce7a
--- /dev/null
+++ b/toolkit/content/tests/chrome/frame_popupremoving_frame.xul
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Popup Removing Frame Tests"
+ onload="setTimeout(init, 0)"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<hbox>
+
+<menu id="separatemenu1" label="Menu">
+ <menupopup id="separatepopup1" onpopupshown="document.getElementById('separatemenu2').open = true">
+ <menuitem label="L1 One"/>
+ <menuitem label="L1 Two"/>
+ <menuitem label="L1 Three"/>
+ </menupopup>
+</menu>
+
+<menu id="separatemenu2" label="Menu">
+ <menupopup id="separatepopup2" onpopupshown="document.getElementById('separatemenu3').open = true">
+ <menuitem label="L2 One"/>
+ <menuitem label="L2 Two"/>
+ <menuitem label="L2 Three"/>
+ </menupopup>
+</menu>
+
+<menu id="separatemenu3" label="Menu" onpopupshown="document.getElementById('separatemenu4').open = true">
+ <menupopup id="separatepopup3">
+ <menuitem label="L3 One"/>
+ <menuitem label="L3 Two"/>
+ <menuitem label="L3 Three"/>
+ </menupopup>
+</menu>
+
+<menu id="separatemenu4" label="Menu" onpopupshown="document.getElementById('nestedmenu1').open = true">
+ <menupopup id="separatepopup3">
+ <menuitem label="L4 One"/>
+ <menuitem label="L4 Two"/>
+ <menuitem label="L4 Three"/>
+ </menupopup>
+</menu>
+
+</hbox>
+
+<menu id="nestedmenu1" label="Menu">
+ <menupopup id="nestedpopup1" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="nestedmenu2" label="Menu">
+ <menupopup id="nestedpopup2" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="nestedmenu3" label="Menu">
+ <menupopup id="nestedpopup3" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="nestedmenu4" label="Menu" onpopupshown="parent.popupsOpened()">
+ <menupopup id="nestedpopup4">
+ <menuitem label="Nested One"/>
+ <menuitem label="Nested Two"/>
+ <menuitem label="Nested Three"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menupopup>
+</menu>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+function init()
+{
+ document.getElementById("separatemenu1").open = true;
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/frame_subframe_origin_subframe1.xul b/toolkit/content/tests/chrome/frame_subframe_origin_subframe1.xul
new file mode 100644
index 000000000..c85083cb7
--- /dev/null
+++ b/toolkit/content/tests/chrome/frame_subframe_origin_subframe1.xul
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<page id="frame1"
+ style="background-color:green;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<spacer height="10px"/>
+<iframe
+ style="margin:10px; min-height:170px; max-width:200px; max-height:200px; border:solid 1px white;"
+ src="frame_subframe_origin_subframe2.xul"></iframe>
+<spacer height="3px"/>
+<caption id="cap1" style="min-width:200px; max-width:200px; background-color:white;" label=""/>
+<script class="testbody" type="application/javascript">
+
+// Fire a mouse move event aimed at this window, and check to be
+// sure the client coords translate from widget to the dom correctly.
+
+function runTests()
+{
+ synthesizeMouse(document.getElementById("frame1"), 3, 4, { type: "mousemove" });
+}
+
+function mouseMove(e) {
+ e.stopPropagation();
+ var element = e.target;
+ var el = document.getElementById("cap1");
+ el.label = "client: (" + e.clientX + "," + e.clientY + ")";
+ parent.opener.wrappedJSObject.SimpleTest.is(e.clientX, 3, "mouse event clientX on sub frame 1");
+ parent.opener.wrappedJSObject.SimpleTest.is(e.clientY, 4, "mouse event clientY on sub frame 1");
+ // fire the next test on the sub frame
+ frames[0].runTests();
+}
+
+window.addEventListener("mousemove", mouseMove, false);
+
+</script>
+</page>
diff --git a/toolkit/content/tests/chrome/frame_subframe_origin_subframe2.xul b/toolkit/content/tests/chrome/frame_subframe_origin_subframe2.xul
new file mode 100644
index 000000000..92ef64b89
--- /dev/null
+++ b/toolkit/content/tests/chrome/frame_subframe_origin_subframe2.xul
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<page id="frame2"
+ style="background-color:red;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<spacer height="10px"/>
+<caption id="cap2" style="background-color:white;" label=""/>
+<script class="testbody" type="application/javascript">
+
+// Fire a mouse move event aimed at this window, and check to be
+// sure the client coords translate from widget to the dom correctly.
+
+function runTests()
+{
+ synthesizeMouse(document.getElementById("frame2"), 6, 5, { type: "mousemove" });
+}
+
+function mouseMove(e) {
+ e.stopPropagation();
+ var element = e.target;
+ var el = document.getElementById("cap2");
+ el.label = "client: (" + e.clientX + "," + e.clientY + ")";
+ parent.parent.opener.wrappedJSObject.SimpleTest.is(e.clientX, 6, "mouse event clientX on sub frame 2");
+ parent.parent.opener.wrappedJSObject.SimpleTest.is(e.clientY, 5, "mouse event clientY on sub frame 2");
+ parent.parent.opener.wrappedJSObject.SimpleTest.finish();
+ parent.parent.close();
+}
+
+window.addEventListener("mousemove",mouseMove, false);
+
+</script>
+</page>
diff --git a/toolkit/content/tests/chrome/popup_childframe_node.xul b/toolkit/content/tests/chrome/popup_childframe_node.xul
new file mode 100644
index 000000000..512f5f8c2
--- /dev/null
+++ b/toolkit/content/tests/chrome/popup_childframe_node.xul
@@ -0,0 +1,2 @@
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="80" height="80"
+ onclick="document.documentElement.setAttribute('data', 'x' + document.popupNode)"/>
diff --git a/toolkit/content/tests/chrome/popup_trigger.js b/toolkit/content/tests/chrome/popup_trigger.js
new file mode 100644
index 000000000..920d4d070
--- /dev/null
+++ b/toolkit/content/tests/chrome/popup_trigger.js
@@ -0,0 +1,859 @@
+var gMenuPopup = null;
+var gTrigger = null;
+var gIsMenu = false;
+var gScreenX = -1, gScreenY = -1;
+var gCachedEvent = null;
+var gCachedEvent2 = null;
+
+function cacheEvent(modifiers)
+{
+ var cachedEvent = null;
+
+ var mouseFn = function(event) {
+ cachedEvent = event;
+ }
+
+ window.addEventListener("mousedown", mouseFn, false);
+ synthesizeMouse(document.documentElement, 0, 0, modifiers);
+ window.removeEventListener("mousedown", mouseFn, false);
+
+ return cachedEvent;
+}
+
+function runTests()
+{
+ if (screen.height < 768) {
+ ok(false, "popup tests are likely to fail for screen heights less than 768 pixels");
+ }
+
+ gMenuPopup = document.getElementById("thepopup");
+ gTrigger = document.getElementById("trigger");
+
+ gIsMenu = gTrigger.boxObject instanceof MenuBoxObject;
+
+ // a hacky way to get the screen position of the document. Cache the event
+ // so that we can use it in calls to openPopup.
+ gCachedEvent = cacheEvent({ shiftKey: true });
+ gScreenX = gCachedEvent.screenX;
+ gScreenY = gCachedEvent.screenY;
+ gCachedEvent2 = cacheEvent({ altKey: true, ctrlKey: true, shiftKey: true, metaKey: true });
+
+ startPopupTests(popupTests);
+}
+
+var popupTests = [
+{
+ testname: "mouse click on trigger",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ test: function() {
+ // for menus, no trigger will be set. For non-menus using the popup
+ // attribute, the trigger will be set to the node with the popup attribute
+ gExpectedTriggerNode = gIsMenu ? "notset" : gTrigger;
+ synthesizeMouse(gTrigger, 4, 4, { });
+ },
+ result: function (testname) {
+ gExpectedTriggerNode = null;
+ // menus are the anchor but non-menus are opened at screen coordinates
+ is(gMenuPopup.anchorNode, gIsMenu ? gTrigger : null, testname + " anchorNode");
+ // menus are opened internally, but non-menus have a mouse event which
+ // triggered them
+ is(gMenuPopup.triggerNode, gIsMenu ? null : gTrigger, testname + " triggerNode");
+ is(document.popupNode, gIsMenu ? null : gTrigger, testname + " document.popupNode");
+ is(document.tooltipNode, null, testname + " document.tooltipNode");
+ // check to ensure the popup node for a different document isn't used
+ if (window.opener)
+ is(window.opener.document.popupNode, null, testname + " opener.document.popupNode");
+
+ // this will be used in some tests to ensure the size doesn't change
+ var popuprect = gMenuPopup.getBoundingClientRect();
+ gPopupWidth = Math.round(popuprect.width);
+ gPopupHeight = Math.round(popuprect.height);
+
+ checkActive(gMenuPopup, "", testname);
+ checkOpen("trigger", testname);
+ // if a menu, the popup should be opened underneath the menu in the
+ // 'after_start' position, otherwise it is opened at the mouse position
+ if (gIsMenu)
+ compareEdge(gTrigger, gMenuPopup, "after_start", 0, 0, testname);
+ }
+},
+{
+ // check that pressing cursor down while there is no selection
+ // highlights the first item
+ testname: "cursor down no selection",
+ events: [ "DOMMenuItemActive item1" ],
+ test: function() { synthesizeKey("VK_DOWN", { }); },
+ result: function(testname) { checkActive(gMenuPopup, "item1", testname); }
+},
+{
+ // check that pressing cursor up wraps and highlights the last item
+ testname: "cursor up wrap",
+ events: [ "DOMMenuItemInactive item1", "DOMMenuItemActive last" ],
+ test: function() { synthesizeKey("VK_UP", { }); },
+ result: function(testname) {
+ checkActive(gMenuPopup, "last", testname);
+ }
+},
+{
+ // check that pressing cursor down wraps and highlights the first item
+ testname: "cursor down wrap",
+ events: [ "DOMMenuItemInactive last", "DOMMenuItemActive item1" ],
+ test: function() { synthesizeKey("VK_DOWN", { }); },
+ result: function(testname) { checkActive(gMenuPopup, "item1", testname); }
+},
+{
+ // check that pressing cursor down highlights the second item
+ testname: "cursor down",
+ events: [ "DOMMenuItemInactive item1", "DOMMenuItemActive item2" ],
+ test: function() { synthesizeKey("VK_DOWN", { }); },
+ result: function(testname) { checkActive(gMenuPopup, "item2", testname); }
+},
+{
+ // check that pressing cursor up highlights the second item
+ testname: "cursor up",
+ events: [ "DOMMenuItemInactive item2", "DOMMenuItemActive item1" ],
+ test: function() { synthesizeKey("VK_UP", { }); },
+ result: function(testname) { checkActive(gMenuPopup, "item1", testname); }
+},
+{
+ // cursor left should not do anything
+ testname: "cursor left",
+ test: function() { synthesizeKey("VK_LEFT", { }); },
+ result: function(testname) { checkActive(gMenuPopup, "item1", testname); }
+},
+{
+ // cursor right should not do anything
+ testname: "cursor right",
+ test: function() { synthesizeKey("VK_RIGHT", { }); },
+ result: function(testname) { checkActive(gMenuPopup, "item1", testname); }
+},
+{
+ // check cursor down when a disabled item exists in the menu
+ testname: "cursor down disabled",
+ events: function() {
+ // On Windows, disabled items are included when navigating, but on
+ // other platforms, disabled items are skipped over
+ if (navigator.platform.indexOf("Win") == 0) {
+ return [ "DOMMenuItemInactive item1", "DOMMenuItemActive item2" ];
+ }
+ return [ "DOMMenuItemInactive item1", "DOMMenuItemActive amenu" ];
+ },
+ test: function() {
+ document.getElementById("item2").disabled = true;
+ synthesizeKey("VK_DOWN", { });
+ }
+},
+{
+ // check cursor up when a disabled item exists in the menu
+ testname: "cursor up disabled",
+ events: function() {
+ if (navigator.platform.indexOf("Win") == 0) {
+ return [ "DOMMenuItemInactive item2", "DOMMenuItemActive amenu",
+ "DOMMenuItemInactive amenu", "DOMMenuItemActive item2",
+ "DOMMenuItemInactive item2", "DOMMenuItemActive item1" ];
+ }
+ return [ "DOMMenuItemInactive amenu", "DOMMenuItemActive item1" ];
+ },
+ test: function() {
+ if (navigator.platform.indexOf("Win") == 0)
+ synthesizeKey("VK_DOWN", { });
+ synthesizeKey("VK_UP", { });
+ if (navigator.platform.indexOf("Win") == 0)
+ synthesizeKey("VK_UP", { });
+ }
+},
+{
+ testname: "mouse click outside",
+ events: [ "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuItemInactive item1", "DOMMenuInactive thepopup" ],
+ test: function() {
+ gMenuPopup.hidePopup();
+ // XXXndeakin event simulation fires events outside of the platform specific
+ // widget code so the popup capturing isn't handled. Thus, the menu won't
+ // rollup this way.
+ // synthesizeMouse(gTrigger, 0, -12, { });
+ },
+ result: function(testname, step) {
+ is(gMenuPopup.anchorNode, null, testname + " anchorNode");
+ is(gMenuPopup.triggerNode, null, testname + " triggerNode");
+ is(document.popupNode, null, testname + " document.popupNode");
+ checkClosed("trigger", testname);
+ }
+},
+{
+ // these tests check to ensure that passing an anchor and position
+ // puts the popup in the right place
+ testname: "open popup anchored",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ steps: ["before_start", "before_end", "after_start", "after_end",
+ "start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap",
+ "topleft topleft", "topcenter topleft", "topright topleft",
+ "leftcenter topright", "rightcenter topright",
+ "bottomleft bottomleft", "bottomcenter bottomleft", "bottomright bottomleft",
+ "topleft bottomright", "bottomcenter bottomright", "rightcenter topright"],
+ test: function(testname, step) {
+ gExpectedTriggerNode = "notset";
+ gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
+ },
+ result: function(testname, step) {
+ // no triggerNode because it was opened without passing an event
+ gExpectedTriggerNode = null;
+ is(gMenuPopup.anchorNode, gTrigger, testname + " anchorNode");
+ is(gMenuPopup.triggerNode, null, testname + " triggerNode");
+ is(document.popupNode, null, testname + " document.popupNode");
+ compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname);
+ }
+},
+{
+ // these tests check the same but with a 10 pixel margin on the popup
+ testname: "open popup anchored with margin",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ steps: ["before_start", "before_end", "after_start", "after_end",
+ "start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap",
+ "topleft topleft", "topcenter topleft", "topright topleft",
+ "leftcenter topright", "rightcenter topright",
+ "bottomleft bottomleft", "bottomcenter bottomleft", "bottomright bottomleft",
+ "topleft bottomright", "bottomcenter bottomright", "rightcenter topright"],
+ test: function(testname, step) {
+ gMenuPopup.setAttribute("style", "margin: 10px;");
+ gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
+ },
+ result: function(testname, step) {
+ var rightmod = step == "before_end" || step == "after_end" ||
+ step == "start_before" || step == "start_after" ||
+ step.match(/topright$/) || step.match(/bottomright$/);
+ var bottommod = step == "before_start" || step == "before_end" ||
+ step == "start_after" || step == "end_after" ||
+ step.match(/bottomleft$/) || step.match(/bottomright$/);
+ compareEdge(gTrigger, gMenuPopup, step, rightmod ? -10 : 10, bottommod ? -10 : 10, testname);
+ gMenuPopup.removeAttribute("style");
+ }
+},
+{
+ // these tests check the same but with a -8 pixel margin on the popup
+ testname: "open popup anchored with negative margin",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ steps: ["before_start", "before_end", "after_start", "after_end",
+ "start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap"],
+ test: function(testname, step) {
+ gMenuPopup.setAttribute("style", "margin: -8px;");
+ gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
+ },
+ result: function(testname, step) {
+ var rightmod = step == "before_end" || step == "after_end" ||
+ step == "start_before" || step == "start_after";
+ var bottommod = step == "before_start" || step == "before_end" ||
+ step == "start_after" || step == "end_after";
+ compareEdge(gTrigger, gMenuPopup, step, rightmod ? 8 : -8, bottommod ? 8 : -8, testname);
+ gMenuPopup.removeAttribute("style");
+ }
+},
+ {
+ testname: "open popup with large positive margin",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ steps: ["before_start", "before_end", "after_start", "after_end",
+ "start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap"],
+ test: function(testname, step) {
+ gMenuPopup.setAttribute("style", "margin: 1000px;");
+ gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
+ },
+ result: function(testname, step) {
+ var popuprect = gMenuPopup.getBoundingClientRect();
+ // as there is more room on the 'end' or 'after' side, popups will always
+ // appear on the right or bottom corners, depending on which side they are
+ // allowed to be flipped by.
+ var expectedleft = step == "before_end" || step == "after_end" ?
+ 0 : Math.round(window.innerWidth - gPopupWidth);
+ var expectedtop = step == "start_after" || step == "end_after" ?
+ 0 : Math.round(window.innerHeight - gPopupHeight);
+ is(Math.round(popuprect.left), expectedleft, testname + " x position " + step);
+ is(Math.round(popuprect.top), expectedtop, testname + " y position " + step);
+ gMenuPopup.removeAttribute("style");
+ }
+},
+{
+ testname: "open popup with large negative margin",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ steps: ["before_start", "before_end", "after_start", "after_end",
+ "start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap"],
+ test: function(testname, step) {
+ gMenuPopup.setAttribute("style", "margin: -1000px;");
+ gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
+ },
+ result: function(testname, step) {
+ var popuprect = gMenuPopup.getBoundingClientRect();
+ // using negative margins causes the reverse of positive margins, and
+ // popups will appear on the left or top corners.
+ var expectedleft = step == "before_end" || step == "after_end" ?
+ Math.round(window.innerWidth - gPopupWidth) : 0;
+ var expectedtop = step == "start_after" || step == "end_after" ?
+ Math.round(window.innerHeight - gPopupHeight) : 0;
+ is(Math.round(popuprect.left), expectedleft, testname + " x position " + step);
+ is(Math.round(popuprect.top), expectedtop, testname + " y position " + step);
+ gMenuPopup.removeAttribute("style");
+ }
+},
+{
+ testname: "popup with unknown step",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function() {
+ gMenuPopup.openPopup(gTrigger, "other", 0, 0, false, false);
+ },
+ result: function (testname) {
+ var triggerrect = gMenuPopup.getBoundingClientRect();
+ var popuprect = gMenuPopup.getBoundingClientRect();
+ is(Math.round(popuprect.left), triggerrect.left, testname + " x position ");
+ is(Math.round(popuprect.top), triggerrect.top, testname + " y position ");
+ }
+},
+{
+ // these tests check to ensure that the position attribute can be used
+ // to set the position of a popup instead of passing it as an argument
+ testname: "open popup anchored with attribute",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ steps: ["before_start", "before_end", "after_start", "after_end",
+ "start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap",
+ "topcenter topleft", "topright bottomright", "leftcenter topright"],
+ test: function(testname, step) {
+ gMenuPopup.setAttribute("position", step);
+ gMenuPopup.openPopup(gTrigger, "", 0, 0, false, false);
+ },
+ result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname); }
+},
+{
+ // this test checks to ensure that the attributes override flag to openPopup
+ // can be used to override the popup's position. This test also passes an
+ // event to openPopup to check the trigger node.
+ testname: "open popup anchored with override",
+ events: [ "popupshowing thepopup 0010", "popupshown thepopup" ],
+ test: function(testname, step) {
+ // attribute overrides the position passed in
+ gMenuPopup.setAttribute("position", "end_after");
+ gExpectedTriggerNode = gCachedEvent.target;
+ gMenuPopup.openPopup(gTrigger, "before_start", 0, 0, false, true, gCachedEvent);
+ },
+ result: function(testname, step) {
+ gExpectedTriggerNode = null;
+ is(gMenuPopup.anchorNode, gTrigger, testname + " anchorNode");
+ is(gMenuPopup.triggerNode, gCachedEvent.target, testname + " triggerNode");
+ is(document.popupNode, gCachedEvent.target, testname + " document.popupNode");
+ compareEdge(gTrigger, gMenuPopup, "end_after", 0, 0, testname);
+ }
+},
+{
+ testname: "close popup with escape",
+ events: [ "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuInactive thepopup", ],
+ test: function(testname, step) {
+ synthesizeKey("VK_ESCAPE", { });
+ checkClosed("trigger", testname);
+ }
+},
+{
+ // check that offsets may be supplied to the openPopup method
+ testname: "open popup anchored with offsets",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function(testname, step) {
+ // attribute is empty so does not override
+ gMenuPopup.setAttribute("position", "");
+ gMenuPopup.openPopup(gTrigger, "before_start", 5, 10, true, true);
+ },
+ result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, "before_start", 5, 10, testname); }
+},
+{
+ // these tests check to ensure that passing an anchor and position
+ // puts the popup in the right place
+ testname: "show popup anchored",
+ condition: function() {
+ // only perform this test for popups not in a menu, such as those using
+ // the popup attribute, as the showPopup implementation in popup.xml
+ // calls openMenu if the popup is inside a menu
+ return !gIsMenu;
+ },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ steps: [["topleft", "topleft"],
+ ["topleft", "topright"], ["topleft", "bottomleft"],
+ ["topright", "topleft"], ["topright", "bottomright"],
+ ["bottomleft", "bottomright"], ["bottomleft", "topleft"],
+ ["bottomright", "bottomleft"], ["bottomright", "topright"]],
+ test: function(testname, step) {
+ // the attributes should be ignored
+ gMenuPopup.setAttribute("popupanchor", "topright");
+ gMenuPopup.setAttribute("popupalign", "bottomright");
+ gMenuPopup.setAttribute("position", "end_after");
+ gMenuPopup.showPopup(gTrigger, -1, -1, "popup", step[0], step[1]);
+ },
+ result: function(testname, step) {
+ var pos = convertPosition(step[0], step[1]);
+ compareEdge(gTrigger, gMenuPopup, pos, 0, 0, testname);
+ gMenuPopup.removeAttribute("popupanchor");
+ gMenuPopup.removeAttribute("popupalign");
+ gMenuPopup.removeAttribute("position");
+ }
+},
+{
+ testname: "show popup with position",
+ condition: function() { return !gIsMenu; },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function(testname, step) {
+ gMenuPopup.showPopup(gTrigger, gScreenX + 60, gScreenY + 15,
+ "context", "topleft", "bottomright");
+ },
+ result: function(testname, step) {
+ var rect = gMenuPopup.getBoundingClientRect();
+ ok(true, gScreenX + "," + gScreenY);
+ is(rect.left, 60, testname + " left");
+ is(rect.top, 15, testname + " top");
+ ok(rect.right, testname + " right is " + rect.right);
+ ok(rect.bottom, testname + " bottom is " + rect.bottom);
+ }
+},
+{
+ // if no anchor is supplied to openPopup, it should be opened relative
+ // to the viewport.
+ testname: "open popup unanchored",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ test: function(testname, step) { gMenuPopup.openPopup(null, "after_start", 6, 8, false); },
+ result: function(testname, step) {
+ var rect = gMenuPopup.getBoundingClientRect();
+ ok(rect.left == 6 && rect.top == 8 && rect.right && rect.bottom, testname);
+ }
+},
+{
+ testname: "activate menuitem with mouse",
+ events: [ "DOMMenuInactive thepopup", "command item3",
+ "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuItemInactive item3" ],
+ test: function(testname, step) {
+ var item3 = document.getElementById("item3");
+ synthesizeMouse(item3, 4, 4, { });
+ },
+ result: function(testname, step) { checkClosed("trigger", testname); }
+},
+{
+ testname: "close popup",
+ condition: function() { return false; },
+ events: [ "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuInactive thepopup" ],
+ test: function(testname, step) { gMenuPopup.hidePopup(); }
+},
+{
+ testname: "open popup at screen",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ test: function(testname, step) {
+ gExpectedTriggerNode = "notset";
+ gMenuPopup.openPopupAtScreen(gScreenX + 24, gScreenY + 20, false);
+ },
+ result: function(testname, step) {
+ gExpectedTriggerNode = null;
+ is(gMenuPopup.anchorNode, null, testname + " anchorNode");
+ is(gMenuPopup.triggerNode, null, testname + " triggerNode");
+ is(document.popupNode, null, testname + " document.popupNode");
+ var rect = gMenuPopup.getBoundingClientRect();
+ is(rect.left, 24, testname + " left");
+ is(rect.top, 20, testname + " top");
+ ok(rect.right, testname + " right is " + rect.right);
+ ok(rect.bottom, testname + " bottom is " + rect.bottom);
+ }
+},
+{
+ // check that pressing a menuitem's accelerator selects it. Note that
+ // the menuitem with the M accesskey overrides the earlier menuitem that
+ // begins with M.
+ testname: "menuitem accelerator",
+ events: [ "DOMMenuItemActive amenu", "DOMMenuItemInactive amenu",
+ "DOMMenuInactive thepopup",
+ "command amenu", "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuItemInactive amenu"
+ ],
+ test: function() { synthesizeKey("M", { }); },
+ result: function(testname) { checkClosed("trigger", testname); }
+},
+{
+ testname: "open context popup at screen",
+ events: [ "popupshowing thepopup 0010", "popupshown thepopup" ],
+ test: function(testname, step) {
+ gExpectedTriggerNode = gCachedEvent.target;
+ gMenuPopup.openPopupAtScreen(gScreenX + 8, gScreenY + 16, true, gCachedEvent);
+ },
+ result: function(testname, step) {
+ gExpectedTriggerNode = null;
+ is(gMenuPopup.anchorNode, null, testname + " anchorNode");
+ is(gMenuPopup.triggerNode, gCachedEvent.target, testname + " triggerNode");
+ is(document.popupNode, gCachedEvent.target, testname + " document.popupNode");
+
+ var childframe = document.getElementById("childframe");
+ if (childframe) {
+ for (var t = 0; t < 2; t++) {
+ var child = childframe.contentDocument;
+ var evt = child.createEvent("Event");
+ evt.initEvent("click", true, true);
+ child.documentElement.dispatchEvent(evt);
+ is(child.documentElement.getAttribute("data"), "xnull",
+ "cannot get popupNode from other document");
+ child.documentElement.setAttribute("data", "none");
+ // now try again with document.popupNode set explicitly
+ document.popupNode = gCachedEvent.target;
+ }
+ }
+
+ var openX = 8;
+ var openY = 16;
+ var rect = gMenuPopup.getBoundingClientRect();
+ is(rect.left, openX + (platformIsMac() ? 1 : 2), testname + " left");
+ is(rect.top, openY + (platformIsMac() ? -6 : 2), testname + " top");
+ ok(rect.right, testname + " right is " + rect.right);
+ ok(rect.bottom, testname + " bottom is " + rect.bottom);
+ }
+},
+{
+ // pressing a letter that doesn't correspond to an accelerator, but does
+ // correspond to the first letter in a menu's label. The menu should not
+ // close because there is more than one item corresponding to that letter
+ testname: "menuitem with non accelerator",
+ events: [ "DOMMenuItemActive one" ],
+ test: function() { synthesizeKey("O", { }); },
+ result: function(testname) {
+ checkOpen("trigger", testname);
+ checkActive(gMenuPopup, "one", testname);
+ }
+},
+{
+ // pressing the letter again should select the next one that starts with
+ // that letter
+ testname: "menuitem with non accelerator again",
+ events: [ "DOMMenuItemInactive one", "DOMMenuItemActive submenu" ],
+ test: function() { synthesizeKey("O", { }); },
+ result: function(testname) {
+ // 'submenu' is a menu but it should not be open
+ checkOpen("trigger", testname);
+ checkClosed("submenu", testname);
+ checkActive(gMenuPopup, "submenu", testname);
+ }
+},
+{
+ // open the submenu with the cursor right key
+ testname: "open submenu with cursor right",
+ events: [ "popupshowing submenupopup", "DOMMenuItemActive submenuitem",
+ "popupshown submenupopup" ],
+ test: function() { synthesizeKey("VK_RIGHT", { }); },
+ result: function(testname) {
+ checkOpen("trigger", testname);
+ checkOpen("submenu", testname);
+ checkActive(gMenuPopup, "submenu", testname);
+ checkActive(document.getElementById("submenupopup"), "submenuitem", testname);
+ }
+},
+{
+ // close the submenu with the cursor left key
+ testname: "close submenu with cursor left",
+ events: [ "popuphiding submenupopup", "popuphidden submenupopup",
+ "DOMMenuItemInactive submenuitem", "DOMMenuInactive submenupopup",
+ "DOMMenuItemActive submenu" ],
+ test: function() { synthesizeKey("VK_LEFT", { }); },
+ result: function(testname) {
+ checkOpen("trigger", testname);
+ checkClosed("submenu", testname);
+ checkActive(gMenuPopup, "submenu", testname);
+ checkActive(document.getElementById("submenupopup"), "", testname);
+ }
+},
+{
+ // open the submenu with the enter key
+ testname: "open submenu with enter",
+ events: [ "popupshowing submenupopup", "DOMMenuItemActive submenuitem",
+ "popupshown submenupopup" ],
+ test: function() { synthesizeKey("VK_RETURN", { }); },
+ result: function(testname) {
+ checkOpen("trigger", testname);
+ checkOpen("submenu", testname);
+ checkActive(gMenuPopup, "submenu", testname);
+ checkActive(document.getElementById("submenupopup"), "submenuitem", testname);
+ }
+},
+{
+ // close the submenu with the escape key
+ testname: "close submenu with escape",
+ events: [ "popuphiding submenupopup", "popuphidden submenupopup",
+ "DOMMenuItemInactive submenuitem", "DOMMenuInactive submenupopup",
+ "DOMMenuItemActive submenu" ],
+ test: function() { synthesizeKey("VK_ESCAPE", { }); },
+ result: function(testname) {
+ checkOpen("trigger", testname);
+ checkClosed("submenu", testname);
+ checkActive(gMenuPopup, "submenu", testname);
+ checkActive(document.getElementById("submenupopup"), "", testname);
+ }
+},
+{
+ // pressing the letter again when the next item is disabled should still
+ // select the disabled item on Windows, but select the next item on other
+ // platforms
+ testname: "menuitem with non accelerator disabled",
+ events: function() {
+ if (navigator.platform.indexOf("Win") == 0) {
+ return [ "DOMMenuItemInactive submenu", "DOMMenuItemActive other",
+ "DOMMenuItemInactive other", "DOMMenuItemActive item1" ];
+ }
+ return [ "DOMMenuItemInactive submenu", "DOMMenuItemActive last",
+ "DOMMenuItemInactive last", "DOMMenuItemActive item1" ];
+ },
+ test: function() { synthesizeKey("O", { }); synthesizeKey("F", { }); },
+ result: function(testname) {
+ checkActive(gMenuPopup, "item1", testname);
+ }
+},
+{
+ // pressing a letter that doesn't correspond to an accelerator nor the
+ // first letter of a menu. This should have no effect.
+ testname: "menuitem with keypress no accelerator found",
+ test: function() { synthesizeKey("G", { }); },
+ result: function(testname) {
+ checkOpen("trigger", testname);
+ checkActive(gMenuPopup, "item1", testname);
+ }
+},
+{
+ // when only one menuitem starting with that letter exists, it should be
+ // selected and the menu closed
+ testname: "menuitem with non accelerator single",
+ events: [ "DOMMenuItemInactive item1", "DOMMenuItemActive amenu",
+ "DOMMenuItemInactive amenu", "DOMMenuInactive thepopup",
+ "command amenu", "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuItemInactive amenu",
+ ],
+ test: function() { synthesizeKey("M", { }); },
+ result: function(testname) {
+ checkClosed("trigger", testname);
+ checkActive(gMenuPopup, "", testname);
+ }
+},
+{
+ testname: "open context popup at screen with all modifiers set",
+ events: [ "popupshowing thepopup 1111", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function(testname, step) {
+ gMenuPopup.openPopupAtScreen(gScreenX + 8, gScreenY + 16, true, gCachedEvent2);
+ }
+},
+{
+ testname: "open popup with open property",
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ test: function(testname, step) { openMenu(gTrigger); },
+ result: function(testname, step) {
+ checkOpen("trigger", testname);
+ if (gIsMenu)
+ compareEdge(gTrigger, gMenuPopup, "after_start", 0, 0, testname);
+ }
+},
+{
+ testname: "open submenu with open property",
+ events: [ "popupshowing submenupopup", "DOMMenuItemActive submenu",
+ "popupshown submenupopup" ],
+ test: function(testname, step) { openMenu(document.getElementById("submenu")); },
+ result: function(testname, step) {
+ checkOpen("trigger", testname);
+ checkOpen("submenu", testname);
+ // XXXndeakin
+ // getBoundingClientRect doesn't seem to working right for submenus
+ // so disable this test for now
+ // compareEdge(document.getElementById("submenu"),
+ // document.getElementById("submenupopup"), "end_before", 0, 0, testname);
+ }
+},
+{
+ testname: "hidePopup hides entire chain",
+ events: [ "popuphiding submenupopup", "popuphidden submenupopup",
+ "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuInactive submenupopup",
+ "DOMMenuItemInactive submenu", "DOMMenuItemInactive submenu",
+ "DOMMenuInactive thepopup", ],
+ test: function() { gMenuPopup.hidePopup(); },
+ result: function(testname, step) {
+ checkClosed("trigger", testname);
+ checkClosed("submenu", testname);
+ }
+},
+{
+ testname: "open submenu with open property without parent open",
+ test: function(testname, step) { openMenu(document.getElementById("submenu")); },
+ result: function(testname, step) {
+ checkClosed("trigger", testname);
+ checkClosed("submenu", testname);
+ }
+},
+{
+ testname: "open popup with open property and position",
+ condition: function() { return gIsMenu; },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ test: function(testname, step) {
+ gMenuPopup.setAttribute("position", "before_start");
+ openMenu(gTrigger);
+ },
+ result: function(testname, step) {
+ compareEdge(gTrigger, gMenuPopup, "before_start", 0, 0, testname);
+ }
+},
+{
+ testname: "close popup with open property",
+ condition: function() { return gIsMenu; },
+ events: [ "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuInactive thepopup" ],
+ test: function(testname, step) { closeMenu(gTrigger, gMenuPopup); },
+ result: function(testname, step) { checkClosed("trigger", testname); }
+},
+{
+ testname: "open popup with open property, position, anchor and alignment",
+ condition: function() { return gIsMenu; },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function(testname, step) {
+ gMenuPopup.setAttribute("position", "start_after");
+ gMenuPopup.setAttribute("popupanchor", "topright");
+ gMenuPopup.setAttribute("popupalign", "bottomright");
+ openMenu(gTrigger);
+ },
+ result: function(testname, step) {
+ compareEdge(gTrigger, gMenuPopup, "start_after", 0, 0, testname);
+ }
+},
+{
+ testname: "open popup with open property, anchor and alignment",
+ condition: function() { return gIsMenu; },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function(testname, step) {
+ gMenuPopup.removeAttribute("position");
+ gMenuPopup.setAttribute("popupanchor", "bottomright");
+ gMenuPopup.setAttribute("popupalign", "topright");
+ openMenu(gTrigger);
+ },
+ result: function(testname, step) {
+ compareEdge(gTrigger, gMenuPopup, "after_end", 0, 0, testname);
+ gMenuPopup.removeAttribute("popupanchor");
+ gMenuPopup.removeAttribute("popupalign");
+ }
+},
+{
+ testname: "focus and cursor down on trigger",
+ condition: function() { return gIsMenu; },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function(testname, step) {
+ gTrigger.focus();
+ synthesizeKey("VK_DOWN", { altKey: !platformIsMac() });
+ },
+ result: function(testname, step) {
+ checkOpen("trigger", testname);
+ checkActive(gMenuPopup, "", testname);
+ }
+},
+{
+ testname: "focus and cursor up on trigger",
+ condition: function() { return gIsMenu; },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ test: function(testname, step) {
+ gTrigger.focus();
+ synthesizeKey("VK_UP", { altKey: !platformIsMac() });
+ },
+ result: function(testname, step) {
+ checkOpen("trigger", testname);
+ checkActive(gMenuPopup, "", testname);
+ }
+},
+{
+ testname: "select and enter on menuitem",
+ condition: function() { return gIsMenu; },
+ events: [ "DOMMenuItemActive item1", "DOMMenuItemInactive item1",
+ "DOMMenuInactive thepopup", "command item1",
+ "popuphiding thepopup", "popuphidden thepopup",
+ "DOMMenuItemInactive item1" ],
+ test: function(testname, step) {
+ synthesizeKey("VK_DOWN", { });
+ synthesizeKey("VK_RETURN", { });
+ },
+ result: function(testname, step) { checkClosed("trigger", testname); }
+},
+{
+ testname: "focus trigger and key to open",
+ condition: function() { return gIsMenu; },
+ events: [ "popupshowing thepopup", "popupshown thepopup" ],
+ autohide: "thepopup",
+ test: function(testname, step) {
+ gTrigger.focus();
+ synthesizeKey(platformIsMac() ? " " : "VK_F4", { });
+ },
+ result: function(testname, step) {
+ checkOpen("trigger", testname);
+ checkActive(gMenuPopup, "", testname);
+ }
+},
+{
+ // the menu should only open when the meta or alt key is not pressed
+ testname: "focus trigger and key wrong modifier",
+ condition: function() { return gIsMenu; },
+ test: function(testname, step) {
+ gTrigger.focus();
+ if (platformIsMac())
+ synthesizeKey("VK_F4", { altKey: true });
+ else
+ synthesizeKey("", { metaKey: true });
+ },
+ result: function(testname, step) {
+ checkClosed("trigger", testname);
+ }
+},
+{
+ testname: "mouse click on disabled menu",
+ condition: function() { return gIsMenu; },
+ test: function(testname, step) {
+ gTrigger.setAttribute("disabled", "true");
+ synthesizeMouse(gTrigger, 4, 4, { });
+ },
+ result: function(testname, step) {
+ checkClosed("trigger", testname);
+ gTrigger.removeAttribute("disabled");
+ }
+},
+{
+ // openPopup should open the menu synchronously, however popupshown
+ // is fired asynchronously
+ testname: "openPopup synchronous",
+ events: [ "popupshowing thepopup", "popupshowing submenupopup",
+ "popupshown thepopup", "DOMMenuItemActive submenu",
+ "popupshown submenupopup" ],
+ test: function(testname, step) {
+ gMenuPopup.openPopup(gTrigger, "after_start", 0, 0, false, true);
+ document.getElementById("submenupopup").
+ openPopup(gTrigger, "end_before", 0, 0, false, true);
+ checkOpen("trigger", testname);
+ checkOpen("submenu", testname);
+ }
+},
+{
+ // remove the content nodes for the popup
+ testname: "remove content",
+ test: function(testname, step) {
+ var submenupopup = document.getElementById("submenupopup");
+ submenupopup.parentNode.removeChild(submenupopup);
+ var popup = document.getElementById("thepopup");
+ popup.parentNode.removeChild(popup);
+ }
+}
+
+];
+
+function platformIsMac()
+{
+ return navigator.platform.indexOf("Mac") > -1;
+}
diff --git a/toolkit/content/tests/chrome/rtlchrome/rtl.css b/toolkit/content/tests/chrome/rtlchrome/rtl.css
new file mode 100644
index 000000000..0fea01001
--- /dev/null
+++ b/toolkit/content/tests/chrome/rtlchrome/rtl.css
@@ -0,0 +1,2 @@
+/* Imitate RTL UI */
+window { direction: rtl; }
diff --git a/toolkit/content/tests/chrome/rtlchrome/rtl.dtd b/toolkit/content/tests/chrome/rtlchrome/rtl.dtd
new file mode 100644
index 000000000..8b32de674
--- /dev/null
+++ b/toolkit/content/tests/chrome/rtlchrome/rtl.dtd
@@ -0,0 +1 @@
+<!ENTITY locale.dir "rtl">
diff --git a/toolkit/content/tests/chrome/rtlchrome/rtl.manifest b/toolkit/content/tests/chrome/rtlchrome/rtl.manifest
new file mode 100644
index 000000000..a4cc6929b
--- /dev/null
+++ b/toolkit/content/tests/chrome/rtlchrome/rtl.manifest
@@ -0,0 +1,5 @@
+content rtlchrome /
+
+# Override intl.css with our own CSS file
+override chrome://global/locale/intl.css chrome://rtlchrome/rtl.css
+override chrome://global/locale/global.dtd chrome://rtlchrome/rtl.dtd
diff --git a/toolkit/content/tests/chrome/rtltest/content/dirtest.xul b/toolkit/content/tests/chrome/rtltest/content/dirtest.xul
new file mode 100644
index 000000000..b75d41eaa
--- /dev/null
+++ b/toolkit/content/tests/chrome/rtltest/content/dirtest.xul
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<html:style>
+hbox, vbox { background-color: white; }
+hbox:-moz-locale-dir(ltr) { background-color: yellow; }
+vbox:-moz-locale-dir(rtl) { background-color: green; }
+</html:style>
+
+<hbox id="hbox">
+ <button label="One"/>
+ <button label="Two"/>
+ <button label="Three"/>
+</hbox>
+<vbox id="vbox">
+ <button label="One"/>
+ <button label="Two"/>
+ <button label="Three"/>
+</vbox>
+
+</window>
diff --git a/toolkit/content/tests/chrome/rtltest/righttoleft.manifest b/toolkit/content/tests/chrome/rtltest/righttoleft.manifest
new file mode 100644
index 000000000..db98656bc
--- /dev/null
+++ b/toolkit/content/tests/chrome/rtltest/righttoleft.manifest
@@ -0,0 +1,3 @@
+content ltrtest content/
+content rtltest content/
+locale rtltest ar-QA content/
diff --git a/toolkit/content/tests/chrome/sample_entireword_latin1.html b/toolkit/content/tests/chrome/sample_entireword_latin1.html
new file mode 100644
index 000000000..b2d66fa3c
--- /dev/null
+++ b/toolkit/content/tests/chrome/sample_entireword_latin1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+ <head><title>Latin entire-word find test page</title></head>
+ <body>
+ <!-- Feel free to extend the contents of this page with more comprehensive
+ - Latin punctuation and/ or word markers.
+ -->
+ <p>The twins of Mammon quarrelled. Their warring plunged the world into a new darkness, and the beast abhorred the darkness. So it began to move swiftly, and grew more powerful, and went forth and multiplied. And the beasts brought fire and light to the darkness.</p>
+ <p>from The Book of Mozilla, 15:1</p>
+ </body>
+</html>
diff --git a/toolkit/content/tests/chrome/test_about_networking.html b/toolkit/content/tests/chrome/test_about_networking.html
new file mode 100644
index 000000000..6ffaf2ba7
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_about_networking.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=912103
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug </title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+
+ function runTest() {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+
+ var dashboard = Cc['@mozilla.org/network/dashboard;1']
+ .getService(Ci.nsIDashboard);
+ dashboard.enableLogging = true;
+
+ var wsURI = "ws://mochi.test:8888/chrome/toolkit/content/tests/chrome/file_about_networking";
+ var websocket = new WebSocket(wsURI);
+
+ websocket.addEventListener("open", function() {
+ dashboard.requestWebsocketConnections(function(data) {
+ var found = false;
+ for (var i = 0; i < data.websockets.length; i++) {
+ if (data.websockets[i].hostport == "mochi.test:8888") {
+ found = true;
+ break;
+ }
+ }
+ isnot(found, false, "tested websocket entry not found");
+ websocket.close();
+ SimpleTest.finish();
+ });
+ });
+ }
+
+ window.addEventListener("DOMContentLoaded", function run() {
+ window.removeEventListener("DOMContentLoaded", run);
+ runTest();
+ });
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=912103">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/toolkit/content/tests/chrome/test_arrowpanel.xul b/toolkit/content/tests/chrome/test_arrowpanel.xul
new file mode 100644
index 000000000..671c33a15
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_arrowpanel.xul
@@ -0,0 +1,327 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Arrow Panels"
+ style="padding: 10px;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<stack flex="1">
+ <label id="topleft" value="Top Left Corner" left="15" top="15"/>
+ <label id="topright" value="Top Right" right="15" top="15"/>
+ <label id="bottomleft" value="Bottom Left Corner" left="15" bottom="15"/>
+ <label id="bottomright" value="Bottom Right" right="15" bottom="15"/>
+ <!-- Our SimpleTest/TestRunner.js runs tests inside an iframe which sizes are W=500 H=300.
+ 'left' and 'top' values need to be set so that the panel (popup) has enough room to display on its 4 sides. -->
+ <label id="middle" value="+/- Centered" left="225" top="135"/>
+ <iframe id="frame" type="content"
+ src="data:text/html,&lt;input id='input'&gt;" width="100" height="100" left="225" top="120"/>
+</stack>
+
+<panel id="panel" type="arrow" animate="false"
+ onpopupshown="checkPanelPosition(this)" onpopuphidden="runNextTest.next()">
+ <box width="115" height="65"/>
+</panel>
+
+<panel id="bigpanel" type="arrow" animate="false"
+ onpopupshown="checkBigPanel(this)" onpopuphidden="runNextTest.next()">
+ <box width="125" height="3000"/>
+</panel>
+
+<panel id="animatepanel" type="arrow"
+ onpopupshown="animatedPopupShown = true;"
+ onpopuphidden="animatedPopupHidden = true; runNextTest.next();">
+ <label value="Animate Closed" height="40"/>
+</panel>
+
+<script type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+const isOSXYosemite = navigator.userAgent.indexOf("Mac OS X 10.10") != -1;
+
+var expectedAnchor = null;
+var expectedSide = "", expectedAnchorEdge = "", expectedPack = "", expectedAlignment = "";
+var zoomFactor = 1;
+var animatedPopupShown = false;
+var animatedPopupHidden = false;
+var runNextTest;
+
+function startTest()
+{
+ runNextTest = nextTest();
+ runNextTest.next();
+}
+
+function nextTest()
+{
+ var panel = $("panel");
+
+ function openPopup(position, anchor, expected, anchorEdge, pack, alignment)
+ {
+ expectedAnchor = anchor instanceof Node ? anchor : $(anchor);
+ expectedSide = expected;
+ expectedAnchorEdge = anchorEdge;
+ expectedPack = pack;
+ expectedAlignment = alignment == undefined ? position : alignment;
+
+ panel.removeAttribute("side");
+ panel.openPopup(expectedAnchor, position, 0, 0, false, false, null);
+ }
+
+ for (var iter = 0; iter < 2; iter++) {
+ openPopup("after_start", "topleft", "top", "left", "start");
+ yield;
+ openPopup("after_start", "bottomleft", "bottom", "left", "start", "before_start");
+ yield;
+ openPopup("before_start", "topleft", "top", "left", "start", "after_start");
+ yield;
+ openPopup("before_start", "bottomleft", "bottom", "left", "start");
+ yield;
+ openPopup("after_start", "middle", "top", "left", "start");
+ yield;
+ openPopup("before_start", "middle", "bottom", "left", "start");
+ yield;
+
+ openPopup("after_start", "topright", "top", "right", "end", "after_end");
+ yield;
+ openPopup("after_start", "bottomright", "bottom", "right", "end", "before_end");
+ yield;
+ openPopup("before_start", "topright", "top", "right", "end", "after_end");
+ yield;
+ openPopup("before_start", "bottomright", "bottom", "right", "end", "before_end");
+ yield;
+
+ openPopup("after_end", "middle", "top", "right", "end");
+ yield;
+ openPopup("before_end", "middle", "bottom", "right", "end");
+ yield;
+
+ openPopup("start_before", "topleft", "left", "top", "start", "end_before");
+ yield;
+ openPopup("start_before", "topright", "right", "top", "start");
+ yield;
+ openPopup("end_before", "topleft", "left", "top", "start");
+ yield;
+ openPopup("end_before", "topright", "right", "top", "start", "start_before");
+ yield;
+ openPopup("start_before", "middle", "right", "top", "start");
+ yield;
+ openPopup("end_before", "middle", "left", "top", "start");
+ yield;
+
+ openPopup("start_before", "bottomleft", "left", "bottom", "end", "end_after");
+ yield;
+ openPopup("start_before", "bottomright", "right", "bottom", "end", "start_after");
+ yield;
+ openPopup("end_before", "bottomleft", "left", "bottom", "end", "end_after");
+ yield;
+ openPopup("end_before", "bottomright", "right", "bottom", "end", "start_after");
+ yield;
+
+ openPopup("start_after", "middle", "right", "bottom", "end");
+ yield;
+ openPopup("end_after", "middle", "left", "bottom", "end");
+ yield;
+
+ openPopup("topcenter bottomleft", "bottomleft", "bottom", "center left", "start", "before_start");
+ yield;
+ openPopup("bottomcenter topleft", "topleft", "top", "center left", "start", "after_start");
+ yield;
+ openPopup("topcenter bottomright", "bottomright", "bottom", "center right", "end", "before_end");
+ yield;
+ openPopup("bottomcenter topright", "topright", "top", "center right", "end", "after_end");
+ yield;
+ openPopup("topcenter bottomleft", "middle", "bottom", "center left", "start", "before_start");
+ yield;
+ openPopup("bottomcenter topleft", "middle", "top", "center left", "start", "after_start");
+ yield;
+
+ openPopup("leftcenter topright", "middle", "right", "center top", "start", "start_before");
+ yield;
+ openPopup("rightcenter bottomleft", "middle", "left", "center bottom", "end", "end_after");
+ yield;
+
+/*
+ XXXndeakin disable these parts of the test which often cause problems, see bug 626563
+
+ openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
+ yield;
+
+ setScale(frames[0], 1.5);
+ openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
+ yield;
+
+ setScale(frames[0], 2.5);
+ openPopup("before_start", frames[0].document.getElementById("input"), "bottom", "left", "start");
+ yield;
+
+ setScale(frames[0], 1);
+*/
+
+ $("bigpanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
+ yield;
+
+ // switch to rtl mode
+ document.documentElement.style.direction = "rtl";
+ $("topleft").setAttribute("right", "15");
+ $("topright").setAttribute("left", "15");
+ $("bottomleft").setAttribute("right", "15");
+ $("bottomright").setAttribute("left", "15");
+ $("topleft").removeAttribute("left");
+ $("topright").removeAttribute("right");
+ $("bottomleft").removeAttribute("left");
+ $("bottomright").removeAttribute("right");
+ }
+
+ // Test that a transition occurs when opening or closing the popup. The transition is
+ // disabled on Linux.
+ if (navigator.platform.indexOf("Linux") == -1) {
+ function transitionEnded(event) {
+ if ($("animatepanel").state != "open") {
+ is($("animatepanel").state, "showing", "state is showing during transitionend");
+ ok(!animatedPopupShown, "popupshown not fired yet")
+ } else {
+ is($("animatepanel").state, "open", "state is open after transitionend");
+ ok(animatedPopupShown, "popupshown now fired")
+ SimpleTest.executeSoon(() => runNextTest.next());
+ }
+ }
+
+ // Check that the transition occurs for an arrow panel with animate="true"
+ window.addEventListener("transitionend", transitionEnded, false);
+ $("animatepanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
+ is($("animatepanel").state, "showing", "state is showing");
+ yield;
+ window.removeEventListener("transitionend", transitionEnded, false);
+
+ synthesizeKey("VK_ESCAPE", { });
+ ok(!animatedPopupHidden, "animated popup not hidden yet");
+ yield;
+ }
+
+ SimpleTest.finish()
+ yield;
+}
+
+function setScale(win, scale)
+{
+ var wn = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebNavigation);
+ var shell = wn.QueryInterface(Components.interfaces.nsIDocShell);
+ var docViewer = shell.contentViewer;
+ docViewer.fullZoom = scale;
+ zoomFactor = scale;
+}
+
+function checkPanelPosition(panel)
+{
+ let anchor = panel.anchorNode;
+ let adj = 0, hwinpos = 0, vwinpos = 0;
+ if (anchor.ownerDocument != document) {
+ var framerect = anchor.ownerDocument.defaultView.frameElement.getBoundingClientRect();
+ hwinpos = framerect.left;
+ vwinpos = framerect.top;
+ }
+
+ // Positions are reversed in rtl yet the coordinates used in the computations
+ // are not, so flip the expected label side and anchor edge.
+ var isRTL = (window.getComputedStyle(panel).direction == "rtl");
+ if (isRTL) {
+ var flipLeftRight = val => val == "left" ? "right" : "left";
+ expectedAnchorEdge = expectedAnchorEdge.replace(/(left|right)/, flipLeftRight);
+ expectedSide = expectedSide.replace(/(left|right)/, flipLeftRight);
+ }
+
+ var panelRect = panel.getBoundingClientRect();
+ var anchorRect = anchor.getBoundingClientRect();
+ var contentBO = panel.firstChild.boxObject;
+ var contentRect = { top: contentBO.y,
+ left: contentBO.x,
+ bottom: contentBO.y + contentBO.height,
+ right: contentBO.x + contentBO.width };
+ switch (expectedSide) {
+ case "top":
+ ok(contentRect.top > vwinpos + anchorRect.bottom * zoomFactor + 5, "panel content is below");
+ break;
+ case "bottom":
+ ok(contentRect.bottom < vwinpos + anchorRect.top * zoomFactor - 5, "panel content is above");
+ break;
+ case "left":
+ ok(contentRect.left > hwinpos + anchorRect.right * zoomFactor + 5, "panel content is right");
+ break;
+ case "right":
+ ok(contentRect.right < hwinpos + anchorRect.left * zoomFactor - 5, "panel content is left");
+ break;
+ }
+
+ let iscentered = false;
+ if (expectedAnchorEdge.indexOf("center ") == 0) {
+ expectedAnchorEdge = expectedAnchorEdge.substring(7);
+ iscentered = true;
+ }
+
+ switch (expectedAnchorEdge) {
+ case "top":
+ adj = vwinpos + parseInt(getComputedStyle(panel, "").marginTop);
+ if (iscentered)
+ adj += Math.round(anchorRect.height) / 2;
+ isWithinHalfPixel(panelRect.top, anchorRect.top * zoomFactor + adj, "anchored on top");
+ break;
+ case "bottom":
+ adj = vwinpos + parseInt(getComputedStyle(panel, "").marginBottom);
+ if (iscentered)
+ adj += Math.round(anchorRect.height) / 2;
+ isWithinHalfPixel(panelRect.bottom, anchorRect.bottom * zoomFactor - adj, "anchored on bottom");
+ break;
+ case "left":
+ adj = hwinpos + parseInt(getComputedStyle(panel, "").marginLeft);
+ if (iscentered)
+ adj += Math.round(anchorRect.width) / 2;
+ isWithinHalfPixel(panelRect.left, anchorRect.left * zoomFactor + adj, "anchored on left ");
+ break;
+ case "right":
+ adj = hwinpos + parseInt(getComputedStyle(panel, "").marginRight);
+ if (iscentered)
+ adj += Math.round(anchorRect.width) / 2;
+ if (!isOSXYosemite)
+ isWithinHalfPixel(panelRect.right, anchorRect.right * zoomFactor - adj, "anchored on right");
+ break;
+ }
+
+ is(anchor, expectedAnchor, "anchor");
+
+ var arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
+ is(arrow.getAttribute("side"), expectedSide, "panel arrow side");
+ is(arrow.hidden, false, "panel hidden");
+ is(arrow.parentNode.pack, expectedPack, "panel arrow pack");
+ is(panel.alignmentPosition, expectedAlignment, "panel alignmentPosition");
+
+ panel.hidePopup();
+}
+
+function isWithinHalfPixel(a, b, desc)
+{
+ ok(Math.abs(a - b) <= 0.5, desc);
+}
+
+function checkBigPanel(panel)
+{
+ ok(panel.firstChild.getBoundingClientRect().height < 2800, "big panel height");
+ panel.hidePopup();
+}
+
+SimpleTest.waitForFocus(startTest);
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml"/>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete2.xul b/toolkit/content/tests/chrome/test_autocomplete2.xul
new file mode 100644
index 000000000..875cddd07
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete2.xul
@@ -0,0 +1,197 @@
+<?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="Autocomplete Widget Test 2"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<textbox id="autocomplete" type="autocomplete"
+ autocompletesearch="simple"
+ onsearchcomplete="checkResult();"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+// Set to indicate whether or not we want autoCompleteSimple to return a result
+var returnResult = false;
+
+const ACR = Components.interfaces.nsIAutoCompleteResult;
+
+// This result can't be constructed in-line, because otherwise we leak memory.
+function nsAutoCompleteSimpleResult(aString)
+{
+ this.searchString = aString;
+ if (returnResult) {
+ this.searchResult = ACR.RESULT_SUCCESS;
+ this.matchCount = 1;
+ this._param = "SUCCESS";
+ }
+}
+
+nsAutoCompleteSimpleResult.prototype = {
+ _param: "",
+ searchString: null,
+ searchResult: ACR.RESULT_FAILURE,
+ defaultIndex: -1,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function() { return this._param; },
+ getCommentAt: function() { return null; },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
+ getLabelAt: function() { return null; },
+ removeValueAt: function() {}
+};
+
+// A basic autocomplete implementation that either returns one result or none
+var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
+var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
+var autoCompleteSimple = {
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsIFactory) ||
+ iid.equals(Components.interfaces.nsIAutoCompleteSearch))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ },
+
+ createInstance: function(outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ startSearch: function(aString, aParam, aResult, aListener) {
+ var result = new nsAutoCompleteSimpleResult(aString);
+ aListener.onSearchResult(this, result);
+ },
+
+ stopSearch: function() {}
+};
+
+var componentManager = Components.manager
+ .QueryInterface(Components.interfaces.nsIComponentRegistrar);
+componentManager.registerFactory(autoCompleteSimpleID, "Test Simple Autocomplete",
+ autoCompleteSimpleName, autoCompleteSimple);
+
+
+// Test Bug 441530 - correctly setting "nomatch"
+// Test Bug 441526 - correctly setting style with "highlightnonmatches"
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(startTest, 0);
+
+function startTest() {
+ var autocomplete = $("autocomplete");
+
+ // Ensure highlightNonMatches can be set correctly.
+
+ // This should not be set by default.
+ is(autocomplete.hasAttribute("highlightnonmatches"), false,
+ "highlight nonmatches not set by default");
+
+ autocomplete.highlightNonMatches = "true";
+
+ is(autocomplete.getAttribute("highlightnonmatches"), "true",
+ "highlight non matches attribute set correctly");
+ is(autocomplete.highlightNonMatches, true,
+ "highlight non matches getter returned correctly");
+
+ autocomplete.highlightNonMatches = "false";
+
+ is(autocomplete.getAttribute("highlightnonmatches"), "false",
+ "highlight non matches attribute set to false correctly");
+ is(autocomplete.highlightNonMatches, false,
+ "highlight non matches getter returned false correctly");
+
+ ok(!autocomplete.popup.hasAttribute("autocompleteinput"),
+ "autocompleteinput on popup not set by default");
+
+ check();
+}
+
+function check() {
+ var autocomplete = $("autocomplete");
+
+ // Toggle this value, so we can re-use the one function.
+ returnResult = !returnResult;
+
+ // blur the field to ensure that the popup is closed and that the previous
+ // search has stopped, then start a new search.
+ autocomplete.blur();
+ autocomplete.focus();
+ synthesizeKey("r", {});
+}
+
+function checkResult() {
+ var autocomplete = $("autocomplete");
+ var style = window.getComputedStyle(autocomplete, "");
+
+ if (returnResult) {
+ // Result was returned, so there should not be a nomatch attribute
+ is(autocomplete.hasAttribute("nomatch"), false,
+ "nomatch attribute shouldn't be present here");
+
+ // Ensure that the style is set correctly whichever way highlightNonMatches
+ // is set.
+ autocomplete.highlightNonMatches = "true";
+
+ isnot(style.getPropertyCSSValue("color").cssText, "rgb(255, 0, 0)",
+ "not nomatch and highlightNonMatches - should not be red");
+
+ autocomplete.highlightNonMatches = "false";
+
+ isnot(style.getPropertyCSSValue("color").cssText, "rgb(255, 0, 0)",
+ "not nomatch and not highlightNonMatches - should not be red");
+
+ is (autocomplete.popup.getAttribute("autocompleteinput"), "autocomplete",
+ "The popup's autocompleteinput attribute is set to the ID of the textbox");
+
+ setTimeout(check, 0);
+ }
+ else {
+ // No result was returned, so there should be nomatch attribute
+ is(autocomplete.getAttribute("nomatch"), "true",
+ "nomatch attribute not correctly set when expected");
+
+ // Ensure that the style is set correctly whichever way highlightNonMatches
+ // is set.
+ autocomplete.highlightNonMatches = "true";
+
+ is(style.getPropertyCSSValue("color").cssText, "rgb(255, 0, 0)",
+ "nomatch and highlightNonMatches - should be red");
+
+ autocomplete.highlightNonMatches = "false";
+
+ isnot(style.getPropertyCSSValue("color").cssText, "rgb(255, 0, 0)",
+ "nomatch and not highlightNonMatches - should not be red");
+
+ ok(!autocomplete.popup.hasAttribute("autocompleteinput"),
+ "autocompleteinput on popup not set when closed");
+
+ setTimeout(function() {
+ // Unregister the factory so that we don't get in the way of other tests
+ componentManager.unregisterFactory(autoCompleteSimpleID, autoCompleteSimple);
+ SimpleTest.finish();
+ }, 0);
+ }
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete3.xul b/toolkit/content/tests/chrome/test_autocomplete3.xul
new file mode 100644
index 000000000..953fd15c8
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete3.xul
@@ -0,0 +1,188 @@
+<?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="Autocomplete Widget Test 3"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<textbox id="autocomplete" type="autocomplete"
+ autocompletesearch="simple"
+ onsearchcomplete="checkResult();"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+// Set to indicate whether or not we want autoCompleteSimple to return a result
+var returnResult = true;
+
+const ACR = Components.interfaces.nsIAutoCompleteResult;
+
+// This result can't be constructed in-line, because otherwise we leak memory.
+function nsAutoCompleteSimpleResult(aString)
+{
+ this.searchString = aString;
+ if (returnResult) {
+ this.searchResult = ACR.RESULT_SUCCESS;
+ this.matchCount = 1;
+ this._param = "Result";
+ }
+}
+
+nsAutoCompleteSimpleResult.prototype = {
+ _param: "",
+ searchString: null,
+ searchResult: ACR.RESULT_FAILURE,
+ defaultIndex: 0,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function() { return this._param; },
+ getCommentAt: function() { return null; },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
+ getLabelAt: function() { return null; },
+ removeValueAt: function() {}
+};
+
+// A basic autocomplete implementation that either returns one result or none
+var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
+var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
+var autoCompleteSimple = {
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsIFactory) ||
+ iid.equals(Components.interfaces.nsIAutoCompleteSearch))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ },
+
+ createInstance: function(outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ startSearch: function(aString, aParam, aResult, aListener) {
+ var result = new nsAutoCompleteSimpleResult(aString);
+ aListener.onSearchResult(this, result);
+ },
+
+ stopSearch: function() {}
+};
+
+var componentManager = Components.manager
+ .QueryInterface(Components.interfaces.nsIComponentRegistrar);
+componentManager.registerFactory(autoCompleteSimpleID, "Test Simple Autocomplete",
+ autoCompleteSimpleName, autoCompleteSimple);
+
+
+// Test Bug 325842 - completeDefaultIndex
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(startTest, 0);
+
+var currentTest = 0;
+
+// Note the entries for these tests (key) are incremental.
+const tests = [
+ { completeDefaultIndex: "false", key: "r", result: "r",
+ start: 1, end: 1 },
+ { completeDefaultIndex: "true", key: "e", result: "result",
+ start: 2, end: 6 },
+ { completeDefaultIndex: "true", key: "t", result: "ret >> Result",
+ start: 3, end: 13 }
+];
+
+function startTest() {
+ var autocomplete = $("autocomplete");
+
+ // These should not be set by default.
+ is(autocomplete.hasAttribute("completedefaultindex"), false,
+ "completedefaultindex not set by default");
+
+ autocomplete.completeDefaultIndex = "true";
+
+ is(autocomplete.getAttribute("completedefaultindex"), "true",
+ "completedefaultindex attribute set correctly");
+ is(autocomplete.completeDefaultIndex, true,
+ "autoFill getter returned correctly");
+
+ autocomplete.completeDefaultIndex = "false";
+
+ is(autocomplete.getAttribute("completedefaultindex"), "false",
+ "completedefaultindex attribute set to false correctly");
+ is(autocomplete.completeDefaultIndex, false,
+ "completeDefaultIndex getter returned false correctly");
+
+ checkNext();
+}
+
+function checkNext() {
+ var autocomplete = $("autocomplete");
+
+ autocomplete.completeDefaultIndex = tests[currentTest].completeDefaultIndex;
+ autocomplete.focus();
+
+ synthesizeKey(tests[currentTest].key, {});
+}
+
+function checkResult() {
+ var autocomplete = $("autocomplete");
+ var style = window.getComputedStyle(autocomplete, "");
+
+ is(autocomplete.value, tests[currentTest].result,
+ "Test " + currentTest + ": autocomplete.value should equal '" +
+ tests[currentTest].result + "'");
+
+ is(autocomplete.selectionStart, tests[currentTest].start,
+ "Test " + currentTest + ": autocomplete selection should start at " +
+ tests[currentTest].start);
+
+ is(autocomplete.selectionEnd, tests[currentTest].end,
+ "Test " + currentTest + ": autocomplete selection should end at " +
+ tests[currentTest].end);
+
+ ++currentTest;
+
+ if (currentTest < tests.length)
+ setTimeout(checkNext, 0);
+ else {
+ // TODO (bug 494809): Autocomplete-in-the-middle should take in count RTL
+ // and complete on VK_RIGHT or VK_LEFT based on that. It should also revert
+ // what user has typed to far if he moves in the opposite direction.
+ if (autocomplete.value.indexOf(">>") == -1) {
+ // Test result if user accepts autocomplete suggestion.
+ synthesizeKey("VK_RIGHT", {});
+ is(autocomplete.value, "Result",
+ "Test complete: autocomplete.value should equal 'Result'");
+ is(autocomplete.selectionStart, 6,
+ "Test complete: autocomplete selection should start at 6");
+ is(autocomplete.selectionEnd, 6,
+ "Test complete: autocomplete selection should end at 6");
+ }
+
+ setTimeout(function() {
+ // Unregister the factory so that we don't get in the way of other tests
+ componentManager.unregisterFactory(autoCompleteSimpleID, autoCompleteSimple);
+ SimpleTest.finish();
+ }, 0);
+ }
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete4.xul b/toolkit/content/tests/chrome/test_autocomplete4.xul
new file mode 100644
index 000000000..007e95661
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete4.xul
@@ -0,0 +1,280 @@
+<?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="Autocomplete Widget Test 4"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<textbox id="autocomplete"
+ type="autocomplete"
+ completedefaultindex="true"
+
+ onsearchcomplete="searchComplete();"
+ autocompletesearch="simple"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+// Set to indicate whether or not we want autoCompleteSimple to return a result
+var returnResult = true;
+
+const ACR = Components.interfaces.nsIAutoCompleteResult;
+
+// This result can't be constructed in-line, because otherwise we leak memory.
+function nsAutoCompleteSimpleResult(aString)
+{
+ this.searchString = aString;
+ if (returnResult) {
+ this.searchResult = ACR.RESULT_SUCCESS;
+ this.matchCount = 1;
+ this._param = "Result";
+ }
+}
+
+nsAutoCompleteSimpleResult.prototype = {
+ _param: "",
+ searchString: null,
+ searchResult: ACR.RESULT_FAILURE,
+ defaultIndex: 0,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function() { return this._param; },
+ getCommentAt: function() { return null; },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
+ getLabelAt: function() { return null; },
+ removeValueAt: function() {}
+};
+
+// A basic autocomplete implementation that either returns one result or none
+var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
+var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
+var autoCompleteSimple = {
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsIFactory) ||
+ iid.equals(Components.interfaces.nsIAutoCompleteSearch))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ },
+
+ createInstance: function(outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ startSearch: function(aString, aParam, aResult, aListener) {
+ var result = new nsAutoCompleteSimpleResult(aString);
+ aListener.onSearchResult(this, result);
+ },
+
+ stopSearch: function() {}
+};
+
+var componentManager = Components.manager
+ .QueryInterface(Components.interfaces.nsIComponentRegistrar);
+componentManager.registerFactory(autoCompleteSimpleID, "Test Simple Autocomplete",
+ autoCompleteSimpleName, autoCompleteSimple);
+
+
+// Test Bug 325842 - completeDefaultIndex
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(nextTest, 0);
+
+var currentTest = null;
+
+// Note the entries for these tests (key) are incremental.
+const tests = [
+ {
+ desc: "HOME key remove selection",
+ key: "VK_HOME",
+ removeSelection: true,
+ result: "re",
+ start: 0, end: 0
+ },
+ {
+ desc: "LEFT key remove selection",
+ key: "VK_LEFT",
+ removeSelection: true,
+ result: "re",
+ start: 1, end: 1
+ },
+ { desc: "RIGHT key remove selection",
+ key: "VK_RIGHT",
+ removeSelection: true,
+ result: "re",
+ start: 2, end: 2
+ },
+ { desc: "ENTER key remove selection",
+ key: "VK_RETURN",
+ removeSelection: true,
+ result: "re",
+ start: 2, end: 2
+ },
+ {
+ desc: "HOME key",
+ key: "VK_HOME",
+ removeSelection: false,
+ result: "Result",
+ start: 0, end: 0
+ },
+ {
+ desc: "LEFT key",
+ key: "VK_LEFT",
+ removeSelection: false,
+ result: "Result",
+ start: 5, end: 5
+ },
+ { desc: "RIGHT key",
+ key: "VK_RIGHT",
+ removeSelection: false,
+ result: "Result",
+ start: 6, end: 6
+ },
+ { desc: "RETURN key",
+ key: "VK_RETURN",
+ removeSelection: false,
+ result: "Result",
+ start: 6, end: 6
+ },
+ { desc: "TAB key should confirm suggestion when forcecomplete is set",
+ key: "VK_TAB",
+ removeSelection: false,
+ forceComplete: true,
+ result: "Result",
+ start: 6, end: 6
+ },
+
+ { desc: "RIGHT key complete from middle",
+ key: "VK_RIGHT",
+ forceComplete: true,
+ completeFromMiddle: true,
+ result: "Result",
+ start: 6, end: 6
+ },
+ {
+ desc: "RIGHT key w/ minResultsForPopup=2",
+ key: "VK_RIGHT",
+ removeSelection: false,
+ minResultsForPopup: 2,
+ result: "Result",
+ start: 6, end: 6
+ },
+];
+
+function nextTest() {
+ if (!tests.length) {
+ // No more tests to run, finish.
+ setTimeout(function() {
+ // Unregister the factory so that we don't get in the way of other tests
+ componentManager.unregisterFactory(autoCompleteSimpleID, autoCompleteSimple);
+ SimpleTest.finish();
+ }, 0);
+ return;
+ }
+
+ var autocomplete = $("autocomplete");
+ autocomplete.value = "";
+ currentTest = tests.shift();
+
+ // HOME key works differently on Mac, so we skip tests using it.
+ if (currentTest.key == "VK_HOME" && navigator.platform.indexOf("Mac") != -1)
+ nextTest();
+ else
+ setTimeout(runCurrentTest, 0);
+}
+
+function runCurrentTest() {
+ var autocomplete = $("autocomplete");
+ if ("minResultsForPopup" in currentTest)
+ autocomplete.setAttribute("minresultsforpopup", currentTest.minResultsForPopup)
+ else
+ autocomplete.removeAttribute("minresultsforpopup");
+
+ autocomplete.focus();
+
+ if (!currentTest.completeFromMiddle) {
+ synthesizeKey("r", {});
+ synthesizeKey("e", {});
+ }
+ else {
+ synthesizeKey("l", {});
+ synthesizeKey("t", {});
+ }
+}
+
+function searchComplete() {
+ var autocomplete = $("autocomplete");
+ autocomplete.setAttribute("forcecomplete", currentTest.forceComplete ? true : false);
+
+ if (currentTest.completeFromMiddle) {
+ if (!currentTest.forceComplete) {
+ synthesizeKey(currentTest.key, {});
+ }
+ else if (!/ >> /.test(autocomplete.value)) {
+ // At this point we should have a value like "lt >> Result" showing.
+ throw new Error("Expected an middle-completed value, got " + autocomplete.value);
+ }
+
+ // For forceComplete a blur should cause a value from the results to get
+ // completed to. E.g. "lt >> Result" will turn into "Result".
+ if (currentTest.forceComplete)
+ autocomplete.blur();
+
+ checkResult();
+ return;
+ }
+
+ is(autocomplete.value, "result",
+ "Test '" + currentTest.desc + "': autocomplete.value should equal 'result'");
+
+ if (autocomplete.selectionStart == 2) { // Finished inserting "re" string.
+ if (currentTest.removeSelection) {
+ // remove current selection
+ synthesizeKey("VK_DELETE", {});
+ }
+
+ synthesizeKey(currentTest.key, {});
+
+ checkResult();
+ }
+}
+
+function checkResult() {
+ var autocomplete = $("autocomplete");
+
+ is(autocomplete.value, currentTest.result,
+ "Test '" + currentTest.desc + "': autocomplete.value should equal '" +
+ currentTest.result + "'");
+
+ is(autocomplete.selectionStart, currentTest.start,
+ "Test '" + currentTest.desc + "': autocomplete selection should start at " +
+ currentTest.start);
+
+ is(autocomplete.selectionEnd, currentTest.end,
+ "Test '" + currentTest.desc + "': autocomplete selection should end at " +
+ currentTest.end);
+
+ setTimeout(nextTest, 0);
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete5.xul b/toolkit/content/tests/chrome/test_autocomplete5.xul
new file mode 100644
index 000000000..2f6dc5a30
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete5.xul
@@ -0,0 +1,152 @@
+<?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="Autocomplete Widget Test 5"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<textbox id="autocomplete" type="autocomplete"
+ autocompletesearch="simple"
+ ontextentered="checkTextEntered();"
+ ontextreverted="checkTextReverted();"
+ onsearchbegin="checkSearchBegin();"
+ onsearchcomplete="checkSearchCompleted();"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+const ACR = Components.interfaces.nsIAutoCompleteResult;
+
+// This result can't be constructed in-line, because otherwise we leak memory.
+function nsAutoCompleteSimpleResult(aString)
+{
+ this.searchString = aString;
+ this.searchResult = ACR.RESULT_SUCCESS;
+ this.matchCount = 1;
+ this._param = "SUCCESS";
+}
+
+nsAutoCompleteSimpleResult.prototype = {
+ _param: "",
+ searchString: null,
+ searchResult: ACR.RESULT_FAILURE,
+ defaultIndex: -1,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function() { return this._param; },
+ getCommentAt: function() { return null; },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
+ getLabelAt: function() { return null; },
+ removeValueAt: function() {}
+};
+
+// A basic autocomplete implementation that either returns one result or none
+var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
+var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
+var autoCompleteSimple = {
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsIFactory) ||
+ iid.equals(Components.interfaces.nsIAutoCompleteSearch))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ },
+
+ createInstance: function(outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ startSearch: function(aString, aParam, aResult, aListener) {
+ var result = new nsAutoCompleteSimpleResult(aString);
+ aListener.onSearchResult(this, result);
+ },
+
+ stopSearch: function() {}
+};
+
+var componentManager = Components.manager
+ .QueryInterface(Components.interfaces.nsIComponentRegistrar);
+componentManager.registerFactory(autoCompleteSimpleID, "Test Simple Autocomplete",
+ autoCompleteSimpleName, autoCompleteSimple);
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(startTest, 0);
+
+function startTest() {
+ let autocomplete = $("autocomplete");
+
+ // blur the field to ensure that the popup is closed and that the previous
+ // search has stopped, then start a new search.
+ autocomplete.blur();
+ autocomplete.focus();
+ synthesizeKey("r", {});
+}
+
+let hasTextEntered = false;
+let hasSearchBegun = false;
+
+function checkSearchBegin() {
+ hasSearchBegun = true;
+}
+
+let test = 0;
+function checkSearchCompleted() {
+ is(hasSearchBegun, true, "onsearchbegin handler has been correctly called.");
+
+ if (test == 0) {
+ hasSearchBegun = false;
+ synthesizeKey("VK_RETURN", { });
+ } else if (test == 1) {
+ hasSearchBegun = false;
+ synthesizeKey("VK_ESCAPE", { });
+ } else {
+ throw "checkSearchCompleted should only be called twice.";
+ }
+}
+
+function checkTextEntered() {
+ is(test, 0, "checkTextEntered should be reached from first test.");
+ is(hasSearchBegun, false, "onsearchbegin handler should not be called on text revert.");
+
+ // fire second test
+ test++;
+
+ let autocomplete = $("autocomplete");
+ autocomplete.textValue = "";
+ autocomplete.blur();
+ autocomplete.focus();
+ synthesizeKey("r", {});
+}
+
+function checkTextReverted() {
+ is(test, 1, "checkTextReverted should be the second test reached.");
+ is(hasSearchBegun, false, "onsearchbegin handler should not be called on text revert.");
+
+ setTimeout(function() {
+ // Unregister the factory so that we don't get in the way of other tests
+ componentManager.unregisterFactory(autoCompleteSimpleID, autoCompleteSimple);
+ SimpleTest.finish();
+ }, 0);
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul b/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
new file mode 100644
index 000000000..19f54ac21
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
@@ -0,0 +1,128 @@
+<?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="Autocomplete Widget Test 4"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="runTest();">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+ <script type="application/javascript"
+ src="chrome://global/content/globalOverlay.js"/>
+
+<textbox id="autocomplete"
+ type="autocomplete"
+ completedefaultindex="true"
+ onsearchcomplete="searchComplete();"
+ timeout="0"
+ autocompletesearch="simple"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function autoCompleteSimpleResult(aString) {
+ this.searchString = aString;
+ this.searchResult = Components.interfaces.nsIAutoCompleteResult.RESULT_SUCCESS;
+ this.matchCount = 1;
+ this._param = "Result";
+}
+autoCompleteSimpleResult.prototype = {
+ _param: "",
+ searchString: null,
+ searchResult: Components.interfaces.nsIAutoCompleteResult.RESULT_FAILURE,
+ defaultIndex: 0,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function() { return this._param; },
+ getCommentAt: function() { return null; },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
+ getLabelAt: function() { return null; },
+ removeValueAt: function() {}
+};
+
+// A basic autocomplete implementation that returns one result.
+let autoCompleteSimple = {
+ classID: Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"),
+ contractID: "@mozilla.org/autocomplete/search;1?name=simple",
+ QueryInterface: XPCOMUtils.generateQI([
+ Components.interfaces.nsIFactory,
+ Components.interfaces.nsIAutoCompleteSearch
+ ]),
+ createInstance: function (outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ registerFactory: function () {
+ let registrar =
+ Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+ registrar.registerFactory(this.classID, "Test Simple Autocomplete",
+ this.contractID, this);
+ },
+ unregisterFactory: function () {
+ let registrar =
+ Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+ registrar.unregisterFactory(this.classID, this);
+ },
+
+ startSearch: function (aString, aParam, aResult, aListener) {
+ let result = new autoCompleteSimpleResult(aString);
+ aListener.onSearchResult(this, result);
+ },
+ stopSearch: function () {}
+};
+
+SimpleTest.waitForExplicitFinish();
+
+// XPFE AutoComplete needs to register early.
+autoCompleteSimple.registerFactory();
+
+let gACTimer;
+let gAutoComplete;
+
+function searchComplete() {
+ is(gAutoComplete.value, "result", "Value should be autocompleted now");
+ ok(Date.now() - gACTimer > 500, "There should be a delay before autocomplete");
+
+ // Unregister the factory so that we don't get in the way of other tests
+ autoCompleteSimple.unregisterFactory();
+ SimpleTest.finish();
+}
+
+function runTest() {
+ gAutoComplete = $("autocomplete");
+
+ const SEARCH_STRING = "res";
+
+ function cbCallback() {
+ gAutoComplete.focus();
+ synthesizeKey("v", { accelKey: true });
+ is(gAutoComplete.value, SEARCH_STRING, "Value should not be autocompleted immediately");
+ }
+
+ SimpleTest.waitForClipboard(SEARCH_STRING, function () {
+ gACTimer = Date.now();
+ Components.classes["@mozilla.org/widget/clipboardhelper;1"]
+ .getService(Components.interfaces.nsIClipboardHelper)
+ .copyStringToClipboard(SEARCH_STRING, Components.interfaces.nsIClipboard.kGlobalClipboard);
+ }, cbCallback, cbCallback);
+}
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete_emphasis.xul b/toolkit/content/tests/chrome/test_autocomplete_emphasis.xul
new file mode 100644
index 000000000..b162742f1
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete_emphasis.xul
@@ -0,0 +1,175 @@
+<?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="Autocomplete emphasis test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<textbox id="richautocomplete" type="autocomplete"
+ autocompletesearch="simple"
+ onsearchcomplete="checkSearchCompleted();"
+ autocompletepopup="richpopup"/>
+<panel id="richpopup" type="autocomplete-richlistbox" noautofocus="true"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+const ACR = Components.interfaces.nsIAutoCompleteResult;
+
+// A global variable to hold the search result for the current search.
+var resultText = "";
+
+// This result can't be constructed in-line, because otherwise we leak memory.
+function nsAutoCompleteSimpleResult(aString)
+{
+ this.searchString = aString;
+ this.searchResult = ACR.RESULT_SUCCESS;
+ this.matchCount = 1;
+}
+
+nsAutoCompleteSimpleResult.prototype = {
+ searchString: null,
+ searchResult: ACR.RESULT_FAILURE,
+ defaultIndex: -1,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function() { return resultText; },
+ getCommentAt: function() { return this.getValueAt(); },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
+ getLabelAt: function() { return this.getValueAt(); },
+ removeValueAt: function() {}
+};
+
+// A basic autocomplete implementation that returns the string contained in 'resultText'.
+var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
+var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
+var autoCompleteSimple = {
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsIFactory) ||
+ iid.equals(Components.interfaces.nsIAutoCompleteSearch))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ },
+
+ createInstance: function(outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ startSearch: function(aString, aParam, aResult, aListener) {
+ var result = new nsAutoCompleteSimpleResult(aString);
+ aListener.onSearchResult(this, result);
+ },
+
+ stopSearch: function() {}
+};
+
+var componentManager = Components.manager
+ .QueryInterface(Components.interfaces.nsIComponentRegistrar);
+componentManager.registerFactory(autoCompleteSimpleID, "Test Simple Autocomplete",
+ autoCompleteSimpleName, autoCompleteSimple);
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(nextTest, 0);
+
+/* Test cases have the following attributes:
+ * - search: A search string, to be emphasized in the result.
+ * - result: A fixed result string, so we can hardcode the expected emphasis.
+ * - emphasis: A list of chunks that should be emphasized or not, in strict alternation.
+ * - emphasizeFirst: Whether the first element of 'emphasis' should be emphasized;
+ * The emphasis of the other elements is defined by the strict alternation rule.
+ */
+let testcases = [
+ { search: "test",
+ result: "A test string",
+ emphasis: ["A ", "test", " string"],
+ emphasizeFirst: false
+ },
+ { search: "tea two",
+ result: "Tea for two, and two for tea...",
+ emphasis: ["Tea", " for ", "two", ", and ", "two", " for ", "tea", "..."],
+ emphasizeFirst: true
+ },
+ { search: "tat",
+ result: "tatatat",
+ emphasis: ["tatatat"],
+ emphasizeFirst: true
+ },
+ { search: "cheval valise",
+ result: "chevalise",
+ emphasis: ["chevalise"],
+ emphasizeFirst: true
+ }
+];
+let test = -1;
+let currentTest = null;
+
+function nextTest() {
+ test++;
+
+ if (test >= testcases.length) {
+ // Unregister the factory so that we don't get in the way of other tests
+ componentManager.unregisterFactory(autoCompleteSimpleID, autoCompleteSimple);
+ SimpleTest.finish();
+ return;
+ }
+
+ // blur the field to ensure that the popup is closed and that the previous
+ // search has stopped, then start a new search.
+ let autocomplete = $("richautocomplete");
+ autocomplete.blur();
+ autocomplete.focus();
+
+ currentTest = testcases[test];
+ resultText = currentTest.result;
+ autocomplete.value = currentTest.search;
+ synthesizeKey("VK_DOWN", {});
+}
+
+function checkSearchCompleted() {
+ let autocomplete = $("richautocomplete");
+ let result = autocomplete.popup.richlistbox.firstChild;
+
+ for (let attribute of [result._titleText, result._urlText]) {
+ is(attribute.childNodes.length, currentTest.emphasis.length,
+ "The element should have the expected number of children.");
+ for (let i = 0; i < currentTest.emphasis.length; i++) {
+ let node = attribute.childNodes[i];
+ // Emphasized parts strictly alternate.
+ if ((i % 2 == 0) == currentTest.emphasizeFirst) {
+ // Check that this part is correctly emphasized.
+ is(node.nodeName, "span", ". That child should be a span node");
+ ok(node.classList.contains("ac-emphasize-text"), ". That child should be emphasized");
+ is(node.textContent, currentTest.emphasis[i], ". That emphasis should be as expected.");
+ } else {
+ // Check that this part is _not_ emphasized.
+ is(node.nodeName, "#text", ". That child should be a text node");
+ is(node.textContent, currentTest.emphasis[i], ". That text should be as expected.");
+ }
+ }
+ }
+
+ setTimeout(nextTest, 0);
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete_mac_caret.xul b/toolkit/content/tests/chrome/test_autocomplete_mac_caret.xul
new file mode 100644
index 000000000..21670215d
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete_mac_caret.xul
@@ -0,0 +1,74 @@
+<?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="Autocomplete Widget Test"
+ onload="setTimeout(keyCaretTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<textbox id="autocomplete" type="autocomplete"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function keyCaretTest()
+{
+ var autocomplete = $("autocomplete");
+
+ autocomplete.focus();
+ checkKeyCaretTest("VK_UP", 0, 0, false, "no value up");
+ checkKeyCaretTest("VK_DOWN", 0, 0, false, "no value down");
+
+ autocomplete.value = "Sample";
+
+ autocomplete.selectionStart = 3;
+ autocomplete.selectionEnd = 3;
+ checkKeyCaretTest("VK_UP", 0, 0, true, "value up with caret in middle");
+ checkKeyCaretTest("VK_UP", 0, 0, false, "value up with caret in middle again");
+
+ autocomplete.selectionStart = 2;
+ autocomplete.selectionEnd = 2;
+ checkKeyCaretTest("VK_DOWN", 6, 6, true, "value down with caret in middle");
+ checkKeyCaretTest("VK_DOWN", 6, 6, false, "value down with caret in middle again");
+
+ autocomplete.selectionStart = 1;
+ autocomplete.selectionEnd = 4;
+ checkKeyCaretTest("VK_UP", 0, 0, true, "value up with selection");
+
+ autocomplete.selectionStart = 1;
+ autocomplete.selectionEnd = 4;
+ checkKeyCaretTest("VK_DOWN", 6, 6, true, "value down with selection");
+
+ SimpleTest.finish();
+}
+
+function checkKeyCaretTest(key, expectedStart, expectedEnd, result, testid)
+{
+ var autocomplete = $("autocomplete");
+
+ var event = result ? "keypress" : "!keypress";
+ synthesizeKeyExpectEvent(key, { }, autocomplete.inputField, event, testid);
+ is(autocomplete.selectionStart, expectedStart, testid + " selectionStart");
+ is(autocomplete.selectionEnd, expectedEnd, testid + " selectionEnd");
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xul b/toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xul
new file mode 100644
index 000000000..01004327d
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xul
@@ -0,0 +1,309 @@
+<?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="Autocomplete Widget Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="runTest();">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+ <script type="application/javascript"
+ src="chrome://global/content/globalOverlay.js"/>
+
+<textbox id="autocomplete"
+ type="autocomplete"
+ completedefaultindex="true"
+ timeout="0"
+ autocompletesearch="simple"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function autoCompleteSimpleResult(aString, searchId) {
+ this.searchString = aString;
+ this.searchResult = Components.interfaces.nsIAutoCompleteResult.RESULT_SUCCESS;
+ this.matchCount = 1;
+ if (aString.startsWith('ret')) {
+ this._param = autoCompleteSimpleResult.retireCompletion;
+ } else {
+ this._param = "Result";
+ }
+ this._searchId = searchId;
+}
+autoCompleteSimpleResult.retireCompletion = "Retire";
+autoCompleteSimpleResult.prototype = {
+ _param: "",
+ searchString: null,
+ searchResult: Components.interfaces.nsIAutoCompleteResult.RESULT_FAILURE,
+ defaultIndex: 0,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function() { return this._param; },
+ getCommentAt: function() { return null; },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getLabelAt: function() { return null; },
+ removeValueAt: function() {}
+};
+
+var searchCounter = 0;
+
+// A basic autocomplete implementation that returns one result.
+let autoCompleteSimple = {
+ classID: Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"),
+ contractID: "@mozilla.org/autocomplete/search;1?name=simple",
+ searchAsync: false,
+ pendingSearch: null,
+
+ QueryInterface: XPCOMUtils.generateQI([
+ Components.interfaces.nsIFactory,
+ Components.interfaces.nsIAutoCompleteSearch
+ ]),
+ createInstance: function (outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ registerFactory: function () {
+ let registrar =
+ Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+ registrar.registerFactory(this.classID, "Test Simple Autocomplete",
+ this.contractID, this);
+ },
+ unregisterFactory: function () {
+ let registrar =
+ Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+ registrar.unregisterFactory(this.classID, this);
+ },
+
+ startSearch: function (aString, aParam, aResult, aListener) {
+ let result = new autoCompleteSimpleResult(aString);
+
+ if (this.searchAsync) {
+ // Simulate an async search by using a timeout before invoking the
+ // |onSearchResult| callback.
+ // Store the searchTimeout such that it can be canceled if stopSearch is called.
+ this.pendingSearch = setTimeout(() => {
+ this.pendingSearch = null;
+
+ aListener.onSearchResult(this, result);
+
+ // Move to the next step in the async test.
+ asyncTest.next();
+ }, 0);
+ } else {
+ aListener.onSearchResult(this, result);
+ }
+ },
+ stopSearch: function () {
+ clearTimeout(this.pendingSearch);
+ }
+};
+
+SimpleTest.waitForExplicitFinish();
+
+// XPFE AutoComplete needs to register early.
+autoCompleteSimple.registerFactory();
+
+let gACTimer;
+let gAutoComplete;
+let asyncTest;
+
+let searchCompleteTimeoutId = null;
+
+function finishTest() {
+ // Unregister the factory so that we don't get in the way of other tests
+ autoCompleteSimple.unregisterFactory();
+ SimpleTest.finish();
+}
+
+function runTest() {
+ gAutoComplete = $("autocomplete");
+ gAutoComplete.focus();
+
+ // Return the search results synchronous, which also makes the completion
+ // happen synchronous.
+ autoCompleteSimple.searchAsync = false;
+
+ synthesizeKey("r", {});
+ is(gAutoComplete.value, "result", "Value should be autocompleted immediately");
+
+ synthesizeKey("e", {});
+ is(gAutoComplete.value, "result", "Value should be autocompleted immediately");
+
+ synthesizeKey("VK_DELETE", {});
+ is(gAutoComplete.value, "re", "Deletion should not complete value");
+
+ synthesizeKey("VK_BACK_SPACE", {});
+ is(gAutoComplete.value, "r", "Backspace should not complete value");
+
+ synthesizeKey("VK_LEFT", {});
+ is(gAutoComplete.value, "r", "Value should stay same when navigating with cursor");
+
+ runAsyncTest();
+}
+
+function* asyncTestGenerator() {
+ synthesizeKey("r", {});
+ synthesizeKey("e", {});
+ is(gAutoComplete.value, "re", "Value should not be autocompleted immediately");
+
+ // Calling |yield undefined| makes this generator function wait until
+ // |asyncTest.next();| is called. This happens from within the
+ // |autoCompleteSimple.startSearch()| function once the simulated async
+ // search has finished.
+ // Therefore, the effect of the |yield undefined;| here (and the ones) below
+ // is to wait until the async search result comes back.
+ yield undefined;
+
+ is(gAutoComplete.value, "result", "Value should be autocompleted");
+
+ // Test if typing the `s` character completes directly based on the last
+ // completion
+ synthesizeKey("s", {});
+ is(gAutoComplete.value, "result", "Value should be completed immediately");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "result", "Value should be autocompleted to same value");
+ synthesizeKey("VK_DELETE", {});
+ is(gAutoComplete.value, "res", "Deletion should not complete value");
+
+ // No |yield undefined| needed here as no completion is triggered by the deletion.
+
+ is(gAutoComplete.value, "res", "Still no complete value after deletion");
+
+ synthesizeKey("VK_BACK_SPACE", {});
+ is(gAutoComplete.value, "re", "Backspace should not complete value");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "re", "Value after search due to backspace should stay the same"); (3)
+
+ // Typing a character that is not like the previous match. In this case, the
+ // completion cannot happen directly and therefore the value will be completed
+ // only after the search has finished.
+ synthesizeKey("t", {});
+ is(gAutoComplete.value, "ret", "Value should not be autocompleted immediately");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "retire", "Value should be autocompleted");
+
+ synthesizeKey("i", {});
+ is(gAutoComplete.value, "retire", "Value should be autocompleted immediately");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "retire", "Value should be autocompleted to the same value");
+
+ // Setup the scene to test how the completion behaves once the placeholder
+ // completion and the result from the search do not agree with each other.
+ gAutoComplete.value = 'r';
+ // Need to type two characters as the input was reset and the autocomplete
+ // controller things, ther user hit the backspace button, in which case
+ // no completion is performed. But as a completion is desired, another
+ // character `t` is typed afterwards.
+ synthesizeKey("e", {});
+ yield undefined;
+ synthesizeKey("t", {});
+ is(gAutoComplete.value, "ret", "Value should not be autocompleted");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "retire", "Value should be autocompleted");
+
+ // The placeholder string is now set to "retire". Changing the completion
+ // string to "retirement" and see what the completion will turn out like.
+ autoCompleteSimpleResult.retireCompletion = "Retirement";
+ synthesizeKey("i", {});
+ is(gAutoComplete.value, "retire", "Value should be autocompleted based on placeholder");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "retirement", "Value should be autocompleted based on search result");
+
+ // Change the search result to `Retire` again and see if the new result is
+ // complited.
+ autoCompleteSimpleResult.retireCompletion = "Retire";
+ synthesizeKey("r", {});
+ is(gAutoComplete.value, "retirement", "Value should be autocompleted based on placeholder");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "retire", "Value should be autocompleted based on search result");
+
+ // Complete the value
+ gAutoComplete.value = 're';
+ synthesizeKey("t", {});
+ yield undefined;
+ synthesizeKey("i", {});
+ is(gAutoComplete.value, "reti", "Value should not be autocompleted");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "retire", "Value should be autocompleted");
+
+ // Remove the selected text "re" (1) and the "et" (2). Afterwards, add it again (3).
+ // This should not cause the completion to kick in.
+ synthesizeKey("VK_DELETE", {}); // (1)
+
+ is(gAutoComplete.value, "reti", "Value should not complete after deletion");
+
+ gAutoComplete.selectionStart = 1;
+ gAutoComplete.selectionEnd = 3;
+ synthesizeKey("VK_DELETE", {}); // (2)
+
+ is(gAutoComplete.value, "ri", "Value should stay unchanged after removing character in the middle");
+
+ yield undefined;
+
+ synthesizeKey("e", {}); // (3.1)
+ is(gAutoComplete.value, "rei", "Inserting a character in the middle should not complete the value");
+
+ yield undefined;
+
+ synthesizeKey("t", {}); // (3.2)
+ is(gAutoComplete.value, "reti", "Inserting a character in the middle should not complete the value");
+
+ yield undefined;
+
+ // Adding a new character at the end should not cause the completion to happen again
+ // as the completion failed before.
+ gAutoComplete.selectionStart = 4;
+ gAutoComplete.selectionEnd = 4;
+ synthesizeKey("r", {});
+ is(gAutoComplete.value, "retir", "Value should not be autocompleted immediately");
+
+ yield undefined;
+
+ is(gAutoComplete.value, "retire", "Value should be autocompleted");
+
+ finishTest();
+ yield undefined;
+}
+
+function runAsyncTest() {
+ gAutoComplete.value = '';
+ autoCompleteSimple.searchAsync = true;
+
+ asyncTest = asyncTestGenerator();
+ asyncTest.next();
+}
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_input.html b/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_input.html
new file mode 100644
index 000000000..3f57a0d6e
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_input.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>autocomplete with composition tests on HTML input element</title>
+ <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="file_autocomplete_with_composition.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+
+<div id="content">
+ <iframe id="formTarget" name="formTarget"></iframe>
+ <form action="data:text/html," target="formTarget">
+ <input name="test" id="input"><input type="submit">
+ </form>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests()
+{
+ var formFillController =
+ SpecialPowers.getFormFillController()
+ .QueryInterface(Components.interfaces.nsIAutoCompleteInput);
+ var originalFormFillTimeout = formFillController.timeout;
+
+ SpecialPowers.attachFormFillControllerTo(window);
+ var target = document.getElementById("input");
+
+ // Register a word to the form history.
+ target.focus();
+ target.value = "Mozilla";
+ synthesizeKey("VK_RETURN", {});
+ target.value = "";
+
+ var test1 = new nsDoTestsForAutoCompleteWithComposition(
+ "Testing on HTML input (asynchronously search)",
+ window, target, formFillController.controller, is,
+ function () { return target.value; },
+ function () {
+ target.setAttribute("timeout", 0);
+ var test2 = new nsDoTestsForAutoCompleteWithComposition(
+ "Testing on HTML input (synchronously search)",
+ window, target, formFillController.controller, is,
+ function () { return target.value; },
+ function () {
+ formFillController.timeout = originalFormFillTimeout;
+ SpecialPowers.detachFormFillControllerFrom(window);
+ SimpleTest.finish();
+ });
+ });
+}
+
+SimpleTest.waitForFocus(runTests);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul b/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul
new file mode 100644
index 000000000..90972b8da
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul
@@ -0,0 +1,124 @@
+<?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 autocomplete with composition"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
+ <script type="text/javascript"
+ src="file_autocomplete_with_composition.js" />
+
+ <textbox id="textbox" type="autocomplete"
+ autocompletesearch="simpleForComposition"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+const nsIAutoCompleteResult = Components.interfaces.nsIAutoCompleteResult;
+
+// This result can't be constructed in-line, because otherwise we leak memory.
+function nsAutoCompleteSimpleResult(aString)
+{
+ this.searchString = aString;
+ if (aString == "" || aString == "Mozilla".substr(0, aString.length)) {
+ this.searchResult = nsIAutoCompleteResult.RESULT_SUCCESS;
+ this.matchCount = 1;
+ this._value = "Mozilla";
+ } else {
+ this.searchResult = nsIAutoCompleteResult.RESULT_NOMATCH;
+ this.matchCount = 0;
+ this._value = "";
+ }
+}
+
+nsAutoCompleteSimpleResult.prototype = {
+ _value: "",
+ searchString: null,
+ searchResult: nsIAutoCompleteResult.RESULT_FAILURE,
+ defaultIndex: 0,
+ errorDescription: null,
+ matchCount: 0,
+ getValueAt: function(aIndex) { return aIndex == 0 ? this._value : null; },
+ getCommentAt: function() { return null; },
+ getStyleAt: function() { return null; },
+ getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function(aIndex) { return this.getValueAt(aIndex); },
+ getLabelAt: function() { return null; },
+ removeValueAt: function() {}
+};
+
+// A basic autocomplete implementation that either returns one result or none
+var autoCompleteSimpleID =
+ Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
+var autoCompleteSimpleName =
+ "@mozilla.org/autocomplete/search;1?name=simpleForComposition"
+var autoCompleteSimple = {
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsIFactory) ||
+ iid.equals(Components.interfaces.nsIAutoCompleteSearch))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ },
+
+ createInstance: function(outer, iid) {
+ return this.QueryInterface(iid);
+ },
+
+ startSearch: function(aString, aParam, aResult, aListener) {
+ var result = new nsAutoCompleteSimpleResult(aString);
+ aListener.onSearchResult(this, result);
+ },
+
+ stopSearch: function() {}
+};
+
+var componentManager =
+ Components.manager
+ .QueryInterface(Components.interfaces.nsIComponentRegistrar);
+componentManager.registerFactory(autoCompleteSimpleID,
+ "Test Simple Autocomplete for composition",
+ autoCompleteSimpleName, autoCompleteSimple);
+
+function runTests()
+{
+ var target = document.getElementById("textbox");
+ target.setAttribute("timeout", 1);
+ var test1 = new nsDoTestsForAutoCompleteWithComposition(
+ "Testing on XUL textbox (asynchronously search)",
+ window, target, target.controller, is,
+ function () { return target.value; },
+ function () {
+ target.setAttribute("timeout", 0);
+ var test2 = new nsDoTestsForAutoCompleteWithComposition(
+ "Testing on XUL textbox (synchronously search)",
+ window, target, target.controller, is,
+ function () { return target.value; },
+ function () {
+ // Unregister the factory so that we don't get in the way of other
+ // tests
+ componentManager.unregisterFactory(autoCompleteSimpleID,
+ autoCompleteSimple);
+ SimpleTest.finish();
+ });
+ });
+}
+
+SimpleTest.waitForFocus(runTests);
+]]>
+</script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_browser_drop.xul b/toolkit/content/tests/chrome/test_browser_drop.xul
new file mode 100644
index 000000000..4ba21c514
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_browser_drop.xul
@@ -0,0 +1,38 @@
+<?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="Browser Drop Test"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"/>
+
+ <script><![CDATA[
+SimpleTest.waitForExplicitFinish();
+function runTest() {
+ add_task(function*() {
+ let win = window.open("window_browser_drop.xul", "_blank", "chrome,width=200,height=200");
+ yield SimpleTest.promiseFocus(win);
+ for (let browserType of ["content", "remote-content"]) {
+ yield win.dropLinksOnBrowser(win.document.getElementById(browserType + "child"), browserType);
+ }
+ yield win.dropLinksOnBrowser(win.document.getElementById("chromechild"), "chrome");
+ });
+}
+//]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug1048178.xul b/toolkit/content/tests/chrome/test_bug1048178.xul
new file mode 100644
index 000000000..79f3acad5
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug1048178.xul
@@ -0,0 +1,86 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1048178
+-->
+<window title="Mozilla Bug 1048178"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml"/>
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1048178"
+ target="_blank">Mozilla Bug 1048178</a>
+
+ <hbox>
+ <scrollbar id="scroller"
+ orient="horizontal"
+ curpos="0"
+ maxpos="500"
+ pageincrement="500"
+ width="500"
+ style="margin:0"/>
+ </hbox>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+/** Test for Bug 1048178 **/
+var scrollbarTester = {
+ scrollbar: null,
+ startTest: function() {
+ this.scrollbar = $("scroller");
+ this.setScrollToClick(false);
+ this.testThumbDragging();
+ SimpleTest.finish();
+ },
+ testThumbDragging: function() {
+ var x = 400; // on the right half of the scroolbar
+ var y = 5;
+
+ this.mousedown(x, y, 0);
+ this.mousedown(x, y, 2);
+ this.mouseup(x, y, 2);
+ this.mouseup(x, y, 0);
+
+ var newPos = this.getPos(); // sould be '500'
+
+ this.mousedown(x, y, 0);
+ this.mousemove(x-1, y, 0);
+ this.mouseup(x-1, y, 0);
+
+ var newPos2 = this.getPos();
+ ok(newPos2 < newPos,
+ "Scrollbar thumb should follow the mouse when dragged.");
+ },
+ setScrollToClick: function(value) {
+ var prefService = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefService);
+ var uiBranch = prefService.getBranch("ui.");
+ uiBranch.setIntPref("scrollToClick", value ? 1 : 0);
+ },
+ getPos: function() {
+ return this.scrollbar.getAttribute("curpos");
+ },
+ mousedown: function(x, y, button) {
+ synthesizeMouse(this.scrollbar, x, y, { type: "mousedown", 'button': button });
+ },
+ mousemove: function(x, y, button) {
+ synthesizeMouse(this.scrollbar, x, y, { type: "mousemove", 'button': button });
+ },
+ mouseup: function(x, y, button) {
+ synthesizeMouse(this.scrollbar, x, y, { type: "mouseup", 'button': button });
+ }
+}
+
+function doTest() {
+ setTimeout(function() { scrollbarTester.startTest(); }, 0);
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug253481.xul b/toolkit/content/tests/chrome/test_bug253481.xul
new file mode 100644
index 000000000..aa5c017c6
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug253481.xul
@@ -0,0 +1,90 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=253481
+-->
+<window title="Mozilla Bug 253481"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=253481">Mozilla Bug 253481</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+</body>
+
+<description>
+ Tests pasting of multi-line content into a single-line xul:textbox.
+</description>
+
+<vbox>
+<textbox id="pasteintact" newlines="pasteintact"/>
+<textbox id="pastetofirst" newlines="pastetofirst"/>
+<textbox id="replacewithspaces" newlines="replacewithspaces"/>
+<textbox id="strip" newlines="strip"/>
+<textbox id="replacewithcommas" newlines="replacewithcommas"/>
+<textbox id="stripsurroundingwhitespace" newlines="stripsurroundingwhitespace"/>
+</vbox>
+<script class="testbody" type="application/javascript;version=1.7">
+<![CDATA[
+/** Test for Bug 253481 **/
+function testPaste(name, element, expected) {
+ element.value = "";
+ element.focus();
+ synthesizeKey("v", { accelKey: true });
+ is(element.value, expected, name);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SimpleTest.waitForFocus(function() {
+setTimeout(function() {
+var testString = "\n hello hello \n world\nworld \n";
+var expectedResults = {
+// even "pasteintact" strips leading/trailing newlines
+"pasteintact": testString.replace(/^\n/, '').replace(/\n$/, ''),
+// "pastetofirst" strips leading newlines
+"pastetofirst": testString.replace(/^\n/, '').split(/\n/)[0],
+// "replacewithspaces" strips trailing newlines first - bug 432415
+"replacewithspaces": testString.replace(/\n$/, '').replace(/\n/g,' '),
+// "strip" is pretty straightforward
+"strip": testString.replace(/\n/g,''),
+// "replacewithcommas" strips leading and trailing newlines first
+"replacewithcommas": testString.replace(/^\n/, '').replace(/\n$/, '').replace(/\n/g,','),
+// "stripsurroundingwhitespace" strips all newlines and whitespace around them
+"stripsurroundingwhitespace": testString.replace(/\s*\n\s*/g,'')
+};
+
+// Put a multi-line string in the clipboard
+SimpleTest.waitForClipboard(testString, function() {
+ var clip = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
+ .getService(Components.interfaces.nsIClipboardHelper);
+ clip.copyString(testString);
+}, function() {
+ for (let [item, expected] of Object.entries(expectedResults)) {
+ testPaste(item, $(item), expected);
+ }
+
+ SimpleTest.finish();
+}, function() {
+ ok(false, "Could not copy the string to clipboard, giving up");
+
+ SimpleTest.finish();
+});
+}, 0);
+});
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug263683.xul b/toolkit/content/tests/chrome/test_bug263683.xul
new file mode 100644
index 000000000..c5755c9f1
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug263683.xul
@@ -0,0 +1,39 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=263683
+-->
+<window title="Mozilla Bug 263683"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=263683">
+ Mozilla Bug 263683
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 263683 **/
+ SimpleTest.waitForExplicitFinish();
+ window.open("bug263683_window.xul", "263683test",
+ "chrome,width=600,height=600");
+
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug304188.xul b/toolkit/content/tests/chrome/test_bug304188.xul
new file mode 100644
index 000000000..f41d24f9b
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug304188.xul
@@ -0,0 +1,37 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=304188
+-->
+<window title="Mozilla Bug 304188"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=304188">Mozilla Bug 304188</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 304188 **/
+SimpleTest.waitForExplicitFinish();
+window.open("bug304188_window.xul", "findbartest",
+ "chrome,width=600,height=600");
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug331215.xul b/toolkit/content/tests/chrome/test_bug331215.xul
new file mode 100644
index 000000000..e0d0d1e0a
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug331215.xul
@@ -0,0 +1,38 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=331215
+-->
+<window title="Mozilla Bug 331215"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=331215">Mozilla Bug 331215</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 331215 **/
+
+SimpleTest.waitForExplicitFinish();
+window.open("bug331215_window.xul", "331215test",
+ "chrome,width=600,height=600");
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug360220.xul b/toolkit/content/tests/chrome/test_bug360220.xul
new file mode 100644
index 000000000..3fcb2bf13
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug360220.xul
@@ -0,0 +1,61 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=360220
+-->
+<window title="Mozilla Bug 360220"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=360220">Mozilla Bug 360220</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<menulist id="menulist">
+ <menupopup>
+ <menuitem id="firstItem" label="foo" selected="true"/>
+ <menuitem id="secondItem" label="bar"/>
+ </menupopup>
+</menulist>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+/** Test for Bug 360220 **/
+
+var menulist = document.getElementById("menulist");
+var secondItem = document.getElementById("secondItem");
+menulist.selectedItem = secondItem;
+
+is(menulist.label, "bar", "second item was not selected");
+
+let mutObserver = new MutationObserver(() => {
+ is(menulist.label, "new label", "menulist label was not updated to the label of its selected item");
+ done();
+});
+mutObserver.observe(menulist, { attributeFilter: ['label'] });
+secondItem.label = "new label";
+
+let failureTimeout = setTimeout(function() {
+ ok(false, "menulist label should have updated");
+ done();
+}, 2000);
+
+function done() {
+ mutObserver.disconnect();
+ clearTimeout(failureTimeout);
+ SimpleTest.finish();
+}
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug360437.xul b/toolkit/content/tests/chrome/test_bug360437.xul
new file mode 100644
index 000000000..eb17adcf5
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug360437.xul
@@ -0,0 +1,40 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=360437
+-->
+<window title="Mozilla Bug 360437"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=360437">Mozilla Bug 360437</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 360437 **/
+SimpleTest.waitForExplicitFinish();
+window.open("bug360437_window.xul", "360437test",
+ "chrome,width=600,height=600");
+
+
+
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug365773.xul b/toolkit/content/tests/chrome/test_bug365773.xul
new file mode 100644
index 000000000..17385365a
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug365773.xul
@@ -0,0 +1,67 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=365773
+-->
+<window title="Mozilla Bug 365773"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=365773">Mozilla Bug 365773</a>
+<p id="display">
+ <radiogroup id="group" collapsed="true" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <radio id="item" label="Item"/>
+ </radiogroup>
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 365773 **/
+
+function selectItem(item, isIndex, testName) {
+ var exception = null;
+ try {
+ if (isIndex)
+ document.getElementById("group").selectedIndex = item;
+ else
+ document.getElementById("group").selectedItem = item;
+ }
+ catch(e) {
+ exception = e;
+ }
+
+ ok(exception == null, testName);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function runTests() {
+ var item = document.getElementById("item");
+
+ selectItem(item, false, "Radio button selected with selectedItem (not focused)");
+ selectItem(null, false, "Radio button deselected with selectedItem (not focused)");
+ selectItem(0, true, "Radio button selected with selectedIndex (not focused)");
+ selectItem(-1, true, "Radio button deselected with selectedIndex (not focused)");
+
+ document.getElementById("group").focus();
+
+ selectItem(item, false, "Radio button selected with selectedItem (focused)");
+ selectItem(null, false, "Radio button deselected with selectedItem (focused)");
+ selectItem(0, true, "Radio button selected with selectedIndex (focused)");
+ selectItem(-1, true, "Radio button deselected with selectedIndex (focused)");
+
+ SimpleTest.finish();
+};
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug366992.xul b/toolkit/content/tests/chrome/test_bug366992.xul
new file mode 100644
index 000000000..2c92defc5
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug366992.xul
@@ -0,0 +1,40 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=366992
+-->
+<window title="Mozilla Bug 366992"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=366992">Mozilla Bug 366992</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 366992 **/
+SimpleTest.waitForExplicitFinish();
+window.open("bug366992_window.xul", "findbartest",
+ "chrome,width=600,height=600");
+
+
+
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug382990.xul b/toolkit/content/tests/chrome/test_bug382990.xul
new file mode 100644
index 000000000..aa3b00431
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug382990.xul
@@ -0,0 +1,44 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=382990
+-->
+<window title="Mozilla Bug 382990"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="startThisTest()">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=382990"
+ target="_blank">Mozilla Bug 382990</a>
+ </body>
+
+ <tree id="testTree" height="200px">
+ <treecols>
+ <treecol flex="1" label="Name" id="name"/>
+ </treecols>
+ <treechildren>
+ <treeitem><treerow><treecell label="a"/></treerow></treeitem>
+ <treeitem><treerow><treecell label="z"/></treerow></treeitem>
+ </treechildren>
+ </tree>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /** Test for Bug 382990 **/
+
+ SimpleTest.waitForExplicitFinish();
+ function startThisTest()
+ {
+ var treeElem = document.getElementById("testTree");
+ treeElem.view.selection.select(0);
+ treeElem.focus();
+ synthesizeKey("z", {ctrlKey: true});
+ ok(!treeElem.view.selection.isSelected(1), "Tree selection should not change for key events with ctrl pressed.");
+ SimpleTest.finish();
+ }
+ ]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug409624.xul b/toolkit/content/tests/chrome/test_bug409624.xul
new file mode 100644
index 000000000..59a862cad
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug409624.xul
@@ -0,0 +1,39 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=409624
+-->
+<window title="Mozilla Bug 409624"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=409624">
+ Mozilla Bug 409624
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 409624 **/
+ SimpleTest.waitForExplicitFinish();
+ window.open("bug409624_window.xul", "409624test",
+ "chrome,width=600,height=600");
+
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug418874.xul b/toolkit/content/tests/chrome/test_bug418874.xul
new file mode 100644
index 000000000..13f0a1453
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug418874.xul
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Textbox with placeholder test" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+ <hbox>
+ <textbox id="t1" placeholder="empty"/>
+ </hbox>
+
+ <hbox>
+ <textbox id="t2" placeholder="empty"/>
+ </hbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;">
+ <p id="display">
+ </p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ function doTest() {
+ var t1 = $("t1");
+ var t2 = $("t2");
+ setTextboxValue(t1, "1");
+ var t1Enabled = {};
+ var t1CanUndo = {};
+ t1.editor.canUndo(t1Enabled, t1CanUndo);
+ is(t1CanUndo.value, true,
+ "undo correctly enabled when placeholder was not changed through property");
+
+ t2.placeholder = "reallyempty";
+ setTextboxValue(t2, "2");
+ var t2Enabled = {};
+ var t2CanUndo = {};
+ t2.editor.canUndo(t2Enabled, t2CanUndo);
+ is(t2CanUndo.value, true,
+ "undo correctly enabled when placeholder explicitly changed through property");
+
+ SimpleTest.finish();
+ }
+
+ function setTextboxValue(textbox, value) {
+ textbox.focus();
+ for (var i = 0; i < value.length; ++i) {
+ synthesizeKey(value.charAt(i), {});
+ }
+ textbox.blur();
+ }
+
+ SimpleTest.waitForFocus(doTest);
+
+ ]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug429723.xul b/toolkit/content/tests/chrome/test_bug429723.xul
new file mode 100644
index 000000000..99ee8acd9
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug429723.xul
@@ -0,0 +1,38 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=429723
+-->
+<window title="Mozilla Bug 429723"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=429723">Mozilla Bug 429723</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 429723 **/
+SimpleTest.waitForExplicitFinish();
+window.open("bug429723_window.xul", "429723test",
+ "chrome,width=600,height=600");
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug437844.xul b/toolkit/content/tests/chrome/test_bug437844.xul
new file mode 100644
index 000000000..b194b3041
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug437844.xul
@@ -0,0 +1,95 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=437844
+https://bugzilla.mozilla.org/show_bug.cgi?id=348233
+-->
+<window title="Mozilla Bug 437844 and Bug 348233"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript"
+ src="RegisterUnregisterChrome.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=437844">
+ Mozilla Bug 437844
+ </a>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=348233">
+ Mozilla Bug 348233
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ SimpleTest.expectAssertions(18, 22);
+
+ /** Test for Bug 437844 and Bug 348233 **/
+ SimpleTest.waitForExplicitFinish();
+
+ let prefs = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+ prefs.setCharPref("intl.uidirection.en-US", "rtl");
+
+ let rootDir = getRootDirectory(window.location.href);
+ let manifest = rootDir + "rtlchrome/rtl.manifest";
+
+ //copy rtlchrome to profile/rtlchrome and generate .manifest
+ let filePath = chromeURIToFile(manifest);
+ let tempProfileDir = copyDirToTempProfile(filePath.path, 'rtlchrome');
+ if (tempProfileDir.path.lastIndexOf('\\') >= 0) {
+ manifest = "content rtlchrome /" + tempProfileDir.path.replace(/\\/g, '/') + "\n";
+ } else {
+ manifest = "content rtlchrome " + tempProfileDir.path + "\n";
+ }
+ manifest += "override chrome://global/locale/intl.css chrome://rtlchrome/content/rtlchrome/rtl.css\n";
+ manifest += "override chrome://global/locale/global.dtd chrome://rtlchrome/content/rtlchrome/rtl.dtd\n";
+
+ let cleanupFunc = createManifestTemporarily(tempProfileDir, manifest);
+
+ // Load about:plugins in an iframe
+ let frame = document.createElement("iframe");
+ frame.setAttribute("src", "about:plugins");
+ frame.addEventListener("load", function () {
+ frame.removeEventListener("load", arguments.callee, false);
+ is(frame.contentDocument.dir, "rtl", "about:plugins should be RTL in RTL locales");
+
+ let gDirSvc = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIDirectoryService).
+ QueryInterface(Components.interfaces.nsIProperties);
+ let tmpd = gDirSvc.get("ProfD", Components.interfaces.nsIFile);
+
+ frame = document.createElement("iframe");
+ frame.setAttribute("src", "file://" + tmpd.path); // a file:// URI, bug 348233
+ frame.addEventListener("load", function () {
+ frame.removeEventListener("load", arguments.callee, false);
+
+ is(frame.contentDocument.body.dir, "rtl", "file:// listings should be RTL in RTL locales");
+
+ cleanupFunc();
+ prefs.clearUserPref("intl.uidirection.en-US");
+ SimpleTest.finish();
+ }, false);
+ document.documentElement.appendChild(frame);
+ }, false);
+ document.documentElement.appendChild(frame);
+
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug451540.xul b/toolkit/content/tests/chrome/test_bug451540.xul
new file mode 100644
index 000000000..64ae43c3c
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug451540.xul
@@ -0,0 +1,39 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=451540
+-->
+<window title="Mozilla Bug 451540"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=451540">
+ Mozilla Bug 451540
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 451540 **/
+ SimpleTest.waitForExplicitFinish();
+ window.open("bug451540_window.xul", "451540test",
+ "chrome,width=600,height=600");
+
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug457632.xul b/toolkit/content/tests/chrome/test_bug457632.xul
new file mode 100644
index 000000000..7bc70f2cc
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug457632.xul
@@ -0,0 +1,178 @@
+<?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"?>
+<!--
+ XUL Widget Test for bug 457632
+ -->
+<window title="Bug 457632" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <notificationbox id="nb"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"
+ onload="test()"/>
+
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+var gNotificationBox;
+
+function completeAnimation(nextTest) {
+ if (!gNotificationBox._animating) {
+ nextTest();
+ return;
+ }
+
+ setTimeout(completeAnimation, 50, nextTest);
+}
+
+function test() {
+ SimpleTest.waitForExplicitFinish();
+ gNotificationBox = document.getElementById("nb");
+
+ is(gNotificationBox.allNotifications.length, 0, "There should be no initial notifications");
+ gNotificationBox.appendNotification("Test notification",
+ "notification1", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ is(gNotificationBox.allNotifications.length, 1, "Notification exists while animating in");
+ let notification = gNotificationBox.getNotificationWithValue("notification1");
+ ok(notification, "Notification should exist while animating in");
+
+ // Wait for the notificaton to finish displaying
+ completeAnimation(test1);
+}
+
+// Tests that a notification that is fully animated in gets removed immediately
+function test1() {
+ let notification = gNotificationBox.getNotificationWithValue("notification1");
+ gNotificationBox.removeNotification(notification);
+ notification = gNotificationBox.getNotificationWithValue("notification1");
+ ok(!notification, "Test 1 showed notification was still present");
+ ok(!gNotificationBox.currentNotification, "Test 1 said there was still a current notification");
+ is(gNotificationBox.allNotifications.length, 0, "Test 1 should show no notifications present");
+
+ // Wait for the notificaton to finish hiding
+ completeAnimation(test2);
+}
+
+// Tests that a notification that is animating in gets removed immediately
+function test2() {
+ let notification = gNotificationBox.appendNotification("Test notification",
+ "notification2", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ gNotificationBox.removeNotification(notification);
+ notification = gNotificationBox.getNotificationWithValue("notification2");
+ ok(!notification, "Test 2 showed notification was still present");
+ ok(!gNotificationBox.currentNotification, "Test 2 said there was still a current notification");
+ is(gNotificationBox.allNotifications.length, 0, "Test 2 should show no notifications present");
+
+ // Get rid of the hiding notifications
+ gNotificationBox.removeAllNotifications(true);
+ test3();
+}
+
+// Tests that a background notification goes away immediately
+function test3() {
+ let notification = gNotificationBox.appendNotification("Test notification",
+ "notification3", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ let notification2 = gNotificationBox.appendNotification("Test notification",
+ "notification4", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ is(gNotificationBox.allNotifications.length, 2, "Test 3 should show 2 notifications present");
+ gNotificationBox.removeNotification(notification);
+ is(gNotificationBox.allNotifications.length, 1, "Test 3 should show 1 notifications present");
+ notification = gNotificationBox.getNotificationWithValue("notification3");
+ ok(!notification, "Test 3 showed notification was still present");
+ gNotificationBox.removeNotification(notification2);
+ is(gNotificationBox.allNotifications.length, 0, "Test 3 should show 0 notifications present");
+ notification2 = gNotificationBox.getNotificationWithValue("notification4");
+ ok(!notification2, "Test 3 showed notification2 was still present");
+ ok(!gNotificationBox.currentNotification, "Test 3 said there was still a current notification");
+
+ // Get rid of the hiding notifications
+ gNotificationBox.removeAllNotifications(true);
+ test4();
+}
+
+// Tests that a foreground notification hiding a background one goes away
+function test4() {
+ let notification = gNotificationBox.appendNotification("Test notification",
+ "notification5", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ let notification2 = gNotificationBox.appendNotification("Test notification",
+ "notification6", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ gNotificationBox.removeNotification(notification2);
+ notification2 = gNotificationBox.getNotificationWithValue("notification6");
+ ok(!notification2, "Test 4 showed notification2 was still present");
+ is(gNotificationBox.currentNotification, notification, "Test 4 said the current notification was wrong");
+ is(gNotificationBox.allNotifications.length, 1, "Test 4 should show 1 notifications present");
+ gNotificationBox.removeNotification(notification);
+ notification = gNotificationBox.getNotificationWithValue("notification5");
+ ok(!notification, "Test 4 showed notification was still present");
+ ok(!gNotificationBox.currentNotification, "Test 4 said there was still a current notification");
+ is(gNotificationBox.allNotifications.length, 0, "Test 4 should show 0 notifications present");
+
+ // Get rid of the hiding notifications
+ gNotificationBox.removeAllNotifications(true);
+ test5();
+}
+
+// Tests that removeAllNotifications gets rid of everything
+function test5() {
+ let notification = gNotificationBox.appendNotification("Test notification",
+ "notification7", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ let notification2 = gNotificationBox.appendNotification("Test notification",
+ "notification8", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ gNotificationBox.removeAllNotifications();
+ notification = gNotificationBox.getNotificationWithValue("notification7");
+ notification2 = gNotificationBox.getNotificationWithValue("notification8");
+ ok(!notification, "Test 5 showed notification was still present");
+ ok(!notification2, "Test 5 showed notification2 was still present");
+ ok(!gNotificationBox.currentNotification, "Test 5 said there was still a current notification");
+ is(gNotificationBox.allNotifications.length, 0, "Test 5 should show 0 notifications present");
+
+ gNotificationBox.appendNotification("Test notification",
+ "notification9", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+
+ // Wait for the notificaton to finish displaying
+ completeAnimation(test6);
+}
+
+// Tests whether removing an already removed notification doesn't break things
+function test6() {
+ let notification = gNotificationBox.getNotificationWithValue("notification9");
+ ok(notification, "Test 6 should have an initial notification");
+ gNotificationBox.removeNotification(notification);
+ gNotificationBox.removeNotification(notification);
+
+ ok(!gNotificationBox.currentNotification, "Test 6 shouldn't be any current notification");
+ is(gNotificationBox.allNotifications.length, 0, "Test 6 allNotifications.length should be 0");
+ notification = gNotificationBox.appendNotification("Test notification",
+ "notification10", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+ is(notification, gNotificationBox.currentNotification, "Test 6 should have made the current notification");
+ gNotificationBox.removeNotification(notification);
+
+ SimpleTest.finish();
+}
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug460942.xul b/toolkit/content/tests/chrome/test_bug460942.xul
new file mode 100644
index 000000000..dae10da57
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug460942.xul
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=460942
+-->
+<window title="Mozilla Bug 460942"
+ onload="runTests()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=460942"
+ target="_blank">Mozilla Bug 460942</a>
+ </body>
+
+ <!-- test code goes here -->
+
+ <richlistbox>
+ <richlistitem id="item1">
+ <label value="one"/>
+ <box>
+ <label value="two"/>
+ </box>
+ </richlistitem>
+ <richlistitem id="item2"><description>one</description><description>two</description></richlistitem>
+ </richlistbox>
+
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 460942 **/
+ function runTests() {
+ is ($("item1").label, "one two");
+ is ($("item2").label, "");
+ SimpleTest.finish();
+ }
+ SimpleTest.waitForExplicitFinish();
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug471776.xul b/toolkit/content/tests/chrome/test_bug471776.xul
new file mode 100644
index 000000000..6002c691a
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug471776.xul
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Textbox with placeholder undo test" width="500" height="600"
+ onload="doTest();"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+ <hbox>
+ <textbox id="t1" placeholder="empty"/>
+ </hbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;">
+ <p id="display">
+ </p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ function doTest() {
+ var t1 = $("t1");
+ t1.focus();
+ var t1Enabled = {};
+ var t1CanUndo = {};
+ t1.editor.canUndo(t1Enabled, t1CanUndo);
+ ok(!t1CanUndo.value, "undo correctly disabled when no user edits");
+ SimpleTest.finish();
+ }
+
+ ]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug509732.xul b/toolkit/content/tests/chrome/test_bug509732.xul
new file mode 100644
index 000000000..cc7ce6807
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug509732.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"?>
+<!--
+ XUL Widget Test for bug 509732
+ -->
+<window title="Bug 509732" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <notificationbox id="nb" hidden="true"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"
+ onload="test()"/>
+
+ <!-- test code goes here -->
+<script type="application/javascript">
+<![CDATA[
+var gNotificationBox;
+
+// Tests that a notification that is added in an hidden box didn't throw the animation
+function test() {
+ SimpleTest.waitForExplicitFinish();
+ gNotificationBox = document.getElementById("nb");
+
+ is(gNotificationBox.allNotifications.length, 0, "There should be no initial notifications");
+
+ gNotificationBox.appendNotification("Test notification",
+ "notification1", null,
+ gNotificationBox.PRIORITY_INFO_LOW,
+ null);
+
+ is(gNotificationBox.allNotifications.length, 1, "Notification exists");
+ is(gNotificationBox._animating, false, "Notification shouldn't be animating");
+
+ test1();
+}
+
+// Tests that a notification that is removed from an hidden box didn't throw the animation
+function test1() {
+ let notification = gNotificationBox.getNotificationWithValue("notification1");
+ gNotificationBox.removeNotification(notification);
+ ok(!gNotificationBox.currentNotification, "Test 1 should show no current animation");
+ is(gNotificationBox._animating, false, "Notification shouldn't be animating");
+ is(gNotificationBox.allNotifications.length, 0, "Test 1 should show no notifications present");
+
+ SimpleTest.finish();
+}
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug554279.xul b/toolkit/content/tests/chrome/test_bug554279.xul
new file mode 100644
index 000000000..d4057b890
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug554279.xul
@@ -0,0 +1,39 @@
+<?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="Toolbar" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="startTest();">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <toolbox>
+ <toolbarpalette id="palette"/>
+
+ <toolbar id="tb1" currentset="p1"/>
+ </toolbox>
+
+ <!-- test resuls are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml"
+ style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="text/javascript"><![CDATA[
+ var toolbar = $("tb1");
+
+ ok(toolbar, "got the toolbar, triggering the xbl constructor");
+
+ var palette = $("palette");
+ ok(palette, "palette is still in the document");
+
+ var button = document.createElement("p1");
+ button.id = button.label = "p1";
+ palette.appendChild(button);
+
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ is(button.parentNode, toolbar, "button has been added to the toolbar");
+ SimpleTest.finish();
+ }
+ ]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug557987.xul b/toolkit/content/tests/chrome/test_bug557987.xul
new file mode 100644
index 000000000..ba680568f
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug557987.xul
@@ -0,0 +1,76 @@
+<?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"?>
+<!--
+ XUL Widget Test for bug 557987
+ -->
+<window title="Bug 557987" width="400" height="400"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+ <toolbarbutton id="button" type="menu-button" label="Test bug 557987"
+ onclick="eventReceived('click');"
+ oncommand="eventReceived('command');">
+ <menupopup onpopupshowing="eventReceived('popupshowing'); return false;" />
+ </toolbarbutton>
+ <menulist id="menulist" editable="true" value="Test bug 557987"
+ onfocus="eventReceived('focus')" />
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+<script type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+SimpleTest.waitForFocus(test);
+
+// Tests that mouse events are correctly dispatched to <toolbarbutton type="menu-button"/>
+function test() {
+
+ disableNonTestMouseEvents(true);
+
+ let button = $("button");
+ let rightEdge = button.getBoundingClientRect().width - 2;
+ let centerX = button.getBoundingClientRect().width / 2;
+ let centerY = button.getBoundingClientRect().height / 2;
+
+ synthesizeMouse(button, rightEdge, centerY, {}, window);
+ synthesizeMouse(button, centerX, centerY, {}, window);
+
+ let menulist = $("menulist");
+ centerX = menulist.getBoundingClientRect().width / 2;
+ centerY = menulist.getBoundingClientRect().height / 2;
+ synthesizeMouse(menulist, centerX, centerY, {}, window);
+
+ synthesizeMouse(document.getElementsByTagName("body")[0], 0, 0, {}, window);
+
+ disableNonTestMouseEvents(false);
+ SimpleTest.executeSoon(finishTest);
+
+}
+
+function finishTest() {
+ is(eventCount.command, 1, "Correct number of command events received");
+ is(eventCount.popupshowing, 1, "Correct number of popupshowing events received");
+ is(eventCount.click, 2, "Correct number of click events received");
+ is(eventCount.focus, 1, "Correct number of focus events received");
+
+ SimpleTest.finish();
+}
+
+let eventCount = {
+ command: 0,
+ popupshowing: 0,
+ click: 0,
+ focus: 0
+};
+
+function eventReceived(eventName) {
+ eventCount[eventName]++;
+}
+
+]]>
+</script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug562554.xul b/toolkit/content/tests/chrome/test_bug562554.xul
new file mode 100644
index 000000000..7ee9ef03d
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug562554.xul
@@ -0,0 +1,92 @@
+<?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"?>
+<!--
+ XUL Widget Test for bug 562554
+ -->
+<window title="Bug 562554" width="400" height="400"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<xbl:bindings xmlns:xbl="http://www.mozilla.org/xbl">
+ <xbl:binding id="menu" display="xul:menu"
+ extends="chrome://global/content/bindings/button.xml#button-base">
+ <xbl:content>
+ <xbl:children includes="menupopup"/>
+ <xul:stack>
+ <xul:button width="100" left="0" top="0" height="30" allowevents="true"
+ onclick="eventReceived('clickbutton1'); return false;"/>
+ <xul:button width="100" left="70" top="0" height="30"
+ onclick="eventReceived('clickbutton2'); return false;"/>
+ </xul:stack>
+ </xbl:content>
+ </xbl:binding>
+</xbl:bindings>
+
+ <toolbarbutton type="menu" id="toolbarmenu" height="200" style="-moz-binding: url(#menu);">
+ <menupopup id="menupopup" onpopupshowing="eventReceived('popupshowing'); return false;"/>
+ </toolbarbutton>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+<script type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(test);
+
+// Tests that mouse events are correctly dispatched to <toolbarbutton type="menu"/>
+function test() {
+ disableNonTestMouseEvents(true);
+ nextTest();
+}
+
+let tests = [
+ // Click on the toolbarbutton itself - should call popupshowing
+ () => synthesizeMouse($("toolbarmenu"), 10, 50, {}, window),
+
+ // Click on button1 which has allowevents="true" - should call clickbutton1
+ () => synthesizeMouse($("toolbarmenu"), 10, 15, {}, window),
+
+ // Click on button2 where it intersects with button1 - should call popupshowing
+ () => synthesizeMouse($("toolbarmenu"), 85, 15, {}, window),
+
+ // Click on button2 outside of intersection - should call popupshowing
+ () => synthesizeMouse($("toolbarmenu"), 150, 15, {}, window)
+];
+
+function nextTest() {
+ if (tests.length) {
+ let func = tests.shift();
+ func();
+ SimpleTest.executeSoon(nextTest);
+ } else {
+ disableNonTestMouseEvents(false);
+ SimpleTest.executeSoon(finishTest);
+ }
+}
+
+function finishTest() {
+ is(eventCount.clickbutton1, 1, "Correct number of clicks on button 1");
+ is(eventCount.clickbutton2, 0, "Correct number of clicks on button 2");
+ is(eventCount.popupshowing, 3, "Correct number of popupshowing events received");
+
+ SimpleTest.finish();
+}
+
+let eventCount = {
+ popupshowing: 0,
+ clickbutton1: 0,
+ clickbutton2: 0
+};
+
+function eventReceived(eventName) {
+ eventCount[eventName]++;
+}
+
+]]>
+</script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug570192.xul b/toolkit/content/tests/chrome/test_bug570192.xul
new file mode 100644
index 000000000..09f73e932
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug570192.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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=570192
+-->
+<window title="Mozilla Bug 558406"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script type="application/javascript"
+ src="RegisterUnregisterChrome.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=570192">
+ Mozilla Bug 570192
+ </a>
+
+ <p id="display">
+ </p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <script type="application/javascript">
+ <![CDATA[
+
+ addLoadEvent(function() {
+ try {
+ var content = document.getElementById("content");
+ content.innerHTML = '<textbox newlines="pasteintact" ' +
+ 'xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>';
+ var textbox = content.firstChild;
+ ok(textbox, "created the textbox");
+ ok(!textbox.editor, "do we have an editor?");
+ } catch (e) {
+ ok(false, "Got an exception: " + e);
+ }
+ SimpleTest.finish();
+ });
+ SimpleTest.waitForExplicitFinish();
+
+ ]]>
+ </script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug585946.xul b/toolkit/content/tests/chrome/test_bug585946.xul
new file mode 100644
index 000000000..738e46b1b
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug585946.xul
@@ -0,0 +1,51 @@
+<?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="Toolbar" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="startTest();">
+
+ <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>
+
+ <toolbox>
+ <toolbarpalette/>
+ <toolbar id="toolbar" defaultset="node1,node2">
+ <toolbarbutton id="node1" label="node1" removable="true"/>
+ <toolbarbutton id="node2" label="node2" removable="true"/>
+ </toolbar>
+ </toolbox>
+
+ <!-- test resuls are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml"
+ style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ var toolbar = $("toolbar");
+
+ var splitter = document.createElement("splitter");
+ splitter.setAttribute("id", "dynsplitter");
+ splitter.setAttribute("skipintoolbarset", "true");
+
+ toolbar.insertBefore(splitter, $("node2"));
+
+ function checkPos() {
+ is($("dynsplitter").previousSibling, $("node1"));
+ is($("dynsplitter").nextSibling, $("node2"));
+ }
+
+ checkPos();
+ toolbar.style.MozBinding = "url(chrome://global/content/bindings/toolbar.xml#toolbar-drag)";
+ toolbar.clientTop; // style flush
+ checkPos();
+
+ SimpleTest.finish();
+}
+
+ ]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug624329.xul b/toolkit/content/tests/chrome/test_bug624329.xul
new file mode 100644
index 000000000..893b38687
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug624329.xul
@@ -0,0 +1,160 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=624329
+-->
+<window title="Mozilla Bug 624329 context menu position"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml"
+ onload="openTestWindow()">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=624329"
+ target="_blank">Mozilla Bug 624329</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 624329 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var win;
+var timeoutID;
+var menu;
+
+function openTestWindow() {
+ win = open("bug624329_window.xul", "_blank", "width=300,resizable=yes,chrome");
+ // Close our window if the test times out so that it doesn't interfere
+ // with later tests.
+ timeoutID = setTimeout(function () {
+ ok(false, "Test timed out.");
+ // Provide some time for a screenshot
+ setTimeout(finish, 1000);
+ }, 20000);
+}
+
+function listenOnce(event, callback) {
+ win.addEventListener(event, function listener() {
+ win.removeEventListener(event, listener, false);
+ callback();
+ }, false);
+}
+
+function childFocused() {
+ // maximizing the window is a simple way to ensure that the menu is near
+ // the right edge of the screen.
+
+ listenOnce("resize", childResized);
+ win.maximize();
+}
+
+function childResized() {
+ const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
+ const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
+ const isOSXMavericks = navigator.userAgent.indexOf("Mac OS X 10.9") != -1;
+ const isOSXYosemite = navigator.userAgent.indexOf("Mac OS X 10.10") != -1;
+ if (isOSXLion || isOSXMtnLion || isOSXMavericks || isOSXYosemite) {
+ todo_is(win.windowState, win.STATE_MAXIMIZED,
+ "A resize before being maximized breaks this test on 10.7 and 10.8 and 10.9 and 10.10");
+ finish();
+ return;
+ }
+
+ is(win.windowState, win.STATE_MAXIMIZED,
+ "window should be maximized");
+
+ isnot(win.innerWidth, 300,
+ "window inner width should have changed");
+
+ openContextMenu();
+}
+
+function openContextMenu() {
+ var mouseX = win.innerWidth - 10;
+ var mouseY = 10;
+
+ menu = win.document.getElementById("menu");
+ var screenX = menu.boxObject.screenX;
+ var screenY = menu.boxObject.screenY;
+ var utils =
+ win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
+ getInterface(Components.interfaces.nsIDOMWindowUtils);
+
+ utils.sendMouseEvent("contextmenu", mouseX, mouseY, 2, 0, 0);
+
+ var interval = setInterval(checkMoved, 200);
+ function checkMoved() {
+ if (menu.boxObject.screenX != screenX ||
+ menu.boxObject.screenY != screenY) {
+ clearInterval(interval);
+ // Wait further to check that the window does not move again.
+ setTimeout(checkPosition, 1000);
+ }
+ }
+
+ function checkPosition() {
+ var menubox = menu.boxObject;
+ var winbox = win.document.documentElement.boxObject;
+ var platformIsMac = navigator.userAgent.indexOf("Mac") > -1;
+
+ var x = menubox.screenX - winbox.screenX;
+ var y = menubox.screenY - winbox.screenY;
+
+ if (platformIsMac)
+ {
+ // This check is alterered slightly for OSX which adds padding to the top
+ // and bottom of its context menus. The menu position calculation must
+ // be changed to allow for the pointer to be outside this padding
+ // when the menu opens.
+ // (Bug 1075089)
+ ok(y + 6 >= mouseY,
+ "menu top " + (y + 6) + " should be below click point " + mouseY);
+ }
+ else
+ {
+ ok(y >= mouseY,
+ "menu top " + y + " should be below click point " + mouseY);
+ }
+
+ ok(y <= mouseY + 20,
+ "menu top " + y + " should not be too far below click point " + mouseY);
+
+ ok(x < mouseX,
+ "menu left " + x + " should be left of click point " + mouseX);
+ var right = x + menubox.width;
+
+ if (platformIsMac) {
+ // Rather than be constrained by the right hand screen edge, OSX menus flip
+ // horizontally and appear to the left of the mouse pointer
+ ok(right < mouseX,
+ "menu right " + right + " should be left of click point " + mouseX);
+ }
+ else {
+ ok(right > mouseX,
+ "menu right " + right + " should be right of click point " + mouseX);
+ }
+
+ clearTimeout(timeoutID);
+ finish();
+ }
+
+}
+
+function finish() {
+ if (menu && navigator.platform.indexOf("Win") >= 0) {
+ todo(false, "Should not have to hide popup before closing its window");
+ // This avoids mochitest "Unable to restore focus" errors (bug 670053).
+ menu.hidePopup();
+ }
+ win.close();
+ SimpleTest.finish();
+}
+
+ ]]>
+ </script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_bug792324.xul b/toolkit/content/tests/chrome/test_bug792324.xul
new file mode 100644
index 000000000..a6fa42505
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug792324.xul
@@ -0,0 +1,75 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=792324
+-->
+<window title="Mozilla Bug 792324"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+<body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=792324">Mozilla Bug 792324</a>
+
+ <p id="display"></p>
+<div id="content" style="display: none">
+</div>
+</body>
+
+<panel id="panel-1">
+ <button label="just a normal button"/>
+ <button id="button-1"
+ accesskey="X"
+ oncommand="clicked(event)"
+ label="Button in panel 1"
+ />
+</panel>
+
+<panel id="panel-2">
+ <button label="just a normal button"/>
+ <button id="button-2"
+ accesskey="X"
+ oncommand="clicked(event)"
+ label="Button in panel 2"
+ />
+</panel>
+
+<script class="testbody" type="application/javascript;version=1.7"><![CDATA[
+
+/** Test for Bug 792324 **/
+let after_click;
+
+function clicked(event) {
+ after_click(event);
+}
+
+function checkAccessKeyOnPanel(panelid, buttonid, cb) {
+ let panel = document.getElementById(panelid);
+ panel.addEventListener("popupshown", function onpopupshown() {
+ panel.removeEventListener("popupshown", onpopupshown);
+ panel.firstChild.focus();
+ after_click = function(event) {
+ is(event.target.id, buttonid, "Accesskey was directed to the button '" + buttonid + "'");
+ panel.hidePopup();
+ cb();
+ }
+ synthesizeKey("X", {});
+ });
+ panel.openPopup(null, "", 100, 100, false, false);
+}
+
+function test() {
+ checkAccessKeyOnPanel("panel-1", "button-1", function() {
+ checkAccessKeyOnPanel("panel-2", "button-2", function() {
+ SimpleTest.finish();
+ });
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(test, window);
+
+]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_button.xul b/toolkit/content/tests/chrome/test_button.xul
new file mode 100644
index 000000000..fa4e7b003
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_button.xul
@@ -0,0 +1,71 @@
+<?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"?>
+<!--
+ XUL Widget Test for button
+ -->
+<window title="Button Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<button id="one" label="One" />
+<button id="two" label="Two"/>
+<hbox>
+ <button id="three" label="Three" open="true"/>
+</hbox>
+<hbox>
+ <button id="four" type="menu" label="Four"/>
+ <button id="five" type="panel" label="Five"/>
+ <button id="six" label="Six"/>
+</hbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+<script type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function test_button()
+{
+ synthesizeMouseExpectEvent($("one"), 2, 2, {}, $("one"), "command", "button press");
+ $("one").focus();
+ synthesizeKeyExpectEvent("VK_SPACE", { }, $("one"), "command", "key press");
+ $("two").disabled = true;
+ synthesizeMouseExpectEvent($("two"), 2, 2, {}, $("two"), "!command", "button press command when disabled");
+ synthesizeMouseExpectEvent($("two"), 2, 2, {}, $("two"), "click", "button press click when disabled");
+
+ if (navigator.platform.indexOf("Mac") == -1) {
+ $("one").focus();
+ synthesizeKey("VK_DOWN", { });
+ is(document.activeElement, $("three"), "key cursor down on button");
+
+ synthesizeKey("VK_RIGHT", { });
+ is(document.activeElement, $("four"), "key cursor right on button");
+ synthesizeKey("VK_DOWN", { });
+ is(document.activeElement, $("four"), "key cursor down on menu button");
+ $("five").focus();
+ synthesizeKey("VK_DOWN", { });
+ is(document.activeElement, $("five"), "key cursor down on panel button");
+
+ $("three").focus();
+ synthesizeKey("VK_UP", { });
+ is(document.activeElement, $("one"), "key cursor up on button");
+ }
+
+ $("two").focus();
+ ok(document.activeElement != $("two"), "focus disabled button");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(test_button);
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_chromemargin.xul b/toolkit/content/tests/chrome/test_chromemargin.xul
new file mode 100644
index 000000000..79c4f7525
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_chromemargin.xul
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Custom chrome margin tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+
+// Tests parsing of the chrome margin attrib on a window.
+
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_chromemargin.xul", "_blank", "chrome,width=600,height=600");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_closemenu_attribute.xul b/toolkit/content/tests/chrome/test_closemenu_attribute.xul
new file mode 100644
index 000000000..c1e93734f
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_closemenu_attribute.xul
@@ -0,0 +1,96 @@
+<?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="Menu closemenu Attribute Tests"
+ onload="setTimeout(nextTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<button id="menu" type="menu" label="Menu" onpopuphidden="popupHidden(event)">
+ <menupopup id="p1" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="l1" label="One">
+ <menupopup id="p2" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="l2" label="Two">
+ <menupopup id="p3" onpopupshown="executeMenuItem()">
+ <menuitem id="l3" label="Three"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menupopup>
+</button>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gExpectedId = "p3";
+var gMode = -1;
+var gModes = ["", "auto", "single", "none"];
+
+function nextTest()
+{
+ gMode++;
+ if (gModes[gMode] != "none")
+ gExpectedId = "p3";
+
+ if (gMode != 0)
+ $("l3").setAttribute("closemenu", gModes[gMode]);
+ if (gModes[gMode] == "none")
+ $("l2").open = true;
+ else
+ $("menu").open = true;
+}
+
+function executeMenuItem()
+{
+ synthesizeKey("VK_DOWN", { });
+ synthesizeKey("VK_RETURN", { });
+ // after a couple of seconds, end the test, as the 'none' closemenu value
+ // should not hide any popups
+ if (gModes[gMode] == "none")
+ setTimeout(function() { $("menu").open = false; }, 2000);
+}
+
+function popupHidden(event)
+{
+ if (gModes[gMode] == "none") {
+ if (event.target.id == "p1")
+ SimpleTest.finish()
+ return;
+ }
+
+ is(event.target.id, gExpectedId,
+ "Expected event " + gModes[gMode] + " " + gExpectedId);
+
+ gExpectedId = "";
+ if (event.target.id == "p3") {
+ if (gModes[gMode] == "" || gModes[gMode] == "auto")
+ gExpectedId = "p2";
+ }
+ else if (event.target.id == "p2") {
+ if (gModes[gMode] == "" || gModes[gMode] == "auto")
+ gExpectedId = "p1";
+ }
+
+ if (!gExpectedId)
+ nextTest();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_colorpicker_popup.xul b/toolkit/content/tests/chrome/test_colorpicker_popup.xul
new file mode 100644
index 000000000..3ac84260b
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_colorpicker_popup.xul
@@ -0,0 +1,148 @@
+<?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="Colorpicker Tests"
+ onload="setTimeout(runTests, 0);"
+ onpopupshown="popupShown();"
+ onpopuphidden="popupHiding();"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<colorpicker id="colorpicker-popup" type="button" color="#FF0000" tabindex="1"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+var gTestPhase = -1;
+var gCp = null;
+
+SimpleTest.waitForExplicitFinish();
+
+function preventDefault(event) {
+ event.preventDefault();
+}
+
+function runTests()
+{
+ gCp = document.getElementById("colorpicker-popup");
+ is(gCp.color, "#FF0000", "popup color is initialized");
+ is(gCp.tabIndex, 1, "button tabindex is initialized");
+ is(gCp.disabled, false, "button is not disabled");
+
+ document.addEventListener("keypress", preventDefault, false);
+
+ goNext();
+}
+
+var phases = [ "mouse click", "showPopup",
+ "key left", "key right", "key up", "key down", "key space" ];
+
+function popupShown()
+{
+ if (gTestPhase >= phases.length)
+ return;
+
+ var phase = phases[gTestPhase];
+
+ is(gCp.open, true, phase + " popup shown, open property is true");
+
+ switch (phase) {
+ case "mouse click":
+ synthesizeMouse(gCp, 2, 2, { });
+ break;
+ case "showPopup":
+ gCp.hidePopup();
+ break;
+ case "key left":
+ synthesizeKey("VK_LEFT", { });
+ synthesizeKeyExpectEvent("VK_RETURN", { });
+ is(gCp.color, "#C0C0C0", "key left while open");
+ break;
+ case "key right":
+ synthesizeKey("VK_RIGHT", { });
+ synthesizeKeyExpectEvent("VK_SPACE", { });
+ is(gCp.color, "#FF0000", "key right while open");
+ break;
+ case "key up":
+ synthesizeKey("VK_UP", { });
+ synthesizeKeyExpectEvent("VK_RETURN", { });
+ is(gCp.color, "#FF6666", "key up while open");
+ break;
+ case "key down":
+ synthesizeKey("VK_DOWN", { });
+ synthesizeKeyExpectEvent("VK_SPACE", { });
+ is(gCp.color, "#FF0000", "key down while open");
+ break;
+ default:
+ synthesizeMouse(gCp, 2, 2, { });
+// this breaks on the Mac, so disable for now
+// synthesizeKey("VK_ESCAPE", { });
+ break;
+ }
+}
+
+function popupHiding()
+{
+ var phase = phases[gTestPhase];
+ if (phase == "showPopup")
+ phase = "hidePopup";
+ if (phase == "key left")
+ phase = "escape";
+ is(gCp.open, false, phase + " popup hidden, open property is false");
+
+ goNext();
+}
+
+function goNext()
+{
+ gTestPhase++;
+ if (gTestPhase >= phases.length) {
+ document.removeEventListener("keypress", preventDefault, false);
+ SimpleTest.finish();
+ return;
+ }
+
+ gCp.focus();
+
+ var phase = phases[gTestPhase];
+ switch (phase) {
+ case "mouse click":
+ synthesizeMouse(gCp, 2, 2, { });
+ break;
+ case "showPopup":
+ gCp.showPopup();
+ break;
+ case "key left":
+ synthesizeKey("VK_LEFT", { });
+ break;
+ case "key right":
+ synthesizeKey("VK_RIGHT", { });
+ break;
+ case "key down":
+ synthesizeKey("VK_UP", { });
+ break;
+ case "key up":
+ synthesizeKey("VK_DOWN", { });
+ break;
+ case "key space":
+ synthesizeKey("VK_SPACE", { });
+ break;
+ }
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_contextmenu_list.xul b/toolkit/content/tests/chrome/test_contextmenu_list.xul
new file mode 100644
index 000000000..157831a58
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_contextmenu_list.xul
@@ -0,0 +1,288 @@
+<?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="Context Menu on List Tests"
+ onload="setTimeout(startTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<spacer height="5"/>
+
+<hbox style="padding-left: 10px;">
+ <spacer width="5"/>
+ <richlistbox id="list" context="themenu" style="padding: 0;" oncontextmenu="checkContextMenu(event)">
+ <richlistitem id="item1" style="padding-top: 3px; margin: 0;"><button label="One"/></richlistitem>
+ <richlistitem id="item2" height="22"><checkbox label="Checkbox"/></richlistitem>
+ <richlistitem id="item3"><button label="Three"/></richlistitem>
+ <richlistitem id="item4"><checkbox label="Four"/></richlistitem>
+ </richlistbox>
+
+ <tree id="tree" rows="5" flex="1" context="themenu" style="-moz-appearance: none; border: 0">
+ <treecols>
+ <treecol label="Name" flex="1"/>
+ <splitter class="tree-splitter"/>
+ <treecol label="Moons"/>
+ </treecols>
+ <treechildren id="treechildren">
+ <treeitem>
+ <treerow>
+ <treecell label="Mercury"/>
+ <treecell label="0"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Venus"/>
+ <treecell label="0"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Earth"/>
+ <treecell label="1"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Mars"/>
+ <treecell label="2"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </tree>
+
+ <menu id="menu" label="Menu">
+ <menupopup id="menupopup" onpopupshown="menuTests()" onpopuphidden="nextTest()"
+ oncontextmenu="checkContextMenuForMenu(event)">
+ <menuitem id="menu1" label="Menu 1"/>
+ <menuitem id="menu2" label="Menu 2"/>
+ <menuitem id="menu3" label="Menu 3"/>
+ </menupopup>
+ </menu>
+
+</hbox>
+
+<menupopup id="themenu" onpopupshowing="if (gTestId == -1) event.preventDefault()"
+ onpopupshown="checkPopup()" onpopuphidden="setTimeout(nextTest, 0);">
+ <menuitem label="Item"/>
+</menupopup>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gTestId = -1;
+var gTestElement = "list";
+var gSelectionStep = 0;
+var gContextMenuFired = false;
+
+function startTest()
+{
+ // first, check if the richlistbox selection changes on a contextmenu mouse event
+ var element = $("list");
+ synthesizeMouse(element.getItemAtIndex(3), 7, 1, { type : "mousedown", button: 2, ctrlKey: true });
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+
+ gSelectionStep++;
+ synthesizeMouse(element.getItemAtIndex(1), 7, 1, { type : "mousedown", button: 2, ctrlKey: true, shiftKey: true });
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+
+ gSelectionStep++;
+ synthesizeMouse(element.getItemAtIndex(1), 7, 1, { type : "mousedown", button: 2 });
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+
+ $("menu").open = true;
+}
+
+function menuTests()
+{
+ gSelectionStep = 0;
+ var element = $("menu");
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+ is(gContextMenuFired, true, "context menu fired when menu open");
+
+ gSelectionStep = 1;
+ $("menu").boxObject.activeChild = $("menu2");
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+
+ $("menu").open = false;
+}
+
+function nextTest()
+{
+ gTestId++;
+ if (gTestId > 2) {
+ if (gTestElement == "list") {
+ gTestElement = "tree";
+ gTestId = 0;
+ }
+ else {
+ SimpleTest.finish();
+ return;
+ }
+ }
+ var element = $(gTestElement);
+ element.focus();
+ if (gTestId == 0) {
+ if (gTestElement == "list")
+ element.selectedIndex = 2;
+ element.currentIndex = 2;
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+ }
+ else if (gTestId == 1) {
+ synthesizeMouse(element, 7, 4, { type : "contextmenu", button: 2 });
+ }
+ else {
+ element.currentIndex = -1;
+ element.selectedIndex = -1;
+ synthesizeMouse(element, 0, 0, { type : "contextmenu", button: 0 });
+ }
+}
+
+// This is nasty so I'd better explain what's going on.
+// The basic problem is that the synthetic mouse coordinate generated
+// by DOMWindowUtils.sendMouseEvent and also the synthetic mouse coordinate
+// generated internally when contextmenu events are redirected to the focused
+// element are rounded to the nearest device pixel. But this rounding is done
+// while the coordinates are relative to the nearest widget. When this test
+// is run in the mochitest harness, the nearest widget is the main mochitest
+// window, and our document can have a fractional position within that
+// mochitest window. So when we round coordinates for comparison in this
+// test, we need to do so very carefully, especially if the target element
+// also has a fractional position within our document.
+//
+// For example, if the y-offset of our containing IFRAME is 100.4px,
+// and the offset of our expected point is 10.3px in our document, the actual
+// mouse event is dispatched to round(110.7) == 111px. This comes back
+// with a clientY of round(111 - 100.4) == round(10.6) == 11. This is not
+// equal to round(10.3) as you might expect.
+
+function isRoundedX(a, b, msg)
+{
+ is(Math.round(a + mozInnerScreenX), Math.round(b + mozInnerScreenX), msg);
+}
+
+function isRoundedY(a, b, msg)
+{
+ is(Math.round(a + mozInnerScreenY), Math.round(b + mozInnerScreenY), msg);
+}
+
+function checkContextMenu(event)
+{
+ var rect = $(gTestElement).getBoundingClientRect();
+
+ var frombase = (gTestId == -1 || gTestId == 1);
+ if (!frombase)
+ rect = event.originalTarget.getBoundingClientRect();
+ var left = frombase ? rect.left + 7 : rect.left;
+ var top = frombase ? rect.top + 4 : rect.bottom;
+
+ isRoundedX(event.clientX, left, gTestElement + " clientX " + gSelectionStep + " " + gTestId + "," + frombase);
+ isRoundedY(event.clientY, top, gTestElement + " clientY " + gSelectionStep + " " + gTestId);
+ ok(event.screenX > left, gTestElement + " screenX " + gSelectionStep + " " + gTestId);
+ ok(event.screenY > top, gTestElement + " screenY " + gSelectionStep + " " + gTestId);
+
+ // context menu from mouse click
+ switch (gTestId) {
+ case -1:
+ var expected = gSelectionStep == 2 ? 1 : (platformIsMac() ? 3 : 0);
+ is($(gTestElement).selectedIndex, expected, "index after click " + gSelectionStep);
+ break;
+ case 0:
+ if (gTestElement == "list")
+ is(event.originalTarget, $("item3"), "list selection target");
+ else
+ is(event.originalTarget, $("treechildren"), "tree selection target");
+ break;
+ case 1:
+ is(event.originalTarget.id, $("item1").id, "list mouse selection target");
+ break;
+ case 2:
+ is(event.originalTarget, $("list"), "list no selection target");
+ break;
+ }
+}
+
+function checkContextMenuForMenu(event)
+{
+ gContextMenuFired = true;
+
+ var popuprect = (gSelectionStep ? $("menu2") : $("menupopup")).getBoundingClientRect();
+ is(event.clientX, Math.round(popuprect.left), "menu left " + gSelectionStep);
+ // the clientY is off by one sometimes on Windows (when loaded in the testing iframe
+ // but not when loaded separately) so just check for both cases for now
+ ok(event.clientY == Math.round(popuprect.bottom) ||
+ event.clientY - 1 == Math.round(popuprect.bottom), "menu top " + gSelectionStep);
+}
+
+function checkPopup()
+{
+ var menurect = $("themenu").getBoundingClientRect();
+
+ // Context menus are offset by a number of pixels from the mouse click
+ // which activates them. This is so that they don't appear exactly
+ // under the mouse which can cause them to be mistakenly dismissed.
+ // The number of pixels depends on the platform and is defined in
+ // each platform's nsLookAndFeel
+ var contextMenuOffsetX = platformIsMac() ? 1 : 2;
+ var contextMenuOffsetY = platformIsMac() ? -6 : 2;
+
+ if (gTestId == 0) {
+ if (gTestElement == "list") {
+ var itemrect = $("item3").getBoundingClientRect();
+ isRoundedX(menurect.left, itemrect.left + contextMenuOffsetX,
+ "list selection keyboard left");
+ isRoundedY(menurect.top, itemrect.bottom + contextMenuOffsetY,
+ "list selection keyboard top");
+ }
+ else {
+ var tree = $("tree");
+ var bodyrect = $("treechildren").getBoundingClientRect();
+ isRoundedX(menurect.left, bodyrect.left + contextMenuOffsetX,
+ "tree selection keyboard left");
+ isRoundedY(menurect.top, bodyrect.top +
+ tree.treeBoxObject.rowHeight * 3 + contextMenuOffsetY,
+ "tree selection keyboard top");
+ }
+ }
+ else if (gTestId == 1) {
+ // activating a context menu with the mouse from position (7, 4).
+ var elementrect = $(gTestElement).getBoundingClientRect();
+ isRoundedX(menurect.left, elementrect.left + 7 + contextMenuOffsetX,
+ gTestElement + " mouse left");
+ isRoundedY(menurect.top, elementrect.top + 4 + contextMenuOffsetY,
+ gTestElement + " mouse top");
+ }
+ else {
+ var elementrect = $(gTestElement).getBoundingClientRect();
+ isRoundedX(menurect.left, elementrect.left + contextMenuOffsetX,
+ gTestElement + " no selection keyboard left");
+ isRoundedY(menurect.top, elementrect.bottom + contextMenuOffsetY,
+ gTestElement + " no selection keyboard top");
+ }
+
+ $("themenu").hidePopup();
+}
+
+function platformIsMac()
+{
+ return navigator.platform.indexOf("Mac") > -1;
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_cursorsnap.xul b/toolkit/content/tests/chrome/test_cursorsnap.xul
new file mode 100644
index 000000000..de153e704
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_cursorsnap.xul
@@ -0,0 +1,127 @@
+<?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="Cursor snapping test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+const kMaxRetryCount = 4;
+const kTimeoutTime = [
+ 100, 100, 1000, 1000, 5000
+];
+
+var gRetryCount;
+
+var gTestingCount = 0;
+var gTestingIndex = -1;
+var gDisable = false;
+var gHidden = false;
+
+function canRetryTest()
+{
+ return gRetryCount <= kMaxRetryCount;
+}
+
+function getTimeoutTime()
+{
+ return kTimeoutTime[gRetryCount];
+}
+
+function runNextTest()
+{
+ gRetryCount = 0;
+ gTestingIndex++;
+ runCurrentTest();
+}
+
+function retryCurrentTest()
+{
+ ok(canRetryTest(), "retry the current test...");
+ gRetryCount++;
+ runCurrentTest();
+}
+
+function runCurrentTest()
+{
+ var position = "top=" + gTestingCount + ",left=" + gTestingCount + ",";
+ gTestingCount++;
+ switch (gTestingIndex) {
+ case 0:
+ gDisable = false;
+ gHidden = false;
+ window.open("window_cursorsnap_dialog.xul", "_blank",
+ position + "chrome,width=100,height=100");
+ break;
+ case 1:
+ gDisable = true;
+ gHidden = false;
+ window.open("window_cursorsnap_dialog.xul", "_blank",
+ position + "chrome,width=100,height=100");
+ break;
+ case 2:
+ gDisable = false;
+ gHidden = true;
+ window.open("window_cursorsnap_dialog.xul", "_blank",
+ position + "chrome,width=100,height=100");
+ break;
+ case 3:
+ gDisable = false;
+ gHidden = false;
+ window.open("window_cursorsnap_wizard.xul", "_blank",
+ position + "chrome,width=100,height=100");
+ break;
+ case 4:
+ gDisable = true;
+ gHidden = false;
+ window.open("window_cursorsnap_wizard.xul", "_blank",
+ position + "chrome,width=100,height=100");
+ break;
+ case 5:
+ gDisable = false;
+ gHidden = true;
+ window.open("window_cursorsnap_wizard.xul", "_blank",
+ position + "chrome,width=100,height=100");
+ break;
+ default:
+ SetPrefs(false);
+ SimpleTest.finish();
+ return;
+ }
+}
+
+function SetPrefs(aSet)
+{
+ var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch);
+ const kPrefName = "ui.cursor_snapping.always_enabled";
+ if (aSet) {
+ prefSvc.setBoolPref(kPrefName, true);
+ } else if (prefSvc.prefHasUserValue(kPrefName)) {
+ prefSvc.clearUserPref(kPrefName);
+ }
+}
+
+SetPrefs(true);
+runNextTest();
+
+]]>
+</script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_datepicker.xul b/toolkit/content/tests/chrome/test_datepicker.xul
new file mode 100644
index 000000000..e7a61f43b
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_datepicker.xul
@@ -0,0 +1,415 @@
+<?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"?>
+<!--
+ XUL Widget Test for datepicker
+ -->
+<window title="datepicker" width="500" height="600"
+ onload="setTimeout(testtag_datepickers, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<hbox onpopupshown="testtag_datepicker_UI_popup()"
+ onpopuphidden="testtag_finish()">
+<datepicker id="datepicker"/>
+<datepicker id="datepicker-popup" type="popup"/>
+<hbox onDOMMouseScroll="mouseScrolled = event.defaultPrevented;">
+ <datepicker id="datepicker-grid" type="grid" value="2007-04-21"/>
+</hbox>
+</hbox>
+
+<!-- Test-only key bindings, but must not conflict with the application. -->
+<keyset id="mainKeyset">
+ <key id="key_alt_z" key="Z" oncommand="return" modifiers="alt"/>
+ <key id="key_ctrl_q" key="Q" oncommand="return" modifiers="control"/>
+ <key id="key_meta_e" key="E" oncommand="return" modifiers="meta"/>
+</keyset>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+var mouseScrolled = false;
+
+SimpleTest.waitForExplicitFinish();
+
+function testtag_datepickers()
+{
+ var dppopup = document.getElementById("datepicker-popup");
+ testtag_datepicker(document.getElementById("datepicker"), "", "datepicker");
+ testtag_datepicker(dppopup, "popup", "datepicker popup");
+
+ var gridpicker = document.getElementById("datepicker-grid");
+ is(gridpicker.monthField.selectedIndex, "3", "datepicker grid correct month is initially selected");
+ testtag_datepicker(gridpicker, "grid", "datepicker grid");
+ dppopup.open = true;
+}
+
+function testtag_finish()
+{
+ ok(!document.getElementById("datepicker-popup").open, "datepicker popup open false again");
+
+ var dpgrid = document.getElementById("datepicker-grid");
+ synthesizeWheel(dpgrid, 5, 5, { deltaY: 10.0,
+ deltaMode: WheelEvent.DOM_DELTA_LINE });
+ is(mouseScrolled, true, "mouse scrolled");
+ is(dpgrid.displayedMonth, 2, "mouse scroll changed month");
+
+ SimpleTest.finish();
+}
+
+function testtag_datepicker(dp, type, testid)
+{
+ testid += " ";
+
+ var today = new Date();
+ var tyear = today.getFullYear();
+ var tmonth = today.getMonth();
+ var tdate = today.getDate();
+
+ // testtag_comparedate(dp, testid + "initial", tyear, tmonth, tdate);
+
+ // check that setting the value property works
+ dp.value = testtag_getdatestring(tyear, tmonth, tdate);
+ testtag_comparedate(dp, testid + "set value", tyear, tmonth, tdate);
+
+ // check that setting the dateValue property works
+ dp.dateValue = today;
+ testtag_comparedate(dp, testid + "set dateValue", tyear, tmonth, tdate);
+ ok(dp.value !== today, testid + " set dateValue different date");
+
+ ok(!dp.readOnly, testid + "readOnly");
+ dp.readOnly = true;
+ ok(dp.readOnly, testid + "set readOnly");
+ dp.readOnly = false;
+ ok(!dp.readOnly, testid + "clear readOnly");
+
+ var setDateField = function(field, value, expectException,
+ expectedYear, expectedMonth, expectedDate)
+ {
+ var exh = false;
+ try {
+ dp[field] = value;
+ } catch (ex) { exh = true; }
+ is(exh, expectException, testid + "set " + field + " " + value);
+ testtag_comparedate(dp, testid + "set " + field + " " + value,
+ expectedYear, expectedMonth, expectedDate);
+ }
+
+ // check the value property
+ setDateField("value", "2003-1-27", false, 2003, 0, 27);
+ setDateField("value", "2002-11-8", false, 2002, 10, 8);
+ setDateField("value", "2001-07-02", false, 2001, 6, 2);
+ setDateField("value", "2002-10-25", false, 2002, 9, 25);
+
+ // check that the year, month and date fields can be set properly
+ setDateField("year", 2002, false, 2002, 9, 25);
+ setDateField("year", 0, true, 2002, 9, 25);
+
+ setDateField("month", 6, false, 2002, 6, 25);
+ setDateField("month", 9, false, 2002, 9, 25);
+ setDateField("month", 10, false, 2002, 10, 25);
+ setDateField("month", -1, true, 2002, 10, 25);
+ setDateField("month", 12, true, 2002, 10, 25);
+
+ setDateField("date", 9, false, 2002, 10, 9);
+ setDateField("date", 10, false, 2002, 10, 10);
+ setDateField("date", 15, false, 2002, 10, 15);
+ setDateField("date", 0, true, 2002, 10, 15);
+ setDateField("date", 32, true, 2002, 10, 15);
+
+ // check leap year handling
+ setDateField("value", "1600-2-29", false, 1600, 1, 29);
+ setDateField("value", "2000-2-29", false, 2000, 1, 29);
+ setDateField("value", "2003-2-29", false, 2003, 2, 1);
+ setDateField("value", "2004-2-29", false, 2004, 1, 29);
+ setDateField("value", "2100-2-29", false, 2100, 2, 1);
+
+ // check invalid values for the value and dateValue properties
+ dp.value = "2002-07-15";
+ setDateField("value", "", true, 2002, 6, 15);
+ setDateField("value", "2-2", true, 2002, 6, 15);
+ setDateField("value", "2000-5-6-6", true, 2002, 6, 15);
+ setDateField("value", "2000-a-19", true, 2002, 6, 15);
+ setDateField("dateValue", "none", true, 2002, 6, 15);
+
+ // grid and popup types can display a different month than the current one
+ var isGridOrPopup = (type == "grid" || type == "popup");
+ dp.displayedMonth = 3;
+ testtag_comparedate(dp, testid + "set displayedMonth",
+ 2002, isGridOrPopup ? 6 : 3, 15, 3);
+
+ dp.displayedYear = 2009;
+ testtag_comparedate(dp, testid + "set displayedYear",
+ isGridOrPopup ? 2002 : 2009, isGridOrPopup ? 6 : 3, 15, 3, 2009);
+
+ if (isGridOrPopup) {
+ dp.value = "2008-02-29";
+ dp.displayedYear = 2009;
+ is(dp.displayedMonth, 1, "set displayedYear during leap year");
+ }
+
+ is(dp.open, false, testid + "open false");
+ if (type != "popup") {
+ dp.open = true;
+ ok(!dp.open, testid + "open still false");
+ }
+
+ // check the fields
+ if (type != "grid") {
+ ok(dp.yearField instanceof HTMLInputElement, testid + "yearField");
+ ok(dp.monthField instanceof HTMLInputElement, testid + "monthField");
+ ok(dp.dateField instanceof HTMLInputElement, testid + "dateField");
+
+ testtag_datepicker_UI_fields(dp, testid);
+
+ dp.readOnly = true;
+
+ // check that keyboard usage doesn't change the value when the datepicker
+ // is read only
+ testtag_datepicker_UI_key(dp, testid + "readonly ", "2003-01-29",
+ dp.yearField, 2003, 0, 29, 2003, 0, 29);
+ testtag_datepicker_UI_key(dp, testid + "readonly ", "2003-04-29",
+ dp.monthField, 2003, 3, 29, 2003, 3, 29);
+ testtag_datepicker_UI_key(dp, testid + "readonly ", "2003-06-15",
+ dp.dateField, 2003, 5, 15, 2003, 5, 15);
+
+ dp.readOnly = false;
+ }
+ else {
+ testtag_datepicker_UI_grid(dp, "grid", testid);
+ }
+}
+
+function testtag_datepicker_UI_fields(dp, testid)
+{
+ testid += "UI";
+ dp.focus();
+
+ // test adjusting the date with the up and down keys
+ testtag_datepicker_UI_key(dp, testid, "2003-01-29", dp.yearField, 2004, 0, 29, 2003, 0, 29);
+ testtag_datepicker_UI_key(dp, testid, "1600-02-29", dp.yearField, 1601, 1, 28, 1600, 1, 28);
+ testtag_datepicker_UI_key(dp, testid, "2000-02-29", dp.yearField, 2001, 1, 28, 2000, 1, 28);
+ testtag_datepicker_UI_key(dp, testid, "2004-02-29", dp.yearField, 2005, 1, 28, 2004, 1, 28);
+
+ testtag_datepicker_UI_key(dp, testid, "2003-04-29", dp.monthField, 2003, 4, 29, 2003, 3, 29);
+ testtag_datepicker_UI_key(dp, testid, "2003-01-15", dp.monthField, 2003, 1, 15, 2003, 0, 15);
+ testtag_datepicker_UI_key(dp, testid, "2003-12-29", dp.monthField, 2003, 0, 29, 2003, 11, 29);
+ testtag_datepicker_UI_key(dp, testid, "2003-03-31", dp.monthField, 2003, 3, 30, 2003, 2, 30);
+
+ testtag_datepicker_UI_key(dp, testid, "2003-06-15", dp.dateField, 2003, 5, 16, 2003, 5, 15);
+ testtag_datepicker_UI_key(dp, testid, "2003-06-01", dp.dateField, 2003, 5, 2, 2003, 5, 1);
+ testtag_datepicker_UI_key(dp, testid, "2003-06-30", dp.dateField, 2003, 5, 1, 2003, 5, 30);
+ testtag_datepicker_UI_key(dp, testid, "1600-02-28", dp.dateField, 1600, 1, 29, 1600, 1, 28);
+ testtag_datepicker_UI_key(dp, testid, "2000-02-28", dp.dateField, 2000, 1, 29, 2000, 1, 28);
+ testtag_datepicker_UI_key(dp, testid, "2003-02-28", dp.dateField, 2003, 1, 1, 2003, 1, 28);
+ testtag_datepicker_UI_key(dp, testid, "2004-02-28", dp.dateField, 2004, 1, 29, 2004, 1, 28);
+ testtag_datepicker_UI_key(dp, testid, "2100-02-28", dp.dateField, 2100, 1, 1, 2100, 1, 28);
+
+ synthesizeKeyExpectEvent('Z', { altKey: true }, $("key_alt_z"), "command", testid + " alt shortcut");
+ synthesizeKeyExpectEvent('Q', { ctrlKey: true }, $("key_ctrl_q"), "command", testid + " ctrl shortcut");
+ synthesizeKeyExpectEvent('E', { metaKey: true }, $("key_meta_e"), "command", testid + " meta shortcut");
+}
+
+function testtag_datepicker_UI_grid(dp, type, testid)
+{
+ testid += "UI ";
+
+ // check that pressing the cursor keys moves the date properly. For grid
+ // types, focus the grid first. For popup types, the grid should be focused
+ // automatically when opening the popup.
+ var ktarget = dp;
+ if (type == "grid")
+ dp.focus();
+ else
+ ktarget = dp.attachedControl;
+
+ dp.value = "2003-02-22";
+
+ synthesizeKeyExpectEvent("VK_LEFT", { }, ktarget, "change", testid + "key left");
+ is(dp.value, "2003-02-21", testid + "key left");
+
+ synthesizeKeyExpectEvent("VK_RIGHT", { }, ktarget, "change", testid + "key right");
+ is(dp.value, "2003-02-22", testid + "key right");
+ synthesizeKeyExpectEvent("VK_RIGHT", { }, ktarget, "change", testid + "key right next week");
+ is(dp.value, "2003-02-23", testid + "key right next week");
+ synthesizeKeyExpectEvent("VK_LEFT", { }, ktarget, "change", testid + "key left previous week");
+ is(dp.value, "2003-02-22", testid + "key left previous week");
+
+ synthesizeKeyExpectEvent("VK_UP", { }, ktarget, "change", testid + "key up");
+ is(dp.value, "2003-02-15", testid + "key up");
+ synthesizeKeyExpectEvent("VK_DOWN", { }, ktarget, "change", testid + "key down");
+ is(dp.value, "2003-02-22", testid + "key down");
+ synthesizeKeyExpectEvent("VK_DOWN", { }, ktarget, "change");
+ is(dp.value, "2003-03-01", testid + "key down next month", testid + "key down next month");
+ synthesizeKeyExpectEvent("VK_UP", { }, ktarget, "change");
+ is(dp.value, "2003-02-22", testid + "key up previous month", testid + "key up previous month");
+
+ // the displayed month may be changed with the page up and page down keys,
+ // however this only changes the displayed month, not the current value.
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "monthchange", testid + "key page down");
+ is(dp.value, "2003-02-22", testid + "key page down");
+
+ // the monthchange event is fired when the displayed month is changed
+ synthesizeKeyExpectEvent("VK_UP", { }, ktarget, "monthchange", testid + "key up after month change");
+ is(dp.value, "2003-02-15", testid + "key up after month change");
+
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "monthchange", testid + "key page up");
+ is(dp.value, "2003-02-15", testid + "key page up");
+
+ // check handling at the start and end of the month
+ dp.value = "2010-10-01";
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "monthchange", testid + "key page up 2010-10-01");
+ is(dp.displayedMonth, 8, testid + "key page up 2010-10-01 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page up 2010-10-01 displayedYear");
+
+ dp.value = "2010-10-01";
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "monthchange", testid + "key page down 2010-10-01");
+ is(dp.displayedMonth, 10, testid + "key page down 2010-10-01 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page down 2010-10-01 displayedYear");
+
+ dp.value = "2010-10-31";
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "monthchange", testid + "key page up 2010-10-31");
+ is(dp.displayedMonth, 8, testid + "key page up 2010-10-31 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page up 2010-10-01 displayedYear");
+ dp.value = "2010-10-31";
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "monthchange", testid + "key page down 2010-10-31");
+ is(dp.displayedMonth, 10, testid + "key page down 2010-10-31 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page up 2010-10-31 displayedYear");
+
+ // check handling at the end of february
+ dp.value = "2010-03-31";
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "monthchange", testid + "key page up 2010-03-31");
+ is(dp.displayedMonth, 1, testid + "key page up 2010-03-31 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page up 2010-03-31 displayedYear");
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "monthchange", testid + "key page up 2010-02-28");
+ is(dp.displayedMonth, 0, testid + "key page up 2010-02-28 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page up 2010-02-28 displayedYear");
+
+ dp.value = "2010-01-31";
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "monthchange", testid + "key page down 2010-01-31");
+ is(dp.displayedMonth, 1, testid + "key page down 2010-01-31 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page up 2010-01-31 displayedYear");
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "monthchange", testid + "key page down 2010-02-28");
+ is(dp.displayedMonth, 2, testid + "key page down 2010-02-28 displayedMonth");
+ is(dp.displayedYear, 2010, testid + "key page up 2010-02-28 displayedYear");
+
+ // check handling at the end of february during a leap year
+ dp.value = "2008-01-31";
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "monthchange", testid + "key page down 2008-01-31");
+ is(dp.displayedMonth, 1, testid + "key page down 2008-01-31 displayedMonth");
+ is(dp.displayedYear, 2008, testid + "key page up 2008-01-31 displayedYear");
+ dp.value = "2008-03-31";
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "monthchange", testid + "key page up 2008-03-31");
+ is(dp.displayedMonth, 1, testid + "key page up 2008-03-31 displayedMonth");
+ is(dp.displayedYear, 2008, testid + "key page up 2008-03-31 displayedYear");
+
+ // the value of a read only datepicker cannot be changed
+ dp.value = "2003-02-15";
+
+ dp.readOnly = true;
+ synthesizeKeyExpectEvent("VK_LEFT", { }, ktarget, "!change", testid + "key left read only");
+ is(dp.value, "2003-02-15", testid + "key left read only");
+ synthesizeKeyExpectEvent("VK_RIGHT", { }, ktarget, "!change", testid + "key right read only");
+ is(dp.value, "2003-02-15", testid + "key right read only");
+ synthesizeKeyExpectEvent("VK_DOWN", { }, ktarget, "!change", testid + "key down read only");
+ is(dp.value, "2003-02-15", testid + "key down read only");
+ synthesizeKeyExpectEvent("VK_UP", { }, ktarget, "!change", testid + "key up read only");
+ is(dp.value, "2003-02-15", testid + "key up read only");
+
+ // month can still be changed even when readonly
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "monthchange",
+ testid + "key page up read only");
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "monthchange",
+ testid + "key page down read only");
+
+ dp.readOnly = false;
+ synthesizeKeyExpectEvent("VK_LEFT", { }, ktarget, "change", testid + "key left changeable again");
+ is(dp.value, "2003-02-14", testid + "key left changeable again");
+
+ // the value of a disabled datepicker cannot be changed
+ dp.disabled = true;
+ synthesizeKeyExpectEvent("VK_LEFT", { }, ktarget, "!change", testid + "key left disabled");
+ is(dp.value, "2003-02-14", testid + "key left disabled");
+ synthesizeKeyExpectEvent("VK_RIGHT", { }, ktarget, "!change", testid + "key right disabled");
+ is(dp.value, "2003-02-14", testid + "key right disabled");
+ synthesizeKeyExpectEvent("VK_DOWN", { }, ktarget, "!change", testid + "key down disabled");
+ is(dp.value, "2003-02-14", testid + "key down disabled");
+ synthesizeKeyExpectEvent("VK_UP", { }, ktarget, "!change", testid + "key up disabled");
+ is(dp.value, "2003-02-14", testid + "key up disabled");
+
+ // month cannot be changed even when disabled
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, ktarget, "!monthchange",
+ testid + "key page down disabled");
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, ktarget, "!monthchange",
+ testid + "key page up disabled");
+
+ dp.disabled = false;
+ synthesizeKeyExpectEvent("VK_RIGHT", { }, ktarget, "change", testid + "key right enabled again");
+ is(dp.value, "2003-02-15", testid + "key right enabled again");
+}
+
+function testtag_datepicker_UI_popup()
+{
+ var dppopup = document.getElementById("datepicker-popup");
+ is(dppopup.open, true, "datepicker popup after open");
+ testtag_datepicker_UI_grid(dppopup, "popup", "datepicker popup ");
+ dppopup.open = false;
+}
+
+function testtag_datepicker_UI_key(dp, testid, value, field,
+ uyear, umonth, udate,
+ dyear, dmonth, ddate)
+{
+ dp.value = value;
+ field.focus();
+
+ synthesizeKey("VK_UP", { });
+ testtag_comparedate(dp, testid + " " + value + " key up", uyear, umonth, udate);
+
+ synthesizeKey("VK_DOWN", { });
+ testtag_comparedate(dp, testid + " " + value + " key down", dyear, dmonth, ddate);
+}
+
+function testtag_getdatestring(year, month, date)
+{
+ month = (month < 9) ? ("0" + ++month) : month + 1;
+ if (date < 10)
+ date = "0" + date;
+ return year + "-" + month + "-" + date;
+}
+
+function testtag_comparedate(dp, testid, year, month, date, displayedMonth, displayedYear)
+{
+ is(dp.value, testtag_getdatestring(year, month, date), testid + " value");
+ if (testid.indexOf("initial") == -1)
+ is(dp.getAttribute("value"),
+ testtag_getdatestring(year, month, date),
+ testid + " value attribute");
+
+ var dateValue = dp.dateValue;
+ ok(dateValue.getFullYear() == year &&
+ dateValue.getMonth() == month &&
+ dateValue.getDate() == date,
+ testid + " dateValue");
+
+ is(dp.year, year, testid + " year");
+ is(dp.month, month, testid + " month");
+ is(dp.displayedMonth, displayedMonth ? displayedMonth : month, testid + " displayedMonth");
+ is(dp.displayedYear, displayedYear ? displayedYear : year, testid + " displayedYear");
+ is(dp.date, date, testid + " date");
+}
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_deck.xul b/toolkit/content/tests/chrome/test_deck.xul
new file mode 100644
index 000000000..25c59c38a
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_deck.xul
@@ -0,0 +1,133 @@
+<?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"?>
+<!--
+ XUL Widget Test for deck
+ -->
+<window title="Deck Test"
+ onload="setTimeout(run_tests, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<deck id="deck1" style="padding-top: 5px; padding-bottom: 12px;">
+ <button id="d1b1" label="Button One"/>
+ <button id="d1b2" label="Button Two is larger" height="80" style="margin: 1px;"/>
+</deck>
+<deck id="deck2" selectedIndex="1">
+ <button id="d2b1" label="Button One"/>
+ <button id="d2b2" label="Button Two"/>
+</deck>
+<deck id="deck3" selectedIndex="1">
+ <button id="d3b1" label="Remove me"/>
+ <button id="d3b2" label="Keep me selected"/>
+</deck>
+<deck id="deck4" selectedIndex="5">
+ <button id="d4b1" label="Remove me"/>
+ <button id="d4b2" label="Remove me"/>
+ <button id="d4b3" label="Remove me"/>
+ <button id="d4b4" label="Button 4"/>
+ <button id="d4b5" label="Button 5"/>
+ <button id="d4b6" label="Keep me selected"/>
+ <button id="d4b7" label="Button 7"/>
+</deck>
+<deck id="deck5" selectedIndex="2">
+ <button id="d5b1" label="Button 1"/>
+ <button id="d5b2" label="Button 2"/>
+ <button id="d5b3" label="Keep me selected"/>
+ <button id="d5b4" label="Remove me"/>
+ <button id="d5b5" label="Remove me"/>
+ <button id="d5b6" label="Remove me"/>
+</deck>
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function run_tests() {
+ test_deck();
+ test_deck_child_removal();
+ SimpleTest.finish();
+}
+
+function test_deck()
+{
+ var deck = $("deck1");
+ ok(deck.selectedIndex === '0', "deck one selectedIndex");
+ // this size is the button height, 80, plus the button padding of 1px on each side,
+ // plus the deck's 5px top padding and the 12px bottom padding.
+ var rect = deck.getBoundingClientRect();
+ is(Math.round(rect.bottom) - Math.round(rect.top), 99, "deck size of largest child");
+ synthesizeMouseExpectEvent(deck, 12, 12, { }, $("d1b1"), "click", "mouse on deck one");
+
+ // change the selected page of the deck and ensure that the mouse click goes
+ // to the button on that page
+ deck.selectedIndex = 1;
+ ok(deck.selectedIndex === '1', "deck one selectedIndex after change");
+ synthesizeMouseExpectEvent(deck, 9, 9, { }, $("d1b2"), "click", "mouse on deck one after change");
+
+ deck = $("deck2");
+ ok(deck.selectedIndex === '1', "deck two selectedIndex");
+ synthesizeMouseExpectEvent(deck, 9, 9, { }, $("d2b2"), "click", "mouse on deck two");
+}
+
+function test_deck_child_removal()
+{
+ // Start with a simple case where we have two child nodes in a deck, with
+ // the second child (index 1) selected. Removing the first node should
+ // automatically set the selectedIndex at 0.
+ let deck = $("deck3");
+ let child = $("d3b1");
+ is(deck.selectedIndex, "1", "Should have the deck element at index 1 selected");
+
+ // Remove the child at the 0th index. The deck should automatically
+ // set the selectedIndex to "0".
+ child.remove();
+ is(deck.selectedIndex, "0", "Should have the deck element at index 0 selected");
+
+ // Now scale it up by using a deck with 7 child nodes, and remove the
+ // first three, making sure that the selectedIndex is decremented
+ // each time.
+ deck = $("deck4");
+ let expectedIndex = 5;
+ is(deck.selectedIndex, String(expectedIndex),
+ "Should have the deck element at index " + expectedIndex + " selected");
+
+ for (let i = 0; i < 3; ++i) {
+ deck.firstChild.remove();
+ expectedIndex--;
+ is(deck.selectedIndex, String(expectedIndex),
+ "Should have the deck element at index " + expectedIndex + " selected");
+ }
+
+ // Check that removing the currently selected node doesn't change
+ // behaviour.
+ deck.childNodes[expectedIndex].remove();
+ is(deck.selectedIndex, String(expectedIndex),
+ "The selectedIndex should not change when removing the node " +
+ "at the selected index.");
+
+ // Finally, make sure we haven't changed the behaviour when removing
+ // nodes at indexes greater than the selected node.
+ deck = $("deck5");
+ expectedIndex = 2;
+ is(deck.selectedIndex, String(expectedIndex),
+ "Should have the deck element at index " + expectedIndex + " selected");
+
+ // And then remove all of the nodes, starting from last to first, making
+ // sure that the selectedIndex does not change.
+ while (deck.lastChild) {
+ deck.lastChild.remove();
+ is(deck.selectedIndex, String(expectedIndex),
+ "Should have the deck element at index " + expectedIndex + " selected");
+ }
+}
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_dialogfocus.xul b/toolkit/content/tests/chrome/test_dialogfocus.xul
new file mode 100644
index 000000000..80474e2b9
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_dialogfocus.xul
@@ -0,0 +1,102 @@
+<?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 width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+<script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<button id="test" label="Test"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestCompleteLog();
+
+var expected = [ "one", "_extra2", "tab", "one", "tabbutton2", "tabbutton", "two", "textbox-yes", "one" ];
+// non-Mac will always focus the default button if any of the dialog buttons
+// would be focused
+if (navigator.platform.indexOf("Mac") == -1)
+ expected[1] = "_accept";
+
+var step = 0;
+var fullKeyboardAccess = false;
+
+function startTest()
+{
+ var testButton = document.getElementById("test");
+ synthesizeKey("VK_TAB", { });
+ fullKeyboardAccess = (document.activeElement == testButton);
+ info("We " + (fullKeyboardAccess ? "have" : "don't have") + " full keyboard access");
+ runTest();
+}
+
+function runTest()
+{
+ step++;
+ info("runTest(), step = " + step + ", expected = " + expected[step - 1]);
+ if (step > expected.length || (!fullKeyboardAccess && step == 2)) {
+ info("finishing");
+ SimpleTest.finish();
+ return;
+ }
+
+ var expectedFocus = expected[step - 1];
+ var win = window.openDialog("dialog_dialogfocus.xul", "_new", "chrome,dialog", step);
+
+ function checkDialogFocus(event)
+ {
+ info("checkDialogFocus()");
+ // if full keyboard access is not on, just skip the tests
+ var match = false;
+ if (fullKeyboardAccess) {
+ if (!(event.target instanceof Element)) {
+ info("target not an Element");
+ return;
+ }
+
+ if (expectedFocus == "textbox-yes")
+ match = (win.document.activeElement == win.document.getElementById(expectedFocus).inputField);
+ else if (expectedFocus[0] == "_")
+ match = (win.document.activeElement.dlgType == expectedFocus.substring(1));
+ else
+ match = (win.document.activeElement.id == expectedFocus);
+ info("match = " + match);
+ if (!match)
+ return;
+ }
+ else {
+ match = (win.document.activeElement == win.document.documentElement);
+ info("match = " + match);
+ }
+
+ win.removeEventListener("focus", checkDialogFocus, true);
+ ok(match, "focus step " + step);
+
+ win.close();
+ SimpleTest.waitForFocus(runTest, window);
+ }
+
+ win.addEventListener("focus", checkDialogFocus, true);
+}
+
+SimpleTest.waitForFocus(startTest, window);
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_findbar.xul b/toolkit/content/tests/chrome/test_findbar.xul
new file mode 100644
index 000000000..9cbe73c47
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_findbar.xul
@@ -0,0 +1,47 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=257061
+https://bugzilla.mozilla.org/show_bug.cgi?id=288254
+-->
+<window title="Mozilla Bug 257061 and Bug 288254"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=257061">Mozilla Bug 257061</a>
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=288254">Mozilla Bug 288254</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 257061 and Bug 288254 **/
+SimpleTest.waitForExplicitFinish();
+
+// Since bug 978861, this pref is set to `false` on OSX. For this test, we'll
+// set it `true` to disable the find clipboard on OSX, which interferes with
+// our tests.
+SpecialPowers.pushPrefEnv({
+ set: [["accessibility.typeaheadfind.prefillwithselection", true]]
+}, () => {
+ window.open("findbar_window.xul", "findbartest", "chrome,width=600,height=600");
+});
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_findbar_entireword.xul b/toolkit/content/tests/chrome/test_findbar_entireword.xul
new file mode 100644
index 000000000..dc39fe09d
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_findbar_entireword.xul
@@ -0,0 +1,41 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=269442
+-->
+<window title="Mozilla Bug 269442"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=269442">
+ Mozilla Bug 269442
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 269442 **/
+ SimpleTest.waitForExplicitFinish();
+ window.open("findbar_entireword_window.xul", "269442test",
+ "chrome,width=600,height=600");
+
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_findbar_events.xul b/toolkit/content/tests/chrome/test_findbar_events.xul
new file mode 100644
index 000000000..d75e5ccb5
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_findbar_events.xul
@@ -0,0 +1,39 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=793275
+-->
+<window title="Mozilla Bug 793275"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=793275">
+ Mozilla Bug 793275
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 793275 **/
+ SimpleTest.waitForExplicitFinish();
+ window.open("findbar_events_window.xul", "793275test",
+ "chrome,width=600,height=600");
+
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_focus_anons.xul b/toolkit/content/tests/chrome/test_focus_anons.xul
new file mode 100644
index 000000000..848590887
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_focus_anons.xul
@@ -0,0 +1,119 @@
+<?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="Tests for focus on elements with anonymous focusable children"
+ onload="SimpleTest.waitForFocus(runTests);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<label accesskey="a" control="menulist"/>
+<label accesskey="b" control="textbox"/>
+<label accesskey="c" control="scale"/>
+
+<menulist id="menulist" editable="true">
+ <menupopup>
+ <menuitem label="One"/>
+ </menupopup>
+</menulist>
+<textbox id="textbox"/>
+<scale id="scale"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gBlurs = 0, gFocuses = 0;
+var gExpectedBlur = "";
+var gExpectedFocus = "";
+
+function blurOccurred(event) {
+ gBlurs++;
+ is(event.originalTarget, gExpectedBlur, "blur " + gBlurs + "," + event.originalTarget.localName);
+}
+
+function focusOccurred(event) {
+ gFocuses++;
+ is(event.originalTarget, gExpectedFocus, "focus " + gFocuses + "," + event.originalTarget.localName);
+}
+
+function runTests()
+{
+ addEventListener("focus", focusOccurred, true);
+ addEventListener("blur", blurOccurred, true);
+
+ gExpectedBlur = null;
+ gExpectedFocus = $("menulist").inputField;
+ $("menulist").focus();
+
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = $("textbox").inputField;
+ $("textbox").focus();
+
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = document.getAnonymousNodes($("scale"))[0];
+ $("scale").focus();
+
+ var accessKeyDetails = (navigator.platform.indexOf("Mac") >= 0) ?
+ { altKey: true, ctrlKey : true } :
+ { altKey : true, shiftKey: true };
+
+ gExpectedBlur = document.getAnonymousNodes($("scale"))[0];
+ gExpectedFocus = $("menulist").inputField;
+ synthesizeKey("a", accessKeyDetails);
+
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = $("textbox").inputField;
+ synthesizeKey("b", accessKeyDetails);
+
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = document.getAnonymousNodes($("scale"))[0];
+ synthesizeKey("c", accessKeyDetails);
+
+ if (navigator.platform.indexOf("Mac") == -1) {
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = $("textbox").inputField;
+ synthesizeKey("VK_TAB", { shiftKey: true });
+
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = $("menulist").inputField;
+ synthesizeKey("VK_TAB", { shiftKey: true });
+
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = $("textbox").inputField;
+ synthesizeKey("VK_TAB", { });
+
+ gExpectedBlur = gExpectedFocus;
+ gExpectedFocus = document.getAnonymousNodes($("scale"))[0];
+ synthesizeKey("VK_TAB", { });
+
+ is(gBlurs, 9, "correct number of blurs");
+ is(gFocuses, 10, "correct number of focuses");
+ }
+ else {
+ is(gBlurs, 5, "correct number of blurs");
+ is(gFocuses, 6, "correct number of focuses");
+ }
+
+ removeEventListener("focus", focusOccurred, true);
+ removeEventListener("blur", blurOccurred, true);
+
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_hiddenitems.xul b/toolkit/content/tests/chrome/test_hiddenitems.xul
new file mode 100644
index 000000000..7e44852df
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_hiddenitems.xul
@@ -0,0 +1,89 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=317422
+-->
+<window title="Mozilla Bug 317422"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=317422"
+ target="_blank">Mozilla Bug 317422</a>
+ </body>
+
+ <richlistbox id="richlistbox" seltype="multiple">
+ <richlistitem id="richlistbox_item1"><label value="Item 1"/></richlistitem>
+ <richlistitem id="richlistbox_item2"><label value="Item 2"/></richlistitem>
+ <richlistitem id="richlistbox_item3" hidden="true"><label value="Item 3"/></richlistitem>
+ <richlistitem id="richlistbox_item4"><label value="Item 4"/></richlistitem>
+ <richlistitem id="richlistbox_item5" collapsed="true"><label value="Item 5"/></richlistitem>
+ <richlistitem id="richlistbox_item6"><label value="Item 6"/></richlistitem>
+ <richlistitem id="richlistbox_item7" hidden="true"><label value="Item 7"/></richlistitem>
+ </richlistbox>
+
+ <listbox id="listbox" seltype="multiple">
+ <listitem id="listbox_item1" label="Item 1"/>
+ <listitem id="listbox_item2" label="Item 2"/>
+ <listitem id="listbox_item3" label="Item 3" hidden="true"/>
+ <listitem id="listbox_item4" label="Item 4"/>
+ <listitem id="listbox_item5" label="Item 5" collapsed="true"/>
+ <listitem id="listbox_item6" label="Item 6"/>
+ <listitem id="listbox_item7" label="Item 7" hidden="true"/>
+ </listbox>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+/** Test for Bug 317422 **/
+SimpleTest.waitForExplicitFinish();
+
+function testListbox(id)
+{
+ var listbox = document.getElementById(id);
+ listbox.focus();
+ is(listbox.getRowCount(), 7, id + ": Returned the wrong number of rows");
+ is(listbox.getItemAtIndex(2).id, id + "_item3", id + ": Should still return hidden items");
+ listbox.selectedIndex = 0;
+ is(listbox.selectedItem.id, id + "_item1", id + ": First item was not selected");
+ sendKey("DOWN");
+ is(listbox.selectedItem.id, id + "_item2", id + ": Down didn't move to second item");
+ sendKey("DOWN");
+ is(listbox.selectedItem.id, id + "_item4", id + ": Down didn't skip hidden item");
+ sendKey("DOWN");
+ is(listbox.selectedItem.id, id + "_item6", id + ": Down didn't skip collapsed item");
+ sendKey("UP");
+ is(listbox.selectedItem.id, id + "_item4", id + ": Up didn't skip collapsed item");
+ sendKey("UP");
+ is(listbox.selectedItem.id, id + "_item2", id + ": Up didn't skip hidden item");
+ listbox.selectAll();
+ is(listbox.selectedItems.length, 7, id + ": Should have still selected all items");
+ listbox.invertSelection();
+ is(listbox.selectedItems.length, 0, id + ": Should have unselected all items");
+ listbox.selectedIndex = 2;
+ ok(listbox.selectedItem == listbox.getItemAtIndex(2), id + ": Should have selected the hidden item");
+ listbox.selectedIndex = 0;
+ sendKey("END");
+ is(listbox.selectedItem.id, id + "_item6", id + ": Should have moved to the last unhidden item");
+ sendMouseEvent({type: 'click'}, id + "_item1");
+ ok(listbox.selectedItem == listbox.getItemAtIndex(0), id + ": Should have selected the first item");
+ is(listbox.selectedItems.length, 1, id + ": Should only be one selected item");
+ sendMouseEvent({type: 'click', shiftKey: true}, id + "_item6");
+ is(listbox.selectedItems.length, 4, id + ": Should have selected all visible items");
+ listbox.selectedIndex = 0;
+ sendKey("PAGE_DOWN");
+ is(listbox.selectedItem.id, id + "_item6", id + ": Page down should go to the last visible item");
+ sendKey("PAGE_UP");
+ is(listbox.selectedItem.id, id + "_item1", id + ": Page up should go to the first visible item");
+}
+
+window.onload = function runTests() {
+ testListbox("richlistbox");
+ testListbox("listbox");
+ SimpleTest.finish();
+};
+ ]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_hiddenpaging.xul b/toolkit/content/tests/chrome/test_hiddenpaging.xul
new file mode 100644
index 000000000..37b109718
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_hiddenpaging.xul
@@ -0,0 +1,161 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=317422
+-->
+<window title="Mozilla Bug 317422"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <style xmlns="http://www.w3.org/1999/xhtml">
+ /* This makes the richlistbox about 4.5 rows high */
+ richlistitem {
+ height: 30px;
+ }
+ richlistbox {
+ height: 135px;
+ }
+ </style>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=317422"
+ target="_blank">Mozilla Bug 317422</a>
+ </body>
+
+ <richlistbox id="richlistbox" seltype="multiple">
+ <richlistitem id="richlistbox_item1"><label value="Item 1"/></richlistitem>
+ <richlistitem id="richlistbox_item2"><label value="Item 2"/></richlistitem>
+ <richlistitem id="richlistbox_item3" hidden="true"><label value="Item 3"/></richlistitem>
+ <richlistitem id="richlistbox_item4"><label value="Item 4"/></richlistitem>
+ <richlistitem id="richlistbox_item5" collapsed="true"><label value="Item 5"/></richlistitem>
+ <richlistitem id="richlistbox_item6"><label value="Item 6"/></richlistitem>
+ <richlistitem id="richlistbox_item7"><label value="Item 7"/></richlistitem>
+ <richlistitem id="richlistbox_item8"><label value="Item 8"/></richlistitem>
+ <richlistitem id="richlistbox_item9"><label value="Item 9"/></richlistitem>
+ <richlistitem id="richlistbox_item10"><label value="Item 10"/></richlistitem>
+ <richlistitem id="richlistbox_item11"><label value="Item 11"/></richlistitem>
+ <richlistitem id="richlistbox_item12"><label value="Item 12"/></richlistitem>
+ <richlistitem id="richlistbox_item13"><label value="Item 13"/></richlistitem>
+ <richlistitem id="richlistbox_item14"><label value="Item 14"/></richlistitem>
+ <richlistitem id="richlistbox_item15" hidden="true"><label value="Item 15"/></richlistitem>
+ </richlistbox>
+
+ <listbox id="listbox" seltype="multiple" rows="5">
+ <listitem id="listbox_item1" label="Item 1"/>
+ <listitem id="listbox_item2" label="Item 2"/>
+ <listitem id="listbox_item3" label="Item 3" hidden="true"/>
+ <listitem id="listbox_item4" label="Item 4"/>
+ <listitem id="listbox_item5" label="Item 5" hidden="true"/>
+ <listitem id="listbox_item6" label="Item 6"/>
+ <listitem id="listbox_item7" label="Item 7"/>
+ <listitem id="listbox_item8" label="Item 8"/>
+ <listitem id="listbox_item9" label="Item 9"/>
+ <listitem id="listbox_item10" label="Item 10"/>
+ <listitem id="listbox_item11" label="Item 11"/>
+ <listitem id="listbox_item12" label="Item 12"/>
+ <listitem id="listbox_item13" label="Item 13"/>
+ <listitem id="listbox_item14" label="Item 14"/>
+ <listitem id="listbox_item15" label="Item 15" hidden="true"/>
+ </listbox>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+/** Test for Bug 317422 **/
+SimpleTest.waitForExplicitFinish();
+
+function testRichlistbox()
+{
+ var id = "richlistbox";
+ var listbox = document.getElementById(id);
+ listbox.focus();
+ listbox.selectedIndex = 0;
+ sendKey("PAGE_DOWN");
+ is(listbox.selectedItem.id, id + "_item7", id + ": Page down should go to the item one visible page away");
+ is(listbox.getIndexOfFirstVisibleRow(), 6, id + ": Page down should have scrolled down a visible page");
+ sendKey("PAGE_DOWN");
+ is(listbox.selectedItem.id, id + "_item11", id + ": Second page down should go to the item two visible pages away");
+ is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Second page down should not scroll beyond the end");
+ sendKey("PAGE_DOWN");
+ is(listbox.selectedItem.id, id + "_item14", id + ": Third page down should go to the last visible item");
+ is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Third page down should not have scrolled at all");
+ sendKey("PAGE_UP");
+ is(listbox.selectedItem.id, id + "_item10", id + ": Page up should go to the item one visible page away");
+ is(listbox.getIndexOfFirstVisibleRow(), 5, id + ": Page up should scroll up a visible page");
+ sendKey("PAGE_UP");
+ is(listbox.selectedItem.id, id + "_item6", id + ": Second page up should go to the item two visible pages away");
+ is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Second page up should not scroll beyond the start");
+ sendKey("PAGE_UP");
+ is(listbox.selectedItem.id, id + "_item1", id + ": Third page up should return to the first visible item");
+ is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Third page up should not have scrolled at all");
+}
+
+function testListbox()
+{
+ var id = "listbox";
+ var listbox = document.getElementById(id);
+
+ if (!window.matchMedia("(-moz-overlay-scrollbars)").matches) {
+ // Check that a scrollbar is visible by comparing the width of the listitem
+ // with the width of the listbox. This is a simple way to do this without
+ // checking the anonymous content.
+ ok(listbox.firstChild.getBoundingClientRect().width < listbox.getBoundingClientRect().width - 10,
+ id + ": Scrollbar visible");
+ }
+
+ var rowHeight = listbox.firstChild.getBoundingClientRect().height;
+
+ listbox.focus();
+ listbox.selectedIndex = 0;
+ sendKey("PAGE_DOWN");
+ is(listbox.selectedItem.id, id + "_item8", id + ": Page down should go to the item one visible page away");
+ is(listbox.getIndexOfFirstVisibleRow(), 7, id + ": Page down should have scrolled down a visible page");
+ sendKey("PAGE_DOWN");
+ is(listbox.selectedItem.id, id + "_item13", id + ": Second page down should go to the item two visible pages away");
+ is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Second page down should not scroll beyond the end");
+ sendKey("PAGE_DOWN");
+ is(listbox.selectedItem.id, id + "_item14", id + ": Third page down should go to the last visible item");
+ is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Third page down should not have scrolled at all");
+ sendKey("PAGE_UP");
+ is(listbox.selectedItem.id, id + "_item9", id + ": Page up should go to the item one visible page away");
+ // the listScrollbox seems to go haywire when scrolling up with hidden listitems
+ todo_is(listbox.getIndexOfFirstVisibleRow(), 3, id + ": Page up should scroll up a visible page");
+ sendKey("PAGE_UP");
+ is(listbox.selectedItem.id, id + "_item2", id + ": Second page up should go to the item two visible pages away");
+ is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Second page up should not scroll beyond the start");
+ sendKey("PAGE_UP");
+ is(listbox.selectedItem.id, id + "_item1", id + ": Third page up should return to the first visible item");
+ is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Third page up should not have scrolled at all");
+
+ var scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+ is(scrollHeight, rowHeight * 15, id + ": scrollHeight when rows set");
+
+ listbox.minHeight = 50;
+ scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+ is(scrollHeight, rowHeight * 15, id + ": scrollHeight when rows and minimium height set");
+
+ listbox.removeAttribute("rows");
+
+ var availHeight = document.getAnonymousNodes(listbox)[1].lastChild.getBoundingClientRect().height;
+ // The listbox layout adds this extra height in GetPrefSize. Not sure what it's for though.
+ var e = (rowHeight * 15 - availHeight) % rowHeight;
+ var extraHeight = (e == 0) ? 0 : rowHeight - e;
+
+ scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+ is(scrollHeight, rowHeight * 15 + extraHeight, id + ": scrollHeight when minimium height set");
+
+ listbox.removeAttribute("minheight");
+ scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+ is(scrollHeight, rowHeight * 15 + extraHeight, id + ": scrollHeight");
+}
+
+window.onload = function runTests() {
+ testRichlistbox();
+ testListbox();
+ SimpleTest.finish();
+};
+ ]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_keys.xul b/toolkit/content/tests/chrome/test_keys.xul
new file mode 100644
index 000000000..97cc8a241
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_keys.xul
@@ -0,0 +1,29 @@
+<?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="Keys Test"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_keys.xul", "_blank", "chrome,width=200,height=200");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_labelcontrol.xul b/toolkit/content/tests/chrome/test_labelcontrol.xul
new file mode 100644
index 000000000..b33667be0
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_labelcontrol.xul
@@ -0,0 +1,44 @@
+<?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"?>
+<!--
+ XUL Widget Test for label control="value"
+ -->
+<window title="tabindex" width="500" height="600"
+ onload="runTests()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<label id="lab" control="ctl"/>
+<textbox id="ctl" value="Test"/>
+<checkbox id="chk" value="Checkbox"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests()
+{
+ is($("lab").control, "ctl", "control");
+ is($("lab").labeledControlElement, $("ctl"), "labeledControlElement");
+ is($("ctl").labelElement, $("lab"), "labelElement");
+ is($("chk").labelElement.className, "checkbox-label", "labelElement");
+
+ SimpleTest.finish();
+}
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_largemenu.xul b/toolkit/content/tests/chrome/test_largemenu.xul
new file mode 100644
index 000000000..8841e2b16
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_largemenu.xul
@@ -0,0 +1,29 @@
+<?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="Large Menu Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_largemenu.xul", "_blank", "chrome,width=200,height=200");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menu.xul b/toolkit/content/tests/chrome/test_menu.xul
new file mode 100644
index 000000000..877efadb1
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menu.xul
@@ -0,0 +1,85 @@
+<?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="Menu Destruction Test"
+ onload="runTests();"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+ <menubar>
+ <menu label="top" id="top">
+ <menupopup>
+ <menuitem label="top item"/>
+
+ <menu label="hello" id="nested">
+ <menupopup>
+ <menuitem label="item1"/>
+ <menuitem label="item2" id="item2"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menubar>
+
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ SimpleTest.waitForExplicitFinish();
+
+ function runTests()
+ {
+ var menu = document.getElementById("nested");
+
+ // nsIDOMXULContainerElement::getIndexOfItem();
+ var item = document.getElementById("item2");
+ is(menu.getIndexOfItem(item), 1,
+ "nsIDOMXULContainerElement::getIndexOfItem() failed.");
+
+ // nsIDOMXULContainerElement::getItemAtIndex();
+ var itemAtIdx = menu.getItemAtIndex(1);
+ is(itemAtIdx, item,
+ "nsIDOMXULContainerElement::getItemAtIndex() failed.");
+
+ // nsIDOMXULContainerElement::itemCount
+ is(menu.itemCount, 2, "nsIDOMXULContainerElement::itemCount failed.");
+
+ // nsIDOMXULContainerElement::parentContainer
+ var topmenu = document.getElementById("top");
+ is(menu.parentContainer, topmenu,
+ "nsIDOMXULContainerElement::parentContainer failed.");
+
+ // nsIDOMXULContainerElement::appendItem();
+ var item = menu.appendItem("item3");
+ is(menu.getIndexOfItem(item), 2,
+ "nsIDOMXULContainerElement::appendItem() failed.");
+
+ // nsIDOMXULContainerElement::insertItemAt();
+ var item = menu.insertItemAt(0, "itemZero");
+ is(item, menu.getItemAtIndex(0),
+ "nsIDOMXULContainerElement::insertItemAt() failed.");
+
+ // nsIDOMXULContainerElement::removeItemAt();
+ var item = menu.removeItemAt(0);
+ is(3, menu.itemCount,
+ "nsIDOMXULContainerElement::removeItemAt() failed.");
+
+ SimpleTest.finish();
+ }
+
+ ]]>
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display">
+ </p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+</window>
+
diff --git a/toolkit/content/tests/chrome/test_menu_anchored.xul b/toolkit/content/tests/chrome/test_menu_anchored.xul
new file mode 100644
index 000000000..8fdda3f25
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menu_anchored.xul
@@ -0,0 +1,77 @@
+<?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"?>
+<!--
+ Test for menus with the anchor attribute set
+ -->
+<window title="Anchored Menus Test"
+ align="start"
+ onload="setTimeout(runTest, 0,'tb1');"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+ <script type="application/javascript" src="xul_selectcontrol.js"/>
+
+<hbox>
+
+<toolbarbutton id="tb1" type="menu-button" label="Open" anchor="dropmarker">
+ <menupopup id="popup1"
+ onpopupshown="checkPopup(this, document.getAnonymousElementByAttribute(this.parentNode, 'anonid', 'dropmarker'))"
+ onpopuphidden="runTest('tb2')">
+ <menuitem label="Item"/>
+ </menupopup>
+</toolbarbutton>
+
+<toolbarbutton id="tb2" type="menu-button" label="Open" anchor="someanchor">
+ <menupopup id="popup2" onpopupshown="checkPopup(this, $('someanchor'))" onpopuphidden="runTest('tb3')">
+ <menuitem label="Item"/>
+ </menupopup>
+</toolbarbutton>
+
+<toolbarbutton id="tb3" type="menu-button" label="Open" anchor="noexist">
+ <menupopup id="popup3" onpopupshown="checkPopup(this, this.parentNode)" onpopuphidden="SimpleTest.finish()">
+ <menuitem label="Item"/>
+ </menupopup>
+</toolbarbutton>
+
+</hbox>
+
+<hbox pack="end" width="180">
+ <button id="someanchor" label="Anchor"/>
+</hbox>
+
+<!-- test results are displayed in the html:body -->
+<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+<script type="application/javascript"><![CDATA[
+
+function runTest(menuid)
+{
+ let menu = $(menuid);
+ let dropmarker = document.getAnonymousElementByAttribute(menu, "anonid", "dropmarker");
+
+ synthesizeMouseAtCenter(dropmarker, { });
+}
+
+function isWithinHalfPixel(a, b)
+{
+ return Math.abs(a - b) <= 0.5;
+}
+
+function checkPopup(popup, anchor)
+{
+ let popupRect = popup.getBoundingClientRect();
+ let anchorRect = anchor.getBoundingClientRect();
+
+ ok(isWithinHalfPixel(popupRect.left, anchorRect.left), popup.id + " left");
+ ok(isWithinHalfPixel(popupRect.top, anchorRect.bottom), popup.id + " top");
+
+ popup.hidePopup();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menu_hide.xul b/toolkit/content/tests/chrome/test_menu_hide.xul
new file mode 100644
index 000000000..b5ce934db
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menu_hide.xul
@@ -0,0 +1,58 @@
+<?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="Menu Destruction Test"
+ onload="setTimeout(runTests, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<menu id="menu">
+ <menupopup onpopupshown="this.firstChild.open = true" onpopuphidden="if (event.target == this) done()">
+ <menu id="submenu" label="One">
+ <menupopup onpopupshown="submenuOpened();">
+ <menuitem label="Two"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+</menu>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests()
+{
+ $("menu").open = true;
+}
+
+function submenuOpened()
+{
+ var submenu = $("submenu")
+ is(submenu.getAttribute('_moz-menuactive'), "true", "menu highlighted");
+ submenu.hidden = true;
+ $("menu").open = false;
+}
+
+function done()
+{
+ ok(!$("submenu").hasAttribute('_moz-menuactive'), "menu unhighlighted");
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menuchecks.xul b/toolkit/content/tests/chrome/test_menuchecks.xul
new file mode 100644
index 000000000..8128b738c
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menuchecks.xul
@@ -0,0 +1,147 @@
+<?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="Menu Checkbox and Radio Tests"
+ onload="runTest()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <hbox>
+ <button id="menu" type="menu" label="View">
+ <menupopup id="popup" onpopupshown="popupShown()" onpopuphidden="popupHidden()">
+ <menuitem id="toolbar" label="Show Toolbar" type="checkbox"/>
+ <menuitem id="statusbar" label="Show Status Bar" type="checkbox" checked="true"/>
+ <menuitem id="bookmarks" label="Show Bookmarks" type="checkbox" autocheck="false"/>
+ <menuitem id="history" label="Show History" type="checkbox" autocheck="false" checked="true"/>
+ <menuseparator/>
+ <menuitem id="byname" label="By Name" type="radio" name="sort"/>
+ <menuitem id="bydate" label="By Date" type="radio" name="sort" checked="true"/>
+ <menuseparator/>
+ <menuitem id="ascending" label="Ascending" type="radio" name="order" checked="true"/>
+ <menuitem id="descending" label="Descending" type="radio" name="order" autocheck="false"/>
+ <menuitem id="bysubject" label="By Subject" type="radio" name="sort"/>
+ </menupopup>
+ </button>
+
+ </hbox>
+
+ <!--
+ This test checks that checkbox and radio menu items work properly
+ -->
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ SimpleTest.waitForExplicitFinish();
+ var gTestIndex = 0;
+
+ // tests to perform
+ var tests = [
+ {
+ testname: "select unchecked checkbox",
+ item: "toolbar",
+ checked: ["toolbar", "statusbar", "history", "bydate", "ascending"]
+ },
+ {
+ testname: "select checked checkbox",
+ item: "statusbar",
+ checked: ["toolbar", "history", "bydate", "ascending"]
+ },
+ {
+ testname: "select unchecked autocheck checkbox",
+ item: "bookmarks",
+ checked: ["toolbar", "history", "bydate", "ascending"]
+ },
+ {
+ testname: "select checked autocheck checkbox",
+ item: "history",
+ checked: ["toolbar", "history", "bydate", "ascending"]
+ },
+ {
+ testname: "select unchecked radio",
+ item: "byname",
+ checked: ["toolbar", "history", "byname", "ascending"]
+ },
+ {
+ testname: "select checked radio",
+ item: "byname",
+ checked: ["toolbar", "history", "byname", "ascending"]
+ },
+ {
+ testname: "select out of order checked radio",
+ item: "bysubject",
+ checked: ["toolbar", "history", "bysubject", "ascending"]
+ },
+ {
+ testname: "select first radio again",
+ item: "byname",
+ checked: ["toolbar", "history", "byname", "ascending"]
+ },
+ {
+ testname: "select autocheck radio",
+ item: "descending",
+ checked: ["toolbar", "history", "byname", "ascending"]
+ }
+ ];
+
+ function runTest()
+ {
+ checkMenus(["statusbar", "history", "bydate", "ascending"], "initial");
+ document.getElementById("menu").open = true;
+ }
+
+ function checkMenus(checkedItems, testname)
+ {
+ var isok = true;
+ var children = document.getElementById("popup").childNodes;
+ for (var c = 0; c < children.length; c++) {
+ var child = children[c];
+ if ((checkedItems.indexOf(child.id) != -1 && child.getAttribute("checked") != "true") ||
+ (checkedItems.indexOf(child.id) == -1 && child.hasAttribute("checked"))) {
+ isok = false;
+ break;
+ }
+ }
+
+ ok(isok, testname);
+ }
+
+ function popupShown()
+ {
+ var test = tests[gTestIndex];
+ synthesizeMouse(document.getElementById(test.item), 4, 4, { });
+ }
+
+ function popupHidden()
+ {
+ if (gTestIndex < tests.length) {
+ var test = tests[gTestIndex];
+ checkMenus(test.checked, test.testname);
+ gTestIndex++;
+ if (gTestIndex < tests.length) {
+ document.getElementById("menu").open = true;
+ }
+ else {
+ // manually setting the checkbox should also update the radio state
+ document.getElementById("bydate").setAttribute("checked", "true");
+ checkMenus(["toolbar", "history", "bydate", "ascending"], "set checked attribute on radio");
+ SimpleTest.finish();
+ }
+ }
+ }
+
+ ]]>
+ </script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menuitem_blink.xul b/toolkit/content/tests/chrome/test_menuitem_blink.xul
new file mode 100644
index 000000000..319c284fd
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menuitem_blink.xul
@@ -0,0 +1,106 @@
+<?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="Blinking Context Menu Item Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+ <menulist id="menulist">
+ <menupopup id="menupopup">
+ <menuitem label="Menu Item" id="menuitem"/>
+ </menupopup>
+ </menulist>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(startTest);
+
+function startTest() {
+ if (!/Mac/.test(navigator.platform)) {
+ ok(true, "Nothing to test on non-Mac.");
+ SimpleTest.finish();
+ return;
+ }
+ // Destroy frame while removing the _moz-menuactive attribute.
+ test_crash("REMOVAL", test2);
+}
+
+function test2() {
+ // Destroy frame while adding the _moz-menuactive attribute.
+ test_crash("ADDITION", test3);
+}
+
+function test3() {
+ // Don't mess with the frame, just test whether we've blinked.
+ test_crash("", SimpleTest.finish);
+}
+
+function test_crash(when, andThen) {
+ var menupopup = document.getElementById("menupopup");
+ var menuitem = document.getElementById("menuitem");
+ var attrChanges = { "REMOVAL": 0, "ADDITION": 0 };
+ var storedEvent = null;
+ menupopup.addEventListener("popupshown", function () {
+ menupopup.removeEventListener("popupshown", arguments.callee, false);
+ menuitem.addEventListener("mouseup", function (e) {
+ menuitem.removeEventListener("mouseup", arguments.callee, true);
+ menuitem.addEventListener("DOMAttrModified", function (e) {
+ if (e.attrName == "_moz-menuactive") {
+ if (!attrChanges[e.attrChange])
+ attrChanges[e.attrChange] = 1;
+ else
+ attrChanges[e.attrChange]++;
+ storedEvent = e;
+ if (e.attrChange == e[when]) {
+ menuitem.hidden = true;
+ menuitem.getBoundingClientRect();
+ ok(true, "Didn't crash on _moz-menuactive " + when.toLowerCase() + " during blinking")
+ menuitem.hidden = false;
+ menuitem.removeEventListener("DOMAttrModified", arguments.callee, false);
+ SimpleTest.executeSoon(function () {
+ menupopup.hidePopup();
+ });
+ }
+ }
+ }, false);
+ }, true);
+ menupopup.addEventListener("popuphidden", function() {
+ menupopup.removeEventListener("popuphidden", arguments.callee, false);
+ if (!when) {
+ // Test whether we've blinked at all.
+ var shouldBlink = navigator.platform.match(/Mac/);
+ var expectedNumRemoval = shouldBlink ? 2 : 1;
+ var expectedNumAddition = shouldBlink ? 1 : 0;
+ ok(storedEvent, "got DOMAttrModified events after clicking menuitem")
+ is(attrChanges[storedEvent.REMOVAL], expectedNumRemoval, "blinking unset attributes correctly");
+ is(attrChanges[storedEvent.ADDITION], expectedNumAddition, "blinking set attributes correctly");
+ }
+ SimpleTest.executeSoon(andThen);
+ }, false);
+ synthesizeMouse(menuitem, 10, 5, { type : "mousemove" });
+ synthesizeMouse(menuitem, 10, 5, { type : "mousemove" });
+ synthesizeMouse(menuitem, 10, 5, { type : "mousedown" });
+ SimpleTest.executeSoon(function () {
+ synthesizeMouse(menuitem, 10, 5, { type : "mouseup" });
+ });
+ }, false);
+ document.getElementById("menulist").open = true;
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menuitem_commands.xul b/toolkit/content/tests/chrome/test_menuitem_commands.xul
new file mode 100644
index 000000000..e31774ccc
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menuitem_commands.xul
@@ -0,0 +1,104 @@
+<?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="Menuitem Commands Test"
+ onload="runOrOpen()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function checkAttributes(elem, label, accesskey, disabled, hidden, isAfter)
+{
+ var is = window.opener.wrappedJSObject.SimpleTest.is;
+
+ is(elem.getAttribute("label"), label, elem.id + " label " + (isAfter ? "after" : "before") + " open");
+ is(elem.getAttribute("accesskey"), accesskey, elem.id + " accesskey " + (isAfter ? "after" : "before") + " open");
+ is(elem.getAttribute("disabled"), disabled, elem.id + " disabled " + (isAfter ? "after" : "before") + " open");
+ is(elem.getAttribute("hidden"), hidden, elem.id + " hidden " + (isAfter ? "after" : "before") + " open");
+}
+
+function runOrOpen()
+{
+ if (window.opener) {
+ SimpleTest.waitForFocus(runTest);
+ }
+ else {
+ window.open("test_menuitem_commands.xul", "", "chrome");
+ }
+}
+
+function runTest()
+{
+ runTestSet("");
+ runTestSet("bar");
+ window.close();
+ window.opener.wrappedJSObject.SimpleTest.finish();
+}
+
+function runTestSet(suffix)
+{
+ var isMac = (navigator.platform.indexOf("Mac") >= 0);
+
+ var one = $("one" + suffix);
+ var two = $("two" + suffix);
+ var three = $("three" + suffix);
+ var four = $("four" + suffix);
+
+ checkAttributes(one, "One", "", "", "true", false);
+ checkAttributes(two, "", "", "false", "", false);
+ checkAttributes(three, "Three", "T", "true", "", false);
+ checkAttributes(four, "Four", "F", "", "", false);
+
+ if (isMac && suffix) {
+ var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
+ getInterface(Components.interfaces.nsIDOMWindowUtils);
+ utils.forceUpdateNativeMenuAt("0");
+ }
+ else {
+ $("menu" + suffix).open = true;
+ }
+
+ checkAttributes(one, "One", "", "", "false", true);
+ checkAttributes(two, "Cat", "C", "", "", true);
+ checkAttributes(three, "Dog", "D", "false", "true", true);
+ checkAttributes(four, "Four", "F", "true", "", true);
+
+ $("menu" + suffix).open = false;
+}
+]]>
+</script>
+
+<command id="cmd_one" hidden="false"/>
+<command id="cmd_two" label="Cat" accesskey="C"/>
+<command id="cmd_three" label="Dog" accesskey="D" disabled="false" hidden="true"/>
+<command id="cmd_four" disabled="true"/>
+
+<button id="menu" type="menu">
+ <menupopup>
+ <menuitem id="one" label="One" hidden="true" command="cmd_one"/>
+ <menuitem id="two" disabled="false" command="cmd_two"/>
+ <menuitem id="three" label="Three" accesskey="T" disabled="true" command="cmd_three"/>
+ <menuitem id="four" label="Four" accesskey="F" command="cmd_four"/>
+ </menupopup>
+</button>
+
+<menubar>
+ <menu id="menubar" label="Sample">
+ <menupopup>
+ <menuitem id="onebar" label="One" hidden="true" command="cmd_one"/>
+ <menuitem id="twobar" disabled="false" command="cmd_two"/>
+ <menuitem id="threebar" label="Three" accesskey="T" disabled="true" command="cmd_three"/>
+ <menuitem id="fourbar" label="Four" accesskey="F" command="cmd_four"/>
+ </menupopup>
+ </menu>
+</menubar>
+
+<body xmlns="http://www.w3.org/1999/xhtml"><p id="display"/></body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menulist.xul b/toolkit/content/tests/chrome/test_menulist.xul
new file mode 100644
index 000000000..4e3817d89
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menulist.xul
@@ -0,0 +1,314 @@
+<?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="Menulist Tests"
+ onload="setTimeout(testtag_menulists, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+ <script type="application/javascript" src="xul_selectcontrol.js"></script>
+
+<vbox id="scroller" style="overflow: auto" height="60">
+ <menulist id="menulist" onpopupshown="test_menulist_open(this, this.parentNode)"
+ onpopuphidden="$('menulist-in-listbox').open = true;">
+ <menupopup id="menulist-popup"/>
+ </menulist>
+ <button label="Two"/>
+ <button label="Three"/>
+</vbox>
+<listbox id="scroller-in-listbox" style="overflow: auto" height="60">
+ <listitem allowevents="true">
+ <menulist id="menulist-in-listbox" onpopupshown="test_menulist_open(this, this.parentNode.parentNode)"
+ onpopuphidden="SimpleTest.executeSoon(checkScrollAndFinish)">
+ <menupopup id="menulist-in-listbox-popup">
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ </menupopup>
+ </menulist>
+ </listitem>
+ <listitem label="Two"/>
+ <listitem label="Three"/>
+ <listitem label="Four"/>
+ <listitem label="Five"/>
+ <listitem label="Six"/>
+</listbox>
+
+<hbox>
+ <menulist id="menulist-size">
+ <menupopup>
+ <menuitem label="Menuitem Label" width="200"/>
+ </menupopup>
+ </menulist>
+</hbox>
+
+<menulist id="menulist-editable" editable="true">
+ <menupopup id="menulist-popup-editable"/>
+</menulist>
+
+<menulist id="menulist-initwithvalue" value="two">
+ <menupopup>
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ <menuitem label="Three" value="three"/>
+ </menupopup>
+</menulist>
+<menulist id="menulist-initwithselected" value="two">
+ <menupopup>
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ <menuitem label="Three" value="three" selected="true"/>
+ </menupopup>
+</menulist>
+<menulist id="menulist-editable-initwithvalue" editable="true" value="Two">
+ <menupopup>
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ <menuitem label="Three" value="three"/>
+ </menupopup>
+</menulist>
+<menulist id="menulist-editable-initwithselected" editable="true" value="two">
+ <menupopup>
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ <menuitem label="Three" value="three" selected="true"/>
+ </menupopup>
+</menulist>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function testtag_menulists()
+{
+ testtag_menulist_UI_start($("menulist"), false);
+}
+
+function testtag_menulist_UI_start(element, editable)
+{
+ var testprefix = editable ? "editable" : "";
+
+ // check the menupopup property
+ var popup = element.menupopup;
+ ok(popup && popup.localName == "menupopup" &&
+ popup.parentNode == element, testprefix + " menupopup");
+
+ // test the interfaces that menulist implements
+ test_nsIDOMXULMenuListElement(element, testprefix, editable);
+}
+
+function testtag_menulist_UI_finish(element, editable)
+{
+ element.value = "";
+
+ test_nsIDOMXULSelectControlElement(element, "menuitem",
+ editable ? "editable" : null);
+
+ if (!editable) {
+ testtag_menulist_UI_start($("menulist-editable"), true);
+ }
+ else {
+ // bug 566154, the menulist width should account for vertical scrollbar
+ ok(document.getElementById("menulist-size").getBoundingClientRect().width >= 210,
+ "menulist popup width includes scrollbar width");
+
+ $("menulist").open = true;
+ }
+}
+
+function test_nsIDOMXULMenuListElement(element, testprefix, editable)
+{
+ is(element.open, false, testprefix + " open");
+ is(element.editable, editable, testprefix + " editable");
+
+ if (editable) {
+ var inputField = element.inputField;
+ is(inputField &&
+ inputField instanceof Components.interfaces.nsIDOMHTMLInputElement,
+ true, testprefix + " inputField");
+
+ // check if the select method works
+ inputField.select();
+ is(inputField.selectionStart, 0, testprefix + " empty select selectionStart");
+ is(inputField.selectionEnd, 0, testprefix + " empty select selectionEnd");
+
+ element.value = "Some Text";
+ inputField.select();
+ is(inputField.selectionStart, 0, testprefix + " empty select selectionStart");
+ is(inputField.selectionEnd, 9, testprefix + " empty select selectionEnd");
+ }
+ else {
+ is(element.inputField, null , testprefix + " inputField");
+ }
+
+ element.appendItem("Item One", "one");
+ var seconditem = element.appendItem("Item Two", "two");
+ var thirditem = element.appendItem("Item Three", "three");
+ element.appendItem("Item Four", "four");
+
+ seconditem.image = "happy.png";
+ seconditem.setAttribute("description", "This is the second description");
+ thirditem.image = "happy.png";
+ thirditem.setAttribute("description", "This is the third description");
+
+ // check the image and description properties
+ // editable menulists don't use the image or description properties currently
+ if (editable) {
+ element.selectedIndex = 1;
+ is(element.image, "", testprefix + " image set to selected");
+ is(element.description, "", testprefix + " description set to selected");
+ test_nsIDOMXULMenuListElement_finish(element, testprefix, editable);
+ }
+ else {
+ element.selectedIndex = 1;
+ is(element.image, "happy.png", testprefix + " image set to selected");
+ is(element.description, "This is the second description", testprefix + " description set to selected");
+ element.selectedIndex = -1;
+ is(element.image, "", testprefix + " image set when none selected");
+ is(element.description, "", testprefix + " description set when none selected");
+ element.selectedIndex = 2;
+ is(element.image, "happy.png", testprefix + " image set to selected again");
+ is(element.description, "This is the third description", testprefix + " description set to selected again");
+
+ // check that changing the properties of the selected item changes the menulist's properties
+ let properties = [{attr: "label", value: "Item Number Three"},
+ {attr: "value", value: "item-three"},
+ {attr: "image", value: "smile.png"},
+ {attr: "description", value: "Changed description"}];
+ test_nsIDOMXULMenuListElement_properties(element, testprefix, editable, thirditem, properties);
+ }
+}
+
+function test_nsIDOMXULMenuListElement_properties(element, testprefix, editable, thirditem, properties)
+{
+ let {attr, value} = properties.shift();
+ let last = (properties.length == 0);
+
+ let mutObserver = new MutationObserver(() => {
+ is(element.getAttribute(attr), value, `${testprefix} ${attr} modified`);
+ done();
+ });
+ mutObserver.observe(element, { attributeFilter: [attr] });
+
+ let failureTimeout = setTimeout(() => {
+ ok(false, `${testprefix} ${attr} should have updated`);
+ done();
+ }, 2000);
+
+ function done()
+ {
+ clearTimeout(failureTimeout);
+ mutObserver.disconnect();
+ if (!last) {
+ test_nsIDOMXULMenuListElement_properties(element, testprefix, editable, thirditem, properties);
+ }
+ else {
+ test_nsIDOMXULMenuListElement_unselected(element, testprefix, editable, thirditem);
+ }
+ }
+
+ thirditem.setAttribute(attr, value)
+}
+
+function test_nsIDOMXULMenuListElement_unselected(element, testprefix, editable, thirditem)
+{
+ let seconditem = thirditem.previousElementSibling;
+ seconditem.label = "Changed Label 2";
+ is(element.label, "Item Number Three", testprefix + " label of another item modified");
+
+ element.selectedIndex = 0;
+ is(element.image, "", testprefix + " image set to selected with no image");
+ is(element.description, "", testprefix + " description set to selected with no description");
+ test_nsIDOMXULMenuListElement_finish(element, testprefix, editable);
+}
+
+function test_nsIDOMXULMenuListElement_finish(element, testprefix, editable)
+{
+ // check the removeAllItems method
+ element.appendItem("An Item", "anitem");
+ element.appendItem("Another Item", "anotheritem");
+ element.removeAllItems();
+ is(element.itemCount, 0, testprefix + " removeAllItems");
+
+ testtag_menulist_UI_finish(element, editable);
+}
+
+function test_menulist_open(element, scroller)
+{
+ element.appendItem("Scroll Item 1", "scrollitem1");
+ element.appendItem("Scroll Item 2", "scrollitem2");
+ element.focus();
+ element.selectedIndex = 0;
+
+/*
+ // bug 530504, mousewheel while menulist is open should not scroll menulist
+ // items or parent
+ var scrolled = false;
+ var mouseScrolled = function (event) { scrolled = true; }
+ window.addEventListener("DOMMouseScroll", mouseScrolled, false);
+ synthesizeWheel(element, 2, 2, { deltaY: 10,
+ deltaMode: WheelEvent.DOM_DELTA_LINE });
+ is(scrolled, true, "mousescroll " + element.id);
+ is(scroller.scrollTop, 0, "scroll position on mousescroll " + element.id);
+ window.removeEventListener("DOMMouseScroll", mouseScrolled, false);
+*/
+
+ // bug 543065, hovering the mouse over an item should highlight it, not
+ // scroll the parent, and not change the selected index.
+ var item = element.menupopup.childNodes[1];
+
+ synthesizeMouse(element.menupopup.childNodes[1], 2, 2, { type: "mousemove" });
+ synthesizeMouse(element.menupopup.childNodes[1], 6, 6, { type: "mousemove" });
+ is(element.menuBoxObject.activeChild, item, "activeChild after menu highlight " + element.id);
+ is(element.selectedIndex, 0, "selectedIndex after menu highlight " + element.id);
+ is(scroller.scrollTop, 0, "scroll position after menu highlight " + element.id);
+
+ element.open = false;
+}
+
+function checkScrollAndFinish()
+{
+ is($("scroller").scrollTop, 0, "mousewheel on menulist does not scroll vbox parent");
+ is($("scroller-in-listbox").scrollTop, 0, "mousewheel on menulist does not scroll listbox parent");
+
+ // bug 561243, outline causes the mouse click to be targeted incorrectly
+ var editableMenulist = $("menulist-editable");
+ editableMenulist.className = "outlined";
+
+ synthesizeMouse(editableMenulist.inputField, 25, 8, { type: "mousedown" });
+ synthesizeMouse(editableMenulist.inputField, 25, 8, { type: "mouseup" });
+ isnot(editableMenulist.inputField.selectionStart, editableMenulist.inputField.textLength,
+ "mouse event on editable menulist with outline caret position");
+
+ let menulist = $("menulist-size");
+ menulist.addEventListener("popupshown", function testAltClose() {
+ menulist.removeEventListener("popupshown", testAltClose);
+
+ sendKey("ALT");
+ is(menulist.menupopup.state, "open", "alt doesn't close menulist");
+ menulist.open = false;
+
+ SimpleTest.finish();
+ });
+
+ menulist.open = true;
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<style>
+.outlined > .menulist-editable-box { outline: 1px solid black; }
+</style>
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menulist_keynav.xul b/toolkit/content/tests/chrome/test_menulist_keynav.xul
new file mode 100644
index 000000000..c2e404c09
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menulist_keynav.xul
@@ -0,0 +1,272 @@
+<?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="Menulist Key Navigation Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<button id="button1" label="One"/>
+<menulist id="list">
+ <menupopup id="popup" onpopupshowing="return gShowPopup;">
+ <menuitem id="i1" label="One"/>
+ <menuitem id="i2" label="Two"/>
+ <menuitem id="i2b" disabled="true" label="Two and a Half"/>
+ <menuitem id="i3" label="Three"/>
+ <menuitem id="i4" label="Four"/>
+ </menupopup>
+</menulist>
+<button id="button2" label="Two"/>
+<menulist id="list2">
+ <menupopup id="popup" onpopupshown="checkCursorNavigation();">
+ <menuitem id="b1" label="One"/>
+ <menuitem id="b2" label="Two" selected="true"/>
+ <menuitem id="b3" label="Three"/>
+ <menuitem id="b4" label="Four"/>
+ </menupopup>
+</menulist>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gShowPopup = false;
+var gModifiers = 0;
+var gOpenPhase = false;
+
+var list = $("list");
+let expectCommandEvent;
+
+var iswin = (navigator.platform.indexOf("Win") == 0);
+var ismac = (navigator.platform.indexOf("Mac") == 0);
+
+function runTests()
+{
+ list.focus();
+
+ // on Mac, up and cursor keys open the menu, but on other platforms, the
+ // cursor keys navigate between items without opening the menu
+ if (navigator.platform.indexOf("Mac") == -1) {
+ expectCommandEvent = true;
+ keyCheck(list, "VK_DOWN", 2, "cursor down");
+ keyCheck(list, "VK_DOWN", 3, "cursor down skip disabled");
+ keyCheck(list, "VK_UP", 2, "cursor up skip disabled");
+ keyCheck(list, "VK_UP", 1, "cursor up");
+ keyCheck(list, "VK_UP", 4, "cursor up wrap");
+ keyCheck(list, "VK_DOWN", 1, "cursor down wrap");
+ }
+
+ // check that attempting to open the menulist does not change the selection
+ synthesizeKey("VK_DOWN", { altKey: navigator.platform.indexOf("Mac") == -1 });
+ is(list.selectedItem, $("i1"), "open menulist down selectedItem");
+ synthesizeKey("VK_UP", { altKey: navigator.platform.indexOf("Mac") == -1 });
+ is(list.selectedItem, $("i1"), "open menulist up selectedItem");
+
+ list.selectedItem = $("i1");
+
+ pressLetter();
+}
+
+function pressLetter()
+{
+ // A command event should be fired only if the menulist is closed, or on Windows,
+ // where items are selected immediately.
+ expectCommandEvent = !gOpenPhase || iswin;
+
+ synthesizeKey("G", { });
+ is(list.selectedItem, $("i1"), "letter pressed not found selectedItem");
+
+ keyCheck(list, "T", 2, "letter pressed");
+
+ if (!gOpenPhase) {
+ SpecialPowers.setIntPref("ui.menu.incremental_search.timeout", 0); // prevent to timeout
+ keyCheck(list, "T", 2, "same letter pressed");
+ SpecialPowers.clearUserPref("ui.menu.incremental_search.timeout");
+ }
+
+ setTimeout(pressedAgain, 1200);
+}
+
+function pressedAgain()
+{
+ keyCheck(list, "T", 3, "letter pressed again");
+ SpecialPowers.setIntPref("ui.menu.incremental_search.timeout", 0); // prevent to timeout
+ keyCheck(list, "W", 2, "second letter pressed");
+ SpecialPowers.clearUserPref("ui.menu.incremental_search.timeout");
+ setTimeout(differentPressed, 1200);
+}
+
+function differentPressed()
+{
+ keyCheck(list, "O", 1, "different letter pressed");
+
+ if (gOpenPhase) {
+ list.open = false;
+ tabAndScroll();
+ }
+ else {
+ // Run the letter tests again with the popup open
+ info("list open phase");
+
+ list.selectedItem = $("i1");
+
+ // Hide and show the list to avoid using any existing incremental key state.
+ list.hidden = true;
+ list.clientWidth;
+ list.hidden = false;
+
+ gShowPopup = true;
+ gOpenPhase = true;
+
+ list.addEventListener("popupshown", function popupShownListener() {
+ list.removeEventListener("popupshown", popupShownListener, false);
+ pressLetter();
+ }, false);
+
+ list.open = true;
+ }
+}
+
+function tabAndScroll()
+{
+ list = $("list");
+
+ if (navigator.platform.indexOf("Mac") == -1) {
+ $("button1").focus();
+ synthesizeKeyExpectEvent("VK_TAB", { }, list, "focus", "focus to menulist");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("button2"), "focus", "focus to button");
+ is(document.activeElement, $("button2"), "tab from menulist focused button");
+ }
+
+ // now make sure that using a key scrolls the menu correctly
+
+ for (let i = 0; i < 65; i++) {
+ list.appendItem("Item" + i, "item" + i);
+ }
+ list.open = true;
+ is(list.getBoundingClientRect().width, list.firstChild.getBoundingClientRect().width,
+ "menu and popup width match");
+ var minScrollbarWidth = window.matchMedia("(-moz-overlay-scrollbars)").matches ? 0 : 3;
+ ok(list.getBoundingClientRect().width >= list.getItemAtIndex(0).getBoundingClientRect().width + minScrollbarWidth,
+ "menuitem width accounts for scrollbar");
+ list.open = false;
+
+ list.menupopup.maxHeight = 100;
+ list.open = true;
+
+ var rowdiff = list.getItemAtIndex(1).getBoundingClientRect().top -
+ list.getItemAtIndex(0).getBoundingClientRect().top;
+
+ var item = list.getItemAtIndex(10);
+ var originalPosition = item.getBoundingClientRect().top;
+
+ list.menuBoxObject.activeChild = item;
+ ok(item.getBoundingClientRect().top < originalPosition,
+ "position of item 1: " + item.getBoundingClientRect().top + " -> " + originalPosition);
+
+ originalPosition = item.getBoundingClientRect().top;
+
+ synthesizeKey("VK_DOWN", { });
+ is(item.getBoundingClientRect().top, originalPosition - rowdiff, "position of item 10");
+
+ list.open = false;
+
+ checkEnter();
+}
+
+function keyCheck(list, key, index, testname)
+{
+ var item = $("i" + index);
+ synthesizeKeyExpectEvent(key, { }, item, expectCommandEvent ? "command" : "!command", testname);
+ is(list.selectedItem, expectCommandEvent ? item : $("i1"), testname + " selectedItem");
+}
+
+function checkModifiers(event)
+{
+ var expectedModifiers = (gModifiers == 1);
+ is(event.shiftKey, expectedModifiers, "shift key pressed");
+ is(event.ctrlKey, expectedModifiers, "ctrl key pressed");
+ is(event.altKey, expectedModifiers, "alt key pressed");
+ is(event.metaKey, expectedModifiers, "meta key pressed");
+ gModifiers++;
+}
+
+function checkEnter()
+{
+ list.addEventListener("popuphidden", checkEnterWithModifiers, false);
+ list.addEventListener("command", checkModifiers, false);
+ list.open = true;
+ synthesizeKey("VK_RETURN", { });
+}
+
+function checkEnterWithModifiers()
+{
+ is(gModifiers, 1, "modifiers checked when not set");
+
+ ok(!list.open, "list closed on enter press");
+ list.removeEventListener("popuphidden", checkEnterWithModifiers, false);
+
+ list.addEventListener("popuphidden", verifyPopupOnClose, false);
+ list.open = true;
+
+ synthesizeKey("VK_RETURN", { shiftKey: true, ctrlKey: true, altKey: true, metaKey: true });
+}
+
+function verifyPopupOnClose()
+{
+ is(gModifiers, 2, "modifiers checked when set");
+
+ ok(!list.open, "list closed on enter press with modifiers");
+ list.removeEventListener("popuphidden", verifyPopupOnClose, false);
+
+ list = $("list2");
+ list.focus();
+ list.open = true;
+}
+
+function checkCursorNavigation()
+{
+ var commandEventsCount = 0;
+ list.addEventListener("command", event => {
+ is(event.target, list.selectedItem, "command event fired on selected item");
+ commandEventsCount++;
+ }, false);
+
+ is(list.selectedIndex, 1, "selectedIndex before cursor down");
+ synthesizeKey("VK_DOWN", { });
+ is(list.selectedIndex, iswin ? 2 : 1, "selectedIndex after cursor down");
+ is(commandEventsCount, iswin ? 1 : 0, "selectedIndex after cursor down command event");
+ is(list.menupopup.state, "open", "cursor down popup state");
+ synthesizeKey("VK_PAGE_DOWN", { });
+ is(list.selectedIndex, iswin ? 3 : 1, "selectedIndex after page down");
+ is(commandEventsCount, iswin ? 2 : 0, "selectedIndex after page down command event");
+ is(list.menupopup.state, "open", "page down popup state");
+
+ synthesizeKey("VK_UP", { altKey: true });
+ is(list.open, ismac, "alt+up closes popup");
+
+ if (ismac) {
+ list.open = false;
+ }
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(runTests);
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menulist_null_value.xul b/toolkit/content/tests/chrome/test_menulist_null_value.xul
new file mode 100644
index 000000000..2545b6cde
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menulist_null_value.xul
@@ -0,0 +1,96 @@
+<?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="Menulist value property"
+ onload="setTimeout(runTests, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<menulist id="list">
+ <menupopup>
+ <menuitem id="i0" label="Zero" value="0"/>
+ <menuitem id="i1" label="One" value="item1"/>
+ <menuitem id="i2" label="Two" value="item2"/>
+ <menuitem id="ifalse" label="False" value="false"/>
+ <menuitem id="iempty" label="Empty" value=""/>
+ </menupopup>
+</menulist>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests()
+{
+ var list = document.getElementById("list");
+
+ list.value = "item2";
+ is(list.value, "item2", "Check list value after setting value");
+ is(list.getAttribute("label"), "Two", "Check list label after setting value");
+
+ list.selectedItem = null;
+ is(list.value, "", "Check list value after setting selectedItem to null");
+ is(list.getAttribute("label"), "", "Check list label after setting selectedItem to null");
+
+ // select something again to make sure the label is not already empty
+ list.selectedIndex = 1;
+ is(list.value, "item1", "Check list value after setting selectedIndex");
+ is(list.getAttribute("label"), "One", "Check list label after setting selectedIndex");
+
+ // check that an item can have the "false" value
+ list.value = false;
+ is(list.value, "false", "Check list value after setting it to false");
+ is(list.getAttribute("label"), "False", "Check list labem after setting value to false");
+
+ // check that an item can have the "0" value
+ list.value = 0;
+ is(list.value, "0", "Check list value after setting it to 0");
+ is(list.getAttribute("label"), "Zero", "Check list label after setting value to 0");
+
+ // check that an item can have the empty string value.
+ list.value = "";
+ is(list.value, "", "Check list value after setting it to an empty string");
+ is(list.getAttribute("label"), "Empty", "Check list label after setting value to an empty string");
+
+ // select something again to make sure the label is not already empty
+ list.selectedIndex = 1;
+ // set the value to null and test it (bug 408940)
+ list.value = null;
+ is(list.value, "", "Check list value after setting value to null");
+ is(list.getAttribute("label"), "", "Check list label after setting value to null");
+
+ // select something again to make sure the label is not already empty
+ list.selectedIndex = 1;
+ // set the value to undefined and test it (bug 408940)
+ list.value = undefined;
+ is(list.value, "", "Check list value after setting value to undefined");
+ is(list.getAttribute("label"), "", "Check list label after setting value to undefined");
+
+ // select something again to make sure the label is not already empty
+ list.selectedIndex = 1;
+ // set the value to something that does not exist in any menuitem of the list
+ // and make sure the previous label is removed
+ list.value = "this does not exist";
+ is(list.value, "this does not exist", "Check the list value after setting it to something not associated witn an existing menuitem");
+ is(list.getAttribute("label"), "", "Check that the list label is empty after selecting a nonexistent item");
+
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menulist_paging.xul b/toolkit/content/tests/chrome/test_menulist_paging.xul
new file mode 100644
index 000000000..c58e0328f
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menulist_paging.xul
@@ -0,0 +1,163 @@
+<?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="Menulist Tests"
+ onload="setTimeout(startTest, 0);"
+ onpopupshown="menulistShown()" onpopuphidden="runTest()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<menulist id="menulist1">
+ <menupopup id="menulist-popup1">
+ <menuitem label="One"/>
+ <menuitem label="Two"/>
+ <menuitem label="Three"/>
+ <menuitem label="Four"/>
+ <menuitem label="Five"/>
+ <menuitem label="Six"/>
+ <menuitem label="Seven"/>
+ <menuitem label="Eight"/>
+ <menuitem label="Nine"/>
+ <menuitem label="Ten"/>
+ </menupopup>
+</menulist>
+
+<menulist id="menulist2">
+ <menupopup id="menulist-popup2">
+ <menuitem label="One" disabled="true"/>
+ <menuitem label="Two" selected="true"/>
+ <menuitem label="Three"/>
+ <menuitem label="Four"/>
+ <menuitem label="Five"/>
+ <menuitem label="Six"/>
+ <menuitem label="Seven"/>
+ <menuitem label="Eight"/>
+ <menuitem label="Nine"/>
+ <menuitem label="Ten" disabled="true"/>
+ </menupopup>
+</menulist>
+
+<menulist id="menulist3">
+ <menupopup id="menulist-popup3">
+ <label value="One"/>
+ <menuitem label="Two" selected="true"/>
+ <menuitem label="Three"/>
+ <menuitem label="Four"/>
+ <menuitem label="Five" disabled="true"/>
+ <menuitem label="Six" disabled="true"/>
+ <menuitem label="Seven"/>
+ <menuitem label="Eight"/>
+ <menuitem label="Nine"/>
+ <label value="Ten"/>
+ </menupopup>
+</menulist>
+
+<menulist id="menulist4">
+ <menupopup id="menulist-popup4">
+ <label value="One"/>
+ <menuitem label="Two"/>
+ <menuitem label="Three"/>
+ <menuitem label="Four"/>
+ <menuitem label="Five"/>
+ <menuitem label="Six" selected="true"/>
+ <menuitem label="Seven"/>
+ <menuitem label="Eight"/>
+ <menuitem label="Nine"/>
+ <label value="Ten"/>
+ </menupopup>
+</menulist>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+let test;
+
+// Fields:
+// list - menulist id
+// initial - initial selected index
+// scroll - index of item at top of the visible scrolled area, -1 to skip this test
+// downs - array of indicies that will be selected when pressing down in sequence
+// ups - array of indicies that will be selected when pressing up in sequence
+let tests = [
+ { list: "menulist1", initial: 0, scroll: 0, downs: [3, 6, 9, 9],
+ ups: [6, 3, 0, 0] },
+ { list: "menulist2", initial: 1, scroll: 0, downs: [4, 7, 8, 8],
+ ups: [5, 2, 1] },
+ { list: "menulist3", initial: 1, scroll: -1, downs: [6, 8, 8],
+ ups: [3, 1, 1] },
+ { list: "menulist4", initial: 5, scroll: 2, downs: [], ups: [] }
+];
+
+function startTest()
+{
+ let popup = document.getElementById("menulist-popup1");
+ let menupopupHeight = popup.getBoundingClientRect().height;
+ let menuitemHeight = popup.firstChild.getBoundingClientRect().height;
+
+ // First, set the height of each popup to the height of four menuitems plus
+ // any padding and border on the menupopup.
+ let height = menuitemHeight * 4 + (menupopupHeight - menuitemHeight * 10);
+ popup.height = height;
+ document.getElementById("menulist-popup2").height = height;
+ document.getElementById("menulist-popup3").height = height;
+ document.getElementById("menulist-popup4").height = height;
+
+ runTest();
+}
+
+function runTest()
+{
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ test = tests.shift();
+ document.getElementById(test.list).open = true;
+}
+
+function menulistShown()
+{
+ let menulist = document.getElementById(test.list);
+ is(menulist.menuBoxObject.activeChild.label, menulist.getItemAtIndex(test.initial).label, test.list + " initial selection");
+
+ let cs = window.getComputedStyle(menulist.menupopup);
+ let bpTop = parseFloat(cs.paddingTop) + parseFloat(cs.borderTopWidth);
+
+ // Skip menulist3 as it has a label that scrolling doesn't need normally deal with.
+ if (test.scroll >= 0) {
+ is(menulist.menupopup.childNodes[test.scroll].getBoundingClientRect().top,
+ menulist.menupopup.getBoundingClientRect().top + bpTop,
+ "Popup scroll at correct position");
+ }
+
+ for (let i = 0; i < test.downs.length; i++) {
+ sendKey("PAGE_DOWN");
+ is(menulist.menuBoxObject.activeChild.label, menulist.getItemAtIndex(test.downs[i]).label, test.list + " page down " + i);
+ }
+
+ for (let i = 0; i < test.ups.length; i++) {
+ sendKey("PAGE_UP");
+ is(menulist.menuBoxObject.activeChild.label, menulist.getItemAtIndex(test.ups[i]).label, test.list + " page up " + i);
+ }
+
+ menulist.open = false;
+}
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_menulist_position.xul b/toolkit/content/tests/chrome/test_menulist_position.xul
new file mode 100644
index 000000000..a146cb85e
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menulist_position.xul
@@ -0,0 +1,97 @@
+<?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="Menulist position Test"
+ onload="setTimeout(init, 0)"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<!--
+ This test checks the position of a menulist's popup.
+ -->
+
+<script>
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var menulist;
+
+function init()
+{
+ menulist = document.getElementById("menulist");
+ menulist.open = true;
+}
+
+function isWithinHalfPixel(a, b)
+{
+ return Math.abs(a - b) <= 0.5;
+}
+
+function popupShown()
+{
+ var menurect = menulist.getBoundingClientRect();
+ var popuprect = menulist.menupopup.getBoundingClientRect();
+
+ let marginLeft = parseFloat(getComputedStyle(menulist.menupopup).marginLeft);
+ ok(isWithinHalfPixel(menurect.left + marginLeft, popuprect.left), "left position");
+ ok(isWithinHalfPixel(menurect.right + marginLeft, popuprect.right), "right position");
+
+ let index = menulist.selectedIndex;
+ if (menulist.selectedItem && navigator.platform.indexOf("Mac") >= 0) {
+ let menulistlabel = document.getAnonymousElementByAttribute(menulist, "class", "menulist-label");
+ let mitemlabel = document.getAnonymousElementByAttribute(menulist.selectedItem, "class", "menu-iconic-text");
+
+ ok(isWithinHalfPixel(menulistlabel.getBoundingClientRect().left,
+ mitemlabel.getBoundingClientRect().left),
+ "Labels horizontally aligned for index " + index);
+ ok(isWithinHalfPixel(menulistlabel.getBoundingClientRect().top,
+ mitemlabel.getBoundingClientRect().top),
+ "Labels vertically aligned for index " + index);
+ }
+ else {
+ let marginTop = parseFloat(getComputedStyle(menulist.menupopup).marginTop);
+ ok(isWithinHalfPixel(menurect.bottom + marginTop, popuprect.top),
+ "Vertical alignment with no selection for index " + index);
+ }
+
+ menulist.open = false;
+}
+
+function popupHidden()
+{
+ if (!menulist.selectedItem) {
+ SimpleTest.finish();
+ }
+ else {
+ menulist.selectedItem = menulist.selectedItem.nextSibling;
+ menulist.open = true;
+ }
+}
+]]>
+</script>
+
+<hbox align="center" pack="center" style="margin-top: 100px;">
+ <menulist id="menulist" onpopupshown="popupShown();" onpopuphidden="popupHidden();">
+ <menupopup>
+ <menuitem label="One"/>
+ <menuitem label="Two"/>
+ <menuitem label="Three"/>
+ <menuitem label="Four"/>
+ <menuitem label="Five"/>
+ </menupopup>
+ </menulist>
+</hbox>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_mousescroll.xul b/toolkit/content/tests/chrome/test_mousescroll.xul
new file mode 100644
index 000000000..91ccf5683
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_mousescroll.xul
@@ -0,0 +1,274 @@
+<?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"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=378028
+-->
+<window title="Mozilla Bug 378028"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=378028"
+ target="_blank">Mozilla Bug 378028</a>
+ </body>
+
+ <!-- richlistbox currently has no way of giving us a defined number of
+ rows, so we just choose an arbitrary height limit that should give
+ us plenty of vertical scrollability -->
+ <richlistbox id="richlistbox" style="height:50px;">
+ <richlistitem id="richlistbox_item0" hidden="true"><label value="Item 0"/></richlistitem>
+ <richlistitem id="richlistbox_item1"><label value="Item 1"/></richlistitem>
+ <richlistitem id="richlistbox_item2"><label value="Item 2"/></richlistitem>
+ <richlistitem id="richlistbox_item3"><label value="Item 3"/></richlistitem>
+ <richlistitem id="richlistbox_item4"><label value="Item 4"/></richlistitem>
+ <richlistitem id="richlistbox_item5"><label value="Item 5"/></richlistitem>
+ <richlistitem id="richlistbox_item6"><label value="Item 6"/></richlistitem>
+ <richlistitem id="richlistbox_item7"><label value="Item 7"/></richlistitem>
+ <richlistitem id="richlistbox_item8"><label value="Item 8"/></richlistitem>
+ </richlistbox>
+
+ <listbox id="listbox" rows="2">
+ <listitem id="listbox_item0" label="Item 0" hidden="true"/>
+ <listitem id="listbox_item1" label="Item 1"/>
+ <listitem id="listbox_item2" label="Item 2"/>
+ <listitem id="listbox_item3" label="Item 3"/>
+ <listitem id="listbox_item4" label="Item 4"/>
+ <listitem id="listbox_item5" label="Item 5"/>
+ <listitem id="listbox_item6" label="Item 6"/>
+ <listitem id="listbox_item7" label="Item 7"/>
+ <listitem id="listbox_item8" label="Item 8"/>
+ </listbox>
+
+ <box orient="horizontal">
+ <arrowscrollbox id="hscrollbox" clicktoscroll="true" orient="horizontal"
+ smoothscroll="false" style="max-width:80px;" flex="1">
+ <hbox style="width:40px; height:20px; background:black;" hidden="true"/>
+ <hbox style="width:40px; height:20px; background:white;"/>
+ <hbox style="width:40px; height:20px; background:black;"/>
+ <hbox style="width:40px; height:20px; background:white;"/>
+ <hbox style="width:40px; height:20px; background:black;"/>
+ <hbox style="width:40px; height:20px; background:white;"/>
+ <hbox style="width:40px; height:20px; background:black;"/>
+ <hbox style="width:40px; height:20px; background:white;"/>
+ <hbox style="width:40px; height:20px; background:black;"/>
+ </arrowscrollbox>
+ </box>
+
+ <arrowscrollbox id="vscrollbox" clicktoscroll="true" orient="vertical"
+ smoothscroll="false" style="max-height:80px;" flex="1">
+ <vbox style="width:100px; height:40px; background:black;" hidden="true"/>
+ <vbox style="width:100px; height:40px; background:white;"/>
+ <vbox style="width:100px; height:40px; background:black;"/>
+ <vbox style="width:100px; height:40px; background:white;"/>
+ <vbox style="width:100px; height:40px; background:black;"/>
+ <vbox style="width:100px; height:40px; background:white;"/>
+ <vbox style="width:100px; height:40px; background:black;"/>
+ <vbox style="width:100px; height:40px; background:white;"/>
+ <vbox style="width:100px; height:40px; background:black;"/>
+ <vbox style="width:100px; height:40px; background:white;"/>
+ <vbox style="width:100px; height:40px; background:black;"/>
+ </arrowscrollbox>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+/** Test for Bug 378028 **/
+/* and for Bug 350471 **/
+var smoothScrollPref = "general.smoothScroll";
+SpecialPowers.setBoolPref(smoothScrollPref, false);
+SimpleTest.waitForExplicitFinish();
+
+const deltaModes = [
+ WheelEvent.DOM_DELTA_PIXEL, // 0
+ WheelEvent.DOM_DELTA_LINE, // 1
+ WheelEvent.DOM_DELTA_PAGE // 2
+];
+
+function testListbox(id)
+{
+ var listbox = document.getElementById(id);
+
+ function helper(aStart, aDelta, aIntDelta, aDeltaMode)
+ {
+ listbox.scrollToIndex(aStart);
+ synthesizeWheel(listbox, 10, 10,
+ { deltaMode: aDeltaMode, deltaY: aDelta,
+ lineOrPageDeltaY: aIntDelta });
+ var expectedPos = aStart;
+ if (aIntDelta) {
+ if (aDeltaMode == WheelEvent.DOM_DELTA_PAGE) {
+ expectedPos += aIntDelta > 0 ? listbox.getNumberOfVisibleRows() :
+ -listbox.getNumberOfVisibleRows();
+ } else {
+ expectedPos += aIntDelta;
+ }
+ }
+ is(listbox.getIndexOfFirstVisibleRow(), expectedPos,
+ "testListbox(" + id + "): vertical, starting " + aStart +
+ " delta " + aDelta + " lineOrPageDelta " + aIntDelta +
+ " aDeltaMode " + aDeltaMode);
+
+ // Check that horizontal scrolling has no effect
+ listbox.scrollToIndex(aStart);
+ synthesizeWheel(listbox, 10, 10,
+ { deltaMode: aDeltaMode, deltaX: aDelta,
+ lineOrPageDeltaX: aIntDelta });
+ is(listbox.getIndexOfFirstVisibleRow(), aStart,
+ "testListbox(" + id + "): horizontal, starting " + aStart +
+ " delta " + aDelta + " lineOrPageDelta " + aIntDelta +
+ " aDeltaMode " + aDeltaMode);
+ }
+ deltaModes.forEach(function(aDeltaMode) {
+ let delta = (aDeltaMode == WheelEvent.DOM_DELTA_PIXEL) ? 5.0 : 0.3;
+ helper(5, -delta, 0, aDeltaMode);
+ helper(5, -delta, -1, aDeltaMode);
+ helper(5, delta, 1, aDeltaMode);
+ helper(5, delta, 0, aDeltaMode);
+ });
+}
+
+function testRichListbox(id, andThen)
+{
+ var listbox = document.getElementById(id);
+ var tests = [];
+
+ var winUtils = SpecialPowers.getDOMWindowUtils(window);
+ winUtils.advanceTimeAndRefresh(100);
+
+ function nextTest() {
+ var [aStart, aDelta, aIntDelta, aDeltaMode] = tests.shift();
+ listbox.scrollToIndex(aStart);
+
+ let event = {
+ deltaMode: aDeltaMode,
+ deltaY: aDelta,
+ lineOrPageDeltaY: aIntDelta
+ };
+ sendWheelAndPaint(listbox, 10, 10, event, function() {
+ var change = listbox.getIndexOfFirstVisibleRow() - aStart;
+ var direction = (change > 0) - (change < 0);
+ var expected = (aDelta > 0) - (aDelta < 0);
+ is(direction, expected,
+ "testRichListbox(" + id + "): vertical, starting " + aStart +
+ " delta " + aDelta + " lineOrPageDeltaY " + aIntDelta +
+ " aDeltaMode " + aDeltaMode);
+
+ // Check that horizontal scrolling has no effect
+ let event = {
+ deltaMode: aDeltaMode,
+ deltaX: aDelta,
+ lineOrPageDeltaX: aIntDelta
+ };
+
+ listbox.scrollToIndex(aStart);
+ sendWheelAndPaint(listbox, 10, 10, event, function() {
+ is(listbox.getIndexOfFirstVisibleRow(), aStart,
+ "testRichListbox(" + id + "): horizontal, starting " + aStart +
+ " delta " + aDelta + " lineOrPageDeltaX " + aIntDelta +
+ " aDeltaMode " + aDeltaMode);
+
+ if (!tests.length) {
+ winUtils.restoreNormalRefresh();
+ andThen();
+ return;
+ }
+
+ nextTest();
+ });
+ });
+ }
+
+ // richlistbox currently uses native XUL scrolling, so the "line"
+ // amounts don't necessarily correspond 1-to-1 with listbox items. So
+ // we just check that scrolling up/down scrolls in the right direction.
+ deltaModes.forEach(function(aDeltaMode) {
+ let delta = (aDeltaMode == WheelEvent.DOM_DELTA_PIXEL) ? 32.0 : 2.0;
+ tests.push([5, -delta, -1, aDeltaMode]);
+ tests.push([5, -delta, 0, aDeltaMode]);
+ tests.push([5, delta, 1, aDeltaMode]);
+ tests.push([5, delta, 0, aDeltaMode]);
+ });
+
+ nextTest();
+}
+
+function testArrowScrollbox(id)
+{
+ var scrollbox = document.getElementById(id);
+ var scrollBoxObject = scrollbox.scrollBoxObject;
+ var orient = scrollbox.getAttribute("orient");
+
+ function helper(aStart, aDelta, aDeltaMode, aExpected)
+ {
+ var lineOrPageDelta = (aDeltaMode == WheelEvent.DOM_DELTA_PIXEL) ? aDelta / 10 : aDelta;
+ var orientIsHorizontal = (orient == "horizontal");
+
+ scrollBoxObject.scrollTo(aStart, aStart);
+
+ for (var i = orientIsHorizontal ? 2 : 0; i >= 0; i--) {
+ synthesizeWheel(scrollbox, 5, 5,
+ { deltaMode: aDeltaMode, deltaY: aDelta,
+ lineOrPageDeltaY: lineOrPageDelta });
+
+ var pos = orientIsHorizontal ? scrollBoxObject.positionX :
+ scrollBoxObject.positionY;
+
+ // Note, vertical mouse scrolling is allowed to scroll horizontal
+ // arrowscrollboxes, because many users have no horizontal mouse scroll
+ // capability
+ let expected = !i ? aExpected : aStart;
+ is(pos, expected,
+ "testArrowScrollbox(" + id + "): vertical, starting " + aStart +
+ " delta " + aDelta + " lineOrPageDelta " + lineOrPageDelta +
+ " aDeltaMode " + aDeltaMode);
+ }
+
+ scrollBoxObject.scrollTo(aStart, aStart);
+ for (var i = orientIsHorizontal ? 2 : 0; i >= 0; i--) {
+ synthesizeWheel(scrollbox, 5, 5,
+ { deltaMode: aDeltaMode, deltaX: aDelta,
+ lineOrPageDeltaX: lineOrPageDelta });
+ // horizontal mouse scrolling is never allowed to scroll vertical
+ // arrowscrollboxes
+ var pos = orientIsHorizontal ? scrollBoxObject.positionX :
+ scrollBoxObject.positionY;
+ let expected = (!i && orientIsHorizontal) ? aExpected : aStart;
+ is(pos, expected,
+ "testArrowScrollbox(" + id + "): horizontal, starting " + aStart +
+ " delta " + aDelta + " lineOrPageDelta " + lineOrPageDelta +
+ " aDeltaMode " + aDeltaMode);
+ }
+ }
+
+ var scrolledWidth = scrollBoxObject.scrolledWidth;
+ var scrolledHeight = scrollBoxObject.scrolledHeight;
+ var scrollMaxX = scrolledWidth - scrollBoxObject.width;
+ var scrollMaxY = scrolledHeight - scrollBoxObject.height;
+ var scrollMax = orient == "horizontal" ? scrollMaxX : scrollMaxY;
+
+ deltaModes.forEach(function(aDeltaMode) {
+ helper(50, -1000, aDeltaMode, 0);
+ helper(50, 1000, aDeltaMode, scrollMax);
+ helper(50, 0, aDeltaMode, 50);
+ helper(50, 0, aDeltaMode, 50);
+ });
+}
+
+function runTests()
+{
+ testRichListbox("richlistbox", function() {
+ testListbox("listbox");
+ testArrowScrollbox("hscrollbox");
+ testArrowScrollbox("vscrollbox");
+ SpecialPowers.clearUserPref(smoothScrollPref);
+ SimpleTest.finish();
+ });
+}
+
+window.onload = function() { setTimeout(runTests, 0); };
+ ]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_notificationbox.xul b/toolkit/content/tests/chrome/test_notificationbox.xul
new file mode 100644
index 000000000..a99d0824e
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_notificationbox.xul
@@ -0,0 +1,522 @@
+<?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"?>
+<!--
+ XUL Widget Test for notificationbox
+ -->
+<window title="Notification Box" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <notificationbox id="nb"/>
+ <menupopup id="menupopup" onpopupshown="this.hidePopup()" onpopuphidden="checkPopupClosed()">
+ <menuitem label="One"/>
+ </menupopup>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var testtag_notificationbox_buttons = [
+ {
+ label: "Button 1",
+ accesskey: "u",
+ callback: testtag_notificationbox_buttonpressed,
+ popup: "menupopup"
+ }
+];
+
+var NSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+function testtag_notificationbox_buttonpressed(event)
+{
+}
+
+function testtag_notificationbox(nb)
+{
+ testtag_notificationbox_State(nb, "initial", null, 0);
+
+ SimpleTest.is(nb.notificationsHidden, false, "initial notificationsHidden");
+ SimpleTest.is(nb.removeAllNotifications(false), undefined, "initial removeAllNotifications");
+ testtag_notificationbox_State(nb, "initial removeAllNotifications", null, 0);
+ SimpleTest.is(nb.removeAllNotifications(true), undefined, "initial removeAllNotifications immediate");
+ testtag_notificationbox_State(nb, "initial removeAllNotifications immediate", null, 0);
+
+ runTimedTests(tests, -1, nb, null);
+}
+
+var notification_last_events = [];
+function notification_eventCallback(event)
+{
+ notification_last_events.push({ actualEvent: event , item: this });
+}
+
+/**
+ * For any notifications that have the notification_eventCallback on
+ * them, we will have recorded instances of those callbacks firing
+ * and stored them. This checks to see that the expected event types
+ * are being fired in order, and targeting the right item.
+ *
+ * @param {Array<string>} expectedEvents
+ * The list of event types, in order, that we expect to have been
+ * fired on the item.
+ * @param {<xul:notification>} ntf
+ * The notification we expect the callback to have been fired from.
+ * @param {string} testName
+ * The name of the current test, for logging.
+ */
+function testtag_notification_eventCallback(expectedEvents, ntf, testName)
+{
+ for (let i = 0; i < expectedEvents; ++i) {
+ let expected = expectedEvents[i];
+ let { actualEvent, item } = notification_last_events[i];
+ SimpleTest.is(actualEvent, expected, testName + ": event name");
+ SimpleTest.is(item, ntf, testName + ": event item");
+ }
+ notification_last_events = [];
+}
+
+var tests =
+[
+ {
+ test: function(nb, ntf) {
+ // append a new notification
+ var ntf = nb.appendNotification("Notification", "note", "happy.png",
+ nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons);
+ SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification");
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "append", ntf, 1);
+ testtag_notification_State(nb, ntf, "append", "Notification", "note",
+ "happy.png", nb.PRIORITY_INFO_LOW);
+
+ // check the getNotificationWithValue method
+ var ntf_found = nb.getNotificationWithValue("note");
+ SimpleTest.is(ntf, ntf_found, "getNotificationWithValue note");
+
+ var none_found = nb.getNotificationWithValue("notenone");
+ SimpleTest.is(none_found, null, "getNotificationWithValue null");
+ return ntf;
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ // check that notifications can be removed properly
+ nb.removeNotification(ntf);
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "removeNotification", null, 0);
+
+ // try removing the notification again to make sure an exception occurs
+ var exh = false;
+ try {
+ nb.removeNotification(ntf);
+ } catch (ex) { exh = true; }
+ SimpleTest.is(exh, true, "removeNotification again");
+ testtag_notificationbox_State(nb, "removeNotification again", null, 0);
+
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ // append a new notification, but now with an event callback
+ var ntf = nb.appendNotification("Notification", "note", "happy.png",
+ nb.PRIORITY_INFO_LOW,
+ testtag_notificationbox_buttons,
+ notification_eventCallback);
+ SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification with callback");
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "append with callback", ntf, 1);
+ return ntf;
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ nb.removeNotification(ntf);
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "removeNotification with callback",
+ null, 0);
+
+ testtag_notification_eventCallback(["removed"], ntf, "removeNotification()");
+ return ntf;
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ var ntf = nb.appendNotification("Notification", "note", "happy.png",
+ nb.PRIORITY_INFO_LOW,
+ testtag_notificationbox_buttons,
+ notification_eventCallback);
+ SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification with callback");
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "append with callback", ntf, 1);
+ return ntf;
+ }
+ },
+ {
+ test: function(rb, ntf) {
+ // Dismissing the notification instead of removing it should
+ // fire a dismissed "event" on the callback, followed by
+ // a removed "event".
+ ntf.dismiss();
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "called dismiss()", null, 0);
+ testtag_notification_eventCallback(["dismissed", "removed"], ntf,
+ "dismiss()");
+ return ntf;
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ // Create a popup to be used by a menu-button.
+ var doc = nb.ownerDocument;
+ var menuPopup = doc.createElementNS(NSXUL, "menupopup");
+ var menuItem = menuPopup.appendChild(doc.createElementNS(NSXUL, "menuitem"));
+ menuItem.setAttribute("label", "Menu Item");
+ // Append a notification with a button of type 'menu-button'.
+ ntf = nb.appendNotification(
+ "Notification", "note", "happy.png",
+ nb.PRIORITY_WARNING_LOW,
+ [{
+ label: "Button",
+ type: "menu-button",
+ popup: menuPopup
+ }]
+ );
+
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "append", ntf, 1);
+ testtag_notification_State(nb, ntf, "append", "Notification", "note",
+ "happy.png", nb.PRIORITY_WARNING_LOW);
+ var button = ntf.querySelector(".notification-button");
+ SimpleTest.is(button.type, "menu-button", "Button type should be set");
+ var menuPopup = button.getElementsByTagNameNS(NSXUL, "menupopup");
+ SimpleTest.is(menuPopup.length, 1, "There should be a menu attached");
+ var menuItem = menuPopup[0].firstChild;
+ SimpleTest.is(menuItem.localName, "menuitem", "There should be a menu item");
+ SimpleTest.is(menuItem.getAttribute("label"), "Menu Item", "Label should match");
+ // Clean up.
+ nb.removeNotification(ntf);
+
+ return [1, null];
+ }
+ },
+ {
+ repeat: true,
+ test: function(nb, arr) {
+ var idx = arr[0];
+ var ntf = arr[1];
+ switch (idx) {
+ case 1:
+ // append a new notification
+ ntf = nb.appendNotification("Notification", "note", "happy.png",
+ nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons);
+ SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification");
+
+ // Test persistence
+ ntf.persistence++;
+
+ return [idx, ntf];
+ case 2:
+ case 3:
+ nb.removeTransientNotifications();
+
+ return [idx, ntf];
+ }
+ },
+ result: function(nb, arr) {
+ var idx = arr[0];
+ var ntf = arr[1];
+ switch (idx) {
+ case 1:
+ testtag_notificationbox_State(nb, "notification added", ntf, 1);
+ testtag_notification_State(nb, ntf, "append", "Notification", "note",
+ "happy.png", nb.PRIORITY_INFO_LOW);
+ SimpleTest.is(ntf.persistence, 1, "persistence is 1");
+
+ return [++idx, ntf];
+ case 2:
+ testtag_notificationbox_State(nb, "first removeTransientNotifications", ntf, 1);
+ testtag_notification_State(nb, ntf, "append", "Notification", "note",
+ "happy.png", nb.PRIORITY_INFO_LOW);
+ SimpleTest.is(ntf.persistence, 0, "persistence is now 0");
+
+ return [++idx, ntf];
+ case 3:
+ testtag_notificationbox_State(nb, "second removeTransientNotifications", null, 0);
+
+ this.repeat = false;
+ }
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ // append another notification
+ var ntf = nb.appendNotification("Notification", "note", "happy.png",
+ nb.PRIORITY_INFO_MEDIUM, testtag_notificationbox_buttons);
+ SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification again");
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ // check that appending a second notification after removing the first one works
+ testtag_notificationbox_State(nb, "append again", ntf, 1);
+ testtag_notification_State(nb, ntf, "append again", "Notification", "note",
+ "happy.png", nb.PRIORITY_INFO_MEDIUM);
+ return ntf;
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ // check the removeCurrentNotification method
+ nb.removeCurrentNotification();
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ testtag_notificationbox_State(nb, "removeCurrentNotification", null, 0);
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ var ntf = nb.appendNotification("Notification", "note", "happy.png",
+ nb.PRIORITY_INFO_HIGH, testtag_notificationbox_buttons);
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ // test the removeAllNotifications method
+ testtag_notificationbox_State(nb, "append info_high", ntf, 1);
+ SimpleTest.is(ntf.priority, nb.PRIORITY_INFO_HIGH,
+ "notification.priority " + nb.PRIORITY_INFO_HIGH);
+ SimpleTest.is(nb.removeAllNotifications(false), undefined, "removeAllNotifications");
+ }
+ },
+ {
+ test: function(nb, unused) {
+ // add a number of notifications and check that they are added in order
+ nb.appendNotification("Four", "4", null, nb.PRIORITY_INFO_HIGH, testtag_notificationbox_buttons);
+ nb.appendNotification("Seven", "7", null, nb.PRIORITY_WARNING_HIGH, testtag_notificationbox_buttons);
+ nb.appendNotification("Two", "2", null, nb.PRIORITY_INFO_LOW, null);
+ nb.appendNotification("Eight", "8", null, nb.PRIORITY_CRITICAL_LOW, null);
+ nb.appendNotification("Five", "5", null, nb.PRIORITY_WARNING_LOW, null);
+ nb.appendNotification("Six", "6", null, nb.PRIORITY_WARNING_HIGH, null);
+ nb.appendNotification("One", "1", null, nb.PRIORITY_INFO_LOW, null);
+ nb.appendNotification("Nine", "9", null, nb.PRIORITY_CRITICAL_MEDIUM, null);
+ var ntf = nb.appendNotification("Ten", "10", null, nb.PRIORITY_CRITICAL_HIGH, null);
+ nb.appendNotification("Three", "3", null, nb.PRIORITY_INFO_MEDIUM, null);
+ return ntf;
+ },
+ result: function(nb, ntf) {
+ SimpleTest.is(nb.currentNotification == ntf ?
+ nb.currentNotification.value : null, "10", "appendNotification order");
+ return 1;
+ }
+ },
+ {
+ // test closing notifications to make sure that the current notification is still set properly
+ repeat: true,
+ test: function(nb, testidx) {
+ switch (testidx) {
+ case 1:
+ nb.getNotificationWithValue("10").close();
+ return [1, 9];
+ case 2:
+ nb.removeNotification(nb.getNotificationWithValue("9"));
+ return [2, 8];
+ case 3:
+ nb.removeCurrentNotification();
+ return [3, 7];
+ case 4:
+ nb.getNotificationWithValue("6").close();
+ return [4, 7];
+ case 5:
+ nb.removeNotification(nb.getNotificationWithValue("5"));
+ return [5, 7];
+ case 6:
+ nb.removeCurrentNotification();
+ return [6, 4];
+ }
+ },
+ result: function(nb, arr) {
+ // arr is [testindex, expectedvalue]
+ SimpleTest.is(nb.currentNotification.value, "" + arr[1], "close order " + arr[0]);
+ SimpleTest.is(nb.allNotifications.length, 10 - arr[0], "close order " + arr[0] + " count");
+ if (arr[0] == 6)
+ this.repeat = false;
+ return ++arr[0];
+ }
+ },
+ {
+ test: function(nb, ntf) {
+ var exh = false;
+ try {
+ nb.appendNotification("no", "no", "no", 0, null);
+ } catch (ex) { exh = true; }
+ SimpleTest.is(exh, true, "appendNotification priority too low");
+
+ exh = false;
+ try {
+ nb.appendNotification("no", "no", "no", 11, null);
+ } catch (ex) { exh = true; }
+ SimpleTest.is(exh, true, "appendNotification priority too high");
+
+ // check that the other priority types work properly
+ runTimedTests(appendPriorityTests, -1, nb, nb.PRIORITY_WARNING_LOW);
+ }
+ }
+];
+
+var appendPriorityTests = [
+ {
+ test: function(nb, priority) {
+ var ntf = nb.appendNotification("Notification", "note", "happy.png",
+ priority, testtag_notificationbox_buttons);
+ SimpleTest.is(ntf && ntf.localName == "notification", true, "append notification " + priority);
+ return [ntf, priority];
+ },
+ result: function(nb, obj) {
+ SimpleTest.is(obj[0].priority, obj[1], "notification.priority " + obj[1]);
+ return obj[1];
+ }
+ },
+ {
+ test: function(nb, priority) {
+ nb.removeCurrentNotification();
+ return priority;
+ },
+ result: function(nb, priority) {
+ if (priority == nb.PRIORITY_CRITICAL_BLOCK) {
+ let ntf = nb.appendNotification("Notification", "note", "happy.png",
+ nb.PRIORITY_INFO_LOW, testtag_notificationbox_buttons);
+ setTimeout(checkPopupTest, 50, nb, ntf);
+ }
+ else {
+ runTimedTests(appendPriorityTests, -1, nb, ++priority);
+ }
+ }
+ }
+];
+
+function testtag_notificationbox_State(nb, testid, expecteditem, expectedcount)
+{
+ SimpleTest.is(nb.currentNotification, expecteditem, testid + " currentNotification");
+ SimpleTest.is(nb.allNotifications ? nb.allNotifications.length : "no value",
+ expectedcount, testid + " allNotifications");
+}
+
+function testtag_notification_State(nb, ntf, testid, label, value, image, priority)
+{
+ SimpleTest.is(ntf.control, nb, testid + " notification.control");
+ SimpleTest.is(ntf.label, label, testid + " notification.label");
+ SimpleTest.is(ntf.value, value, testid + " notification.value");
+ SimpleTest.is(ntf.image, image, testid + " notification.image");
+ SimpleTest.is(ntf.priority, priority, testid + " notification.priority");
+
+ var type;
+ switch (priority) {
+ case nb.PRIORITY_INFO_LOW:
+ case nb.PRIORITY_INFO_MEDIUM:
+ case nb.PRIORITY_INFO_HIGH:
+ type = "info";
+ break;
+ case nb.PRIORITY_WARNING_LOW:
+ case nb.PRIORITY_WARNING_MEDIUM:
+ case nb.PRIORITY_WARNING_HIGH:
+ type = "warning";
+ break;
+ case nb.PRIORITY_CRITICAL_LOW:
+ case nb.PRIORITY_CRITICAL_MEDIUM:
+ case nb.PRIORITY_CRITICAL_HIGH:
+ case nb.PRIORITY_CRITICAL_BLOCK:
+ type = "critical";
+ break;
+ }
+
+ SimpleTest.is(ntf.type, type, testid + " notification.type");
+}
+
+function checkPopupTest(nb, ntf)
+{
+ if (nb._animating)
+ setTimeout(checkPopupTest, ntf);
+ else {
+ var evt = new Event("");
+ ntf.dispatchEvent(evt);
+ evt.target.buttonInfo = testtag_notificationbox_buttons[0];
+ ntf._doButtonCommand(evt);
+ }
+}
+
+function checkPopupClosed()
+{
+ is(document.popupNode, null, "popupNode null after popup is closed");
+ SimpleTest.finish();
+}
+
+/**
+ * run one or more tests which perform a test operation, wait for a delay,
+ * then perform a result operation.
+ *
+ * tests - array of objects where each object is :
+ * {
+ * test: test function,
+ * result: result function
+ * repeat: true to repeat the test
+ * }
+ * idx - starting index in tests
+ * element - element to run tests on
+ * arg - argument to pass between test functions
+ *
+ * If, after executing the result part, the repeat property of the test is
+ * true, then the test is repeated. If the repeat property is not true,
+ * continue on to the next test.
+ *
+ * The test and result functions take two arguments, the element and the arg.
+ * The test function may return a value which will passed to the result
+ * function as its arg. The result function may also return a value which
+ * will be passed to the next repetition or the next test in the array.
+ */
+function runTimedTests(tests, idx, element, arg)
+{
+ if (idx >= 0 && "result" in tests[idx])
+ arg = tests[idx].result(element, arg);
+
+ // if not repeating, move on to the next test
+ if (idx == -1 || !tests[idx].repeat)
+ idx++;
+
+ if (idx < tests.length) {
+ var result = tests[idx].test(element, arg);
+ setTimeout(runTimedTestsWait, 50, tests, idx, element, result);
+ }
+}
+
+function runTimedTestsWait(tests, idx, element, arg)
+{
+ // use this secret property to check if the animation is still running. If it
+ // is, then the notification hasn't fully opened or closed yet
+ if (element._animating)
+ setTimeout(runTimedTestsWait, 50, tests, idx, element, arg);
+ else
+ runTimedTests(tests, idx, element, arg);
+}
+
+setTimeout(testtag_notificationbox, 0, document.getElementById('nb'));
+]]>
+</script>
+
+</window>
+
diff --git a/toolkit/content/tests/chrome/test_panel.xul b/toolkit/content/tests/chrome/test_panel.xul
new file mode 100644
index 000000000..3b2188d9e
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_panel.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="Panel Tests"
+ onload="runTest()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_panel.xul", "_blank", "chrome,left=200,top=200,width=200,height=200");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_panel_focus.xul b/toolkit/content/tests/chrome/test_panel_focus.xul
new file mode 100644
index 000000000..e18f28ca8
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_panel_focus.xul
@@ -0,0 +1,38 @@
+<?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="Panel Focus Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<script>
+// use a chrome window for this test as the focus in content windows can be
+// adjusted by the current selection position
+
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ // move the mouse so any tooltips that might be open go away, otherwise this
+ // test can fail on Mac
+ synthesizeMouse(document.documentElement, 1, 1, { type: "mousemove" });
+
+ window.open("window_panel_focus.xul", "_blank", "chrome,width=600,height=600");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_panelfrommenu.xul b/toolkit/content/tests/chrome/test_panelfrommenu.xul
new file mode 100644
index 000000000..72e396516
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_panelfrommenu.xul
@@ -0,0 +1,118 @@
+<?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="Open panel from menuitem"
+ onload="setTimeout(runTests, 0);"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<!--
+ This test does the following:
+ 1. Opens the menu, causing the popupshown event to fire, which will call menuOpened.
+ 2. Keyboard events are fired to cause the first item on the menu to be executed.
+ 3. The command event handler for the first menuitem opens the panel.
+ 4. As a menuitem was executed, the menu will roll up, hiding it.
+ 5. The popuphidden event for the menu calls menuClosed which tests the popup states.
+ 6. The panelOpened function tests the popup states again and hides the popup.
+ 7. Once the panel's popuphidden event fires, tests are performed to see if
+ panels inside buttons and toolbarbuttons work. Each is opened and the closed.
+ -->
+
+<menu id="menu" onpopupshown="menuOpened()" onpopuphidden="menuClosed();">
+ <menupopup>
+ <menuitem id="i1" label="One" oncommand="$('panel').openPopup($('menu'), 'after_start');"/>
+ <menuitem id="i2" label="Two"/>
+ </menupopup>
+</menu>
+
+<panel id="hiddenpanel" hidden="true"/>
+
+<panel id="panel" onpopupshown="panelOpened()"
+ onpopuphidden="$('button').focus(); $('button').open = true">
+ <textbox/>
+</panel>
+
+<button id="button" type="panel" label="Button">
+ <panel onpopupshown="panelOnButtonOpened(this)"
+ onpopuphidden="$('tbutton').open = true;">
+ <button label="OK" oncommand="this.parentNode.parentNode.open = false"/>
+ </panel>
+</button>
+
+<toolbarbutton id="tbutton" type="panel" label="Toolbarbutton">
+ <panel onpopupshown="panelOnToolbarbuttonOpened(this)"
+ onpopuphidden="SimpleTest.finish()">
+ <textbox/>
+ </panel>
+</toolbarbutton>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests()
+{
+ is($("hiddenpanel").state, "closed", "hidden popup is closed");
+
+ var menu = $("menu");
+ menu.open = true;
+}
+
+function menuOpened()
+{
+ synthesizeKey("VK_DOWN", { });
+ synthesizeKey("VK_RETURN", { });
+}
+
+function menuClosed()
+{
+ // the panel will be open at this point, but the popupshown event
+ // still needs to fire
+ is($("panel").state, "showing", "panel is open after menu hide");
+ is($("menu").firstChild.state, "closed", "menu is closed after menu hide");
+}
+
+function panelOpened()
+{
+ is($("panel").state, "open", "panel is open");
+ is($("menu").firstChild.state, "closed", "menu is closed");
+ $("panel").hidePopup();
+}
+
+function panelOnButtonOpened(panel)
+{
+ is(panel.state, 'open', 'button panel is open');
+ is(document.activeElement, document.documentElement, "focus blurred on panel from button open");
+ synthesizeKey("VK_DOWN", { });
+ is(document.activeElement, document.documentElement, "focus not modified on cursor down from button");
+ panel.firstChild.doCommand()
+}
+
+function panelOnToolbarbuttonOpened(panel)
+{
+ is(panel.state, 'open', 'toolbarbutton panel is open');
+ is(document.activeElement, document.documentElement, "focus blurred on panel from toolbarbutton open");
+ panel.firstChild.focus();
+ synthesizeKey("VK_DOWN", { });
+ is(document.activeElement, panel.firstChild.inputField, "focus not modified on cursor down from toolbarbutton");
+ panel.parentNode.open = false;
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_anchor.xul b/toolkit/content/tests/chrome/test_popup_anchor.xul
new file mode 100644
index 000000000..5839c52a3
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_anchor.xul
@@ -0,0 +1,30 @@
+<?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="Popup Anchor Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_popup_anchor.xul", "_blank", "chrome,width=600,height=600");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_anchoratrect.xul b/toolkit/content/tests/chrome/test_popup_anchoratrect.xul
new file mode 100644
index 000000000..c12e22502
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_anchoratrect.xul
@@ -0,0 +1,28 @@
+<?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="Menu Button Popup Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_popup_anchoratrect.xul", "_blank", "chrome,width=200,height=200");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_attribute.xul b/toolkit/content/tests/chrome/test_popup_attribute.xul
new file mode 100644
index 000000000..2a256078d
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_attribute.xul
@@ -0,0 +1,28 @@
+<?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="Popup Attribute Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_popup_attribute.xul", "_blank", "width=600,height=700");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_button.xul b/toolkit/content/tests/chrome/test_popup_button.xul
new file mode 100644
index 000000000..3803e465f
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_button.xul
@@ -0,0 +1,28 @@
+<?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="Menu Button Popup Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_popup_button.xul", "_blank", "width=700,height=700");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_coords.xul b/toolkit/content/tests/chrome/test_popup_coords.xul
new file mode 100644
index 000000000..4597b5cc0
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_coords.xul
@@ -0,0 +1,91 @@
+<?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="Popup Coordinate Tests"
+ onload="setTimeout(openThePopup, 0, 'outer');"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<deck style="margin-top: 5px; padding-top: 5px;">
+ <label id="outer" popup="outerpopup" value="Popup"/>
+</deck>
+
+<panel id="outerpopup"
+ onpopupshowing="popupShowingEventOccurred(event);"
+ onpopupshown="eventOccurred(event); openThePopup('inner')"
+ onpopuphiding="eventOccurred(event);"
+ onpopuphidden="eventOccurred(event); SimpleTest.finish();">
+ <button id="item1" label="First"/>
+ <label id="inner" value="Second" popup="innerpopup"/>
+ <button id="item2" label="Third"/>
+</panel>
+
+<menupopup id="innerpopup"
+ onpopupshowing="popupShowingEventOccurred(event);"
+ onpopupshown="eventOccurred(event); event.target.hidePopup();"
+ onpopuphiding="eventOccurred(event);"
+ onpopuphidden="eventOccurred(event); document.getElementById('outerpopup').hidePopup();">
+ <menuitem id="inner1" label="Inner First"/>
+ <menuitem id="inner2" label="Inner Second"/>
+</menupopup>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function openThePopup(id)
+{
+ if (id == "inner")
+ document.getElementById("item1").focus();
+
+ var trigger = document.getElementById(id);
+ synthesizeMouse(trigger, 4, 5, { });
+}
+
+function eventOccurred(event)
+{
+ var testname = event.type + " on " + event.target.id + " ";
+ ok(event instanceof MouseEvent, testname + "is a mouse event");
+ is(event.clientX, 0, testname + "clientX");
+ is(event.clientY, 0, testname + "clientY");
+ is(event.rangeParent, null, testname + "rangeParent");
+ is(event.rangeOffset, 0, testname + "rangeOffset");
+}
+
+function popupShowingEventOccurred(event)
+{
+ // the popupshowing event should have the event coordinates and
+ // range position filled in.
+ var testname = "popupshowing on " + event.target.id + " ";
+ ok(event instanceof MouseEvent, testname + "is a mouse event");
+
+ var trigger = document.getElementById(event.target.id == "outerpopup" ? "outer" : "inner");
+ var rect = trigger.getBoundingClientRect();
+ is(event.clientX, Math.round(rect.left + 4), testname + "clientX");
+ is(event.clientY, Math.round(rect.top + 5), testname + "clientY");
+ // rangeOffset should be just after the trigger element. As rangeOffset
+ // considers the zeroth position to be before the first element, the value
+ // should be one higher than its index within its parent.
+ is(event.rangeParent, trigger.parentNode, testname + "rangeParent");
+ is(event.rangeOffset, Array.indexOf(trigger.parentNode.childNodes, trigger) + 1, testname + "rangeOffset");
+
+ var popuprect = event.target.getBoundingClientRect();
+ is(Math.round(popuprect.left), Math.round(rect.left + 4), "popup left");
+ is(Math.round(popuprect.top), Math.round(rect.top + 5), "popup top");
+ ok(popuprect.width > 0, "popup width");
+ ok(popuprect.height > 0, "popup height");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_keys.xul b/toolkit/content/tests/chrome/test_popup_keys.xul
new file mode 100644
index 000000000..37135af57
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_keys.xul
@@ -0,0 +1,148 @@
+<?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="Menu ignorekeys Test"
+ onkeydown="keyDown()" onkeypress="gKeyPressCount++; event.stopPropagation(); event.preventDefault();"
+ onload="runTests();"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<!--
+ This test checks that the ignorekeys attribute can be used on a menu to
+ disable key navigation. The test is performed twice by opening the menu,
+ simulating a cursor down key, and closing the popup. When keys are enabled,
+ the first item on the menu should be highlighted, otherwise the first item
+ should not be highlighted.
+ -->
+
+<menupopup id="popup">
+ <menuitem id="i1" label="One" onDOMAttrModified="attrModified(event)"/>
+ <menuitem id="i2" label="Two"/>
+ <menuitem id="i3" label="Three"/>
+ <menuitem id="i4" label="Four"/>
+</menupopup>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gIgnoreKeys = false;
+var gIgnoreAttrChange = false;
+var gKeyPressCount = 0;
+
+let {Task} = Components.utils.import("resource://gre/modules/Task.jsm", {});
+
+function waitForEvent(target, eventName) {
+ return new Promise(resolve => {
+ target.addEventListener(eventName, function eventOccurred(event) {
+ target.removeEventListener(eventName, eventOccurred, false);
+ resolve();
+ }, false);
+ });
+}
+
+function runTests()
+{
+ Task.async(function* () {
+ var popup = $("popup");
+ popup.enableKeyboardNavigator(false);
+ is(popup.getAttribute("ignorekeys"), "true", "keys disabled");
+ popup.enableKeyboardNavigator(true);
+ is(popup.hasAttribute("ignorekeys"), false, "keys enabled");
+
+ let popupShownPromise = waitForEvent(popup, "popupshown");
+ popup.openPopup(null, "after_start");
+ yield popupShownPromise;
+
+ let popupHiddenPromise = waitForEvent(popup, "popuphidden");
+ synthesizeKey("VK_DOWN", { });
+ yield popupHiddenPromise;
+
+ is(gKeyPressCount, 0, "keypresses with ignorekeys='false'");
+
+ gIgnoreKeys = true;
+ popup.setAttribute("ignorekeys", "true");
+ // clear this first to avoid confusion
+ gIgnoreAttrChange = true;
+ $("i1").removeAttribute("_moz-menuactive")
+ gIgnoreAttrChange = false;
+
+ popupShownPromise = waitForEvent(popup, "popupshown");
+ popup.openPopup(null, "after_start");
+ yield popupShownPromise;
+
+ synthesizeKey("VK_DOWN", { });
+
+ yield new Promise(resolve => setTimeout(() => resolve(), 1000));
+ popupHiddenPromise = waitForEvent(popup, "popuphidden");
+ popup.hidePopup();
+ yield popupHiddenPromise;
+
+ is(gKeyPressCount, 1, "keypresses with ignorekeys='true'");
+
+ popup.setAttribute("ignorekeys", "shortcuts");
+ // clear this first to avoid confusion
+ gIgnoreAttrChange = true;
+ $("i1").removeAttribute("_moz-menuactive")
+ gIgnoreAttrChange = false;
+
+ popupShownPromise = waitForEvent(popup, "popupshown");
+ popup.openPopup(null, "after_start");
+ yield popupShownPromise;
+
+ // When ignorekeys="shortcuts", T should be handled but accel+T should propagate.
+ synthesizeKey("t", { });
+ is(gKeyPressCount, 1, "keypresses after t pressed with ignorekeys='shortcuts'");
+
+ synthesizeKey("t", { accelKey: true });
+ is(gKeyPressCount, 2, "keypresses after accel+t pressed with ignorekeys='shortcuts'");
+
+ popupHiddenPromise = waitForEvent(popup, "popuphidden");
+ popup.hidePopup();
+ yield popupHiddenPromise;
+
+ SimpleTest.finish();
+ })();
+}
+
+function attrModified(event)
+{
+ if (gIgnoreAttrChange || event.attrName != "_moz-menuactive")
+ return;
+
+ // the attribute should not be changed when ignorekeys is enabled
+ if (gIgnoreKeys) {
+ ok(false, "move key with keys disabled");
+ }
+ else {
+ is($("i1").getAttribute("_moz-menuactive"), "true", "move key with keys enabled");
+ $("popup").hidePopup();
+ }
+}
+
+function keyDown()
+{
+ // when keys are enabled, the menu should have stopped propagation of the
+ // event, so a bubbling listener for a keydown event should only occur
+ // when keys are disabled.
+ ok(gIgnoreKeys, "key listener fired with keys " +
+ (gIgnoreKeys ? "disabled" : "enabled"));
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_moveToAnchor.xul b/toolkit/content/tests/chrome/test_popup_moveToAnchor.xul
new file mode 100644
index 000000000..344002fdf
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_moveToAnchor.xul
@@ -0,0 +1,84 @@
+<?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 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<vbox align="start">
+ <button id="button1" label="Button 1" style="margin-top: 50px;"/>
+ <button id="button2" label="Button 2" style="margin-top: 60px;"/>
+</vbox>
+
+<menupopup id="popup" onpopupshown="popupshown()" onpopuphidden="SimpleTest.finish()">
+ <menuitem label="One"/>
+ <menuitem label="Two"/>
+</menupopup>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function runTest(id)
+{
+ $("popup").openPopup($("button1"), "after_start");
+}
+
+function popupshown()
+{
+ var popup = $("popup");
+ var popupheight = popup.getBoundingClientRect().height;
+ var button1rect = $("button1").getBoundingClientRect();
+ var button2rect = $("button2").getBoundingClientRect();
+
+ checkCoords(popup, button1rect.left, button1rect.bottom, "initial");
+
+ popup.moveToAnchor($("button1"), "after_start", 0, 8);
+ checkCoords(popup, button1rect.left, button1rect.bottom + 8, "move anchor top + 8");
+
+ popup.moveToAnchor($("button1"), "after_start", 6, -10);
+ checkCoords(popup, button1rect.left + 6, button1rect.bottom - 10, "move anchor left + 6, top - 10");
+
+ popup.moveToAnchor($("button1"), "before_start", -2, 0);
+ checkCoords(popup, button1rect.left - 2, button1rect.top - popupheight, "move anchor before_start");
+
+ popup.moveToAnchor($("button2"), "before_start");
+ checkCoords(popup, button2rect.left, button2rect.top - popupheight, "move button2");
+
+ popup.moveToAnchor($("button1"), "end_before");
+ checkCoords(popup, button1rect.right, button1rect.top, "move anchor end_before");
+
+ popup.moveToAnchor($("button2"), "after_start", 5, 4);
+ checkCoords(popup, button2rect.left + 5, button2rect.bottom + 4, "move button2 left + 5, top + 4");
+
+ popup.moveTo($("button1").boxObject.screenX + 10, $("button1").boxObject.screenY + 12);
+ checkCoords(popup, button1rect.left + 10, button1rect.top + 12, "move to button1 screen with offset");
+
+ popup.moveToAnchor($("button1"), "after_start", 1, 2);
+ checkCoords(popup, button1rect.left + 1, button1rect.bottom + 2, "move button2 after screen");
+
+ popup.hidePopup();
+}
+
+function checkCoords(popup, expectedx, expectedy, testid)
+{
+ var rect = popup.getBoundingClientRect();
+ is(Math.round(rect.left), Math.round(expectedx), testid + " left");
+ is(Math.round(rect.top), Math.round(expectedy), testid + " top");
+}
+
+SimpleTest.waitForFocus(runTest);
+
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_preventdefault.xul b/toolkit/content/tests/chrome/test_popup_preventdefault.xul
new file mode 100644
index 000000000..7de5dc3be
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_preventdefault.xul
@@ -0,0 +1,76 @@
+<?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="Popup Prevent Default Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<!--
+ This tests checks that preventDefault can be called on a popupshowing
+ event and that preventDefault has no effect for the popuphiding event.
+ -->
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+var gBlockShowing = true;
+var gShownNotAllowed = true;
+
+function runTest()
+{
+ document.getElementById("menu").open = true;
+}
+
+function popupShowing(event)
+{
+ if (gBlockShowing) {
+ event.preventDefault();
+ gBlockShowing = false;
+ setTimeout(function() {
+ gShownNotAllowed = false;
+ document.getElementById("menu").open = true;
+ }, 3000, true);
+ }
+}
+
+function popupShown()
+{
+ ok(!gShownNotAllowed, "popupshowing preventDefault");
+ document.getElementById("menu").open = false;
+}
+
+function popupHiding(event)
+{
+ // since this is a content test, preventDefault should have no effect
+ event.preventDefault();
+}
+
+function popupHidden()
+{
+ ok(true, "popuphiding preventDefault not allowed");
+ SimpleTest.finish();
+}
+</script>
+
+<button id="menu" type="menu" label="Menu">
+ <menupopup onpopupshowing="popupShowing(event);"
+ onpopupshown="popupShown();"
+ onpopuphiding="popupHiding(event);"
+ onpopuphidden="popupHidden();">
+ <menuitem label="Item"/>
+ </menupopup>
+</button>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_preventdefault_chrome.xul b/toolkit/content/tests/chrome/test_popup_preventdefault_chrome.xul
new file mode 100644
index 000000000..46f14cd6a
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_preventdefault_chrome.xul
@@ -0,0 +1,29 @@
+<?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="Popup Attribute Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_popup_preventdefault_chrome.xul", "_blank", "chrome,width=600,height=600");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_recreate.xul b/toolkit/content/tests/chrome/test_popup_recreate.xul
new file mode 100644
index 000000000..14822acbd
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_recreate.xul
@@ -0,0 +1,83 @@
+<?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="Popup Recreate Test"
+ onload="setTimeout(init, 0)"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<!--
+ This is a test for bug 388361.
+
+ This test checks that a menulist's popup is properly created and sized when
+ the popup node is removed and another added in its place.
+
+ -->
+
+<script>
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var gState = "before";
+
+function init()
+{
+ document.getElementById("menulist").open = true;
+}
+
+function isWithinHalfPixel(a, b)
+{
+ return Math.abs(a - b) <= 0.5;
+}
+
+function recreate()
+{
+ if (gState == "before") {
+ var element = document.getElementById("menulist");
+ while (element.hasChildNodes())
+ element.removeChild(element.firstChild);
+ element.appendItem("Cat");
+ gState = "after";
+ document.getElementById("menulist").open = true;
+ }
+ else {
+ SimpleTest.finish();
+ }
+}
+
+function checkSize()
+{
+ var menulist = document.getElementById("menulist");
+ var menurect = menulist.getBoundingClientRect();
+ var popuprect = menulist.menupopup.getBoundingClientRect();
+
+ let marginLeft = parseFloat(getComputedStyle(menulist.menupopup).marginLeft);
+ ok(isWithinHalfPixel(menurect.left + marginLeft, popuprect.left), "left position " + gState);
+ ok(isWithinHalfPixel(menurect.right + marginLeft, popuprect.right), "right position " + gState);
+ ok(Math.round(popuprect.right) - Math.round(popuprect.left) > 0, "height " + gState)
+ document.getElementById("menulist").open = false;
+}
+]]>
+</script>
+
+<hbox align="center" pack="center">
+ <menulist id="menulist" onpopupshown="checkSize();" onpopuphidden="recreate();">
+ <menupopup position="after_start">
+ <menuitem label="Cat"/>
+ </menupopup>
+ </menulist>
+</hbox>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_scaled.xul b/toolkit/content/tests/chrome/test_popup_scaled.xul
new file mode 100644
index 000000000..6bbf6c653
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_scaled.xul
@@ -0,0 +1,105 @@
+<?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="Popups in Scaled Content"
+ onload="setTimeout(runTests, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<!-- This test checks that the position is correct in two cases:
+ - a popup anchored at an element in a scaled document
+ - a popup opened at a screen coordinate in a scaled window
+ -->
+
+<iframe id="frame" width="60" height="140"
+ src="data:text/html,&lt;html&gt;&lt;body&gt;&lt;input size='4' id='one'&gt;&lt;input size='4' id='two'&gt;&lt;/body&gt;&lt;/html&gt;"/>
+
+<menupopup id="popup" onpopupshown="shown()" onpopuphidden="nextTest()">
+ <menuitem label="One"/>
+</menupopup>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+var screenTest = false;
+var screenx = -1, screeny = -1;
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests()
+{
+ setScale($("frame").contentWindow, 2);
+
+ var anchor = $("frame").contentDocument.getElementById("two");
+ anchor.getBoundingClientRect(); // flush to update display after scale change
+ $("popup").openPopup(anchor, "after_start");
+}
+
+function setScale(win, scale)
+{
+ var wn = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebNavigation);
+ var shell = wn.QueryInterface(Components.interfaces.nsIDocShell);
+ var docViewer = shell.contentViewer;
+ docViewer.fullZoom = scale;
+}
+
+function shown()
+{
+ if (screenTest) {
+ var box = $("popup").boxObject;
+ is(box.screenX, screenx, "screen left position");
+ is(box.screenY, screeny, "screen top position");
+ }
+ else {
+ var anchor = $("frame").contentDocument.getElementById("two");
+
+ is(Math.round(anchor.getBoundingClientRect().left * 2),
+ Math.round($("popup").getBoundingClientRect().left), "anchored left position");
+ is(Math.round(anchor.getBoundingClientRect().bottom * 2),
+ Math.round($("popup").getBoundingClientRect().top), "anchored top position");
+ }
+
+ $("popup").hidePopup();
+}
+
+function nextTest()
+{
+ if (screenTest) {
+ setScale(window, 1);
+ SimpleTest.finish();
+ }
+ else {
+ screenTest = true;
+ var box = document.documentElement.boxObject;
+
+ // - the iframe is at 4×, but out here css pixels are only 2× device pixels
+ // - the popup manager rounds off (or truncates) the coordinates to
+ // integers, so ensure we pass in even numbers to openPopupAtScreen
+ screenx = (x = even(box.screenX + 120))/2;
+ screeny = (y = even(box.screenY + 120))/2;
+ setScale(window, 2);
+ $("popup").openPopupAtScreen(x, y);
+ }
+}
+
+function even(n)
+{
+ return (n % 2) ? n+1 : n;
+}
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popup_tree.xul b/toolkit/content/tests/chrome/test_popup_tree.xul
new file mode 100644
index 000000000..779f13e68
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popup_tree.xul
@@ -0,0 +1,72 @@
+<?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="Tree in Popup Test"
+ onload="setTimeout(runTests, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<panel id="panel" onpopupshown="treeClick()" onpopuphidden="SimpleTest.finish()">
+ <tree id="tree" width="350" rows="5">
+ <treecols>
+ <treecol id="name" label="Name" flex="1"/>
+ <treecol id="address" label="Street" flex="1"/>
+ </treecols>
+ <treechildren id="treechildren">
+ <treeitem>
+ <treerow>
+ <treecell label="Justin Thyme"/>
+ <treecell label="800 Bay Street"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary Goround"/>
+ <treecell label="47 University Avenue"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </tree>
+</panel>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests()
+{
+ $("panel").openPopup(null, "overlap", 2, 2);
+}
+
+function treeClick()
+{
+ var tree = $("tree");
+ is(tree.currentIndex, -1, "selectedIndex before click");
+ synthesizeMouseExpectEvent($("treechildren"), 2, 2, { }, $("treechildren"), "click", "");
+ is(tree.currentIndex, 0, "selectedIndex after click");
+
+ var rect = tree.treeBoxObject.getCoordsForCellItem(1, tree.columns.address, "");
+ synthesizeMouseExpectEvent($("treechildren"), rect.x, rect.y + 2,
+ { }, $("treechildren"), "click", "");
+ is(tree.currentIndex, 1, "selectedIndex after second click " + rect.x + "," + rect.y);
+
+ $("panel").hidePopup();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popuphidden.xul b/toolkit/content/tests/chrome/test_popuphidden.xul
new file mode 100644
index 000000000..4c344b3d2
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popuphidden.xul
@@ -0,0 +1,74 @@
+<?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="Hidden Popup Test"
+ onload="setTimeout(runTests, 0, $('popup'));"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<menupopup id="popup" hidden="true" onpopupshown="ok(true, 'popupshown'); this.hidePopup()"
+ onpopuphidden="$('popup-hideonshow').openPopup(null, 'after_start')">
+ <menuitem id="i1" label="One"/>
+ <menuitem id="i2" label="Two"/>
+</menupopup>
+
+<menupopup id="popup-hideonshow" onpopupshowing="hidePopupWhileShowing(this)"
+ onpopupshown="ok(false, 'popupshown when hidden')">
+ <menuitem id="i1" label="One"/>
+ <menuitem id="i2" label="Two"/>
+</menupopup>
+
+<button id="button" type="menu" label="Menu" onDOMAttrModified="checkEndTest(event)">
+ <menupopup id="popupinbutton" hidden="true"
+ onpopupshown="ok(true, 'popupshown'); ok($('button').open, 'open'); this.hidden = true;">
+ <menuitem id="i1" label="One"/>
+ <menuitem id="i2" label="Two"/>
+ </menupopup>
+</button>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests(popup)
+{
+ popup.hidden = false;
+ popup.openPopup(null, "after_start");
+}
+
+function hidePopupWhileShowing(popup)
+{
+ popup.hidden = true;
+ popup.clientWidth; // flush layout
+ is(popup.state, 'closed', 'popupshowing hidden');
+ SimpleTest.executeSoon(() => runTests($('popupinbutton')));
+}
+
+function checkEndTest(event)
+{
+ var button = $("button");
+ if (event.originalTarget != button || event.attrName != 'open' || event.attrChange != event.REMOVAL)
+ return;
+
+ ok($("popupinbutton").hidden, "popup hidden");
+ is($("popupinbutton").state, "closed", "popup state");
+ ok(!button.open, "not open after hidden");
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popupincontent.xul b/toolkit/content/tests/chrome/test_popupincontent.xul
new file mode 100644
index 000000000..dafcd09e5
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popupincontent.xul
@@ -0,0 +1,131 @@
+<?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="Popup in Content Positioning Tests"
+ onload="setTimeout(nextTest, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<!--
+ This test checks that popups in content areas don't extend past the content area.
+ -->
+
+<hbox>
+ <spacer width="100"/>
+ <menu id="menu" label="Menu">
+ <menupopup style="margin:10px;" id="popup" onpopupshown="popupShown()" onpopuphidden="nextTest()">
+ <menuitem label="One"/>
+ <menuitem label="Two"/>
+ <menuitem label="Three"/>
+ <menuitem label="A final longer label that is actually quite long. Very long indeed."/>
+ </menupopup>
+ </menu>
+</hbox>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var step = "";
+var originalHeight = -1;
+
+function nextTest()
+{
+ // there are five tests here:
+ // openPopupAtScreen - checks that opening a popup using openPopupAtScreen
+ // constrains the popup to the content area
+ // left and top - check with the left and top attributes set
+ // open near bottom - open the menu near the bottom of the window
+ // large menu - try with a menu that is very large and should be scaled
+ // shorter menu again - try with a menu that is shorter again. It should have
+ // the same height as the 'left and top' test
+ var popup = $("popup");
+ var menu = $("menu");
+ switch (step) {
+ case "":
+ step = "openPopupAtScreen";
+ popup.openPopupAtScreen(1000, 1200);
+ break;
+ case "openPopupAtScreen":
+ step = "left and top";
+ popup.setAttribute("left", "800");
+ popup.setAttribute("top", "2900");
+ synthesizeMouse(menu, 2, 2, { });
+ break;
+ case "left and top":
+ step = "open near bottom";
+ // request that the menu be opened with a target point near the bottom of the window,
+ // so that the menu's top margin will push it completely outside the window.
+ var bo = document.documentElement.boxObject;
+ popup.setAttribute("top", bo.screenY + window.innerHeight - 5);
+ synthesizeMouse(menu, 2, 2, { });
+ break;
+ case "open near bottom":
+ step = "large menu";
+ popup.removeAttribute("left");
+ popup.removeAttribute("top");
+ for (var i = 0; i < 80; i++)
+ menu.appendItem("Test", "");
+ synthesizeMouse(menu, 2, 2, { });
+ break;
+ case "large menu":
+ step = "shorter menu again";
+ for (var i = 0; i < 80; i++)
+ menu.removeItemAt(menu.itemCount - 1);
+ synthesizeMouse(menu, 2, 2, { });
+ break;
+ case "shorter menu again":
+ SimpleTest.finish();
+ break;
+ }
+}
+
+function popupShown()
+{
+ var windowrect = document.documentElement.getBoundingClientRect();
+ var popuprect = $("popup").getBoundingClientRect();
+
+ // subtract one off the edge due to a rounding issue
+ ok(popuprect.left >= windowrect.left, step + " left");
+ ok(popuprect.right - 1 <= windowrect.right, step + " right");
+
+ if (step == "left and top") {
+ originalHeight = popuprect.bottom - popuprect.top;
+ }
+ else if (step == "open near bottom") {
+ // check that the menu flipped up so it's above our requested point
+ ok(popuprect.bottom - 1 <= windowrect.bottom - 5, step + " bottom");
+ }
+ else if (step == "large menu") {
+ // add 10 to account for the margin
+ is(popuprect.top, $("menu").getBoundingClientRect().bottom + 10, step + " top");
+ ok(popuprect.bottom == windowrect.bottom ||
+ popuprect.bottom - 1 == windowrect.bottom, step + " bottom");
+ }
+ else {
+ ok(popuprect.top >= windowrect.top, step + " top");
+ ok(popuprect.bottom - 1 <= windowrect.bottom, step + " bottom");
+ if (step == "shorter menu again")
+ is(popuprect.bottom - popuprect.top, originalHeight, step + " height shortened");
+ }
+
+ $("menu").open = false;
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popupremoving.xul b/toolkit/content/tests/chrome/test_popupremoving.xul
new file mode 100644
index 000000000..f795590f5
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popupremoving.xul
@@ -0,0 +1,165 @@
+<?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="Popup Removing Tests"
+ onload="setTimeout(nextTest, 0)"
+ onDOMAttrModified="modified(event)"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<!--
+ This test checks that popup elements can be removed in various ways without
+ crashing. It tests two situations, one with menus that are 'separate', and
+ one with menus that are 'nested'. In each case, there are four levels of menu.
+
+ The nextTest function starts the process by opening the first menu. A set of
+ popupshown event listeners are used to open the next menu until all four are
+ showing. This last one calls removePopup to remove the menu node from the
+ tree. This should hide the popups as they are no longer in a document.
+
+ A mutation listener is triggered when the fourth menu closes by having its
+ open attribute cleared. This listener hides the third popup which causes
+ its frame to be removed. Naturally, we want to ensure that this doesn't
+ crash when the third menu is removed.
+ -->
+
+ <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>
+
+<hbox>
+
+<menu id="nestedmenu1" label="1">
+ <menupopup id="nestedpopup1" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="nestedmenu2" label="2">
+ <menupopup id="nestedpopup2" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="nestedmenu3" label="3">
+ <menupopup id="nestedpopup3" onpopupshown="if (event.target == this) this.firstChild.open = true">
+ <menu id="nestedmenu4" label="4" onpopupshown="removePopups()">
+ <menupopup id="nestedpopup4">
+ <menuitem label="Nested 1"/>
+ <menuitem label="Nested 2"/>
+ <menuitem label="Nested 3"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menupopup>
+</menu>
+
+<menu id="separatemenu1" label="1">
+ <menupopup id="separatepopup1" onpopupshown="$('separatemenu2').open = true">
+ <menuitem label="L1 One"/>
+ <menuitem label="L1 Two"/>
+ <menuitem label="L1 Three"/>
+ </menupopup>
+</menu>
+
+<menu id="separatemenu2" label="2">
+ <menupopup id="separatepopup2" onpopupshown="$('separatemenu3').open = true"
+ onpopuphidden="popup2Hidden()">
+ <menuitem label="L2 One"/>
+ <menuitem label="L2 Two"/>
+ <menuitem label="L2 Three"/>
+ </menupopup>
+</menu>
+
+<menu id="separatemenu3" label="3" onpopupshown="$('separatemenu4').open = true">
+ <menupopup id="separatepopup3">
+ <menuitem label="L3 One"/>
+ <menuitem label="L3 Two"/>
+ <menuitem label="L3 Three"/>
+ </menupopup>
+</menu>
+
+<menu id="separatemenu4" label="4" onpopupshown="removePopups()"
+ onpopuphidden="$('separatemenu2').open = false">
+ <menupopup id="separatepopup3">
+ <menuitem label="L4 One"/>
+ <menuitem label="L4 Two"/>
+ <menuitem label="L4 Three"/>
+ </menupopup>
+</menu>
+
+</hbox>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gKey = "";
+gTriggerMutation = null;
+gChangeMutation = null;
+
+function nextTest()
+{
+ if (gKey == "") {
+ gKey = "separate";
+ }
+ else if (gKey == "separate") {
+ gKey = "nested";
+ }
+ else {
+ SimpleTest.finish();
+ return;
+ }
+
+ $(gKey + "menu1").open = true;
+}
+
+function modified(event)
+{
+ // use this mutation listener to hide the third popup, destroying its frame.
+ // It gets triggered when the open attribute is cleared on the fourth menu.
+
+ if (event.target == gTriggerMutation &&
+ event.attrName == "open") {
+ gChangeMutation.hidden = true;
+ // force a layout flush
+ document.documentElement.boxObject.width;
+ gTriggerMutation = null;
+ gChangeMutation = null;
+ }
+}
+
+function removePopups()
+{
+ var menu2 = $(gKey + "menu2");
+ var menu3 = $(gKey + "menu3");
+ is(menu2.getAttribute("open"), "true", gKey + " menu 2 open before");
+ is(menu3.getAttribute("open"), "true", gKey + " menu 3 open before");
+
+ gTriggerMutation = menu3;
+ gChangeMutation = $(gKey + "menu4");
+ var menu = $(gKey + "menu1");
+ menu.parentNode.removeChild(menu);
+
+ if (gKey == "nested") {
+ // the 'separate' test checks this during the popup2 hidden event handler
+ is(menu2.hasAttribute("open"), false, gKey + " menu 2 open after");
+ is(menu3.hasAttribute("open"), false, gKey + " menu 3 open after");
+ nextTest();
+ }
+}
+
+function popup2Hidden()
+{
+ is($(gKey + "menu2").hasAttribute("open"), false, gKey + " menu 2 open after");
+ nextTest();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_popupremoving_frame.xul b/toolkit/content/tests/chrome/test_popupremoving_frame.xul
new file mode 100644
index 000000000..dec73c7f7
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_popupremoving_frame.xul
@@ -0,0 +1,80 @@
+<?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="Popup Unload Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<!--
+ This test checks that popup elements are removed when the document is changed.
+ -->
+
+ <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>
+
+<iframe id="frame" width="300" height="150" src="frame_popupremoving_frame.xul"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gMenus = [];
+
+function popupsOpened()
+{
+ var framedoc = $("frame").contentDocument;
+ framedoc.addEventListener("DOMAttrModified", modified, false);
+
+ // this is the order in which the menus should be hidden (reverse of the
+ // order they were opened in). The second menu is removed during the
+ // mutation listener, so gets the event afterwards.
+ gMenus.push(framedoc.getElementById("nestedmenu4"));
+ gMenus.push(framedoc.getElementById("nestedmenu2"));
+ gMenus.push(framedoc.getElementById("nestedmenu3"));
+ gMenus.push(framedoc.getElementById("nestedmenu1"));
+ gMenus.push(framedoc.getElementById("separatemenu4"));
+ gMenus.push(framedoc.getElementById("separatemenu2"));
+ gMenus.push(framedoc.getElementById("separatemenu3"));
+ gMenus.push(framedoc.getElementById("separatemenu1"));
+
+ framedoc.location = "about:blank";
+}
+
+function modified(event)
+{
+ if (event.attrName != "open")
+ return;
+
+ var framedoc = $("frame").contentDocument;
+
+ var tohide = null;
+ if (event.target.id == "separatemenu3")
+ tohide = framedoc.getElementById("separatemenu2");
+ else if (event.target.id == "nestedmenu3")
+ tohide = framedoc.getElementById("nestedmenu2");
+
+ if (tohide) {
+ tohide.hidden = true;
+ // force a layout flush
+ $("frame").contentDocument.documentElement.boxObject.width;
+ }
+
+ is(event.target, gMenus.shift(), event.target.id + " hidden");
+ if (gMenus.length == 0)
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_position.xul b/toolkit/content/tests/chrome/test_position.xul
new file mode 100644
index 000000000..695c1bf22
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_position.xul
@@ -0,0 +1,136 @@
+<?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"?>
+<!--
+ XUL Widget Test for positioning
+ -->
+<window title="position" width="500" height="600"
+ onload="setTimeout(runTest, 0);"
+ style="margin: 0; border: 0; padding; 0;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+
+<hbox id="box1">
+ <button label="0" width="100" height="40" style="margin: 3px;"/>
+</hbox>
+<scrollbox id="box2" orient="vertical" align="start" width="200" height="50"
+ style="overflow: hidden; margin-left: 2px; padding: 1px;">
+ <deck>
+ <scrollbox id="box3" orient="vertical" align="start" height="100"
+ style="overflow: scroll; margin: 1px; padding: 0;">
+ <vbox id="innerscroll" width="200" align="start">
+ <button id="button1" label="1" width="90" maxwidth="100"
+ minheight="25" height="35" maxheight="50"
+ style="min-width: 80px; margin: 5px; border: 4px; padding: 7px;
+ -moz-appearance: none;"/>
+ <menu id="menu">
+ <menupopup id="popup" style="-moz-appearance: none; margin:0; border: 0; padding: 0;"
+ onpopupshown="menuOpened()"
+ onpopuphidden="if (event.target == this) SimpleTest.finish()">
+ <menuitem label="One"/>
+ <menu id="submenu" label="Three">
+ <menupopup id="subpopup" style="-moz-appearance: none; margin:0; border: 0; padding: 0;"
+ onpopupshown="submenuOpened()">
+ <menuitem label="Four"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ <button label="2" maxwidth="100" maxheight="20" style="margin: 5px;"/>
+ <button label="3" maxwidth="100" maxheight="20" style="margin: 5px;"/>
+ <button label="4" maxwidth="100" maxheight="20" style="margin: 5px;"/>
+ </vbox>
+ <box height="200"/>
+ </scrollbox>
+ </deck>
+</scrollbox>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest()
+{
+ var winwidth = document.documentElement.boxObject.width;
+ var innerscroll = $("innerscroll").boxObject.width;
+
+ var box1 = $("box1");
+ checkPosition("box1", box1, 0, 0, winwidth, 46);
+
+ var box2 = $("box2");
+ checkPosition("box2", box2, 2, 46, winwidth, 96);
+
+ // height is height(box1) = 46 + margin-top(box3) = 1 + margin-top(button1) = 5
+ var button1 = $("button1");
+ checkPosition("button1", button1, 9, 53, 99, 88);
+
+ var sbo = box2.boxObject;
+ sbo.scrollTo(7, 16);
+
+ // clientRect height is offset from root so is 16 pixels vertically less
+ checkPosition("button1 scrolled", button1, 9, 37, 99, 72);
+
+ var box3 = $("box3");
+ sbo = box3.boxObject;
+ sbo.scrollTo(1, 2);
+
+ checkPosition("button1 scrolled", button1, 9, 35, 99, 70);
+
+ $("menu").open = true;
+}
+
+function menuOpened()
+{
+ $("submenu").open = true;
+}
+
+function submenuOpened()
+{
+ var menu = $("menu");
+ var menuleft = Math.round(menu.getBoundingClientRect().left);
+ var menubottom = Math.round(menu.getBoundingClientRect().bottom);
+
+ var submenu = $("submenu");
+ var submenutop = Math.round(submenu.getBoundingClientRect().top);
+ var submenuright = Math.round(submenu.getBoundingClientRect().right);
+
+ checkPosition("popup", $("popup"), menuleft, menubottom, -1, -1);
+ checkPosition("subpopup", $("subpopup"), submenuright, submenutop, -1, -1);
+
+ menu.open = false;
+}
+
+function checkPosition(testid, elem, cleft, ctop, cright, cbottom)
+{
+ // -1 for right or bottom means that the exact size should not be
+ // checked, just ensure it is larger then the left or top position
+ var rect = elem.getBoundingClientRect();
+ is(Math.round(rect.left), cleft, testid + " client rect left");
+ if (testid != "popup")
+ is(Math.round(rect.top), ctop, testid + " client rect top");
+ if (cright >= 0)
+ is(Math.round(rect.right), cright, testid + " client rect right");
+ else
+ ok(rect.right - rect.left > 20, testid + " client rect right");
+ if (cbottom >= 0)
+ is(Math.round(rect.bottom), cbottom, testid + " client rect bottom");
+ else
+ ok(rect.bottom - rect.top > 15, testid + " client rect bottom");
+}
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_preferences.xul b/toolkit/content/tests/chrome/test_preferences.xul
new file mode 100644
index 000000000..22e7e2fe9
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_preferences.xul
@@ -0,0 +1,533 @@
+<?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="Preferences Window Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="RunTest();">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <script type="application/javascript">
+ <![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ const kPref = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+
+ // preference values, set 1
+ const kPrefValueSet1 =
+ {
+ int: 23,
+ bool: true,
+ string: "rheeet!",
+ wstring_data: "日本語",
+ unichar_data: "äöüßÄÖÜ",
+ file_data: "/",
+
+ wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
+ .createInstance(Components.interfaces.nsIPrefLocalizedString),
+ unichar: Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(Components.interfaces.nsISupportsString),
+ file: Components.classes["@mozilla.org/file/local;1"]
+ .createInstance(Components.interfaces.nsILocalFile)
+ };
+ kPrefValueSet1.wstring.data = kPrefValueSet1.wstring_data;
+ kPrefValueSet1.unichar.data = kPrefValueSet1.unichar_data;
+ SafeFileInit(kPrefValueSet1.file, kPrefValueSet1.file_data);
+
+ // preference values, set 2
+ const kPrefValueSet2 =
+ {
+ int: 42,
+ bool: false,
+ string: "Mozilla",
+ wstring_data: "헤드라인A",
+ unichar_data: "áôùšŽ",
+ file_data: "/home",
+
+ wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
+ .createInstance(Components.interfaces.nsIPrefLocalizedString),
+ unichar: Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(Components.interfaces.nsISupportsString),
+ file: Components.classes["@mozilla.org/file/local;1"]
+ .createInstance(Components.interfaces.nsILocalFile)
+ };
+ kPrefValueSet2.wstring.data = kPrefValueSet2.wstring_data;
+ kPrefValueSet2.unichar.data = kPrefValueSet2.unichar_data;
+ SafeFileInit(kPrefValueSet2.file, kPrefValueSet2.file_data);
+
+
+ function SafeFileInit(aFile, aPath)
+ {
+ // set file path without dying for exceptions
+ try
+ {
+ aFile.initWithPath(aPath);
+ }
+ catch (ignored) {}
+ }
+
+ function CreateEmptyPrefValueSet()
+ {
+ var result =
+ {
+ int: undefined,
+ bool: undefined,
+ string: undefined,
+ wstring_data: undefined,
+ unichar_data: undefined,
+ file_data: undefined,
+ wstring: undefined,
+ unichar: undefined,
+ file: undefined
+ };
+ return result;
+ }
+
+ function WritePrefsToSystem(aPrefValueSet)
+ {
+ // write preference data via XPCOM
+ kPref.setIntPref ("tests.static_preference_int", aPrefValueSet.int);
+ kPref.setBoolPref("tests.static_preference_bool", aPrefValueSet.bool);
+ kPref.setCharPref("tests.static_preference_string", aPrefValueSet.string);
+ kPref.setComplexValue("tests.static_preference_wstring",
+ Components.interfaces.nsIPrefLocalizedString,
+ aPrefValueSet.wstring);
+ kPref.setComplexValue("tests.static_preference_unichar",
+ Components.interfaces.nsISupportsString,
+ aPrefValueSet.unichar);
+ kPref.setComplexValue("tests.static_preference_file",
+ Components.interfaces.nsILocalFile,
+ aPrefValueSet.file);
+ }
+
+ function ReadPrefsFromSystem()
+ {
+ // read preference data via XPCOM
+ var result = CreateEmptyPrefValueSet();
+ try {result.int = kPref.getIntPref ("tests.static_preference_int") } catch (ignored) {};
+ try {result.bool = kPref.getBoolPref("tests.static_preference_bool") } catch (ignored) {};
+ try {result.string = kPref.getCharPref("tests.static_preference_string")} catch (ignored) {};
+ try
+ {
+ result.wstring = kPref.getComplexValue("tests.static_preference_wstring",
+ Components.interfaces.nsIPrefLocalizedString);
+ result.wstring_data = result.wstring.data;
+ }
+ catch (ignored) {};
+ try
+ {
+ result.unichar = kPref.getComplexValue("tests.static_preference_unichar",
+ Components.interfaces.nsISupportsString);
+ result.unichar_data = result.unichar.data;
+ }
+ catch (ignored) {};
+ try
+ {
+ result.file = kPref.getComplexValue("tests.static_preference_file",
+ Components.interfaces.nsILocalFile);
+ result.file_data = result.file.data;
+ }
+ catch (ignored) {};
+ return result;
+ }
+
+ function GetXULElement(aPrefWindow, aID)
+ {
+ return aPrefWindow.document.getElementById(aID);
+ }
+
+ function WritePrefsToPreferences(aPrefWindow, aPrefValueSet)
+ {
+ // write preference data into <preference>s
+ GetXULElement(aPrefWindow, "tests.static_preference_int" ).value = aPrefValueSet.int;
+ GetXULElement(aPrefWindow, "tests.static_preference_bool" ).value = aPrefValueSet.bool;
+ GetXULElement(aPrefWindow, "tests.static_preference_string" ).value = aPrefValueSet.string;
+ GetXULElement(aPrefWindow, "tests.static_preference_wstring").value = aPrefValueSet.wstring_data;
+ GetXULElement(aPrefWindow, "tests.static_preference_unichar").value = aPrefValueSet.unichar_data;
+ GetXULElement(aPrefWindow, "tests.static_preference_file" ).value = aPrefValueSet.file_data;
+ }
+
+ function ReadPrefsFromPreferences(aPrefWindow)
+ {
+ // read preference data from <preference>s
+ var result =
+ {
+ int: GetXULElement(aPrefWindow, "tests.static_preference_int" ).value,
+ bool: GetXULElement(aPrefWindow, "tests.static_preference_bool" ).value,
+ string: GetXULElement(aPrefWindow, "tests.static_preference_string" ).value,
+ wstring_data: GetXULElement(aPrefWindow, "tests.static_preference_wstring").value,
+ unichar_data: GetXULElement(aPrefWindow, "tests.static_preference_unichar").value,
+ file_data: GetXULElement(aPrefWindow, "tests.static_preference_file" ).value,
+ wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
+ .createInstance(Components.interfaces.nsIPrefLocalizedString),
+ unichar: Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(Components.interfaces.nsISupportsString),
+ file: Components.classes["@mozilla.org/file/local;1"]
+ .createInstance(Components.interfaces.nsILocalFile)
+ }
+ result.wstring.data = result.wstring_data;
+ result.unichar.data = result.unichar_data;
+ SafeFileInit(result.file, result.file_data);
+ return result;
+ }
+
+ function WritePrefsToUI(aPrefWindow, aPrefValueSet)
+ {
+ // write preference data into UI elements
+ GetXULElement(aPrefWindow, "static_element_int" ).value = aPrefValueSet.int;
+ GetXULElement(aPrefWindow, "static_element_bool" ).checked = aPrefValueSet.bool;
+ GetXULElement(aPrefWindow, "static_element_string" ).value = aPrefValueSet.string;
+ GetXULElement(aPrefWindow, "static_element_wstring").value = aPrefValueSet.wstring_data;
+ GetXULElement(aPrefWindow, "static_element_unichar").value = aPrefValueSet.unichar_data;
+ GetXULElement(aPrefWindow, "static_element_file" ).value = aPrefValueSet.file_data;
+ }
+
+ function ReadPrefsFromUI(aPrefWindow)
+ {
+ // read preference data from <preference>s
+ var result =
+ {
+ int: GetXULElement(aPrefWindow, "static_element_int" ).value,
+ bool: GetXULElement(aPrefWindow, "static_element_bool" ).checked,
+ string: GetXULElement(aPrefWindow, "static_element_string" ).value,
+ wstring_data: GetXULElement(aPrefWindow, "static_element_wstring").value,
+ unichar_data: GetXULElement(aPrefWindow, "static_element_unichar").value,
+ file_data: GetXULElement(aPrefWindow, "static_element_file" ).value,
+ wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
+ .createInstance(Components.interfaces.nsIPrefLocalizedString),
+ unichar: Components.classes["@mozilla.org/supports-string;1"]
+ .createInstance(Components.interfaces.nsISupportsString),
+ file: Components.classes["@mozilla.org/file/local;1"]
+ .createInstance(Components.interfaces.nsILocalFile)
+ }
+ result.wstring.data = result.wstring_data;
+ result.unichar.data = result.unichar_data;
+ SafeFileInit(result.file, result.file_data);
+ return result;
+ }
+
+
+ function RunInstantPrefTest(aPrefWindow)
+ {
+ // remark: there's currently no UI element binding for files
+
+ // were all <preferences> correctly initialized?
+ var expected = kPrefValueSet1;
+ var found = ReadPrefsFromPreferences(aPrefWindow);
+ ok(found.int === expected.int, "instant pref init int" );
+ ok(found.bool === expected.bool, "instant pref init bool" );
+ ok(found.string === expected.string, "instant pref init string" );
+ ok(found.wstring_data === expected.wstring_data, "instant pref init wstring");
+ ok(found.unichar_data === expected.unichar_data, "instant pref init unichar");
+ todo(found.file_data === expected.file_data, "instant pref init file" );
+
+ // were all elements correctly initialized? (loose check)
+ found = ReadPrefsFromUI(aPrefWindow);
+ ok(found.int == expected.int, "instant element init int" );
+ ok(found.bool == expected.bool, "instant element init bool" );
+ ok(found.string == expected.string, "instant element init string" );
+ ok(found.wstring_data == expected.wstring_data, "instant element init wstring");
+ ok(found.unichar_data == expected.unichar_data, "instant element init unichar");
+ todo(found.file_data == expected.file_data, "instant element init file" );
+
+ // do some changes in the UI
+ expected = kPrefValueSet2;
+ WritePrefsToUI(aPrefWindow, expected);
+
+ // UI changes should get passed to the <preference>s,
+ // but currently they aren't if the changes are made programmatically
+ // (the handlers preference.change/prefpane.input and prefpane.change
+ // are called for manual changes, though).
+ found = ReadPrefsFromPreferences(aPrefWindow);
+ todo(found.int === expected.int, "instant change pref int" );
+ todo(found.bool === expected.bool, "instant change pref bool" );
+ todo(found.string === expected.string, "instant change pref string" );
+ todo(found.wstring_data === expected.wstring_data, "instant change pref wstring");
+ todo(found.unichar_data === expected.unichar_data, "instant change pref unichar");
+ todo(found.file_data === expected.file_data, "instant change pref file" );
+
+ // and these changes should get passed to the system instantly
+ // (which obviously can't pass with the above failing)
+ found = ReadPrefsFromSystem();
+ todo(found.int === expected.int, "instant change element int" );
+ todo(found.bool === expected.bool, "instant change element bool" );
+ todo(found.string === expected.string, "instant change element string" );
+ todo(found.wstring_data === expected.wstring_data, "instant change element wstring");
+ todo(found.unichar_data === expected.unichar_data, "instant change element unichar");
+ todo(found.file_data === expected.file_data, "instant change element file" );
+
+ // try resetting the prefs to default values (which should be empty here)
+ GetXULElement(aPrefWindow, "tests.static_preference_int" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_bool" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_file" ).reset();
+
+ // check system
+ expected = CreateEmptyPrefValueSet();
+ found = ReadPrefsFromSystem();
+ ok(found.int === expected.int, "instant reset system int" );
+ ok(found.bool === expected.bool, "instant reset system bool" );
+ ok(found.string === expected.string, "instant reset system string" );
+ ok(found.wstring_data === expected.wstring_data, "instant reset system wstring");
+ ok(found.unichar_data === expected.unichar_data, "instant reset system unichar");
+ ok(found.file_data === expected.file_data, "instant reset system file" );
+
+ // check UI
+ expected =
+ {
+ // alas, we don't have XUL elements with typeof(value) == int :(
+ // int: 0,
+ int: "",
+ bool: false,
+ string: "",
+ wstring_data: "",
+ unichar_data: "",
+ file_data: "",
+ wstring: {},
+ unichar: {},
+ file: {}
+ };
+ found = ReadPrefsFromUI(aPrefWindow);
+ ok(found.int === expected.int, "instant reset element int" );
+ ok(found.bool === expected.bool, "instant reset element bool" );
+ ok(found.string === expected.string, "instant reset element string" );
+ ok(found.wstring_data === expected.wstring_data, "instant reset element wstring");
+ ok(found.unichar_data === expected.unichar_data, "instant reset element unichar");
+// ok(found.file_data === expected.file_data, "instant reset element file" );
+
+ // check hasUserValue
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_int" ).hasUserValue === false, "instant reset hasUserValue int" );
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_bool" ).hasUserValue === false, "instant reset hasUserValue bool" );
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "instant reset hasUserValue string" );
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "instant reset hasUserValue wstring");
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "instant reset hasUserValue unichar");
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_file" ).hasUserValue === false, "instant reset hasUserValue file" );
+
+ // done with instant apply checks
+ }
+
+ function RunNonInstantPrefTestGeneral(aPrefWindow)
+ {
+ // Non-instant apply tests are harder: not only do we need to check that
+ // fiddling with the values does *not* change the system settings, but
+ // also that they *are* (not) set after closing (cancelling) the dialog...
+
+ // remark: there's currently no UI element binding for files
+
+ // were all <preferences> correctly initialized?
+ var expected = kPrefValueSet1;
+ var found = ReadPrefsFromPreferences(aPrefWindow);
+ ok(found.int === expected.int, "non-instant pref init int" );
+ ok(found.bool === expected.bool, "non-instant pref init bool" );
+ ok(found.string === expected.string, "non-instant pref init string" );
+ ok(found.wstring_data === expected.wstring_data, "non-instant pref init wstring");
+ ok(found.unichar_data === expected.unichar_data, "non-instant pref init unichar");
+ todo(found.file_data === expected.file_data, "non-instant pref init file" );
+
+ // were all elements correctly initialized? (loose check)
+ found = ReadPrefsFromUI(aPrefWindow);
+ ok(found.int == expected.int, "non-instant element init int" );
+ ok(found.bool == expected.bool, "non-instant element init bool" );
+ ok(found.string == expected.string, "non-instant element init string" );
+ ok(found.wstring_data == expected.wstring_data, "non-instant element init wstring");
+ ok(found.unichar_data == expected.unichar_data, "non-instant element init unichar");
+ todo(found.file_data == expected.file_data, "non-instant element init file" );
+
+ // do some changes in the UI
+ expected = kPrefValueSet2;
+ WritePrefsToUI(aPrefWindow, expected);
+
+ // UI changes should get passed to the <preference>s,
+ // but currently they aren't if the changes are made programmatically
+ // (the handlers preference.change/prefpane.input and prefpane.change
+ // are called for manual changes, though).
+ found = ReadPrefsFromPreferences(aPrefWindow);
+ todo(found.int === expected.int, "non-instant change pref int" );
+ todo(found.bool === expected.bool, "non-instant change pref bool" );
+ todo(found.string === expected.string, "non-instant change pref string" );
+ todo(found.wstring_data === expected.wstring_data, "non-instant change pref wstring");
+ todo(found.unichar_data === expected.unichar_data, "non-instant change pref unichar");
+ todo(found.file_data === expected.file_data, "non-instant change pref file" );
+
+ // and these changes should *NOT* get passed to the system
+ // (which obviously always passes with the above failing)
+ expected = kPrefValueSet1;
+ found = ReadPrefsFromSystem();
+ ok(found.int === expected.int, "non-instant change element int" );
+ ok(found.bool === expected.bool, "non-instant change element bool" );
+ ok(found.string === expected.string, "non-instant change element string" );
+ ok(found.wstring_data === expected.wstring_data, "non-instant change element wstring");
+ ok(found.unichar_data === expected.unichar_data, "non-instant change element unichar");
+ todo(found.file_data === expected.file_data, "non-instant change element file" );
+
+ // try resetting the prefs to default values (which should be empty here)
+ GetXULElement(aPrefWindow, "tests.static_preference_int" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_bool" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_file" ).reset();
+
+ // check system: the current values *MUST NOT* change
+ expected = kPrefValueSet1;
+ found = ReadPrefsFromSystem();
+ ok(found.int === expected.int, "non-instant reset system int" );
+ ok(found.bool === expected.bool, "non-instant reset system bool" );
+ ok(found.string === expected.string, "non-instant reset system string" );
+ ok(found.wstring_data === expected.wstring_data, "non-instant reset system wstring");
+ ok(found.unichar_data === expected.unichar_data, "non-instant reset system unichar");
+ todo(found.file_data === expected.file_data, "non-instant reset system file" );
+
+ // check UI: these values should be reset
+ expected =
+ {
+ // alas, we don't have XUL elements with typeof(value) == int :(
+ // int: 0,
+ int: "",
+ bool: false,
+ string: "",
+ wstring_data: "",
+ unichar_data: "",
+ file_data: "",
+ wstring: {},
+ unichar: {},
+ file: {}
+ };
+ found = ReadPrefsFromUI(aPrefWindow);
+ ok(found.int === expected.int, "non-instant reset element int" );
+ ok(found.bool === expected.bool, "non-instant reset element bool" );
+ ok(found.string === expected.string, "non-instant reset element string" );
+ ok(found.wstring_data === expected.wstring_data, "non-instant reset element wstring");
+ ok(found.unichar_data === expected.unichar_data, "non-instant reset element unichar");
+// ok(found.file_data === expected.file_data, "non-instant reset element file" );
+
+ // check hasUserValue
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_int" ).hasUserValue === false, "non-instant reset hasUserValue int" );
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_bool" ).hasUserValue === false, "non-instant reset hasUserValue bool" );
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "non-instant reset hasUserValue string" );
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "non-instant reset hasUserValue wstring");
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "non-instant reset hasUserValue unichar");
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_file" ).hasUserValue === false, "non-instant reset hasUserValue file" );
+ }
+
+ function RunNonInstantPrefTestClose(aPrefWindow)
+ {
+ WritePrefsToPreferences(aPrefWindow, kPrefValueSet2);
+ }
+
+ function RunCheckCommandRedirect(aPrefWindow)
+ {
+ GetXULElement(aPrefWindow, "checkbox").click();
+ ok(GetXULElement(aPrefWindow, "tests.static_preference_bool").value, "redirected command bool");
+ GetXULElement(aPrefWindow, "checkbox").click();
+ ok(!GetXULElement(aPrefWindow, "tests.static_preference_bool").value, "redirected command bool");
+ }
+
+ function RunResetPrefTest(aPrefWindow)
+ {
+ // try resetting the prefs to default values
+ GetXULElement(aPrefWindow, "tests.static_preference_int" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_bool" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
+ GetXULElement(aPrefWindow, "tests.static_preference_file" ).reset();
+ }
+
+ function InitTestPrefs(aInstantApply)
+ {
+ // set instant apply mode and init prefs to set 1
+ kPref.setBoolPref("browser.preferences.instantApply", aInstantApply);
+ WritePrefsToSystem(kPrefValueSet1);
+ }
+
+ function RunTestInstant()
+ {
+ // test with instantApply
+ InitTestPrefs(true);
+ openDialog("window_preferences.xul", "", "modal", RunInstantPrefTest, false);
+
+ // - test deferred reset in child window
+ InitTestPrefs(true);
+ openDialog("window_preferences2.xul", "", "modal", RunResetPrefTest, false);
+ expected = kPrefValueSet1;
+ found = ReadPrefsFromSystem();
+ ok(found.int === expected.int, "instant reset deferred int" );
+ ok(found.bool === expected.bool, "instant reset deferred bool" );
+ ok(found.string === expected.string, "instant reset deferred string" );
+ ok(found.wstring_data === expected.wstring_data, "instant reset deferred wstring");
+ ok(found.unichar_data === expected.unichar_data, "instant reset deferred unichar");
+ todo(found.file_data === expected.file_data, "instant reset deferred file" );
+ }
+
+ function RunTestNonInstant()
+ {
+ // test without instantApply
+ // - general tests, similar to instant apply
+ InitTestPrefs(false);
+ openDialog("window_preferences.xul", "", "modal", RunNonInstantPrefTestGeneral, false);
+
+ // - test Cancel
+ InitTestPrefs(false);
+ openDialog("window_preferences.xul", "", "modal", RunNonInstantPrefTestClose, false);
+ var expected = kPrefValueSet1;
+ var found = ReadPrefsFromSystem();
+ ok(found.int === expected.int, "non-instant cancel system int" );
+ ok(found.bool === expected.bool, "non-instant cancel system bool" );
+ ok(found.string === expected.string, "non-instant cancel system string" );
+ ok(found.wstring_data === expected.wstring_data, "non-instant cancel system wstring");
+ ok(found.unichar_data === expected.unichar_data, "non-instant cancel system unichar");
+ todo(found.file_data === expected.file_data, "non-instant cancel system file" );
+
+ // - test Accept
+ InitTestPrefs(false);
+ openDialog("window_preferences.xul", "", "modal", RunNonInstantPrefTestClose, true);
+ expected = kPrefValueSet2;
+ found = ReadPrefsFromSystem();
+ ok(found.int === expected.int, "non-instant accept system int" );
+ ok(found.bool === expected.bool, "non-instant accept system bool" );
+ ok(found.string === expected.string, "non-instant accept system string" );
+ ok(found.wstring_data === expected.wstring_data, "non-instant accept system wstring");
+ ok(found.unichar_data === expected.unichar_data, "non-instant accept system unichar");
+ todo(found.file_data === expected.file_data, "non-instant accept system file" );
+
+ // - test deferred reset in child window
+ InitTestPrefs(false);
+ openDialog("window_preferences2.xul", "", "modal", RunResetPrefTest, true);
+ expected = CreateEmptyPrefValueSet();
+ found = ReadPrefsFromSystem();
+ ok(found.int === expected.int, "non-instant reset deferred int" );
+ ok(found.bool === expected.bool, "non-instant reset deferred bool" );
+ ok(found.string === expected.string, "non-instant reset deferred string" );
+ ok(found.wstring_data === expected.wstring_data, "non-instant reset deferred wstring");
+ ok(found.unichar_data === expected.unichar_data, "non-instant reset deferred unichar");
+ ok(found.file_data === expected.file_data, "non-instant reset deferred file" );
+ }
+
+ function RunTestCommandRedirect()
+ {
+ openDialog("window_preferences_commandretarget.xul", "", "modal", RunCheckCommandRedirect, true);
+ }
+
+ function RunTest()
+ {
+ RunTestInstant();
+ RunTestNonInstant();
+ RunTestCommandRedirect();
+ SimpleTest.finish();
+ }
+ ]]>
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test"></pre>
+ </body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_preferences_beforeaccept.xul b/toolkit/content/tests/chrome/test_preferences_beforeaccept.xul
new file mode 100644
index 000000000..a1abad3cc
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_preferences_beforeaccept.xul
@@ -0,0 +1,55 @@
+<?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="Preferences Window beforeaccept Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <script type="application/javascript">
+ <![CDATA[
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({"set":[["browser.preferences.instantApply", false]]}, function() {
+
+ // No instant-apply for this test
+ var prefWindow = openDialog("window_preferences_beforeaccept.xul", "", "", windowOnload);
+
+ function windowOnload() {
+ var dialogShown = prefWindow.document.getElementById("tests.beforeaccept.dialogShown");
+ var called = prefWindow.document.getElementById("tests.beforeaccept.called");
+ is(dialogShown.value, true, "dialog opened, shown pref set");
+ is(dialogShown.valueFromPreferences, null, "shown pref not committed");
+ is(called.value, null, "beforeaccept not yet called");
+ is(called.valueFromPreferences, null, "beforeaccept not yet called, pref not committed");
+
+ // try to accept the dialog, should fail the first time
+ prefWindow.document.documentElement.acceptDialog();
+ is(prefWindow.closed, false, "window not closed");
+ is(dialogShown.value, true, "shown pref still set");
+ is(dialogShown.valueFromPreferences, null, "shown pref still not committed");
+ is(called.value, true, "beforeaccept called");
+ is(called.valueFromPreferences, null, "called pref not committed");
+
+ // try again, this one should succeed
+ prefWindow.document.documentElement.acceptDialog();
+ is(prefWindow.closed, true, "window now closed");
+ is(dialogShown.valueFromPreferences, true, "shown pref committed");
+ is(called.valueFromPreferences, true, "called pref committed");
+
+ SimpleTest.finish();
+ }
+});
+ ]]>
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test"></pre>
+ </body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_preferences_onsyncfrompreference.xul b/toolkit/content/tests/chrome/test_preferences_onsyncfrompreference.xul
new file mode 100644
index 000000000..8a191d97a
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_preferences_onsyncfrompreference.xul
@@ -0,0 +1,62 @@
+<?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"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ - You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<window title="Preferences Window beforeaccept Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <script type="application/javascript">
+ <![CDATA[
+ const PREFS = ['tests.onsyncfrompreference.pref1',
+ 'tests.onsyncfrompreference.pref2',
+ 'tests.onsyncfrompreference.pref3'];
+
+ SimpleTest.waitForExplicitFinish();
+
+ for (let pref of PREFS) {
+ SpecialPowers.setIntPref(pref, 1);
+ }
+
+ let counter = 0;
+ let prefWindow = openDialog("window_preferences_onsyncfrompreference.xul", "", "", onSync);
+
+ SimpleTest.registerCleanupFunction(() => {
+ for (let pref of PREFS) {
+ SpecialPowers.clearUserPref(pref);
+ }
+ prefWindow.close();
+ });
+
+ // Onsyncfrompreference handler for the prefs
+ function onSync() {
+ for (let pref of PREFS) {
+ // The `value` field of each <preference> element should be initialized by now.
+
+ is(SpecialPowers.getIntPref(pref), prefWindow.document.getElementById(pref).value,
+ "Pref constructor was called correctly")
+ }
+
+ counter++;
+
+ if (counter == PREFS.length) {
+ SimpleTest.finish();
+ }
+ return true;
+ }
+ ]]>
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test"></pre>
+ </body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_progressmeter.xul b/toolkit/content/tests/chrome/test_progressmeter.xul
new file mode 100644
index 000000000..7810f6991
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_progressmeter.xul
@@ -0,0 +1,74 @@
+<?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"?>
+<!--
+ XUL Widget Test for progressmeter
+ -->
+<window title="Progressmeter" width="500" height="600"
+ onload="doTests()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <progressmeter id="n1"/>
+ <progressmeter id="n2" mode="undetermined"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function doTests() {
+ var n1 = document.getElementById("n1");
+ var n2 = document.getElementById("n2");
+
+ SimpleTest.is(n1.mode, "", "mode determined");
+ SimpleTest.is(n2.mode, "undetermined", "mode undetermined");
+
+ SimpleTest.is(n1.value, "0", "determined value");
+ SimpleTest.is(n2.value, "0", "undetermined value");
+
+ // values can only be incremented in multiples of 4
+ n1.value = 2;
+ SimpleTest.is(n1.value, "0", "determined value set 2");
+ n1.value = -1;
+ SimpleTest.is(n1.value, "0", "determined value set -1");
+ n1.value = 125;
+ SimpleTest.is(n1.value, "100", "determined value set 125");
+ n1.value = 7;
+ SimpleTest.is(n1.value, "7", "determined value set 7");
+ n1.value = "17";
+ SimpleTest.is(n1.value, "17", "determined value set 17 string");
+ n1.value = 18;
+ SimpleTest.is(n1.value, "17", "determined value set 18");
+ n1.value = "Cat";
+ SimpleTest.is(n1.value, "17", "determined value set invalid");
+
+ n1.max = 200;
+ is(n1.max, "200", "max changed");
+ n1.value = 150;
+ n1.max = 120;
+ is(n1.value, "120", "max lowered below value");
+
+ n2.value = 2;
+ SimpleTest.is(n2.value, "0", "undetermined value set 2");
+ n2.value = -1;
+ SimpleTest.is(n2.value, "0", "undetermined value set -1");
+ n2.value = 125;
+ SimpleTest.is(n2.value, "100", "undetermined value set 125");
+ n2.value = 7;
+ SimpleTest.is(n2.value, "7", "undetermined value set 7");
+ n2.value = "17";
+ SimpleTest.is(n2.value, "17", "undetermined value set 17 string");
+ n2.value = 18;
+ SimpleTest.is(n2.value, "17", "undetermined value set 18");
+ n2.value = "Cat";
+ SimpleTest.is(n2.value, "17", "determined value set invalid");
+
+ SimpleTest.finish();
+}
+
+]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_props.xul b/toolkit/content/tests/chrome/test_props.xul
new file mode 100644
index 000000000..17513df5c
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_props.xul
@@ -0,0 +1,91 @@
+<?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"?>
+<!--
+ XUL Widget Test for basic properties - this test checks that the basic
+ properties defined in general.xml and inherited by a number of elements
+ work properly.
+ -->
+<window title="Basic Properties Test"
+ onload="setTimeout(test_props, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<command id="cmd_nothing"/>
+<command id="cmd_action"/>
+
+<button id="button" label="Button" accesskey="B"
+ crop="end" image="happy.png" command="cmd_nothing"/>
+<checkbox id="checkbox" label="Checkbox" accesskey="B"
+ crop="end" image="happy.png" command="cmd_nothing"/>
+<radiogroup>
+ <radio id="radio" label="Radio Button" value="rb1" accesskey="B"
+ crop="end" image="happy.png" command="cmd_nothing"/>
+</radiogroup>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function test_props()
+{
+ test_props_forelement($("button"), "Button", null);
+ test_props_forelement($("checkbox"), "Checkbox", null);
+ test_props_forelement($("radio"), "Radio Button", "rb1");
+
+ SimpleTest.finish();
+}
+
+function test_props_forelement(element, label, value)
+{
+ // check the initial values
+ is(element.label, label, "element label");
+ if (value)
+ is(element.value, value, "element value");
+ is(element.accessKey, "B", "element accessKey");
+ is(element.crop, "end", "element crop");
+ is(element.image, "happy.png", "element image");
+ is(element.command, "cmd_nothing", "element command");
+ ok(element.tabIndex === 0, "element tabIndex");
+
+ synthesizeMouseExpectEvent(element, 4, 4, { }, $("cmd_nothing"), "command", "element");
+
+ // make sure that setters return the value
+ is(element.label = "Label", "Label", "element label setter return");
+ if (value)
+ is(element.value = "lb", "lb", "element value setter return");
+ is(element.accessKey = "L", "L", "element accessKey setter return");
+ is(element.crop = "start", "start", "element crop setter return");
+ is(element.image = "sad.png", "sad.png", "element image setter return");
+ is(element.command = "cmd_action", "cmd_action", "element command setter return");
+
+ // check the value after it was changed
+ is(element.label, "Label", "element label after set");
+ if (value)
+ is(element.value, "lb", "element value after set");
+ is(element.accessKey, "L", "element accessKey after set");
+ is(element.crop, "start", "element crop after set");
+ is(element.image, "sad.png", "element image after set");
+ is(element.command, "cmd_action", "element command after set");
+
+ synthesizeMouseExpectEvent(element, 4, 4, { }, $("cmd_action"), "command", "element");
+
+ // check that clicks on disabled items don't fire a command event
+ ok((element.disabled = true) === true, "element disabled setter return");
+ ok(element.disabled === true, "element disabled after set");
+ synthesizeMouseExpectEvent(element, 4, 4, { }, $("cmd_action"), "!command", "element");
+
+ element.disabled = false;
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_radio.xul b/toolkit/content/tests/chrome/test_radio.xul
new file mode 100644
index 000000000..74ab66a34
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_radio.xul
@@ -0,0 +1,66 @@
+<?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"?>
+<!--
+ XUL Widget Test for radio buttons
+ -->
+<window title="Radio Buttons" width="500" height="600"
+ onload="setTimeout(test_radio, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+ <script type="application/javascript" src="xul_selectcontrol.js"/>
+
+<radiogroup id="radiogroup"/>
+
+<radiogroup id="radiogroup-initwithvalue" value="two">
+ <radio label="One" value="one"/>
+ <radio label="Two" value="two"/>
+ <radio label="Three" value="three"/>
+</radiogroup>
+<radiogroup id="radiogroup-initwithselected" value="two">
+ <radio id="one" label="One" value="one" accesskey="o"/>
+ <radio id="two" label="Two" value="two" accesskey="t"/>
+ <radio label="Three" value="three" selected="true"/>
+</radiogroup>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function test_radio()
+{
+ var element = document.getElementById("radiogroup");
+ test_nsIDOMXULSelectControlElement(element, "radio", null);
+ test_nsIDOMXULSelectControlElement_UI(element, null);
+
+ window.blur();
+
+ var accessKeyDetails = (navigator.platform.indexOf("Mac") >= 0) ?
+ { altKey : true, ctrlKey : true } :
+ { altKey : true, shiftKey: true };
+ synthesizeKey("t", accessKeyDetails);
+
+ var radiogroup = $("radiogroup-initwithselected");
+ is(document.activeElement, radiogroup, "accesskey focuses radiogroup");
+ is(radiogroup.selectedItem, $("two"), "accesskey selects radio");
+
+ $("radiogroup-initwithvalue").focus();
+
+ $("one").disabled = true;
+ synthesizeKey("o", accessKeyDetails);
+
+ is(document.activeElement, $("radiogroup-initwithvalue"), "accesskey on disabled radio doesn't focus");
+ is(radiogroup.selectedItem, $("two"), "accesskey on disabled radio doesn't change selection");
+
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_richlist_direction.xul b/toolkit/content/tests/chrome/test_richlist_direction.xul
new file mode 100644
index 000000000..f94f1b3ba
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_richlist_direction.xul
@@ -0,0 +1,138 @@
+<?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"?>
+<!--
+ XUL Widget Test for listbox direction
+ -->
+<window title="Listbox direction test"
+ onload="test_richlistbox()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+ <richlistbox seltype="multiple" id="richlistbox" flex="1" minheight="80" maxheight="80" height="80" />
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+<script type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var richListBox = document.getElementById("richlistbox");
+
+function getScrollIndexAmount(aDirection) {
+ return (4 * aDirection + richListBox.currentIndex);
+}
+
+function test_richlistbox()
+{
+ richListBox.minHeight = richListBox.maxHeight = richListBox.height =
+ 80 + (80 - richListBox.scrollBoxObject.height);
+ var height = richListBox.scrollBoxObject.height;
+ var item;
+ do {
+ item = richListBox.appendItem("Test", "");
+ item.height = item.minHeight = item.maxHeight = Math.floor(height / 4);
+ } while (item.getBoundingClientRect().bottom < (height * 2))
+ richListBox.appendItem("Test", "");
+ richListBox.firstChild.nextSibling.id = "list-box-first";
+ richListBox.lastChild.previousSibling.id = "list-box-last";
+
+ // direction = "reverse", the values here are backwards due to the fact that
+ // richlistboxes respond differently when a user initiates a selection
+ richListBox.dir = "reverse";
+ var count = richListBox.itemCount;
+ richListBox.focus();
+ richListBox.selectedIndex = count - 1;
+ sendKey("DOWN");
+ is(richListBox.currentIndex, count - 2, "Selection should move to the next item");
+ sendKey("UP");
+ is(richListBox.currentIndex, count - 1, "Selection should move to the previous item");
+ sendKey("END");
+ is(richListBox.currentIndex, 0, "Selection should move to the last item");
+ sendKey("HOME");
+ is(richListBox.currentIndex, count - 1, "Selection should move to the first item");
+ var currentIndex = richListBox.currentIndex;
+ var index = getScrollIndexAmount(-1);
+ sendKey("PAGE_DOWN");
+ is(richListBox.currentIndex, index, "Selection should move to one page down");
+ ok(richListBox.currentIndex < currentIndex, "Selection should move downwards");
+ sendKey("END");
+ currentIndex = richListBox.currentIndex;
+ index = getScrollIndexAmount(1);
+ sendKey("PAGE_UP");
+ is(richListBox.currentIndex, index, "Selection should move to one page up");
+ ok(richListBox.currentIndex > currentIndex, "Selection should move upwards");
+ richListBox.selectedItem = richListBox.lastChild;
+ richListBox.focus();
+ synthesizeKey("KEY_ArrowDown", { shiftKey: true, code: "ArrowDown" }, window);
+ let items = [richListBox.selectedItems[0],
+ richListBox.selectedItems[1]];
+ is(items[0], richListBox.lastChild, "The last element should still be selected");
+ is(items[1], richListBox.lastChild.previousSibling, "Both elements should now be selected");
+ richListBox.clearSelection();
+ richListBox.selectedItem = richListBox.lastChild;
+ sendMouseEvent({type: "click", shiftKey: true, clickCount: 1},
+ "list-box-last",
+ window);
+ items = [richListBox.selectedItems[0],
+ richListBox.selectedItems[1]];
+ is(items[0], richListBox.lastChild, "The last element should still be selected");
+ is(items[1], richListBox.lastChild.previousSibling, "Both elements should now be selected");
+ richListBox.addEventListener("keypress", function(aEvent) {
+ richListBox.removeEventListener("keypress", arguments.callee, true);
+ aEvent.preventDefault();
+ }, true);
+ richListBox.selectedIndex = 1;
+ sendKey("HOME");
+ is(richListBox.selectedIndex, 1, "A stopped event should return indexing to normal");
+
+ // direction = "normal"
+ richListBox.dir = "normal";
+ richListBox.selectedIndex = 0;
+ sendKey("DOWN");
+ is(richListBox.currentIndex, 1, "Selection should move to the next item");
+ sendKey("UP");
+ is(richListBox.currentIndex, 0, "Selection should move to the previous item");
+ sendKey("END");
+ is(richListBox.currentIndex, count - 1, "Selection should move to the last item");
+ sendKey("HOME");
+ is(richListBox.currentIndex, 0, "Selection should move to the first item");
+ var currentIndex = richListBox.currentIndex;
+ var index = richListBox.scrollOnePage(1);
+ sendKey("PAGE_DOWN");
+ is(richListBox.currentIndex, index, "Selection should move to one page down");
+ ok(richListBox.currentIndex > currentIndex, "Selection should move downwards");
+ sendKey("END");
+ currentIndex = richListBox.currentIndex;
+ index = richListBox.scrollOnePage(-1) + richListBox.currentIndex;
+ sendKey("PAGE_UP");
+ is(richListBox.currentIndex, index, "Selection should move to one page up");
+ ok(richListBox.currentIndex < currentIndex, "Selection should move upwards");
+ richListBox.selectedItem = richListBox.firstChild;
+ richListBox.focus();
+ synthesizeKey("KEY_ArrowDown", { shiftKey: true, code: "ArrowDown" }, window);
+ items = [richListBox.selectedItems[0],
+ richListBox.selectedItems[1]];
+ is(items[0], richListBox.firstChild, "The last element should still be selected");
+ is(items[1], richListBox.firstChild.nextSibling, "Both elements should now be selected");
+ richListBox.clearSelection();
+ richListBox.selectedItem = richListBox.firstChild;
+ sendMouseEvent({type: "click", shiftKey: true, clickCount: 1},
+ "list-box-first",
+ window);
+ items = [richListBox.selectedItems[0],
+ richListBox.selectedItems[1]];
+ is(items[0], richListBox.firstChild, "The last element should still be selected");
+ is(items[1], richListBox.firstChild.nextSibling, "Both elements should now be selected");
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_righttoleft.xul b/toolkit/content/tests/chrome/test_righttoleft.xul
new file mode 100644
index 000000000..64b1419da
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_righttoleft.xul
@@ -0,0 +1,126 @@
+<?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="Right to Left UI Test"
+ onload="runTest()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript"
+ src="RegisterUnregisterChrome.js"></script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <iframe id="subframe" width="100" height="100" onload="frameLoaded();"/>
+
+ <script type="application/javascript">
+ <![CDATA[
+
+ SimpleTest.waitForExplicitFinish();
+
+ let prefs = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+ const UI_DIRECTION_PREF = "intl.uidirection.ar";
+ prefs.setCharPref(UI_DIRECTION_PREF, "rtl");
+
+ let rootDir = getRootDirectory(window.location.href);
+ registerManifestPermanently(rootDir + "rtltest/righttoleft.manifest");
+
+ function runTest()
+ {
+ var subframe = document.getElementById("subframe");
+ subframe.setAttribute("src", "chrome://ltrtest/content/dirtest.xul");
+ }
+
+ function frameLoaded()
+ {
+ var subframe = document.getElementById("subframe");
+ var subwin = subframe.contentWindow;
+ var subdoc = subframe.contentDocument;
+ var url = String(subwin.location);
+ if (url.indexOf("chrome://ltrtest") == 0) {
+ is(subwin.getComputedStyle(subdoc.getElementById("hbox"), "").backgroundColor,
+ "rgb(255, 255, 0)", "left to right with :-moz-locale-dir(ltr)");
+ is(subwin.getComputedStyle(subdoc.getElementById("vbox"), "").backgroundColor,
+ "rgb(255, 255, 255)", "left to right with :-moz-locale-dir(rtl)");
+
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "ltr",
+ "left to right direction");
+
+ subdoc.documentElement.setAttribute("localedir", "rtl");
+
+ is(subwin.getComputedStyle(subdoc.getElementById("hbox"), "").backgroundColor,
+ "rgb(255, 255, 255)", "left to right with :-moz-locale-dir(ltr) and localedir='rtl'");
+ is(subwin.getComputedStyle(subdoc.getElementById("vbox"), "").backgroundColor,
+ "rgb(0, 128, 0)", "left to right with :-moz-locale-dir(rtl) and localedir='rtl'");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "rtl",
+ "left to right direction with localedir='rtl'");
+
+ subdoc.documentElement.removeAttribute("localedir");
+
+ is(subwin.getComputedStyle(subdoc.getElementById("hbox"), "").backgroundColor,
+ "rgb(255, 255, 0)", "left to right with :-moz-locale-dir(ltr) and localedir removed");
+ is(subwin.getComputedStyle(subdoc.getElementById("vbox"), "").backgroundColor,
+ "rgb(255, 255, 255)", "left to right with :-moz-locale-dir(rtl) and localedir removed");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "ltr",
+ "left to right direction with localedir removed");
+
+ subframe.setAttribute("src", "chrome://rtltest/content/dirtest.xul");
+ }
+ else if (url.indexOf("chrome://rtltest") == 0) {
+ is(subwin.getComputedStyle(subdoc.getElementById("hbox"), "").backgroundColor,
+ "rgb(255, 255, 255)", "right to left with :-moz-locale-dir(ltr)");
+ is(subwin.getComputedStyle(subdoc.getElementById("vbox"), "").backgroundColor,
+ "rgb(0, 128, 0)", "right to left with :-moz-locale-dir(rtl)");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "rtl",
+ "right to left direction");
+
+ subdoc.documentElement.setAttribute("localedir", "ltr");
+
+ is(subwin.getComputedStyle(subdoc.getElementById("hbox"), "").backgroundColor,
+ "rgb(255, 255, 0)", "right to left with :-moz-locale-dir(ltr) and localedir='ltr'");
+ is(subwin.getComputedStyle(subdoc.getElementById("vbox"), "").backgroundColor,
+ "rgb(255, 255, 255)", "right to left with :-moz-locale-dir(rtl) and localedir='ltr'");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "ltr",
+ "right to left direction with localedir='ltr'");
+
+ subdoc.documentElement.removeAttribute("localedir");
+
+ prefs.setCharPref(UI_DIRECTION_PREF, "");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "ltr",
+ "left to right direction with no preference set");
+ prefs.setCharPref(UI_DIRECTION_PREF + "-QA", "rtl");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "rtl",
+ "right to left direction with more specific preference set");
+ prefs.setCharPref(UI_DIRECTION_PREF, "ltr");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "rtl",
+ "right to left direction with less specific and more specific preference set");
+ prefs.setCharPref(UI_DIRECTION_PREF, "rtl");
+ prefs.setCharPref(UI_DIRECTION_PREF + "-QA", "ltr");
+ is(subwin.getComputedStyle(subdoc.documentElement, "").direction, "ltr",
+ "left to right direction specific preference overrides");
+ if (prefs.prefHasUserValue(UI_DIRECTION_PREF + "-QA"))
+ prefs.clearUserPref(UI_DIRECTION_PREF + "-QA");
+
+ if (prefs.prefHasUserValue(UI_DIRECTION_PREF))
+ prefs.clearUserPref(UI_DIRECTION_PREF);
+
+ SimpleTest.finish();
+ }
+ }
+ ]]>
+ </script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_scale.xul b/toolkit/content/tests/chrome/test_scale.xul
new file mode 100644
index 000000000..c1adea7ff
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_scale.xul
@@ -0,0 +1,277 @@
+<?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"?>
+<!--
+ XUL Widget Test for scale
+ -->
+<window title="scale" width="500" height="600"
+ onload="setTimeout(testtag_scale, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<hbox>
+ <vbox>
+ <scale id="scale-horizontal-normal"/>
+ <scale id="scale-horizontal-reverse" dir="reverse"/>
+ </vbox>
+ <scale id="scale-vertical-normal" orient="vertical"/>
+ <scale id="scale-vertical-reverse" orient="vertical" dir="reverse"/>
+</hbox>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function testtag_scale()
+{
+ testtag_scale_inner("scale-horizontal-normal", true, false);
+ testtag_scale_inner("scale-horizontal-reverse", true, true);
+ testtag_scale_inner("scale-vertical-normal", false, false);
+ testtag_scale_inner("scale-vertical-reverse", false, true);
+
+ SimpleTest.finish();
+}
+
+function testtag_scale_inner(elementid, horiz, reverse)
+{
+ var testid = (horiz ? "horizontal " : "vertical ") +
+ (reverse ? "reverse " : "normal ");
+
+ var element = document.getElementById(elementid);
+
+ testtag_scale_States(element, 0, "", 0, 100, testid + "initial");
+
+ element.min = 0;
+ element.max = 10;
+ testtag_scale_States(element, 0, "", 0, 10, testid + "first set");
+
+ element.decrease();
+ is(element.value, 0, testid + "decrease");
+ element.increase();
+ is(element.value, 1, testid + "increase");
+ element.value = 0;
+ is(element.value, 0, testid + "set value");
+
+ testtag_scale_Increments(element, 0, 10, 6, 7, testid + "increase decrease");
+
+ // check if changing the min and max adjusts the value to fit in range
+ element.min = 5;
+ testtag_scale_States(element, 5, "5", 5, 10, testid + "change min");
+ element.value = 15;
+ is(element.value, 10, testid + "change minmax value set too high");
+ element.max = 8;
+ is(element.value, 8, testid + "change max");
+ element.value = 2;
+ is(element.value, 5, testid + "change minmax set too low");
+
+ // check negative values
+ element.min = -15;
+ element.max = -5;
+ testtag_scale_States(element, -5, "-5", -15, -5, testid + "minmax negative");
+ element.value = -15;
+ is(element.value, -15, testid + "change max negative");
+ testtag_scale_Increments(element, -15, -5, 7, 8, testid + "increase decrease negative");
+
+ // check case when min is negative and max is positive
+ element.min = -10;
+ element.max = 35;
+ testtag_scale_States(element, -10, "-10", -10, 35, testid + "minmax mixed sign");
+ testtag_scale_Increments(element, -10, 35, 25, 30, testid + "increase decrease mixed sign");
+
+ testtag_scale_UI(element, testid, horiz, reverse);
+}
+
+function testtag_scale_UI(element, testid, horiz, reverse)
+{
+ element.min = 0;
+ element.max = 20;
+ element.value = 7;
+ element.increment = 2;
+ element.pageIncrement = 4;
+
+ element.focus();
+
+ var leftIncrements = horiz && reverse;
+ var upDecrements = !horiz && !reverse;
+ synthesizeKeyExpectEvent("VK_LEFT", { }, element, "change", testid + "key left");
+ is(element.value, leftIncrements ? 9 : 5, testid + " key left");
+ synthesizeKeyExpectEvent("VK_RIGHT", { }, element, "change", testid + "key right");
+ is(element.value, 7, testid + " key right");
+ synthesizeKeyExpectEvent("VK_UP", { }, element, "change", testid + "key up");
+ is(element.value, upDecrements ? 5 : 9, testid + " key up");
+ synthesizeKeyExpectEvent("VK_DOWN", { }, element, "change", testid + "key down");
+ is(element.value, 7, testid + " key down");
+
+ synthesizeKeyExpectEvent("VK_PAGE_UP", { }, element, "change", testid + "key page up");
+ is(element.value, upDecrements ? 3 : 11, testid + " key page up");
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", { }, element, "change", testid + "key page down");
+ is(element.value, 7, testid + " key page down");
+
+ synthesizeKeyExpectEvent("VK_HOME", { }, element, "change", testid + "key home");
+ is(element.value, reverse ? 20 : 0, testid + " key home");
+ synthesizeKeyExpectEvent("VK_END", { }, element, "change", testid + "key end");
+ is(element.value, reverse ? 0 : 20, testid + " key end");
+
+ testtag_scale_UI_Mouse(element, testid, horiz, reverse, 4);
+
+ element.min = 4;
+ element.pageIncrement = 3;
+ testtag_scale_UI_Mouse(element, testid + " with min", horiz, reverse, 3);
+
+ element.pageIncrement = 30;
+ testtag_scale_UI_Mouse(element, testid + " with min past", horiz, reverse, 30);
+}
+
+function testtag_scale_UI_Mouse(element, testid, horiz, reverse, pinc)
+{
+ var initial = reverse ? 8 : 12;
+ var newval = initial + (reverse ? pinc : -pinc);
+ var endval = initial;
+ // in the pinc == 30 case, the page increment is large enough that it would
+ // just cause the thumb to reach the end of the scale. Make sure that the
+ // mouse click does not go past the end.
+ if (pinc == 30) {
+ newval = reverse ? 20 : 4;
+ endval = reverse ? 4 : 20;
+ }
+ element.value = initial;
+
+ var hmove = horiz ? 25 : 10;
+ var vmove = horiz ? 10 : 25;
+
+ var leftFn = function () { return reverse ? element.value < newval + 3 : element.value > newval - 3; }
+ var rightFn = function () { return reverse ? element.value < endval - 3 : element.value < endval + 3; }
+
+ // check that clicking the mouse on the trough moves the thumb properly
+ synthesizeMouseExpectEvent(element, hmove, vmove, { }, element, "change", testid + "mouse on left movetoclick=default");
+
+ if (navigator.platform.indexOf("Mac") >= 0) {
+ if (pinc == 30)
+ ok(element.value > 4, testid + " mouse on left movetoclick=default");
+ else
+ ok(leftFn, testid + " mouse on left movetoclick=default");
+ }
+ else {
+ is(element.value, newval, testid + " mouse on left movetoclick=default");
+ }
+
+ var rect = element.getBoundingClientRect();
+ synthesizeMouseExpectEvent(element, rect.right - rect.left - hmove,
+ rect.bottom - rect.top - vmove, { },
+ element, "change", testid + " mouse on right movetoclick=default");
+
+ if (navigator.platform.indexOf("Mac") >= 0) {
+ if (pinc == 30)
+ ok(element.value < 20, testid + " mouse on right movetoclick=default");
+ else
+ ok(rightFn, testid + " mouse on right movetoclick=default");
+ }
+ else {
+ is(element.value, endval, testid + " mouse on right movetoclick=default");
+ }
+
+ element.setAttribute("movetoclick", "true");
+ element.value = initial;
+
+ synthesizeMouseExpectEvent(element, hmove, vmove, { }, element, "change", testid + "mouse on left movetoclick=true");
+ if (pinc == 30)
+ ok(element.value > 4, testid + " mouse on left movetoclick=true");
+ else
+ ok(leftFn, testid + " mouse on left movetoclick=true");
+
+ var rect = element.getBoundingClientRect();
+ synthesizeMouseExpectEvent(element, rect.right - rect.left - hmove,
+ rect.bottom - rect.top - vmove, { },
+ element, "change", testid + " mouse on right movetoclick=true");
+ if (pinc == 30)
+ ok(element.value < 20, testid + " mouse on right movetoclick=true");
+ else
+ ok(rightFn, testid + " mouse on right movetoclick=true");
+
+ element.setAttribute("movetoclick", "false");
+ element.value = initial;
+
+ synthesizeMouseExpectEvent(element, hmove, vmove, { }, element, "change", testid + "mouse on left movetoclick=false");
+ is(element.value, newval, testid + " mouse on left movetoclick=false");
+
+ var rect = element.getBoundingClientRect();
+ synthesizeMouseExpectEvent(element, rect.right - rect.left - hmove,
+ rect.bottom - rect.top - vmove, { },
+ element, "change", testid + " mouse on right movetoclick=false");
+ is(element.value, endval, testid + " mouse on right movetoclick=false");
+
+ element.removeAttribute("movetoclick");
+
+ element.value = reverse ? element.max : element.min;
+
+ synthesizeMouse(element, 8, 8, { type: "mousedown" });
+ synthesizeMouse(element, horiz ? 2000 : 8, horiz ? 8 : 2000, { type: "mousemove" });
+ is(element.value, reverse ? element.min : element.max, testid + " move mouse too far after end");
+ synthesizeMouse(element, 2, 2, { type: "mouseup" });
+
+ synthesizeMouse(element, rect.width - 8, rect.height - 8, { type: "mousedown" });
+ synthesizeMouse(element, horiz ? -2000 : rect.width - 8, horiz ? rect.height - 8 : -2000, { type: "mousemove" });
+ is(element.value, reverse ? element.max : element.min, testid + " move mouse too far before start");
+
+ synthesizeMouse(element, 2, 2, { type: "mouseup" });
+
+ // now check if moving outside in both directions works. On Windows,
+ // it should snap back to the original location.
+ element.value = reverse ? element.max : element.min;
+
+ var expected = (navigator.platform.indexOf("Win") >= 0) ? element.value :
+ (reverse ? element.min : element.max);
+ synthesizeMouse(element, 7, 7, { type: "mousedown" });
+ synthesizeMouse(element, 2000, 2000, { type: "mousemove" });
+ is(element.value, expected, testid + " move mouse ouside in both directions");
+ synthesizeMouse(element, 2, 2, { type: "mouseup" });
+}
+
+function testtag_scale_States(element, evalue, evalueattr, emin, emax, testid)
+{
+ is(element.getAttribute("value"), evalueattr, testid + " value attribute");
+ is(element.value, evalue, testid + " value");
+ is(element.min, emin, testid + " min");
+ is(element.max, emax, testid + " max");
+}
+
+function testtag_scale_Increments(element, min, max, increment, pageIncrement, testid)
+{
+ // check the increase and decrease methods
+ element.increment = increment;
+ element.increase();
+ is(element.value, min + increment, testid + " increase 1");
+ element.increase();
+ is(element.value, max, testid + " increase 2");
+ element.decrease();
+ is(element.value, max - increment, testid + " decrease 1");
+ element.decrease();
+ is(element.value, min, testid + " decrease 2");
+
+ // check the increasePage and decreasePage methods
+ element.pageIncrement = pageIncrement;
+ element.increasePage();
+ is(element.value, min + pageIncrement, testid + " increasePage 1");
+ element.increasePage();
+ is(element.value, max, testid + " increasePage 2");
+ element.decreasePage();
+ is(element.value, max - pageIncrement, testid + " decreasePage 1");
+ element.decreasePage();
+ is(element.value, min, testid + " decreasePage 2");
+}
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_scaledrag.xul b/toolkit/content/tests/chrome/test_scaledrag.xul
new file mode 100644
index 000000000..82356ca1e
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_scaledrag.xul
@@ -0,0 +1,197 @@
+<?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"?>
+<!--
+XUL <scale> dragging tests
+-->
+<window title="Dragging XUL scale tests" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+ <hbox flex="1">
+ <scale id="scale1" orient="horizontal" flex="1" min="0" max="4" value="2"/>
+ <scale id="scale2" orient="vertical" flex="1" min="0" max="4" value="2"/>
+ <scale id="scale3" orient="horizontal" flex="1" movetoclick="true" min="0" max="4" value="2"/>
+ </hbox>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+function getThumb(aScale) {
+ return document.getAnonymousElementByAttribute(aScale, "class", "scale-thumb");
+}
+
+function sendTouch(aType, aRect, aDX, aDY, aMods) {
+ var cwu = SpecialPowers.getDOMWindowUtils(window);
+ var x = aRect.left + aRect.width/2 + aDX;
+ var y = aRect.top + aRect.height/2 + aDY;
+ if (/mouse/.test(aType))
+ cwu.sendMouseEvent(aType, x, y, 0, 1, aMods || 0, false);
+ else
+ cwu.sendTouchEvent(aType, [0], [x], [y], [1], [1], [0], [1], 1, aMods || 0, true);
+}
+
+function getOffset(aScale, aDir) {
+ var rect = aScale.getBoundingClientRect();
+ var d = aScale.orient == "horizontal" ? rect.width/4 : rect.height/4;
+ switch (aDir) {
+ case "right": return [ d, 0];
+ case "left": return [-1*d, 0];
+ case "up": return [ 0,-1*d];
+ case "down": return [ 0, d];
+ case "downleft": return [ -1*d, d];
+ case "upleft": return [ -1*d,-1*d];
+ case "downright": return [d, d];
+ case "upright": return [d,-1*d];
+ }
+ return [0,0];
+}
+
+function testTouchDragThumb(aDesc, aId, aDir, aVal1, aVal2, aMods) {
+ info(aDesc);
+ var scale = document.getElementById(aId);
+ var [x,y] = getOffset(scale, aDir);
+
+ sendTouch("touchstart", getThumb(scale).getBoundingClientRect(), 0, 0, aMods);
+ is(scale.value, aVal1, "Touchstart on thumb has correct value");
+ sendTouch("touchmove", getThumb(scale).getBoundingClientRect(), x, y, aMods);
+ sendTouch("touchend", getThumb(scale).getBoundingClientRect(), 0, 0, aMods);
+ is(scale.value, aVal2, "After touch " + (aDir ? ("and drag " + aDir + " ") : "") + "on thumb, scale has correct value");
+
+ scale.value = 2;
+}
+
+function testMouseDragThumb(aDesc, aId, aDir, aVal1, aVal2, aMods) {
+ info(aDesc);
+ var scale = document.getElementById(aId);
+ var [x,y] = getOffset(scale, aDir);
+
+ sendTouch("mousedown", getThumb(scale).getBoundingClientRect(), 0, 0, aMods);
+ is(scale.value, aVal1, "Mousedown on thumb has correct value");
+ sendTouch("mousemove", getThumb(scale).getBoundingClientRect(), x, y, aMods);
+ sendTouch("mouseup", getThumb(scale).getBoundingClientRect(), 0, 0, aMods);
+ is(scale.value, aVal2, "After mouseup " + (aDir ? ("and drag " + aDir + " ") : "") + "on thumb, scale has correct value");
+
+ scale.value = 2;
+}
+
+function testTouchDragSlider(aDesc, aId, aDir, aVal1, aVal2, aMods) {
+ info(aDesc);
+ var scale = document.getElementById(aId);
+ var [x,y] = getOffset(scale, aDir);
+
+ sendTouch("touchstart", getThumb(scale).getBoundingClientRect(), x, y, aMods);
+ is(scale.value, aVal1, "Touchstart on slider has correct value");
+ sendTouch("touchmove", getThumb(scale).getBoundingClientRect(), -x, -y, aMods);
+ sendTouch("touchend", getThumb(scale).getBoundingClientRect(), 0, 0, aMods);
+ is(scale.value, aVal2, "After touch " + (aDir ? ("and drag " + aDir + " ") : "") + "on slider, scale has correct value");
+
+ scale.value = 2;
+}
+
+function testMouseDragSlider(aDesc, aId, aDir, aVal1, aVal2, aMods) {
+ info(aDesc);
+ var scale = document.getElementById(aId);
+ var [x,y] = getOffset(scale, aDir);
+
+ sendTouch("mousedown", getThumb(scale).getBoundingClientRect(), x, y, aMods);
+ is(scale.value, aVal1, "Mousedown on slider has correct value");
+ sendTouch("mousemove", getThumb(scale).getBoundingClientRect(), -x, -y, aMods);
+ sendTouch("mouseup", getThumb(scale).getBoundingClientRect(), 0, 0, aMods);
+ is(scale.value, aVal2, "After mouseup " + (aDir ? ("and drag " + aDir + " ") : "") + "on slider, scale has correct value");
+
+ scale.value = 2;
+}
+
+function runTests() {
+ // test dragging a horizontal slider with touch events by tapping on the thumb
+ testTouchDragThumb("Touch Horizontal Thumb", "scale1", "", 2, 2);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Left", "scale1", "left", 2, 1);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Right", "scale1", "right", 2, 3);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Up", "scale1", "up", 2, 2);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Down", "scale1", "down", 2, 2);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Downleft", "scale1", "downleft", 2, 1);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Upleft", "scale1", "upleft", 2, 1);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Upright", "scale1", "upright", 2, 3);
+ testTouchDragThumb("TouchDrag Horizontal Thumb Downright", "scale1", "downright", 2, 3);
+
+ // test dragging a horizontal slider with mouse events by clicking on the thumb
+ testMouseDragThumb("Click Horizontal Thumb", "scale1", "", 2, 2);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Left", "scale1", "left", 2, 1);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Right", "scale1", "right", 2, 3);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Up", "scale1", "up", 2, 2);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Down", "scale1", "down", 2, 2);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Downleft", "scale1", "downleft", 2, 1);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Upleft", "scale1", "upleft", 2, 1);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Upright", "scale1", "upright", 2, 3);
+ testMouseDragThumb("MouseDrag Horizontal Thumb Downright", "scale1", "downright", 2, 3);
+
+ // test dragging a vertical slider with touch events by tapping on the thumb
+ testTouchDragThumb("Touch Vertical Thumb", "scale2", "", 2, 2);
+ testTouchDragThumb("TouchDrag Vertical Thumb Left", "scale2", "left", 2, 2);
+ testTouchDragThumb("TouchDrag Vertical Thumb Right", "scale2", "right", 2, 2);
+ testTouchDragThumb("TouchDrag Vertical Thumb Up", "scale2", "up", 2, 1);
+ testTouchDragThumb("TouchDrag Vertical Thumb Down", "scale2", "down", 2, 3);
+ testTouchDragThumb("TouchDrag Vertical Thumb Downleft", "scale2", "downleft", 2, 3);
+ testTouchDragThumb("TouchDrag Vertical Thumb Upleft", "scale2", "upleft", 2, 1);
+ testTouchDragThumb("TouchDrag Vertical Thumb Upright", "scale2", "upright", 2, 1);
+ testTouchDragThumb("TouchDrag Vertical Thumb Downright", "scale2", "downright", 2, 3);
+
+ // test dragging a vertical slider with mouse events by clicking on the thumb
+ testMouseDragThumb("Click Vertical Thumb", "scale2", "", 2, 2);
+ testMouseDragThumb("MouseDrag Vertical Thumb Left", "scale2", "left", 2, 2);
+ testMouseDragThumb("MouseDrag Vertical Thumb Right", "scale2", "right", 2, 2);
+ testMouseDragThumb("MouseDrag Vertical Thumb Up", "scale2", "up", 2, 1);
+ testMouseDragThumb("MouseDrag Vertical Thumb Down", "scale2", "down", 2, 3);
+ testMouseDragThumb("MouseDrag Vertical Thumb Downleft", "scale2", "downleft", 2, 3);
+ testMouseDragThumb("MouseDrag Vertical Thumb Upleft", "scale2", "upleft", 2, 1);
+ testMouseDragThumb("MouseDrag Vertical Thumb Upright", "scale2", "upright", 2, 1);
+ testMouseDragThumb("MouseDrag Vertical Thumb Downright", "scale2", "downright", 2, 3);
+
+ var isMac = /Mac/.test(navigator.platform);
+
+ // test dragging a slider by tapping off the thumb
+ testTouchDragSlider("TouchDrag Slider Left", "scale1", "left", isMac ? 1 : 0, isMac ? 2 : 0);
+ testTouchDragSlider("TouchDrag Slider Right", "scale1", "right", isMac ? 3 : 4, isMac ? 2 : 4);
+ testMouseDragSlider("MouseDrag Slider Left", "scale1", "left", isMac ? 1 : 0, isMac ? 2 : 0);
+ testMouseDragSlider("MouseDrag Slider Right", "scale1", "right", isMac ? 3 : 4, isMac ? 2 : 4);
+
+ // test dragging a slider by tapping off the thumb and holding shift
+ // modifiers don't affect touch events
+ var mods = /Mac/.test(navigator.platform) ? Components.interfaces.nsIDOMNSEvent.ALT_MASK :
+ Components.interfaces.nsIDOMNSEvent.SHIFT_MASK;
+ testTouchDragSlider("TouchDrag Slider Left+Shift", "scale1", "left", isMac ? 1 : 0, isMac ? 2 : 0, mods);
+ testTouchDragSlider("TouchDrag Slider Right+Shift", "scale1", "right", isMac ? 3 : 4, isMac ? 2 : 4, mods);
+ testMouseDragSlider("MouseDrag Slider Left+Shift", "scale1", "left", isMac ? 0 : 1, isMac ? 0 : 2, mods);
+ testMouseDragSlider("MouseDrag Slider Right+Shift", "scale1", "right", isMac ? 4 : 3, isMac ? 4 : 2, mods);
+
+ // test dragging a slider with movetoclick="true" by tapping off the thumb
+ testTouchDragSlider("TouchDrag Slider Left+MoveToClick", "scale3", "left", 1, 2);
+ testTouchDragSlider("TouchDrag Slider Right+MoveToClick", "scale3", "right", 3, 2);
+ testMouseDragSlider("MouseDrag Slider Left+MoveToClick", "scale3", "left", 1, 2);
+ testMouseDragSlider("MouseDrag Slider Right+MoveToClick", "scale3", "right", 3, 2);
+
+ // test dragging a slider by tapping off the thumb and holding shift
+ // modifiers don't affect touch events
+ testTouchDragSlider("MouseDrag Slider Left+MoveToClick+Shift", "scale3", "left", 1, 2, mods);
+ testTouchDragSlider("MouseDrag Slider Right+MoveToClick+Shift", "scale3", "right", 3, 2, mods);
+ testMouseDragSlider("MouseDrag Slider Left+MoveToClick+Shift", "scale3", "left", 0, 0, mods);
+ testMouseDragSlider("MouseDrag Slider Right+MoveToClick+Shift", "scale3", "right", 4, 4, mods);
+
+ SimpleTest.finish();
+}
+
+addLoadEvent(function() { SimpleTest.executeSoon(runTests); });
+]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_screenPersistence.xul b/toolkit/content/tests/chrome/test_screenPersistence.xul
new file mode 100644
index 000000000..7d6325293
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_screenPersistence.xul
@@ -0,0 +1,63 @@
+<?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="Window Open Test"
+ onload="runTest()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<script class="testbody" type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+ let win;
+ var left = 60 + screen.availLeft;
+ var upper = 60 + screen.availTop;
+
+ function runTest() {
+ win = window.openDialog("window_screenPosSize.xul",
+ null,
+ "chrome,dialog=no,all,screenX=" + left + ",screenY=" + upper + ",outerHeight=200,outerWidth=200");
+ SimpleTest.waitForFocus(checkTest, win);
+ }
+ function checkTest() {
+ is(win.screenX, left, "The window should be placed now at x=" + left + "px");
+ is(win.screenY, upper, "The window should be placed now at y=" + upper + "px");
+ is(win.outerHeight, 200, "The window size should be height=200px");
+ is(win.outerWidth, 200, "The window size should be width=200px");
+ runTest2();
+ }
+ function runTest2() {
+ win.close();
+ win = window.openDialog("window_screenPosSize.xul",
+ null,
+ "chrome,dialog=no,all");
+ SimpleTest.waitForFocus(checkTest2, win);
+ }
+ function checkTest2() {
+ let runTime = Components.classes["@mozilla.org/xre/app-info;1"]
+ .getService(Components.interfaces.nsIXULRuntime);
+ if (runTime.OS != "Linux") {
+ is(win.screenX, 80, "The window should be placed now at x=80px");
+ is(win.screenY, 80, "The window should be placed now at y=80px");
+ }
+ is(win.outerHeight, 300, "The window size should be height=300px");
+ is(win.outerWidth, 300, "The window size should be width=300px");
+ win.close();
+ SimpleTest.finish();
+ }
+]]></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_scrollbar.xul b/toolkit/content/tests/chrome/test_scrollbar.xul
new file mode 100644
index 000000000..11dccbee9
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_scrollbar.xul
@@ -0,0 +1,137 @@
+<?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"?>
+<!--
+ XUL Widget Test for scrollbars
+ -->
+<window title="Scrollbar"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml"/>
+
+ <hbox>
+ <scrollbar orient="horizontal"
+ id="scroller"
+ curpos="0"
+ maxpos="600"
+ pageincrement="400"
+ width="500"
+ style="margin:0"/>
+ </hbox>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+/** Test for Scrollbar **/
+var scrollbarTester = {
+ scrollbar: null,
+ middlePref: false,
+ startTest: function() {
+ this.scrollbar = $("scroller");
+ this.middlePref = this.getMiddlePref();
+ var self = this;
+ [0, 1, 2].map(function(button) {
+ [false, true].map(function(alt) {
+ [false, true].map(function(shift) {
+ self.testThumbDragging(button, alt, shift);
+ })
+ })
+ });
+ SimpleTest.finish();
+ },
+ testThumbDragging: function(button, withAlt, withShift) {
+ this.reset();
+ var x = 160; // on the right half of the thumb
+ var y = 5;
+
+ var isMac = navigator.platform.indexOf("Mac") != -1;
+ var runtime = Components.classes["@mozilla.org/xre/app-info;1"]
+ .getService(Components.interfaces.nsIXULRuntime);
+ var isGtk = runtime.widgetToolkit.indexOf("gtk") != -1;
+
+ // Start the drag.
+ this.mousedown(x, y, button, withAlt, withShift);
+ var newPos = this.getPos();
+ var scrollToClick = (newPos != 0);
+ if (isMac || isGtk) {
+ ok(!scrollToClick, "On Linux and Mac OS X, clicking the scrollbar thumb "+
+ "should never move it.");
+ } else if (button == 0 && withShift) {
+ ok(scrollToClick, "On platforms other than Linux and Mac OS X, holding "+
+ "shift should enable scroll-to-click on the scrollbar thumb.");
+ } else if (button == 1 && this.middlePref) {
+ ok(scrollToClick, "When middlemouse.scrollbarPosition is on, clicking the "+
+ "thumb with the middle mouse button should center it "+
+ "around the cursor.")
+ }
+
+ // Move one pixel to the right.
+ this.mousemove(x+1, y, button, withAlt, withShift);
+ var newPos2 = this.getPos();
+ if (newPos2 != newPos) {
+ ok(newPos2 > newPos, "Scrollbar thumb should follow the mouse when dragged.");
+ ok(newPos2 - newPos < 3, "Scrollbar shouldn't move further than the mouse when dragged.");
+ ok(button == 0 || (button == 1 && this.middlePref) || (button == 2 && isGtk),
+ "Dragging the scrollbar should only be possible with the left mouse button.");
+ } else {
+ // Dragging had no effect.
+ if (button == 0) {
+ ok(false, "Dragging the scrollbar thumb should work.");
+ } else if (button == 1 && this.middlePref && (!isGtk && !isMac)) {
+ ok(false, "When middlemouse.scrollbarPosition is on, dragging the "+
+ "scrollbar thumb should be possible using the middle mouse button.");
+ } else {
+ ok(true, "Dragging works correctly.");
+ }
+ }
+
+ // Release the mouse button.
+ this.mouseup(x+1, y, button, withAlt, withShift);
+ var newPos3 = this.getPos();
+ ok(newPos3 == newPos2,
+ "Releasing the mouse button after dragging the thumb shouldn't move it.");
+ },
+ getMiddlePref: function() {
+ // It would be better to test with different middlePref settings,
+ // but the setting is only queried once, at browser startup, so
+ // changing it here wouldn't have any effect
+ var prefService = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefService);
+ var mouseBranch = prefService.getBranch("middlemouse.");
+ return mouseBranch.getBoolPref("scrollbarPosition");
+ },
+ setPos: function(pos) {
+ this.scrollbar.setAttribute("curpos", pos);
+ },
+ getPos: function() {
+ return this.scrollbar.getAttribute("curpos");
+ },
+ reset: function() {
+ this.setPos(0);
+ },
+ mousedown: function(x, y, button, alt, shift) {
+ synthesizeMouse(this.scrollbar, x, y, { type: "mousedown", 'button': button,
+ altKey: alt, shiftKey: shift });
+ },
+ mousemove: function(x, y, button, alt, shift) {
+ synthesizeMouse(this.scrollbar, x, y, { type: "mousemove", 'button': button,
+ altKey: alt, shiftKey: shift });
+ },
+ mouseup: function(x, y, button, alt, shift) {
+ synthesizeMouse(this.scrollbar, x, y, { type: "mouseup", 'button': button,
+ altKey: alt, shiftKey: shift });
+ }
+}
+
+function doTest() {
+ setTimeout(function() { scrollbarTester.startTest(); }, 0);
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_showcaret.xul b/toolkit/content/tests/chrome/test_showcaret.xul
new file mode 100644
index 000000000..75a8cf6a2
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_showcaret.xul
@@ -0,0 +1,101 @@
+<?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="Show Caret Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<iframe id="f1" width="100" height="100" onload="frameLoaded()"
+ src="data:text/html,%3Cbody%20style='height:%208000px'%3E%3Cp%3EHello%3C/p%3EGoodbye%3C/body%3E"/>
+<!-- <body style='height: 8000px'><p>Hello</p><span id='s'>Goodbye<span></body> -->
+<iframe id="f2" type="content" showcaret="true" width="100" height="100" onload="frameLoaded()"
+ src="data:text/html,%3Cbody%20style%3D%27height%3A%208000px%27%3E%3Cp%3EHello%3C%2Fp%3E%3Cspan%20id%3D%27s%27%3EGoodbye%3Cspan%3E%3C%2Fbody%3E"/>
+
+<script>
+<![CDATA[
+
+var framesLoaded = 0;
+var otherWindow = null;
+
+function frameLoaded() { if (++framesLoaded == 2) SimpleTest.waitForFocus(runTest); }
+
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ var sel1 = frames[0].getSelection();
+ sel1.collapse(frames[0].document.body, 0);
+
+ var sel2 = frames[1].getSelection();
+ sel2.collapse(frames[1].document.body, 0);
+ window.frames[0].focus();
+ document.commandDispatcher.getControllerForCommand("cmd_moveBottom").doCommand("cmd_moveBottom");
+
+ var listener = function() {
+ if (!(frames[0].scrollY > 0)) {
+ window.content.removeEventListener("scroll", listener, false);
+ }
+ }
+ window.frames[0].addEventListener("scroll", listener, false);
+
+ var sel1 = frames[0].getSelection();
+ sel1.collapse(frames[0].document.body, 0);
+
+ var sel2 = frames[1].getSelection();
+ sel2.collapse(frames[1].document.body, 0);
+
+ window.frames[0].focus();
+ document.commandDispatcher.getControllerForCommand("cmd_moveBottom").doCommand("cmd_moveBottom");
+ is(sel1.focusNode, frames[0].document.body, "focusNode for non-showcaret");
+ is(sel1.focusOffset, 0, "focusOffset for non-showcaret");
+
+ window.frames[1].focus();
+ document.commandDispatcher.getControllerForCommand("cmd_moveBottom").doCommand("cmd_moveBottom");
+
+ ok(frames[1].scrollY <
+ frames[1].document.getElementById('s').getBoundingClientRect().top,
+ "scrollY for showcaret");
+ isnot(sel2.focusNode, frames[1].document.body, "focusNode for showcaret");
+ ok(sel2.anchorOffset > 0, "focusOffset for showcaret");
+
+ otherWindow = window.open("window_showcaret.xul", "_blank", "chrome,width=400,height=200");
+ otherWindow.addEventListener("focus", otherWindowFocused, false);
+}
+
+function otherWindowFocused()
+{
+ otherWindow.removeEventListener("focus", otherWindowFocused, false);
+
+ // enable caret browsing temporarily to test caret movement
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch);
+ prefs.setBoolPref("accessibility.browsewithcaret", true);
+
+ var hbox = otherWindow.document.documentElement.firstChild;
+ hbox.focus();
+ is(otherWindow.document.activeElement, hbox, "hbox in other window is focused");
+
+ document.commandDispatcher.getControllerForCommand("cmd_lineNext").doCommand("cmd_lineNext");
+ is(otherWindow.document.activeElement, hbox, "hbox still focused in other window after down movement");
+
+ prefs.setBoolPref("accessibility.browsewithcaret", false);
+
+ otherWindow.close();
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_sorttemplate.xul b/toolkit/content/tests/chrome/test_sorttemplate.xul
new file mode 100644
index 000000000..a08e3b6a8
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_sorttemplate.xul
@@ -0,0 +1,89 @@
+<?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"?>
+<?xml-stylesheet href="data:text/css,window > |people { display: none }" type="text/css"?>
+<!--
+ XUL Widget Test for tabindex
+ -->
+<window title="tabindex" width="500" height="600"
+ onfocus="runTest()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<people id="famouspeople" xmlns="">
+ <person name="Napoleon Bonaparte" gender="male"/>
+ <person name="Cleopatra" gender="female"/>
+ <person name="Julius Caesar" gender="male"/>
+ <person name="Ferdinand Magellan" gender="male"/>
+ <person name="Laura Secord" gender="female"/>
+</people>
+
+<tree id="tree" datasources="#famouspeople" ref="*" querytype="xml" flex="1">
+ <treecols>
+ <treecol label="Name" flex="1" sort="?name"/>
+ <treecol label="Gender" flex="1" sort="?gender"/>
+ </treecols>
+ <template>
+ <query/>
+ <rule>
+ <action>
+ <treechildren id="treechildren-strings">
+ <treeitem uri="?">
+ <treerow>
+ <treecell label="?name"/>
+ <treecell label="?gender"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </action>
+ </rule>
+ </template>
+</tree>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest()
+{
+ var tree = $("tree");
+ var col = tree.columns[0].element;
+ synthesizeMouse(col, 12, 2, { });
+ checkRowOrder(tree, ["Cleopatra", "Ferdinand Magellan", "Julius Caesar", "Laura Secord", "Napoleon Bonaparte"], "acsending");
+
+ synthesizeMouse(col, 12, 2, { });
+ checkRowOrder(tree, ["Napoleon Bonaparte", "Laura Secord", "Julius Caesar", "Ferdinand Magellan", "Cleopatra"], "descending");
+
+ synthesizeMouse(col, 12, 2, { });
+ checkRowOrder(tree, ["Napoleon Bonaparte", "Laura Secord", "Julius Caesar", "Ferdinand Magellan", "Cleopatra"], "natural");
+
+ SimpleTest.finish();
+}
+
+function checkRowOrder(tree, expected, testid)
+{
+ var index = 0;
+ var item = tree.firstChild.nextSibling.nextSibling.firstChild;
+ while (item && index < expected.length) {
+ if (item.firstChild.firstChild.getAttribute("label") != expected[index++])
+ break;
+ item = item.nextSibling;
+ }
+ ok(index == expected.length && !item, testid + " row order");
+}
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_statusbar.xul b/toolkit/content/tests/chrome/test_statusbar.xul
new file mode 100644
index 000000000..160cc25d0
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_statusbar.xul
@@ -0,0 +1,42 @@
+<?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"?>
+<!--
+ XUL Widget Test for statusbar
+ -->
+<window title="Statusbar Test"
+ onload="setTimeout(test_statusbar, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<statusbar>
+ <statusbarpanel id="panel" label="OK" image="happy.png"/>
+</statusbar>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function test_statusbar()
+{
+ var panel = $("panel");
+ ok(panel.label, "OK", "statusbarpanel label");
+ ok(panel.image, "happy.png", "statusbarpanel image");
+ panel.src = "sad.png";
+ ok(panel.src, "sad.png", "statusbarpanel set src");
+ ok(panel.getAttribute("src"), "sad.png", "statusbarpanel set src attribute");
+
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_subframe_origin.xul b/toolkit/content/tests/chrome/test_subframe_origin.xul
new file mode 100644
index 000000000..bde1e4945
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_subframe_origin.xul
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Subframe Event Tests"
+ onload="setTimeout(runTest, 0);"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<script>
+
+// Added after content child widgets were removed from ui windows. Tests sub frame
+// event client coordinate offsets.
+
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_subframe_origin.xul", "_blank", "chrome,width=600,height=600");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_tabbox.xul b/toolkit/content/tests/chrome/test_tabbox.xul
new file mode 100644
index 000000000..3cbacb15a
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tabbox.xul
@@ -0,0 +1,224 @@
+<?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"?>
+<!--
+ XUL Widget Test for tabboxes
+ -->
+<window title="Tabbox Test" width="500" height="600"
+ onload="setTimeout(test_tabbox, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+ <script type="application/javascript" src="xul_selectcontrol.js"/>
+
+<vbox id="tabboxes">
+
+<tabbox id="tabbox">
+ <tabs id="tabs">
+ <tab id="tab1" label="Tab 1"/>
+ <tab id="tab2" label="Tab 2"/>
+ </tabs>
+ <tabpanels id="tabpanels">
+ <button id="panel1" label="Panel 1"/>
+ <button id="panel2" label="Panel 2"/>
+ </tabpanels>
+</tabbox>
+
+<tabbox id="tabbox-initwithvalue">
+ <tabs id="tabs-initwithvalue" value="two">
+ <tab label="Tab 1" value="one"/>
+ <tab label="Tab 2" value="two"/>
+ <tab label="Tab 3" value="three"/>
+ </tabs>
+ <tabpanels id="tabpanels-initwithvalue">
+ <button label="Panel 1"/>
+ <button label="Panel 2"/>
+ <button label="Panel 3"/>
+ </tabpanels>
+</tabbox>
+
+<tabbox id="tabbox-initwithselected">
+ <tabs id="tabs-initwithselected" value="two">
+ <tab label="Tab 1" value="one"/>
+ <tab label="Tab 2" value="two"/>
+ <tab label="Tab 3" value="three" selected="true"/>
+ </tabs>
+ <tabpanels id="tabpanels-initwithselected">
+ <button label="Panel 1"/>
+ <button label="Panel 2"/>
+ <button label="Panel 3"/>
+ </tabpanels>
+</tabbox>
+
+</vbox>
+
+<tabbox id="tabbox-nofocus">
+ <textbox id="textbox-extra" hidden="true"/>
+ <tabs>
+ <tab label="Tab 1" value="one"/>
+ <tab id="tab-nofocus" label="Tab 2" value="two"/>
+ </tabs>
+ <tabpanels>
+ <tabpanel>
+ <button id="tab-nofocus-button" label="Label"/>
+ </tabpanel>
+ <tabpanel id="tabpanel-nofocusinpaneltab">
+ <label id="tablabel" value="Label"/>
+ </tabpanel>
+ </tabpanels>
+</tabbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function test_tabbox()
+{
+ var tabbox = document.getElementById("tabbox");
+ var tabs = document.getElementById("tabs");
+ var tabpanels = document.getElementById("tabpanels");
+
+ test_tabbox_State(tabbox, "tabbox initial", 0, tabs.firstChild, tabpanels.firstChild);
+
+ // check the selectedIndex property
+ tabbox.selectedIndex = 1;
+ test_tabbox_State(tabbox, "tabbox selectedIndex 1", 1, tabs.lastChild, tabpanels.lastChild);
+
+ tabbox.selectedIndex = 2;
+ test_tabbox_State(tabbox, "tabbox selectedIndex 2", 1, tabs.lastChild, tabpanels.lastChild);
+
+ // tabbox must have a selection, so setting to -1 should do nothing
+ tabbox.selectedIndex = -1;
+ test_tabbox_State(tabbox, "tabbox selectedIndex -1", 1, tabs.lastChild, tabpanels.lastChild);
+
+ // check the selectedTab property
+ tabbox.selectedTab = tabs.firstChild;
+ test_tabbox_State(tabbox, "tabbox selected", 0, tabs.firstChild, tabpanels.firstChild);
+
+ // setting selectedTab to null should not do anything
+ tabbox.selectedTab = null;
+ test_tabbox_State(tabbox, "tabbox selectedTab null", 0, tabs.firstChild, tabpanels.firstChild);
+
+ // check the selectedPanel property
+ tabbox.selectedPanel = tabpanels.lastChild;
+ test_tabbox_State(tabbox, "tabbox selectedPanel", 0, tabs.firstChild, tabpanels.lastChild);
+
+ // setting selectedPanel to null should not do anything
+ tabbox.selectedPanel = null;
+ test_tabbox_State(tabbox, "tabbox selectedPanel null", 0, tabs.firstChild, tabpanels.lastChild);
+
+ tabbox.selectedIndex = 0;
+ test_tabpanels(tabpanels, tabbox);
+
+ tabs.removeChild(tabs.firstChild);
+ tabs.removeChild(tabs.firstChild);
+
+ test_tabs(tabs);
+
+ test_tabbox_focus();
+}
+
+function test_tabpanels(tabpanels, tabbox)
+{
+ var tab = tabbox.selectedTab;
+
+ // changing the selection on the tabpanels should not affect the tabbox
+ // or tabs within
+ // check the selectedIndex property
+ tabpanels.selectedIndex = 1;
+ test_tabbox_State(tabbox, "tabpanels tabbox selectedIndex 1", 0, tab, tabpanels.lastChild);
+ test_tabpanels_State(tabpanels, "tabpanels selectedIndex 1", 1, tabpanels.lastChild);
+
+ tabpanels.selectedIndex = 0;
+ test_tabbox_State(tabbox, "tabpanels tabbox selectedIndex 2", 0, tab, tabpanels.firstChild);
+ test_tabpanels_State(tabpanels, "tabpanels selectedIndex 2", 0, tabpanels.firstChild);
+
+ // setting selectedIndex to -1 should do nothing
+ tabpanels.selectedIndex = 1;
+ tabpanels.selectedIndex = -1;
+ test_tabbox_State(tabbox, "tabpanels tabbox selectedIndex -1", 0, tab, tabpanels.lastChild);
+ test_tabpanels_State(tabpanels, "tabpanels selectedIndex -1", 1, tabpanels.lastChild);
+
+ // check the tabpanels.selectedPanel property
+ tabpanels.selectedPanel = tabpanels.lastChild;
+ test_tabbox_State(tabbox, "tabpanels tabbox selectedPanel", 0, tab, tabpanels.lastChild);
+ test_tabpanels_State(tabpanels, "tabpanels selectedPanel", 1, tabpanels.lastChild);
+
+ // check setting the tabpanels.selectedPanel property to null
+ tabpanels.selectedPanel = null;
+ test_tabbox_State(tabbox, "tabpanels selectedPanel null", 0, tab, tabpanels.lastChild);
+}
+
+function test_tabs(tabs)
+{
+ test_nsIDOMXULSelectControlElement(tabs, "tab", "tabs");
+ // XXXndeakin would test the UI aspect of tabs, but the mouse
+ // events on tabs are fired in a timeout causing the generic
+ // test_nsIDOMXULSelectControlElement_UI method not to work
+ // test_nsIDOMXULSelectControlElement_UI(tabs, null);
+}
+
+function test_tabbox_State(tabbox, testid, index, tab, panel)
+{
+ is(tabbox.selectedIndex, index, testid + " selectedIndex");
+ is(tabbox.selectedTab, tab, testid + " selectedTab");
+ is(tabbox.selectedPanel, panel, testid + " selectedPanel");
+}
+
+function test_tabpanels_State(tabpanels, testid, index, panel)
+{
+ is(tabpanels.selectedIndex, index, testid + " selectedIndex");
+ is(tabpanels.selectedPanel, panel, testid + " selectedPanel");
+}
+
+function test_tabbox_focus()
+{
+ $("tabboxes").hidden = true;
+ $(document.activeElement).blur();
+
+ var tabbox = $("tabbox-nofocus");
+ var tab = $("tab-nofocus");
+
+ when_tab_focused(tab, function () {
+ ok(document.activeElement, tab, "focus in tab with no focusable elements");
+
+ tabbox.selectedIndex = 0;
+ $("tab-nofocus-button").focus();
+
+ when_tab_focused(tab, function () {
+ ok(document.activeElement, tab, "focus in tab with no focusable elements, but with something in another tab focused");
+
+ var textboxExtra = $("textbox-extra");
+ textboxExtra.addEventListener("focus", function () {
+ textboxExtra.removeEventListener("focus", arguments.callee, true);
+ ok(document.activeElement, textboxExtra, "focus in tab with focus currently in textbox that is sibling of tabs");
+
+ SimpleTest.finish();
+ }, true);
+
+ tabbox.selectedIndex = 0;
+ textboxExtra.hidden = false;
+ synthesizeMouseAtCenter(tab, { });
+ });
+
+ synthesizeMouseAtCenter(tab, { });
+ });
+
+ synthesizeMouseAtCenter(tab, { });
+}
+
+function when_tab_focused(tab, callback) {
+ tab.addEventListener("focus", function onFocused() {
+ tab.removeEventListener("focus", onFocused, true);
+ SimpleTest.executeSoon(callback);
+ }, true);
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_tabindex.xul b/toolkit/content/tests/chrome/test_tabindex.xul
new file mode 100644
index 000000000..425cb7b9e
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tabindex.xul
@@ -0,0 +1,120 @@
+<?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"?>
+<!--
+ XUL Widget Test for tabindex
+ -->
+<window title="tabindex" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<!--
+ Elements are navigated in the following order:
+ 1. tabindex > 0 in tree order
+ 2. tabindex = 0 in tree order
+ Elements with tabindex = -1 are not in the tab order
+ -->
+<hbox>
+ <button id="t5" label="One"/>
+ <checkbox id="no1" label="Two" tabindex="-1"/>
+ <button id="t6" label="Three" tabindex="0"/>
+ <checkbox id="t1" label="Four" tabindex="1"/>
+</hbox>
+<hbox>
+ <textbox id="t7" idmod="t3" size="3"/>
+ <textbox id="no2" size="3" tabindex="-1"/>
+ <textbox id="t8" idmod="t4" size="3" tabindex="0"/>
+ <textbox id="t2" idmod="t1" size="3" tabindex="1"/>
+</hbox>
+<hbox>
+ <button id="no3" style="-moz-user-focus: ignore;" label="One"/>
+ <checkbox id="no4" style="-moz-user-focus: ignore;" label="Two" tabindex="-1"/>
+ <button id="t9" style="-moz-user-focus: ignore;" label="Three" tabindex="0"/>
+ <checkbox id="t3" style="-moz-user-focus: ignore;" label="Four" tabindex="1"/>
+</hbox>
+<hbox>
+ <textbox id="t10" idmod="t5" style="-moz-user-focus: ignore;" size="3"/>
+ <textbox id="no5" style="-moz-user-focus: ignore;" size="3" tabindex="-1"/>
+ <textbox id="t11" idmod="t6" style="-moz-user-focus: ignore;" size="3" tabindex="0"/>
+ <textbox id="t4" idmod="t2" style="-moz-user-focus: ignore;" size="3" tabindex="1"/>
+</hbox>
+<listbox id="t12" idmod="t7">
+ <listitem label="Item One"/>
+</listbox>
+
+<hbox>
+ <!-- the tabindex attribute does not apply to non-controls, so it
+ should be treated as -1 for non-focusable dropmarkers, and 0
+ for focusable dropmarkers. Thus, the first four dropmarkers
+ are not in the tab order, and the last four dropmarkers should
+ be in the tab order just after the listbox above.
+ -->
+ <dropmarker id="no6"/>
+ <dropmarker id="no7" tabindex="-1"/>
+ <dropmarker id="no8" tabindex="0"/>
+ <dropmarker id="no9" tabindex="1"/>
+ <dropmarker id="t13" style="-moz-user-focus: normal;"/>
+ <dropmarker id="t14" style="-moz-user-focus: normal;" tabindex="-1"/>
+ <dropmarker id="t15" style="-moz-user-focus: normal;" tabindex="0"/>
+ <dropmarker id="t16" style="-moz-user-focus: normal;" tabindex="1"/>
+</hbox>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gAdjustedTabFocusModel = false;
+var gTestCount = 16;
+var gTestsOccurred = 0;
+
+function runTests()
+{
+ var t;
+ window.addEventListener("focus", function (event) {
+ if (t == 1 && event.target.id == "t2") {
+ // looks to be using the MacOSX Full Keyboard Access set to Textboxes
+ // and lists only so use the idmod attribute instead
+ gAdjustedTabFocusModel = true;
+ gTestCount = 7;
+ }
+
+ var attrcompare = gAdjustedTabFocusModel ? "idmod" : "id";
+
+ // check for the last test which should wrap aorund to the first item
+ // consider the focus event on the inner input of textboxes instead
+ if (event.originalTarget.localName == "input") {
+ is(document.getBindingParent(event.originalTarget).getAttribute(attrcompare),
+ "t" + t, "tab " + t + " to inner input");
+ gTestsOccurred++;
+ }
+ else {
+ is(event.target.getAttribute(attrcompare), "t" + t, "tab " + t + " to " + event.target.localName)
+ if (event.target.localName != "textbox")
+ gTestsOccurred++;
+ }
+ }, true);
+
+ for (t = 1; t <= gTestCount; t++)
+ synthesizeKey("VK_TAB", { });
+
+ is(gTestsOccurred, gTestCount, "test count");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(runTests);
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_textbox_dictionary.xul b/toolkit/content/tests/chrome/test_textbox_dictionary.xul
new file mode 100644
index 000000000..8e69dd15e
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_textbox_dictionary.xul
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+ XUL Widget Test for textbox with Add and Undo Add to Dictionary
+ -->
+<window title="Textbox Add and Undo Add to Dictionary Test" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+ <hbox>
+ <textbox id="t1" value="Hellop" oncontextmenu="runContextMenuTest()" spellcheck="true"/>
+ </hbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var textbox;
+var testNum;
+
+function bringUpContextMenu(element)
+{
+ synthesizeMouseAtCenter(element, { type: "contextmenu", button: 2});
+}
+
+function leftClickElement(element)
+{
+ synthesizeMouseAtCenter(element, { button: 0 });
+}
+
+function startTests()
+{
+ textbox = document.getElementById("t1");
+ textbox.focus();
+ testNum = 0;
+
+ Components.utils.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm");
+ onSpellCheck(textbox, function () {
+ bringUpContextMenu(textbox);
+ });
+}
+
+function runContextMenuTest()
+{
+ SimpleTest.executeSoon( function() {
+ // The textbox has its children in an hbox XUL element, so get that first
+ var hbox = document.getAnonymousNodes(textbox).item(0);
+
+ var contextMenu = document.getAnonymousElementByAttribute(hbox, "anonid", "input-box-contextmenu");
+
+ switch(testNum)
+ {
+ case 0: // "Add to Dictionary" button
+ var addToDict = contextMenu.querySelector("[anonid=spell-add-to-dictionary]");
+ ok(!addToDict.hidden, "Is Add to Dictionary visible?");
+
+ var separator = contextMenu.querySelector("[anonid=spell-suggestions-separator]");
+ ok(!separator.hidden, "Is separator visible?");
+
+ addToDict.doCommand();
+
+ contextMenu.hidePopup();
+ testNum++;
+
+ onSpellCheck(textbox, function () {
+ bringUpContextMenu(textbox);
+ });
+ break;
+
+ case 1: // "Undo Add to Dictionary" button
+ var undoAddDict = contextMenu.querySelector("[anonid=spell-undo-add-to-dictionary]");
+ ok(!undoAddDict.hidden, "Is Undo Add to Dictioanry visible?");
+
+ var separator = contextMenu.querySelector("[anonid=spell-suggestions-separator]");
+ ok(!separator.hidden, "Is separator hidden?");
+
+ undoAddDict.doCommand();
+
+ contextMenu.hidePopup();
+ onSpellCheck(textbox, function () {
+ SimpleTest.finish();
+ });
+ break;
+ }
+ });
+}
+
+SimpleTest.waitForFocus(startTests);
+
+ ]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_textbox_emptytext.xul b/toolkit/content/tests/chrome/test_textbox_emptytext.xul
new file mode 100644
index 000000000..41c702a90
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_textbox_emptytext.xul
@@ -0,0 +1,48 @@
+<?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"?>
+<!--
+ XUL Widget Test for textbox with placeholder
+ -->
+<window title="Textbox with placeholder test" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <hbox>
+ <textbox id="t1"/>
+ </hbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function doTests() {
+ var t1 = $("t1");
+
+ t1.placeholder = 1;
+ ok("1" === t1.label, "placeholder exposed as label");
+ ok("" === t1.value, "placeholder not exposed as value");
+
+ t1.label = 2;
+ ok("2" === t1.label, "label can be set explicitly");
+ ok("1" === t1.placeholder, "placeholder persists after setting label");
+
+ t1.value = 3;
+ ok("3" === t1.value, "value setter/getter works while placeholder is present");
+ ok("1" === t1.placeholder, "placeholder persists after setting value");
+
+ t1.value = "";
+ is(t1.textLength, 0, "textLength while placeholder is displayed");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(doTests);
+
+ ]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_textbox_number.xul b/toolkit/content/tests/chrome/test_textbox_number.xul
new file mode 100644
index 000000000..369e92785
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_textbox_number.xul
@@ -0,0 +1,353 @@
+<?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"?>
+<!--
+ XUL Widget Test for textbox type="number"
+ -->
+<window title="Textbox type='number' test" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<hbox>
+ <textbox id="n1" type="number" size="4"/>
+ <textbox id="n2" type="number" value="10" min="5" max="15" wraparound="true"/>
+</hbox>
+<hbox>
+ <textbox id="n3" type="number" size="4" value="25" min="1" max="12" increment="3"/>
+</hbox>
+<hbox>
+ <textbox id="n4" type="number" size="4" value="-2" min="-8" max="18"/>
+ <textbox id="n5" type="number" value="-17" min="-10" max="-3"/>
+</hbox>
+<hbox>
+ <textbox id="n6" type="number" size="4" value="9" min="12" max="8"/>
+</hbox>
+<hbox>
+ <textbox id="n7" type="number" size="4" value="4.678" min="2" max="10.5" decimalplaces="2"/>
+ <textbox id="n8" type="number" hidespinbuttons="true"/>
+</hbox>
+<hbox>
+ <textbox id="n9" type="number" size="4" oninput="updateInputEventCount();"/>
+</hbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+// ---- NOTE: the numbers used in these tests are carefully chosen to avoid
+// ---- floating point rounding issues
+
+function doTests() {
+ var n1 = $("n1");
+ var n2 = $("n2");
+ var n3 = $("n3");
+ var n4 = $("n4");
+ var n5 = $("n5");
+ var n6 = $("n6");
+ var n7 = $("n7");
+
+ testValsMinMax(n1, "initial n1", 0, 0, Infinity);
+ testValsMinMax(n2, "initial n2", 10, 5, 15);
+ testValsMinMax(n3, "initial n3", 12, 1, 12);
+ testValsMinMax(n4, "initial n4", -2, -8, 18);
+ testValsMinMax(n5, "initial n5", -10, -10, -3);
+ testValsMinMax(n6, "initial n6", 12, 12, 12);
+ testValsMinMax(n7, "initial n7", 4.68, 2, 10.5); // value should be rounded
+
+ ok(n1.spinButtons != null && n1.spinButtons.localName == "spinbuttons", "spinButtons set");
+ isnot(n1.decimalSymbol, "", "n1.decimalSymbol is set to something");
+ n1.decimalSymbol = ".";
+ SimpleTest.is(n1.decimalSymbol, ".", "n1.decimalSymbol set to '.'");
+ SimpleTest.is(n1.wrapAround, false, "wrapAround defaults to false");
+ SimpleTest.is(n1.increment, 1, "increment defaults to 1");
+ SimpleTest.is(n1.decimalPlaces, 0, "decimalPlaces defaults to 0");
+
+ SimpleTest.is(n2.wrapAround, true, "wrapAround when set to true");
+ SimpleTest.is(n3.increment, 3, "increment when set to 1");
+ SimpleTest.is(n7.decimalPlaces, 2, "decimalPlaces when set to 2");
+
+ // test changing the value
+ n1.value = "1700";
+ testVals(n1, "set value,", 1700);
+ n1.value = 1600;
+ testVals(n1, "set value int,", 1600);
+ n2.value = "2";
+ testVals(n2, "set value below min,", 5);
+ n2.value = 2;
+ testVals(n2, "set value below min int,", 5);
+ n2.value = 18;
+ testVals(n2, "set value above max,", 15);
+ n2.value = -6;
+ testVals(n2, "set value below min negative,", 5);
+ n5.value = -2;
+ testVals(n5, "set value above max positive,", -3);
+ n7.value = 5.999;
+ testVals(n7, "set value to decimal,", 6, "6.00");
+ n7.value = "1.42";
+ testVals(n7, "set value to decimal below min,", 2.00, "2.00");
+ n7.value = 24.1;
+ testVals(n7, "set value to decimal above max,", 10.5, "10.50");
+ n1.value = 4.75;
+ testVals(n1, "set value to decimal round,", 5);
+
+ // test changing the valueNumber
+ n1.valueNumber = 27;
+ testVals(n1, "set valueNumber,", 27);
+ n2.valueNumber = 1;
+ testVals(n2, "set valueNumber below min,", 5);
+ n2.valueNumber = 77;
+ testVals(n2, "set valueNumber above max,", 15);
+ n2.valueNumber = -5;
+ testVals(n2, "set valueNumber below min negative,", 5);
+ n5.valueNumber = -8;
+ n5.valueNumber = -1;
+ testVals(n5, "set valueNumber above max positive,", -3);
+ n7.valueNumber = 8.23;
+ testVals(n7, "set valueNumber to decimal,", 8.23);
+ n7.valueNumber = 0.77;
+ testVals(n7, "set valueNumber to decimal below min,", 2.00, "2.00");
+ n7.valueNumber = 29.157;
+ testVals(n7, "set valueNumber to decimal above max,", 10.5, "10.50");
+ n1.value = 8.9;
+ testVals(n1, "set valueNumber to decimal round,", 9);
+
+ // test changing the min
+ n1.value = 6;
+ n1.min = 8;
+ testValsMinMax(n1, "set integer min,", 8, 8, Infinity);
+ n7.value = 5.5;
+ n7.min = 6.7;
+ testValsMinMax(n7, "set decimal min,", 6.7, 6.7, 10.5, "6.70");
+
+ // test changing the max
+ n1.value = 25;
+ n1.max = 22;
+ testValsMinMax(n1, "set integer max,", 22, 8, 22);
+ n7.value = 10.2;
+ n7.max = 10.1;
+ testValsMinMax(n7, "set decimal max,", 10.1, 6.7, 10.1, "10.10");
+
+ // test decrease() and increase() methods
+ testIncreaseDecrease(n1, "integer", 1, 0, 8, 22);
+ testIncreaseDecrease(n7, "decimal", 1, 2, 6.7, 10.1);
+ testIncreaseDecrease(n3, "integer with increment", 3, 0, 1, 12);
+
+ n7.min = 2.7;
+ n7.value = 10.1;
+ n7.increment = 4.3;
+ SimpleTest.is(n7.increment, 4.3, "increment changed");
+ testIncreaseDecrease(n7, "integer with increment", 4.3, 2, 2.7, 10.1);
+
+ n2.value = n2.min;
+ n2.decrease();
+ testVals(n2, "integer wraparound decrease method", n2.max);
+ n2.increase();
+ testVals(n2, "integer wraparound decrease method", n2.min);
+
+ n7.wrapAround = true;
+ SimpleTest.is(n7.wrapAround, true, "change wrapAround");
+ n7.value = n7.min + 0.01;
+ n7.decrease();
+ testVals(n7, "decimal wraparound decrease method", n7.max, n7.max.toFixed(2));
+ n7.increase();
+ testVals(n7, "decimal wraparound decrease method", n7.min, n7.min.toFixed(2));
+
+ n1.value = 22;
+ n1.decimalPlaces = 3;
+ testVals(n1, "set decimalPlaces 3", 22, "22.000");
+ n1.value = 10.624;
+ testVals(n1, "set decimalPlaces 3 set value,", 10.624);
+ n1.decimalPlaces = 0;
+ testVals(n1, "set decimalPlaces 0 set value,", 11);
+ n1.decimalPlaces = Infinity;
+ n1.value = 10.678123;
+ testVals(n1, "set decimalPlaces Infinity set value,", 10.678123);
+
+ n1.decimalSymbol = ",";
+ SimpleTest.is(n1.decimalSymbol, ",", "n1.decimalSymbol set to ','");
+ n1.value = "9.67";
+ testVals(n1, "set decimalPlaces set value,", 9.67);
+
+ n1.decimalSymbol = ".";
+ SimpleTest.is(n1.decimalSymbol, ".", "n1.decimalSymbol set back to '.'");
+ n1.decimalPlaces = 0;
+
+ // UI tests
+ n1.min = 5;
+ n1.max = 15;
+ n1.value = 5;
+ n1.focus();
+
+ var sb = n1.spinButtons;
+ var sbbottom = sb.getBoundingClientRect().bottom - sb.getBoundingClientRect().top - 2;
+
+ synthesizeKey("VK_UP", {});
+ testVals(n1, "key up", 6);
+
+ synthesizeKey("VK_DOWN", {});
+ testVals(n1, "key down", 5);
+
+ synthesizeMouse(sb, 2, 2, {});
+ testVals(n1, "spinbuttons up", 6);
+ synthesizeMouse(sb, 2, sbbottom, {});
+ testVals(n1, "spinbuttons down", 5);
+
+ n1.value = 15;
+ synthesizeKey("VK_UP", {});
+ testVals(n1, "key up at max", 15);
+ synthesizeMouse(sb, 2, 2, {});
+ testVals(n1, "spinbuttons up at max", 15);
+
+ n1.value = 5;
+ synthesizeKey("VK_DOWN", {});
+ testVals(n1, "key down at min", 5);
+ synthesizeMouse(sb, 2, sbbottom, {});
+ testVals(n1, "spinbuttons down at min", 5);
+
+ n1.wrapAround = true;
+ n1.value = 15;
+ synthesizeKey("VK_UP", {});
+ testVals(n1, "key up wraparound at max", 5);
+ n1.value = 5;
+ synthesizeKey("VK_DOWN", {});
+ testVals(n1, "key down wraparound at min", 15);
+
+ n1.value = 15;
+ synthesizeMouse(sb, 2, 2, {});
+ testVals(n1, "spinbuttons up wraparound at max", 5);
+ n1.value = 5;
+ synthesizeMouse(sb, 2, sbbottom, {});
+ testVals(n1, "spinbuttons down wraparound at min", 15);
+
+ // check read only state
+ n1.readOnly = true;
+ n1.min = -10;
+ n1.max = 15;
+ n1.value = 12;
+ // no events should fire and no changes should occur when the field is read only
+ synthesizeKeyExpectEvent("VK_UP", { }, n1, "!change", "key up read only");
+ is(n1.value, "12", "key up read only value");
+ synthesizeKeyExpectEvent("VK_DOWN", { }, n1, "!change", "key down read only");
+ is(n1.value, "12", "key down read only value");
+
+ synthesizeMouseExpectEvent(sb, 2, 2, { }, n1, "!change", "mouse up read only");
+ is(n1.value, "12", "mouse up read only value");
+ synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, n1, "!change", "mouse down read only");
+ is(n1.value, "12", "mouse down read only value");
+
+ n1.readOnly = false;
+ n1.disabled = true;
+ synthesizeMouseExpectEvent(sb, 2, 2, { }, n1, "!change", "mouse up disabled");
+ is(n1.value, "12", "mouse up disabled value");
+ synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, n1, "!change", "mouse down disabled");
+ is(n1.value, "12", "mouse down disabled value");
+
+ var nsbrect = $("n8").spinButtons.getBoundingClientRect();
+ ok(nsbrect.left == 0 && nsbrect.top == 0 && nsbrect.right == 0, nsbrect.bottom == 0,
+ "hidespinbuttons");
+
+ var n9 = $("n9");
+ is(n9.value, "0", "initial value");
+ n9.select();
+ synthesizeKey("4", {});
+ is(inputEventCount, 1, "input event count");
+ is(inputEventValue, "4", "input value");
+ is(n9.value, "4", "updated value");
+ synthesizeKey("2", {});
+ is(inputEventCount, 2, "input event count");
+ is(inputEventValue, "42", "input value");
+ is(n9.value, "42", "updated value");
+ synthesizeKey("VK_BACK_SPACE", {});
+ is(inputEventCount, 3, "input event count");
+ is(inputEventValue, "4", "input value");
+ is(n9.value, "4", "updated value");
+ synthesizeKey("A", {accelKey: true});
+ synthesizeKey("VK_DELETE", {});
+ is(inputEventCount, 4, "input event count");
+ is(inputEventValue, "0", "input value");
+ is(n9.value, "0", "updated value");
+
+ SimpleTest.finish();
+}
+
+var inputEventCount = 0;
+var inputEventValue = null;
+function updateInputEventCount() {
+ inputEventValue = $("n9").value;
+ inputEventCount++;
+};
+
+function testVals(nb, name, valueNumber, valueFieldNumber) {
+ if (valueFieldNumber === undefined)
+ valueFieldNumber = "" + valueNumber;
+
+ SimpleTest.is(nb.value, "" + valueNumber, name + " value is '" + valueNumber + "'");
+ SimpleTest.is(nb.valueNumber, valueNumber, name + " valueNumber is " + valueNumber);
+
+ // This value format depends on the localized decimal symbol.
+ var localizedValue = valueFieldNumber.replace(/\./, nb.decimalSymbol);
+ SimpleTest.is(nb.inputField.value, localizedValue,
+ name + " inputField value is '" + localizedValue + "'");
+}
+
+function testValsMinMax(nb, name, valueNumber, min, max, valueFieldNumber) {
+ testVals(nb, name, valueNumber, valueFieldNumber);
+ SimpleTest.is(nb.min, min, name + " min is " + min);
+ SimpleTest.is(nb.max, max, name + " max is " + max);
+}
+
+function testIncreaseDecrease(nb, testid, increment, fixedCount, min, max)
+{
+ testid += " ";
+
+ nb.value = max;
+ nb.decrease();
+ testVals(nb, testid + "decrease method", max - increment,
+ (max - increment).toFixed(fixedCount));
+ nb.increase();
+ testVals(nb, testid + "increase method", max, max.toFixed(fixedCount));
+ nb.value = min;
+ nb.decrease();
+ testVals(nb, testid + "decrease method at min", min, min.toFixed(fixedCount));
+ nb.value = max;
+ nb.increase();
+ testVals(nb, testid + "increase method at max", max, max.toFixed(fixedCount));
+
+ nb.focus();
+ nb.value = min;
+
+ // pressing the cursor up and down keys should adjust the value
+ synthesizeKeyExpectEvent("VK_UP", { }, nb, "change", testid + "key up");
+ is(nb.value, String(min + increment), testid + "key up");
+ nb.value = max;
+ synthesizeKeyExpectEvent("VK_UP", { }, nb, "!change", testid + "key up at max");
+ is(nb.value, String(max), testid + "key up at max");
+ synthesizeKeyExpectEvent("VK_DOWN", { }, nb, "change", testid + "key down");
+ is(nb.value, String(max - increment), testid + "key down");
+ nb.value = min;
+ synthesizeKeyExpectEvent("VK_DOWN", { }, nb, "!change", testid + "key down at min");
+ is(nb.value, String(min), testid + "key down at min");
+
+ // check pressing the spinbutton arrows
+ var sb = nb.spinButtons;
+ var sbbottom = sb.getBoundingClientRect().bottom - sb.getBoundingClientRect().top - 2;
+ nb.value = min;
+ synthesizeMouseExpectEvent(sb, 2, 2, { }, nb, "change", testid + "mouse up");
+ is(nb.value, String(min + increment), testid + "mouse up");
+ nb.value = max;
+ synthesizeMouseExpectEvent(sb, 2, 2, { }, nb, "!change", testid + "mouse up at max");
+ synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, nb, "change", testid + "mouse down");
+ is(nb.value, String(max - increment), testid + "mouse down");
+ nb.value = min;
+ synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, nb, "!change", testid + "mouse down at min");
+}
+
+SimpleTest.waitForFocus(doTests);
+
+ ]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_textbox_search.xul b/toolkit/content/tests/chrome/test_textbox_search.xul
new file mode 100644
index 000000000..ae6153361
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_textbox_search.xul
@@ -0,0 +1,170 @@
+<?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"?>
+<!--
+ XUL Widget Test for search textbox
+ -->
+<window title="Search textbox test" width="500" height="600"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <hbox>
+ <textbox id="searchbox"
+ type="search"
+ oncommand="doSearch(this.value);"
+ placeholder="random placeholder"
+ timeout="1"/>
+ </hbox>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gExpectedValue;
+var gLastTest;
+
+function doTests() {
+ var textbox = $("searchbox");
+ var icons = document.getAnonymousElementByAttribute(textbox, "anonid", "search-icons");
+ var searchIcon = document.getAnonymousElementByAttribute(textbox, "class", "textbox-search-icon");
+ var clearIcon = document.getAnonymousElementByAttribute(textbox, "class", "textbox-search-clear");
+
+ ok(icons, "icon deck found");
+ ok(searchIcon, "search icon found");
+ ok(clearIcon, "clear icon found");
+ is(icons.selectedPanel, searchIcon, "search icon is displayed");
+
+ is(textbox.placeholder, "random placeholder", "search textbox supports placeholder");
+ is(textbox.value, "", "placeholder doesn't interfere with the real value");
+
+ function iconClick(aIcon) {
+ is(icons.selectedPanel, aIcon, aIcon.className + " icon must be displayed in order to be clickable");
+
+ //XXX synthesizeMouse worked on Linux but failed on Windows an Mac
+ // for unknown reasons. Manually dispatch the event for now.
+ //synthesizeMouse(aIcon, 0, 0, {});
+
+ var event = document.createEvent("MouseEvent");
+ event.initMouseEvent("click", true, true, window, 1,
+ 0, 0, 0, 0,
+ false, false, false, false,
+ 0, null);
+ aIcon.dispatchEvent(event);
+ }
+
+ iconClick(searchIcon);
+ is(textbox.getAttribute("focused"), "true", "clicking the search icon focuses the textbox");
+
+ textbox.value = "foo";
+ is(icons.selectedPanel, clearIcon, "clear icon is displayed when setting a value");
+
+ textbox.reset();
+ is(textbox.defaultValue, "", "defaultValue is empty");
+ is(textbox.value, "", "reset method clears the textbox");
+ is(icons.selectedPanel, searchIcon, "search icon is displayed after textbox.reset()");
+
+ textbox.value = "foo";
+ gExpectedValue = "";
+ iconClick(clearIcon);
+ is(textbox.value, "", "clicking the clear icon clears the textbox");
+ ok(gExpectedValue == null, "search triggered when clearing the textbox with the clear icon");
+
+ textbox.value = "foo";
+ gExpectedValue = "";
+ synthesizeKey("VK_ESCAPE", {});
+ is(textbox.value, "", "escape key clears the textbox");
+ ok(gExpectedValue == null, "search triggered when clearing the textbox with the escape key");
+
+ textbox.value = "bar";
+ gExpectedValue = "bar";
+ textbox.doCommand();
+ ok(gExpectedValue == null, "search triggered with doCommand");
+
+ gExpectedValue = "bar";
+ synthesizeKey("VK_RETURN", {});
+ ok(gExpectedValue == null, "search triggered with enter key");
+
+ textbox.value = "";
+ textbox.searchButton = true;
+ is(textbox.getAttribute("searchbutton"), "true", "searchbutton attribute set on the textbox");
+ is(searchIcon.getAttribute("searchbutton"), "true", "searchbutton attribute inherited to the search icon");
+
+ textbox.value = "foo";
+ is(icons.selectedPanel, searchIcon, "search icon displayed in search button mode if there's a value");
+
+ gExpectedValue = "foo";
+ iconClick(searchIcon);
+ ok(gExpectedValue == null, "search triggered when clicking the search icon in search button mode");
+ is(icons.selectedPanel, clearIcon, "clear icon displayed in search button mode after submitting");
+
+ synthesizeKey("o", {});
+ is(icons.selectedPanel, searchIcon, "search icon displayed in search button mode when typing a key");
+
+ gExpectedValue = "fooo";
+ iconClick(searchIcon); // display the clear icon (tested above)
+
+ textbox.value = "foo";
+ is(icons.selectedPanel, searchIcon, "search icon displayed in search button mode when the value is changed");
+
+ gExpectedValue = "foo";
+ synthesizeKey("VK_RETURN", {});
+ ok(gExpectedValue == null, "search triggered with enter key in search button mode");
+ is(icons.selectedPanel, clearIcon, "clear icon displayed in search button mode after submitting with enter key");
+
+ textbox.value = "x";
+ synthesizeKey("VK_BACK_SPACE", {});
+ is(icons.selectedPanel, searchIcon, "search icon displayed in search button mode when deleting the value with the backspace key");
+
+ gExpectedValue = "";
+ synthesizeKey("VK_RETURN", {});
+ ok(gExpectedValue == null, "search triggered with enter key in search button mode");
+ is(icons.selectedPanel, searchIcon, "search icon displayed in search button mode after submitting an empty string");
+
+ textbox.readOnly = true;
+ gExpectedValue = "foo";
+ textbox.value = "foo";
+ iconClick(searchIcon);
+ ok(gExpectedValue == null, "search triggered when clicking the search icon in search button mode while the textbox is read-only");
+ is(icons.selectedPanel, searchIcon, "search icon persists in search button mode after submitting while the textbox is read-only");
+ textbox.readOnly = false;
+
+ textbox.disabled = true;
+ is(searchIcon.getAttribute("disabled"), "true", "disabled attribute inherited to the search icon");
+ is(clearIcon.getAttribute("disabled"), "true", "disabled attribute inherited to the clear icon");
+ gExpectedValue = false;
+ textbox.value = "foo";
+ iconClick(searchIcon);
+ ok(gExpectedValue == false, "search *not* triggered when clicking the search icon in search button mode while the textbox is disabled");
+ is(icons.selectedPanel, searchIcon, "search icon persists in search button mode when trying to submit while the textbox is disabled");
+ textbox.disabled = false;
+ ok(!searchIcon.hasAttribute("disabled"), "disabled attribute removed from the search icon");
+ ok(!clearIcon.hasAttribute("disabled"), "disabled attribute removed from the clear icon");
+
+ textbox.searchButton = false;
+ ok(!textbox.hasAttribute("searchbutton"), "searchbutton attribute removed from the textbox");
+ ok(!searchIcon.hasAttribute("searchbutton"), "searchbutton attribute removed from the search icon");
+
+ gLastTest = true;
+ gExpectedValue = "123";
+ textbox.value = "1";
+ synthesizeKey("2", {});
+ synthesizeKey("3", {});
+}
+
+function doSearch(aValue) {
+ is(aValue, gExpectedValue, "search triggered with expected value");
+ gExpectedValue = null;
+ if (gLastTest)
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(doTests);
+
+ ]]></script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_timepicker.xul b/toolkit/content/tests/chrome/test_timepicker.xul
new file mode 100644
index 000000000..98e370137
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_timepicker.xul
@@ -0,0 +1,207 @@
+<?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"?>
+<!--
+ XUL Widget Test for timepicker
+ -->
+<window title="timepicker" width="500" height="600"
+ onload="setTimeout(testtag_timepicker, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<timepicker id="timepicker"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function testtag_timepicker()
+{
+ var tp = document.getElementById("timepicker");
+
+ var testid = "timepicker ";
+
+ var today = new Date();
+ var thour = today.getHours();
+ var tminute = today.getMinutes();
+ var tsecond = today.getSeconds();
+
+ // testtag_comparetime(tp, testid + "initial", thour, tminute, tsecond);
+
+ // check that setting the value property works
+ tp.value = testtag_gettimestring(thour, tminute, tsecond);
+ testtag_comparetime(tp, testid + "set value", thour, tminute, tsecond);
+
+ var numberOrder = /^(\D*)\s*(\d+)(\D*)(\d+)(\D*)(\d+)\s*(\D*)$/;
+ var locale = Intl.DateTimeFormat().resolvedOptions().locale + "-u-ca-gregory-nu-latn";
+ var fdt = new Date(2000,0,1,16,7,9).toLocaleTimeString(locale);
+ is(tp.is24HourClock, Number(fdt.match(numberOrder)[2]) > 12, "is24HourClock");
+
+ // check that setting the dateValue property works
+ tp.dateValue = today;
+ testtag_comparetime(tp, testid + "set dateValue", thour, tminute, tsecond);
+ ok(tp.value !== today, testid + " set dateValue different time");
+
+ ok(!tp.readOnly, testid + "readOnly");
+ tp.readOnly = true;
+ ok(tp.readOnly, testid + "set readOnly");
+ tp.readOnly = false;
+ ok(!tp.readOnly, testid + "clear readOnly");
+
+ function setTimeField(field, value, expectException,
+ expectedHour, expectedMinute, expectedSecond)
+ {
+ var exh = false;
+ try {
+ tp[field] = value;
+ } catch (ex) { exh = true; }
+ is(exh, expectException, testid + "set " + field + " " + value);
+ testtag_comparetime(tp, testid + "set " + field + " " + value,
+ expectedHour, expectedMinute, expectedSecond);
+ }
+
+ // check the value property
+ setTimeField("value", "0:0:0", false, 0, 0, 0);
+ setTimeField("value", "21:1:40", false, 21, 1, 40);
+ setTimeField("value", "7:11:8", false, 7, 11, 8);
+ setTimeField("value", "04:07:02", false, 4, 7, 2);
+ setTimeField("value", "10:42:20", false, 10, 42, 20);
+
+ // check that the hour, minute and second fields can be set properly
+ setTimeField("hour", 7, false, 7, 42, 20);
+ setTimeField("hour", 0, false, 0, 42, 20);
+ setTimeField("hour", 21, false, 21, 42, 20);
+ setTimeField("hour", -1, true, 21, 42, 20);
+ setTimeField("hour", 24, true, 21, 42, 20);
+
+ setTimeField("minute", 0, false, 21, 0, 20);
+ setTimeField("minute", 9, false, 21, 9, 20);
+ setTimeField("minute", 10, false, 21, 10, 20);
+ setTimeField("minute", 35, false, 21, 35, 20);
+ setTimeField("minute", -1, true, 21, 35, 20);
+ setTimeField("minute", 60, true, 21, 35, 20);
+
+ setTimeField("second", 0, false, 21, 35, 0);
+ setTimeField("second", 9, false, 21, 35, 9);
+ setTimeField("second", 10, false, 21, 35, 10);
+ setTimeField("second", 51, false, 21, 35, 51);
+ setTimeField("second", -1, true, 21, 35, 51);
+ setTimeField("second", 60, true, 21, 35, 51);
+
+ // check when seconds is not specified
+ setTimeField("value", "06:05", false, 6, 5, 0);
+ setTimeField("value", "06:15", false, 6, 15, 0);
+ setTimeField("value", "16:15", false, 16, 15, 0);
+
+ // check that times overflow properly
+ setTimeField("value", "5:65:21", false, 6, 5, 21);
+ setTimeField("value", "5:25:72", false, 5, 26, 12);
+
+ // check invalid values for the value and dateValue properties
+ tp.value = "14:25:48";
+ setTimeField("value", "", true, 14, 25, 48);
+ setTimeField("value", "1:5:6:6", true, 14, 25, 48);
+ setTimeField("value", "2:a:19", true, 14, 25, 48);
+ setTimeField("dateValue", "none", true, 14, 25, 48);
+
+ // check the fields
+ ok(tp.hourField instanceof HTMLInputElement, testid + "hourField");
+ ok(tp.minuteField instanceof HTMLInputElement, testid + "minuteField");
+ ok(tp.secondField instanceof HTMLInputElement, testid + "secondField");
+
+ testtag_timepicker_UI(tp, testid);
+
+ tp.readOnly = true;
+
+ // check that keyboard usage doesn't change the value when the timepicker
+ // is read only
+ testtag_timepicker_UI_key(tp, testid + "readonly ", "14:25:48",
+ tp.hourField, 14, 25, 48, 14, 25, 48);
+ testtag_timepicker_UI_key(tp, testid + "readonly ", "14:25:48",
+ tp.minuteField, 14, 25, 48, 14, 25, 48);
+ testtag_timepicker_UI_key(tp, testid + "readonly ", "14:25:48",
+ tp.secondField, 14, 25, 48, 14, 25, 48);
+
+ SimpleTest.finish();
+}
+
+function testtag_timepicker_UI(tp, testid)
+{
+ testid += "UI";
+
+ // test adjusting the time with the up and down keys
+ testtag_timepicker_UI_key(tp, testid, "0:12:25", tp.hourField, 1, 12, 25, 0, 12, 25);
+ testtag_timepicker_UI_key(tp, testid, "11:12:25", tp.hourField, 12, 12, 25, 11, 12, 25);
+ testtag_timepicker_UI_key(tp, testid, "7:12:25", tp.hourField, 8, 12, 25, 7, 12, 25);
+ testtag_timepicker_UI_key(tp, testid, "16:12:25", tp.hourField, 17, 12, 25, 16, 12, 25);
+ testtag_timepicker_UI_key(tp, testid, "23:12:25", tp.hourField, 0, 12, 25, 23, 12, 25);
+
+ testtag_timepicker_UI_key(tp, testid, "15:23:46", tp.minuteField, 15, 24, 46, 15, 23, 46);
+ testtag_timepicker_UI_key(tp, testid, "15:0:46", tp.minuteField, 15, 1, 46, 15, 0, 46);
+ testtag_timepicker_UI_key(tp, testid, "15:59:46", tp.minuteField, 15, 0, 46, 15, 59, 46);
+
+ testtag_timepicker_UI_key(tp, testid, "11:50:46", tp.secondField, 11, 50, 47, 11, 50, 46);
+ testtag_timepicker_UI_key(tp, testid, "11:50:0", tp.secondField, 11, 50, 1, 11, 50, 0);
+ testtag_timepicker_UI_key(tp, testid, "11:50:59", tp.secondField, 11, 50, 0, 11, 50, 59);
+}
+
+function testtag_timepicker_UI_key(tp, testid, value, field,
+ uhour, uminute, usecond,
+ dhour, dminute, dsecond)
+{
+ tp.value = value;
+ field.focus();
+
+ var eventTarget = tp.readOnly ? null : tp;
+
+ var testname = testid + " " + value + " key up";
+ synthesizeKeyExpectEvent("VK_UP", { }, eventTarget, "change", testname);
+ testtag_comparetime(tp, testname, uhour, uminute, usecond);
+
+ testname = testid + " " + value + " key down";
+ synthesizeKeyExpectEvent("VK_DOWN", { }, eventTarget, "change", testname);
+ testtag_comparetime(tp, testname, dhour, dminute, dsecond);
+}
+
+function testtag_gettimestring(hour, minute, second)
+{
+ if (minute < 10)
+ minute = "0" + minute;
+ if (second < 10)
+ second = "0" + second;
+ return hour + ":" + minute + ":" + second;
+}
+
+function testtag_comparetime(tp, testid, hour, minute, second)
+{
+ is(tp.value, testtag_gettimestring(hour, minute, second), testid + " value");
+ is(tp.getAttribute("value"),
+ testtag_gettimestring(hour, minute, second),
+ testid + " value attribute");
+
+ var dateValue = tp.dateValue;
+ ok(dateValue.getHours() == hour &&
+ dateValue.getMinutes() == minute &&
+ dateValue.getSeconds() == second,
+ testid + " dateValue");
+
+ is(tp.hour, hour, testid + " hour");
+ is(tp.minute, minute, testid + " minute");
+ is(tp.second, second, testid + " second");
+}
+
+]]>
+
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_titlebar.xul b/toolkit/content/tests/chrome/test_titlebar.xul
new file mode 100644
index 000000000..d48e04a12
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_titlebar.xul
@@ -0,0 +1,35 @@
+<?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"?>
+<!--
+ XUL Widget Test for the titlebar element and window dragging
+ -->
+<window title="Titlebar" width="200" height="200"
+ onload="setTimeout(test_titlebar, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function test_titlebar()
+{
+ window.open("window_titlebar.xul", "_blank", "chrome,left=200,top=200");
+}
+
+function done(testWindow)
+{
+ testWindow.close();
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_toolbar.xul b/toolkit/content/tests/chrome/test_toolbar.xul
new file mode 100644
index 000000000..7adaa6aa3
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_toolbar.xul
@@ -0,0 +1,227 @@
+<?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="Toolbar" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="startTest();">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <toolbox id="toolbox">
+ <toolbarpalette>
+ <toolbarbutton id="p1" label="p1"/>
+ <toolbarbutton id="p2" label="p2"/>
+ <toolbarbutton id="p3" label="p3"/>
+ <toolbarbutton id="p4" label="p4"/>
+ <toolbarbutton id="p5" label="p5"/>
+ <toolbarbutton id="p6" label="p6"/>
+ <toolbarbutton id="p7" label="p7"/>
+ <toolbarbutton id="p8" label="p8"/>
+ <toolbarbutton id="p9" label="p9"/>
+ <toolbarbutton id="p10" label="p10"/>
+ <toolbarbutton id="p11" label="p11"/>
+ <toolbarbutton id="p12" label="p12"/>
+ </toolbarpalette>
+
+ <toolbar id="tb1" defaultset="p1,p2"/>
+ <toolbar id="tb2" defaultset="p4,p3"/>
+ <toolbar id="tb3" defaultset="p5,p6,t31">
+ <toolbarbutton id="t31" label="t31" removable="true"/>
+ </toolbar>
+ <toolbar id="tb4" defaultset="t41,p7,p8">
+ <toolbarbutton id="t41" label="t41" removable="true"/>
+ </toolbar>
+ <toolbar id="tb5" defaultset="p9,t51,p10">
+ <toolbarbutton id="t51" label="t51" removable="true"/>
+ </toolbar>
+
+ <toolbar id="tb-test" defaultset="p11,p12"/>
+ <toolbar id="tb-test2" defaultset=""/>
+ <!-- fixed toolbarbuttons always have 'fixed' in their id -->
+ <toolbar id="tb-test3" defaultset="">
+ <toolbarbutton id="tb-fixed-1" label="tb-test3-1"/>
+ <toolbarbutton id="tb-fixed-2" label="tb-test3-2" removable="false"/>
+ <toolbarbutton id="tb-fixed-3" label="tb-test3-3"/>
+ </toolbar>
+ </toolbox>
+
+ <toolbar id="notoolbox"/>
+
+ <!-- test resuls are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml"
+ style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="text/javascript"><![CDATA[
+ const SPACER = /^spacer\d+/;
+ const SEPARATOR = /^separator\d+/;
+ const SPRING = /^spring\d+/;
+
+ function testSet(aTb, aIDs, aResultIDs, aUseFixed) {
+ // build a list of the fixed items in the order they appear on the toolbar
+ var fixedSet = [];
+ if (aUseFixed) {
+ for (let i = 0; i < aTb.childNodes.length; i++) {
+ var id = aTb.childNodes[i].id;
+ if (id.indexOf("fixed") >= 0)
+ fixedSet.push(id);
+ }
+ }
+
+ var currentSet = aIDs.join(",");
+ ok(currentSet, "setting currentSet: " + currentSet);
+ aTb.currentSet = currentSet;
+ var resultIDs = aResultIDs || aIDs;
+ checkSet(aTb, resultIDs, fixedSet);
+ }
+
+ var checkSetCount = 0;
+ function checkSet(aTb, aResultIDs, aFixedSet) {
+ checkSetCount++;
+ var testID = "checkSet(" + checkSetCount + ") ";
+
+ for (let i = 0; i < aTb.childNodes.length; i++) {
+ let id = aTb.childNodes[i].id;
+ if (aResultIDs[i] instanceof RegExp) {
+ ok(aResultIDs[i].test(id),
+ testID + "correct ID " + aResultIDs[i] + " for toolbar " + aTb.id + "; got: " + id);
+ }
+ else if (aResultIDs[i] == "*") {
+ is(id, aFixedSet.shift(), testID + "is fixed with ID " + id + " for toolbar " + aTb.id);
+ }
+ else {
+ is(id, aResultIDs[i],
+ testID + "correct ID " + aResultIDs[i] + " for toolbar " + aTb.id +
+ "****" + aResultIDs + "," + i + ",");
+ // remove the item from the fixed set once found
+ if (aFixedSet && id.indexOf("fixed") >= 0)
+ aFixedSet.splice(aFixedSet.indexOf(id), 1);
+ }
+ }
+
+ if (aFixedSet)
+ is(aFixedSet.length, 0, testID + "extra fixed items for " + aTb.id);
+ is(aTb.childNodes.length, aResultIDs.length,
+ testID + "correct number of children for " + aTb.id);
+ }
+
+ function test_defaultSet() {
+ checkSet($("tb1"), ["p1", "p2"]);
+ checkSet($("tb2"), ["p4", "p3"]);
+ checkSet($("tb3"), ["p5", "p6", "t31"]);
+ checkSet($("tb4"), ["t41", "p7", "p8"]);
+ checkSet($("tb5"), ["p9", "t51", "p10"]);
+ }
+
+ function test_currentSet(aTb) {
+ ok(aTb, "have toolbar");
+ var defaultSet = aTb.getAttribute("defaultset");
+ var setLength = (defaultSet && defaultSet.split(",").length) || 0;
+ is(setLength, aTb.childNodes.length, "correct # of children initially");
+
+ var emptySet = [["__empty"], []];
+ var testSets = [
+ emptySet,
+ [["p11"]],
+ [["p11","p12"]],
+ [["p11","p12","bogus"], ["p11","p12"]],
+ [["p11"]],
+ emptySet,
+ [["spacer"], [SPACER]],
+ [["spring"], [SPRING]],
+ [["separator"], [SEPARATOR]],
+ [["p11", "p11", "p12", "spacer", "p11"], ["p11", "p12", SPACER]],
+ [["separator", "separator", "p11", "spring", "spacer"],
+ [SEPARATOR, SEPARATOR, "p11", SPRING, SPACER]],
+ [["separator", "spacer", "separator", "p11", "spring", "spacer", "p12", "spring"],
+ [SEPARATOR, SPACER, SEPARATOR, "p11", SPRING, SPACER, "p12", SPRING]],
+ emptySet
+ ];
+
+ cycleSets(aTb, testSets, emptySet, false);
+ }
+
+ function test_currentSet_nonremovable() {
+ var tb = $("tb-test3");
+ ok(tb, "have tb-test-3");
+
+ // the * used in the tests below means that any fixed item can appear in that position
+ var emptySet = [["__empty"], ["*", "*", "*"]];
+ var testSets = [
+ [["p1", "tb-fixed-1", "p2"],
+ ["p1", "tb-fixed-1", "p2", "*", "*"]],
+ [["p1", "tb-fixed-2", "p2"],
+ ["p1", "tb-fixed-2", "p2", "*", "*"]],
+ [["p1", "tb-fixed-3", "p2"],
+ ["p1", "tb-fixed-3", "p2", "*", "*"]],
+ emptySet,
+
+ [["tb-fixed-1", "tb-fixed-2", "tb-fixed-3"],
+ ["tb-fixed-1", "tb-fixed-2", "tb-fixed-3"]],
+ [["tb-fixed-3", "tb-fixed-2", "tb-fixed-1"],
+ ["tb-fixed-3", "tb-fixed-2", "tb-fixed-1"]],
+
+ [["tb-fixed-1", "tb-fixed-2", "tb-fixed-3", "p1", "p2"],
+ ["tb-fixed-1", "tb-fixed-2", "tb-fixed-3", "p1", "p2"]],
+
+ [["tb-fixed-1", "p2", "p1"],
+ ["tb-fixed-1", "p2", "p1", "*", "*"]],
+
+ [["tb-fixed-1", "p2"],
+ ["tb-fixed-1", "p2", "*", "*"]],
+
+ [["p1", "p2"], ["p1", "p2", "*", "*", "*"]],
+ [["p2", "p1"], ["p2", "p1", "*", "*", "*"]],
+
+ [["tb-fixed-3", "spacer", "p1"],
+ ["tb-fixed-3", SPACER, "p1", "*", "*"]]
+ ];
+
+ cycleSets(tb, testSets, emptySet, true);
+ }
+
+ function cycleSets(aTb, aSets, aEmptySet, aUseFixed) {
+ // Since a lot of the tricky cases handled in the currentSet setter
+ // depend on going from one state to another, run through the test set
+ // multiple times in different orders.
+ var length = aSets.length;
+
+ for (var i = 0; i < length; i++) {
+ testSet(aTb, aSets[i][0], aSets[i][1], aUseFixed);
+ }
+ for (var i = length - 1; i >= 0; i--) {
+ testSet(aTb, aSets[i][0], aSets[i][1], aUseFixed);
+ }
+ for (var i = 0; i < length; i++) {
+ testSet(aTb, aSets[i][0], aSets[i][1], aUseFixed);
+ testSet(aTb, aSets[length - i - 1][0], aSets[length - i - 1][1], aUseFixed);
+ testSet(aTb, aSets[i][0], aSets[i][1], aUseFixed);
+ testSet(aTb, aSets[i][0], aSets[i][1], aUseFixed);
+ }
+ for (var i = 0; i < length; i++) {
+ testSet(aTb, aEmptySet[0], aEmptySet[1], aUseFixed);
+ testSet(aTb, aSets[i][0], aSets[i][1], aUseFixed);
+ }
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ test_defaultSet();
+ test_currentSet($("tb-test"));
+ test_currentSet($("tb-test2"));
+ test_currentSet_nonremovable();
+
+ var toolbox = $("toolbox");
+ var toolbars = document.getElementsByTagName("toolbar");
+ for (var t = 0; t < toolbars.length; t++) {
+ var toolbar = toolbars[t];
+ is(toolbar.toolbox, toolbar.id == "notoolbox" ? null : toolbox,
+ "toolbar " + toolbar.id + " has correct toolbox");
+ }
+
+ $("tb1").toolbox = document.documentElement;
+ is($("tb1").toolbox, toolbox, "toolbox still correct after set");
+ SimpleTest.finish();
+ }
+ ]]></script>
+</window>
diff --git a/toolkit/content/tests/chrome/test_tooltip.xul b/toolkit/content/tests/chrome/test_tooltip.xul
new file mode 100644
index 000000000..b5650352d
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tooltip.xul
@@ -0,0 +1,28 @@
+<?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="Tooltip Tests"
+ onload="setTimeout(runTest, 0)"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+ window.open("window_tooltip.xul", "_blank", "chrome,width=700,height=700");
+}
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_tooltip_noautohide.xul b/toolkit/content/tests/chrome/test_tooltip_noautohide.xul
new file mode 100644
index 000000000..979e42477
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tooltip_noautohide.xul
@@ -0,0 +1,57 @@
+<?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="Tooltip Noautohide Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+
+<tooltip id="thetooltip" noautohide="true"
+ onpopupshown="setTimeout(tooltipStillShown, 6000)"
+ onpopuphidden="ok(gChecked, 'tooltip did not hide'); SimpleTest.finish()">
+ <label id="label" value="This is a tooltip"/>
+</tooltip>
+
+<button id="button" label="Tooltip Text" tooltip="thetooltip"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+var gChecked = false;
+
+function runTests()
+{
+ var button = document.getElementById("button");
+ var windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+ windowUtils.disableNonTestMouseEvents(true);
+ synthesizeMouse(button, 2, 2, { type: "mouseover" });
+ synthesizeMouse(button, 4, 4, { type: "mousemove" });
+ synthesizeMouse(button, 6, 6, { type: "mousemove" });
+ windowUtils.disableNonTestMouseEvents(false);
+}
+
+function tooltipStillShown()
+{
+ gChecked = true;
+ document.getElementById("thetooltip").hidePopup();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests);
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_tree.xul b/toolkit/content/tests/chrome/test_tree.xul
new file mode 100644
index 000000000..52de74e46
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tree.xul
@@ -0,0 +1,84 @@
+<?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"?>
+<!--
+ XUL Widget Test for tree using multiple row selection
+ -->
+<window title="Tree" width="500" height="600"
+ onload="setTimeout(testtag_tree, 0, 'tree-simple', 'treechildren-simple', 'multiple', 'simple', 'tree');"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<script src="tree_shared.js"/>
+
+<tree id="tree-simple" rows="4">
+ <treecols>
+ <treecol id="name" label="Name" sort="label" properties="one two" flex="1"/>
+ <treecol id="address" label="Address" flex="1"/>
+ </treecols>
+ <treechildren id="treechildren-simple">
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue" editable="false"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+</tree>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+]]>
+</script>
+
+</window>
+
diff --git a/toolkit/content/tests/chrome/test_tree_hier.xul b/toolkit/content/tests/chrome/test_tree_hier.xul
new file mode 100644
index 000000000..d1a599eaa
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tree_hier.xul
@@ -0,0 +1,136 @@
+<?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"?>
+<!--
+ XUL Widget Test for hierarchical tree
+ -->
+<window title="Hierarchical Tree" width="500" height="600"
+ onload="setTimeout(testtag_tree, 0, 'tree-hier', 'treechildren-hier', 'multiple', '', 'hierarchical tree');"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<script src="tree_shared.js"/>
+
+<tree id="tree-hier" rows="4">
+ <treecols>
+ <treecol id="name" label="Name" primary="true"
+ sort="label" properties="one two" flex="1"/>
+ <treecol id="address" label="Address" flex="2"/>
+ <treecol id="planet" label="Planet" flex="1"/>
+ <treecol id="gender" label="Gender" flex="1" cycler="true"/>
+ </treecols>
+ <treechildren id="treechildren-hier">
+ <treeitem>
+ <treerow properties="firstrow">
+ <treecell label="Mary" value="mary" properties="firstname"/>
+ <treecell label="206 Garden Avenue" value="206ga"/>
+ <treecell label="Earth"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell/>
+ <treecell value="19ms"/>
+ <treecell label="Earth"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem container="true">
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue" editable="false"/>
+ <treecell label="Saturn"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ <treechildren>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue"/>
+ <treecell label="Female" value="f"/>
+ <treecell label="Neptune"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ <treecell label="Omicron Persei 8"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue" editable="false"/>
+ <treecell label="Earth"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ <treecell label="Neptune"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ <treecell/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue" selectable="false"/>
+ <treecell label=""/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ <treecell label="Neptune"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue"/>
+ <treecell label="Earth"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ <treecell label="Mars"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+</tree>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_tree_hier_cell.xul b/toolkit/content/tests/chrome/test_tree_hier_cell.xul
new file mode 100644
index 000000000..29e92ba3b
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tree_hier_cell.xul
@@ -0,0 +1,136 @@
+<?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"?>
+<!--
+ XUL Widget Test for cell selection tree
+ -->
+<window title="Cell Selection Tree" width="500" height="600"
+ onload="setTimeout(testtag_tree, 0, 'tree-cell', 'treechildren-cell', 'cell', '', 'cell selection tree');"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<script src="tree_shared.js"/>
+
+<tree id="tree-cell" rows="4" seltype="cell">
+ <treecols>
+ <treecol id="name" label="Name" primary="true"
+ sort="label" properties="one two" flex="1"/>
+ <treecol id="address" label="Address" flex="2"/>
+ <treecol id="planet" label="Planet" flex="1"/>
+ <treecol id="gender" label="Gender" flex="1" cycler="true"/>
+ </treecols>
+ <treechildren id="treechildren-cell">
+ <treeitem>
+ <treerow properties="firstrow">
+ <treecell label="Mary" value="mary" properties="firstname"/>
+ <treecell label="206 Garden Avenue" value="206ga"/>
+ <treecell label="Earth"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell/>
+ <treecell value="19ms"/>
+ <treecell label="Earth"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem container="true">
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue" editable="false"/>
+ <treecell label="Saturn"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ <treechildren>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue"/>
+ <treecell label="Female" value="f"/>
+ <treecell label="Neptune"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ <treecell label="Omicron Persei 8"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue" editable="false"/>
+ <treecell label="Earth"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ <treecell label="Neptune"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ <treecell/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue" selectable="false"/>
+ <treecell label=""/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ <treecell label="Neptune"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue"/>
+ <treecell label="Earth"/>
+ <treecell label="Female" value="f"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ <treecell label="Mars"/>
+ <treecell label="Male" value="m"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+</tree>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_tree_single.xul b/toolkit/content/tests/chrome/test_tree_single.xul
new file mode 100644
index 000000000..9b64cb488
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tree_single.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"?>
+<!--
+ XUL Widget Test for single selection tree
+ -->
+<window title="Single Selection Tree" width="500" height="600"
+ onload="setTimeout(testtag_tree, 0, 'tree-single', 'treechildren-single',
+ 'single', 'simple', 'single selection tree');"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<script src="tree_shared.js"/>
+
+<tree id="tree-single" rows="4" seltype="single">
+ <treecols>
+ <treecol id="name" label="Name" sort="label" properties="one two" flex="1"/>
+ <treecol id="address" label="Address" flex="1"/>
+ </treecols>
+ <treechildren id="treechildren-single">
+ <treeitem>
+ <treerow properties="firstrow">
+ <treecell label="Mary" value="mary" properties="firstname"/>
+ <treecell label="206 Garden Avenue" value="206ga"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell/>
+ <treecell value="19ms"/>
+ </treerow>
+ </treeitem>
+ <treeitem container="true">
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue" editable="false"/>
+ </treerow>
+ <treechildren>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue" editable="false"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Mary"/>
+ <treecell label="206 Garden Avenue" selectable="false"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Chris"/>
+ <treecell label="19 Marion Street"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="Sarah"/>
+ <treecell label="702 Fern Avenue"/>
+ </treerow>
+ </treeitem>
+ <treeitem>
+ <treerow>
+ <treecell label="John"/>
+ <treecell label="99 Westminster Avenue"/>
+ </treerow>
+ </treeitem>
+ </treechildren>
+</tree>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/test_tree_view.xul b/toolkit/content/tests/chrome/test_tree_view.xul
new file mode 100644
index 000000000..235e3a594
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_tree_view.xul
@@ -0,0 +1,118 @@
+<?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"?>
+<!--
+ XUL Widget Test for tree using a custom nsITreeView
+ -->
+<window title="Tree" onload="init()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <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>
+
+<script src="tree_shared.js"/>
+
+<script>
+<![CDATA[
+
+// This is our custom view, based on the treeview interface
+var view =
+{
+ treeData: [["Mary", "206 Garden Avenue"],
+ ["Chris", "19 Marion Street"],
+ ["Sarah", "702 Fern Avenue"],
+ ["John", "99 Westminster Avenue"]],
+ value: "",
+ rowCount: 8,
+ getCellText: function(row, column) { return this.treeData[row % 4][column.index]; },
+ getCellValue: function(row, column) { return this.value; },
+ setCellText: function(row, column, val) { this.treeData[row % 4][column.index] = val; },
+ setCellValue: function(row, column, val) { this.value = val; },
+ setTree: function(tree) { this.tree = tree; },
+ isContainer: function(row) { return false; },
+ isContainerOpen: function(row) { return false; },
+ isContainerEmpty: function(row) { return false; },
+ isSeparator: function(row) { return false; },
+ isSorted: function(row) { return false; },
+ isSelectable: function(row, column) { return true; },
+ isEditable: function(row, column) { return row != 2 || column.index != 1; },
+ getProgressMode: function(row, column) { return Components.interfaces.nsITreeView.PROGRESS_NORMAL; },
+ getParentIndex: function(row, column) { return -1; },
+ getLevel: function(row) { return 0; },
+ hasNextSibling: function(row, column) { return row != this.rowCount - 1; },
+ getImageSrc: function(row, column) { return ""; },
+ cycleHeader: function(column) { },
+ getRowProperties: function(row) { return ""; },
+ getCellProperties: function(row, column) { return ""; },
+ getColumnProperties: function(column)
+ {
+ if (!column.index) {
+ return "one two";
+ }
+
+ return "";
+ }
+}
+
+function getCustomTreeViewCellInfo()
+{
+ var obj = { rows: [] };
+
+ for (var row = 0; row < view.rowCount; row++) {
+ var cellInfo = [ ];
+ for (var column = 0; column < 1; column++) {
+ cellInfo.push({ label: "" + view.treeData[row % 4][column],
+ value: "",
+ properties: "",
+ editable: row != 2 || column.index != 1,
+ selectable: true,
+ image: "",
+ mode: Components.interfaces.nsITreeView.PROGRESS_NORMAL });
+ }
+
+ obj.rows.push({ cells: cellInfo,
+ properties: "",
+ container: false,
+ separator: false,
+ children: null,
+ level: 0,
+ parent: -1 });
+ }
+
+ return obj;
+}
+
+function init()
+{
+ var tree = document.getElementById("tree-view");
+ tree.view = view;
+ tree.treeBoxObject.ensureRowIsVisible(0);
+ is(tree.treeBoxObject.getFirstVisibleRow(), 0, "first visible after ensureRowIsVisible on load");
+ tree.setAttribute("rows", "4");
+
+ setTimeout(testtag_tree, 0, "tree-view", "treechildren-view", "multiple", "simple", "tree view");
+}
+
+]]>
+</script>
+
+<tree id="tree-view">
+ <treecols>
+ <treecol id="name" label="Name" sort="label" flex="1"/>
+ <treecol id="address" label="Address" flex="1"/>
+ </treecols>
+ <treechildren id="treechildren-view"/>
+</tree>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+]]>
+</script>
+
+</window>
+
diff --git a/toolkit/content/tests/chrome/window_browser_drop.xul b/toolkit/content/tests/chrome/window_browser_drop.xul
new file mode 100644
index 000000000..8a22ccce9
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_browser_drop.xul
@@ -0,0 +1,254 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Browser Drop Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<script>
+<![CDATA[
+
+Components.utils.import("resource://testing-common/ContentTask.jsm");
+
+function dropOnRemoteBrowserAsync(browser, data, shouldExpectStateChange) {
+ ContentTask.setTestScope(window); // Need this so is/isnot/ok are available inside the contenttask
+ return ContentTask.spawn(browser, {data, shouldExpectStateChange}, function*({data, shouldExpectStateChange}) {
+ let { interfaces: Ci, utils: Cu } = Components;
+ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+ if (!content.document.documentElement) {
+ // Wait until the testing document gets loaded.
+ yield new Promise(resolve => {
+ let onload = function() {
+ content.window.removeEventListener("load", onload);
+ resolve();
+ };
+ content.window.addEventListener("load", onload);
+ });
+ }
+
+ let dataTransfer = new content.DataTransfer("dragstart", false);
+ for (let i = 0; i < data.length; i++) {
+ let types = data[i];
+ for (let j = 0; j < types.length; j++) {
+ dataTransfer.mozSetDataAt(types[j].type, types[j].data, i);
+ }
+ }
+ let event = content.document.createEvent("DragEvent");
+ event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null, dataTransfer);
+ content.document.body.dispatchEvent(event);
+
+ let links = [];
+ try {
+ links = Services.droppedLinkHandler.dropLinks(event, true);
+ } catch (ex) {
+ if (shouldExpectStateChange) {
+ ok(false, "Should not have gotten an exception from the dropped link handler, but got: " + ex);
+ Cu.reportError(ex);
+ }
+ }
+
+ return links;
+ });
+}
+
+function* expectLink(browser, expectedLinks, data, testid, onbody=false) {
+ let lastLinks = [];
+ let lastLinksPromise = new Promise(resolve => {
+ browser.droppedLinkHandler = function(event, links) {
+ info(`droppedLinkHandler called, received links ${JSON.stringify(links)}`);
+ if (expectedLinks.length == 0) {
+ ok(false, `droppedLinkHandler called for ${JSON.stringify(links)} which we didn't expect.`);
+ }
+ lastLinks = links;
+ resolve(links);
+ };
+ });
+
+ function dropOnBrowserSync() {
+ let dropEl = onbody ? browser.contentDocument.body : browser;
+ synthesizeDrop(dropEl, dropEl, data, "", dropEl.ownerDocument.defaultView);
+ }
+ let links;
+ if (browser.isRemoteBrowser) {
+ let remoteLinks = yield dropOnRemoteBrowserAsync(browser, data, expectedLinks.length != 0);
+ is(remoteLinks.length, expectedLinks.length, testid + " remote links length");
+ for (let i = 0, length = remoteLinks.length; i < length; i++) {
+ is(remoteLinks[i].url, expectedLinks[i].url, testid + "[" + i + "] remote link");
+ is(remoteLinks[i].name, expectedLinks[i].name, testid + "[" + i + "] remote name");
+ }
+
+ if (expectedLinks.length == 0) {
+ // There is no way to check if nothing happens asynchronously.
+ return;
+ }
+
+ links = yield lastLinksPromise;
+ } else {
+ dropOnBrowserSync();
+ links = lastLinks;
+ }
+
+ is(links.length, expectedLinks.length, testid + " links length");
+ for (let i = 0, length = links.length; i < length; i++) {
+ is(links[i].url, expectedLinks[i].url, testid + "[" + i + "] link");
+ is(links[i].name, expectedLinks[i].name, testid + "[" + i + "] name");
+ }
+};
+
+function* dropLinksOnBrowser(browser, type) {
+ // Dropping single text/plain item with single link should open single
+ // page.
+ yield* expectLink(browser,
+ [ { url: "http://www.mozilla.org/",
+ name: "http://www.mozilla.org/" } ],
+ [ [ { type: "text/plain",
+ data: "http://www.mozilla.org/" } ] ],
+ "text/plain drop on browser " + type);
+
+ // Dropping single text/plain item with multiple links should open
+ // multiple pages.
+ yield* expectLink(browser,
+ [ { url: "http://www.mozilla.org/",
+ name: "http://www.mozilla.org/" },
+ { url: "http://www.example.com/",
+ name: "http://www.example.com/" } ],
+ [ [ { type: "text/plain",
+ data: "http://www.mozilla.org/\nhttp://www.example.com/" } ] ],
+ "text/plain with 2 URLs drop on browser " + type);
+
+ // Dropping sinlge unsupported type item should not open anything.
+ yield* expectLink(browser,
+ [],
+ [ [ { type: "text/link",
+ data: "http://www.mozilla.org/" } ] ],
+ "text/link drop on browser " + type);
+
+ // Dropping single text/uri-list item with single link should open single
+ // page.
+ yield* expectLink(browser,
+ [ { url: "http://www.example.com/",
+ name: "http://www.example.com/" } ],
+ [ [ { type: "text/uri-list",
+ data: "http://www.example.com/" } ] ],
+ "text/uri-list drop on browser " + type);
+
+ // Dropping single text/uri-list item with multiple links should open
+ // multiple pages.
+ yield* expectLink(browser,
+ [ { url: "http://www.example.com/",
+ name: "http://www.example.com/" },
+ { url: "http://www.mozilla.org/",
+ name: "http://www.mozilla.org/" }],
+ [ [ { type: "text/uri-list",
+ data: "http://www.example.com/\nhttp://www.mozilla.org/" } ] ],
+ "text/uri-list with 2 URLs drop on browser " + type);
+
+ // Name in text/x-moz-url should be handled.
+ yield* expectLink(browser,
+ [ { url: "http://www.example.com/",
+ name: "Example.com" } ],
+ [ [ { type: "text/x-moz-url",
+ data: "http://www.example.com/\nExample.com" } ] ],
+ "text/x-moz-url drop on browser " + type);
+
+ yield* expectLink(browser,
+ [ { url: "http://www.mozilla.org/",
+ name: "Mozilla.org" },
+ { url: "http://www.example.com/",
+ name: "Example.com" } ],
+ [ [ { type: "text/x-moz-url",
+ data: "http://www.mozilla.org/\nMozilla.org\nhttp://www.example.com/\nExample.com" } ] ],
+ "text/x-moz-url with 2 URLs drop on browser " + type);
+
+ // Dropping multiple items should open multiple pages.
+ yield* expectLink(browser,
+ [ { url: "http://www.example.com/",
+ name: "Example.com" },
+ { url: "http://www.mozilla.org/",
+ name: "http://www.mozilla.org/" }],
+ [ [ { type: "text/x-moz-url",
+ data: "http://www.example.com/\nExample.com" } ],
+ [ { type: "text/plain",
+ data: "http://www.mozilla.org/" } ] ],
+ "text/x-moz-url and text/plain drop on browser " + type);
+
+ // Dropping single item with multiple types should open single page.
+ yield* expectLink(browser,
+ [ { url: "http://www.example.org/",
+ name: "Example.com" } ],
+ [ [ { type: "text/plain",
+ data: "http://www.mozilla.org/" },
+ { type: "text/x-moz-url",
+ data: "http://www.example.org/\nExample.com" } ] ],
+ "text/plain and text/x-moz-url drop on browser " + type);
+
+ // Dropping javascript or data: URLs should fail:
+ yield* expectLink(browser,
+ [],
+ [ [ { type: "text/plain",
+ data: "javascript:'bad'" } ] ],
+ "text/plain javascript url drop on browser " + type);
+ yield* expectLink(browser,
+ [],
+ [ [ { type: "text/plain",
+ data: "jAvascript:'also bad'" } ] ],
+ "text/plain mixed-case javascript url drop on browser " + type);
+ yield* expectLink(browser,
+ [],
+ [ [ { type: "text/plain",
+ data: "data:text/html,bad" } ] ],
+ "text/plain data url drop on browser " + type);
+
+ // Dropping a chrome url should fail as we don't have a source node set,
+ // defaulting to a source of file:///
+ yield* expectLink(browser,
+ [],
+ [ [ { type: "text/x-moz-url",
+ data: "chrome://browser/content/browser.xul" } ] ],
+ "text/x-moz-url chrome url drop on browser " + type);
+
+ if (browser.type == "content") {
+ yield ContentTask.spawn(browser, null, function() {
+ content.window.stopMode = true;
+ });
+
+ // stopPropagation should not prevent the browser link handling from occuring
+ yield* expectLink(browser,
+ [ { url: "http://www.mozilla.org/",
+ name: "http://www.mozilla.org/" } ],
+ [ [ { type: "text/uri-list",
+ data: "http://www.mozilla.org/" } ] ],
+ "text/x-moz-url drop on browser with stopPropagation drop event", true);
+
+ yield ContentTask.spawn(browser, null, function() {
+ content.window.cancelMode = true;
+ });
+
+ // Canceling the event, however, should prevent the link from being handled.
+ yield* expectLink(browser,
+ [],
+ [ [ { type: "text/uri-list", data: "http://www.mozilla.org/" } ] ],
+ "text/x-moz-url drop on browser with cancelled drop event", true);
+ }
+}
+
+function info(msg) { window.opener.wrappedJSObject.SimpleTest.info(msg); }
+function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
+function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
+
+]]>
+</script>
+
+<browser id="chromechild" src="about:blank"/>
+<browser id="contentchild" type="content" width="100" height="100"
+ src="data:text/html,&lt;html draggable='true'&gt;&lt;body draggable='true' style='width: 100px; height: 100px;' ondragover='event.preventDefault()' ondrop='if (window.stopMode) event.stopPropagation(); if (window.cancelMode) event.preventDefault();'&gt;&lt;/body&gt;&lt;/html&gt;"/>
+
+<browser id="remote-contentchild" type="content" width="100" height="100" remote="true"
+ src="data:text/html,&lt;html draggable='true'&gt;&lt;body draggable='true' style='width: 100px; height: 100px;' ondragover='event.preventDefault()' ondrop='if (window.stopMode) event.stopPropagation(); if (window.cancelMode) event.preventDefault();'&gt;&lt;/body&gt;&lt;/html&gt;"/>
+</window>
diff --git a/toolkit/content/tests/chrome/window_chromemargin.xul b/toolkit/content/tests/chrome/window_chromemargin.xul
new file mode 100644
index 000000000..3dec6d137
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_chromemargin.xul
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window id="window" title="Subframe Origin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+chrome margins rock!
+<script>
+
+// Tests parsing of the chrome margin attrib on a window.
+
+function ok(condition, message) {
+ window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+}
+
+function doSingleTest(param, shouldSucceed)
+{
+ var exception = null;
+ try {
+ document.documentElement.removeAttribute("chromemargin");
+ document.documentElement.setAttribute("chromemargin", param);
+ ok(document.
+ documentElement.
+ getAttribute("chromemargin") == param, "couldn't set/get chromemargin?");
+ } catch (ex) {
+ exception = ex;
+ }
+ if (shouldSucceed)
+ ok(!exception, "failed for param:'" + param + "'");
+ else
+ ok(exception, "did not fail for invalid param:'" + param + "'");
+ return true;
+}
+
+function runTests()
+{
+ var doc = document.documentElement;
+
+ // make sure we can set and get
+ doc.setAttribute("chromemargin", "0,0,0,0");
+ ok(doc.getAttribute("chromemargin") == "0,0,0,0", "couldn't set/get chromemargin?");
+ doc.setAttribute("chromemargin", "-1,-1,-1,-1");
+ ok(doc.getAttribute("chromemargin") == "-1,-1,-1,-1", "couldn't set/get chromemargin?");
+
+ // test remove
+ doc.removeAttribute("chromemargin");
+ ok(doc.getAttribute("chromemargin") == "", "couldn't remove chromemargin?");
+
+ // we already test these really well in a c++ test in widget
+ doSingleTest("1,2,3,4", true);
+ doSingleTest("-2,-2,-2,-2", true);
+ doSingleTest("1,1,1,1", true);
+ doSingleTest("", false);
+ doSingleTest("12123123", false);
+ doSingleTest("0,-1,-1,-1", true);
+ doSingleTest("-1,0,-1,-1", true);
+ doSingleTest("-1,-1,0,-1", true);
+ doSingleTest("-1,-1,-1,0", true);
+ doSingleTest("1234567890,1234567890,1234567890,1234567890", true);
+ doSingleTest("-1,-1,-1,-1", true);
+
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ window.close();
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window);
+
+</script>
+</window>
diff --git a/toolkit/content/tests/chrome/window_cursorsnap_dialog.xul b/toolkit/content/tests/chrome/window_cursorsnap_dialog.xul
new file mode 100644
index 000000000..df6f0bf02
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_cursorsnap_dialog.xul
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<dialog title="Cursor snapping test" id="dialog"
+ width="600" height="600"
+ onload="onload();"
+ onunload="onunload();"
+ buttons="accept,cancel"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+function ok(aCondition, aMessage)
+{
+ window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
+}
+
+function is(aLeft, aRight, aMessage)
+{
+ window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
+}
+
+function isnot(aLeft, aRight, aMessage)
+{
+ window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage);
+}
+
+function canRetryTest()
+{
+ return window.opener.wrappedJSObject.canRetryTest();
+}
+
+function getTimeoutTime()
+{
+ return window.opener.wrappedJSObject.getTimeoutTime();
+}
+
+var gTimer;
+var gRetry;
+
+function finishByTimeout()
+{
+ var button = document.getElementById("dialog").getButton("accept");
+ if (button.disabled)
+ ok(true, "cursor is NOT snapped to the disabled button (dialog)");
+ else if (button.hidden)
+ ok(true, "cursor is NOT snapped to the hidden button (dialog)");
+ else {
+ if (!canRetryTest()) {
+ ok(false, "cursor is NOT snapped to the default button (dialog)");
+ } else {
+ // otherwise, this may be unexpected timeout, we should retry the test.
+ gRetry = true;
+ }
+ }
+ finish();
+}
+
+function finish()
+{
+ window.close();
+}
+
+function onMouseMove(aEvent)
+{
+ var button = document.getElementById("dialog").getButton("accept");
+ if (button.disabled)
+ ok(false, "cursor IS snapped to the disabled button (dialog)");
+ else if (button.hidden)
+ ok(false, "cursor IS snapped to the hidden button (dialog)");
+ else
+ ok(true, "cursor IS snapped to the default button (dialog)");
+ clearTimeout(gTimer);
+ finish();
+}
+
+function onload()
+{
+ var button = document.getElementById("dialog").getButton("accept");
+ button.addEventListener("mousemove", onMouseMove, false);
+
+ if (window.opener.wrappedJSObject.gDisable) {
+ button.disabled = true;
+ }
+ if (window.opener.wrappedJSObject.gHidden) {
+ button.hidden = true;
+ }
+ gRetry = false;
+ gTimer = setTimeout(finishByTimeout, getTimeoutTime());
+}
+
+function onunload()
+{
+ if (gRetry) {
+ window.opener.wrappedJSObject.retryCurrentTest();
+ } else {
+ window.opener.wrappedJSObject.runNextTest();
+ }
+}
+
+]]>
+</script>
+
+</dialog>
diff --git a/toolkit/content/tests/chrome/window_cursorsnap_wizard.xul b/toolkit/content/tests/chrome/window_cursorsnap_wizard.xul
new file mode 100644
index 000000000..a226d02b7
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_cursorsnap_wizard.xul
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<wizard title="Cursor snapping test" id="wizard"
+ width="600" height="600"
+ onload="onload();"
+ onunload="onunload();"
+ buttons="accept,cancel"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <wizardpage>
+ <label value="first page"/>
+ </wizardpage>
+
+ <wizardpage>
+ <label value="second page"/>
+ </wizardpage>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+function ok(aCondition, aMessage)
+{
+ window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
+}
+
+function is(aLeft, aRight, aMessage)
+{
+ window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
+}
+
+function isnot(aLeft, aRight, aMessage)
+{
+ window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage);
+}
+
+function canRetryTest()
+{
+ return window.opener.wrappedJSObject.canRetryTest();
+}
+
+function getTimeoutTime()
+{
+ return window.opener.wrappedJSObject.getTimeoutTime();
+}
+
+var gTimer;
+var gRetry = false;
+
+function finishByTimeout()
+{
+ var button = document.getElementById("wizard").getButton("next");
+ if (button.disabled)
+ ok(true, "cursor is NOT snapped to the disabled button (wizard)");
+ else if (button.hidden)
+ ok(true, "cursor is NOT snapped to the hidden button (wizard)");
+ else {
+ if (!canRetryTest()) {
+ ok(false, "cursor is NOT snapped to the default button (wizard)");
+ } else {
+ // otherwise, this may be unexpected timeout, we should retry the test.
+ gRetry = true;
+ }
+ }
+ finish();
+}
+
+function finish()
+{
+ window.close();
+}
+
+function onMouseMove()
+{
+ var button = document.getElementById("wizard").getButton("next");
+ if (button.disabled)
+ ok(false, "cursor IS snapped to the disabled button (wizard)");
+ else if (button.hidden)
+ ok(false, "cursor IS snapped to the hidden button (wizard)");
+ else
+ ok(true, "cursor IS snapped to the default button (wizard)");
+ clearTimeout(gTimer);
+ finish();
+}
+
+function onload()
+{
+ var button = document.getElementById("wizard").getButton("next");
+ button.addEventListener("mousemove", onMouseMove, false);
+
+ if (window.opener.wrappedJSObject.gDisable) {
+ button.disabled = true;
+ }
+ if (window.opener.wrappedJSObject.gHidden) {
+ button.hidden = true;
+ }
+ gTimer = setTimeout(finishByTimeout, getTimeoutTime());
+}
+
+function onunload()
+{
+ if (gRetry) {
+ window.opener.wrappedJSObject.retryCurrentTest();
+ } else {
+ window.opener.wrappedJSObject.runNextTest();
+ }
+}
+
+]]>
+</script>
+
+</wizard>
diff --git a/toolkit/content/tests/chrome/window_keys.xul b/toolkit/content/tests/chrome/window_keys.xul
new file mode 100644
index 000000000..79de9ac45
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_keys.xul
@@ -0,0 +1,202 @@
+<?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="Key Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var gExpected = null;
+
+const kIsWin = navigator.platform.indexOf("Win") >= 0;
+
+// Only on Windows, osKey state is ignored when there is no shortcut key handler
+// which exactly matches with osKey state.
+var keysToTest = [
+ ["k-v", "V", { } ],
+ ["", "V", { shiftKey: true } ],
+ ["k-v-scy", "V", { ctrlKey: true } ],
+ ["", "V", { altKey: true } ],
+ ["", "V", { metaKey: true } ],
+ [kIsWin ? "k-v" : "", "V", { osKey: true } ],
+ ["k-v-scy", "V", { shiftKey: true, ctrlKey: true } ],
+ ["", "V", { shiftKey: true, ctrlKey: true, altKey: true } ],
+ ["k-e-y", "E", { } ],
+ ["", "E", { shiftKey: true } ],
+ ["", "E", { ctrlKey: true } ],
+ ["", "E", { altKey: true } ],
+ ["", "E", { metaKey: true } ],
+ [kIsWin ? "k-e-y" : "", "E", { osKey: true } ],
+ ["k-d-a", "D", { altKey: true } ],
+ ["k-8-m", "8", { metaKey: true } ],
+ [kIsWin ? "k-8-m" : "", "8", { metaKey: true, osKey: true } ],
+ ["k-a-o", "A", { osKey: true } ],
+ ["", "A", { osKey: true, metaKey: true } ],
+ ["", "B", {} ],
+ ["k-b-myo", "B", { osKey: true } ],
+ ["k-b-myo", "B", { osKey: true, metaKey: true } ],
+ ["k-f-oym", "F", { metaKey: true } ],
+ ["k-f-oym", "F", { metaKey: true, osKey: true } ],
+ ["k-c-scaym", "C", { metaKey: true } ],
+ ["k-c-scaym", "C", { shiftKey: true, ctrlKey: true, altKey: true, metaKey: true } ],
+ [kIsWin ? "k-c-scaym" : "", "C", { shiftKey: true, ctrlKey: true, altKey: true, metaKey: true, osKey: true } ],
+ ["", "V", { shiftKey: true, ctrlKey: true, altKey: true } ],
+ ["k-h-l", "H", { accelKey: true } ],
+// ["k-j-s", "J", { accessKey: true } ],
+ ["", "T", { } ],
+ ["k-g-c", "G", { ctrlKey: true } ],
+ ["k-g-co", "G", { ctrlKey: true, osKey: true } ],
+ ["scommand", "Y", { } ],
+ ["", "U", { } ],
+];
+
+function runTest()
+{
+ iterateKeys(true, "normal");
+
+ var keyset = document.getElementById("keyset");
+ keyset.setAttribute("disabled", "true");
+ iterateKeys(false, "disabled");
+
+ var keyset = document.getElementById("keyset");
+ keyset.removeAttribute("disabled");
+ iterateKeys(true, "reenabled");
+
+ keyset.parentNode.removeChild(keyset);
+ iterateKeys(false, "removed");
+
+ document.documentElement.appendChild(keyset);
+ iterateKeys(true, "appended");
+
+ var accelText = menuitem => menuitem.getAttribute("acceltext").toLowerCase();
+
+ $("menubutton").open = true;
+
+ // now check if a menu updates its accelerator text when a key attribute is changed
+ var menuitem1 = $("menuitem1");
+ ok(accelText(menuitem1).indexOf("d") >= 0, "menuitem1 accelText before");
+ if (kIsWin) {
+ ok(accelText(menuitem1).indexOf("alt") >= 0, "menuitem1 accelText modifier before");
+ }
+
+ menuitem1.setAttribute("key", "k-s-c");
+ ok(accelText(menuitem1).indexOf("s") >= 0, "menuitem1 accelText after");
+ if (kIsWin) {
+ ok(accelText(menuitem1).indexOf("ctrl") >= 0, "menuitem1 accelText modifier after");
+ }
+
+ menuitem1.setAttribute("acceltext", "custom");
+ is(accelText(menuitem1), "custom", "menuitem1 accelText set custom");
+ menuitem1.removeAttribute("acceltext");
+ ok(accelText(menuitem1).indexOf("s") >= 0, "menuitem1 accelText remove");
+ if (kIsWin) {
+ ok(accelText(menuitem1).indexOf("ctrl") >= 0, "menuitem1 accelText modifier remove");
+ }
+
+ var menuitem2 = $("menuitem2");
+ is(accelText(menuitem2), "", "menuitem2 accelText before");
+ menuitem2.setAttribute("key", "k-s-c");
+ ok(accelText(menuitem2).indexOf("s") >= 0, "menuitem2 accelText before");
+ if (kIsWin) {
+ ok(accelText(menuitem2).indexOf("ctrl") >= 0, "menuitem2 accelText modifier before");
+ }
+
+ menuitem2.setAttribute("key", "k-h-l");
+ ok(accelText(menuitem2).indexOf("h") >= 0, "menuitem2 accelText after");
+ if (kIsWin) {
+ ok(accelText(menuitem2).indexOf("ctrl") >= 0, "menuitem2 accelText modifier after");
+ }
+
+ menuitem2.removeAttribute("key");
+ is(accelText(menuitem2), "", "menuitem2 accelText after remove");
+
+ $("menubutton").open = false;
+
+ window.close();
+ window.opener.wrappedJSObject.SimpleTest.finish();
+}
+
+function iterateKeys(enabled, testid)
+{
+ for (var k = 0; k < keysToTest.length; k++) {
+ gExpected = keysToTest[k];
+ var expectedKey = gExpected[0];
+ if (!gExpected[2].accessKey || navigator.platform.indexOf("Mac") == -1) {
+ synthesizeKey(gExpected[1], gExpected[2]);
+ ok((enabled && expectedKey) || expectedKey == "k-d-a" ?
+ !gExpected : gExpected, testid + " key step " + (k + 1));
+ }
+ }
+}
+
+function checkKey(event)
+{
+ // the first element of the gExpected array holds the id of the <key> element
+ // that was expected. If this is empty, a handler wasn't expected to be called
+ if (gExpected[0])
+ is(event.originalTarget.id, gExpected[0], "key " + gExpected[1]);
+ else
+ is("key " + event.originalTarget.id + " was activated", "", "key " + gExpected[1]);
+ gExpected = null;
+}
+
+function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
+function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
+
+SimpleTest.waitForFocus(runTest);
+
+]]>
+</script>
+
+<command id="scommand" oncommand="checkKey(event)"/>
+<command id="scommand-disabled" disabled="true"/>
+
+<keyset id="keyset">
+ <key id="k-v" key="v" oncommand="checkKey(event)"/>
+ <key id="k-v-scy" key="v" modifiers="shift any control" oncommand="checkKey(event)"/>
+ <key id="k-e-y" key="e" modifiers="any" oncommand="checkKey(event)"/>
+ <key id="k-8-m" key="8" modifiers="meta" oncommand="checkKey(event)"/>
+ <key id="k-a-o" key="a" modifiers="os" oncommand="checkKey(event)"/>
+ <key id="k-b-myo" key="b" modifiers="meta any os" oncommand="checkKey(event)"/>
+ <key id="k-f-oym" key="f" modifiers="os any meta" oncommand="checkKey(event)"/>
+ <key id="k-c-scaym" key="c" modifiers="shift control alt any meta" oncommand="checkKey(event)"/>
+ <key id="k-h-l" key="h" modifiers="accel" oncommand="checkKey(event)"/>
+ <key id="k-j-s" key="j" modifiers="access" oncommand="checkKey(event)"/>
+ <key id="k-t-y" disabled="true" key="t" oncommand="checkKey(event)"/>
+ <key id="k-g-c" key="g" modifiers="control" oncommand="checkKey(event)"/>
+ <key id="k-g-co" key="g" modifiers="control os" oncommand="checkKey(event)"/>
+ <key id="k-y" key="y" command="scommand"/>
+ <key id="k-u" key="u" command="scommand-disabled"/>
+</keyset>
+
+<keyset id="keyset2">
+ <key id="k-d-a" key="d" modifiers="alt" oncommand="checkKey(event)"/>
+ <key id="k-s-c" key="s" modifiers="control" oncommand="checkKey(event)"/>
+</keyset>
+
+<button id="menubutton" label="Menu" type="menu">
+ <menupopup>
+ <menuitem id="menuitem1" label="Item 1" key="k-d-a"/>
+ <menuitem id="menuitem2" label="Item 2"/>
+ </menupopup>
+</button>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_largemenu.xul b/toolkit/content/tests/chrome/window_largemenu.xul
new file mode 100644
index 000000000..72e1c077d
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_largemenu.xul
@@ -0,0 +1,425 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Large Menu Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<!--
+ This test checks that a large menu is displayed with arrow buttons
+ and is on the screen.
+ -->
+
+<script>
+<![CDATA[
+
+var gOverflowed = false, gUnderflowed = false;
+var gContextMenuTests = false;
+var gScreenY = -1;
+var gTestIndex = 0;
+var gTests = ["open normal", "open when bottom would overlap", "open with scrolling",
+ "open after scrolling", "open small again",
+ "menu movement", "panel movement",
+ "context menu enough space below",
+ "context menu more space above",
+ "context menu too big either side",
+ "context menu larger than screen",
+ "context menu flips horizontally on osx"];
+function getScreenXY(element)
+{
+ var screenX, screenY;
+ var mouseFn = function(event) {
+ screenX = event.screenX - 1;
+ screenY = event.screenY - 1;
+ }
+
+ // a hacky way to get the screen position of an element without using the box object
+ window.addEventListener("mousedown", mouseFn, false);
+ synthesizeMouse(element, 1, 1, { });
+ window.removeEventListener("mousedown", mouseFn, false);
+
+ return [screenX, screenY];
+}
+
+function hidePopup() {
+ window.requestAnimationFrame(
+ function() {
+ setTimeout(
+ function() {
+ document.getElementById("popup").hidePopup();
+ }, 0);
+ });
+}
+
+function runTests()
+{
+ [, gScreenY] = getScreenXY(document.documentElement);
+ nextTest();
+}
+
+function nextTest()
+{
+ gOverflowed = false, gUnderflowed = false;
+
+ var y = screen.height;
+ if (gTestIndex == 1) // open with bottom overlap test:
+ y -= 100;
+ else
+ y /= 2;
+
+ var popup = document.getElementById("popup");
+ if (gTestIndex == 2) {
+ // add some more menuitems so that scrolling will be necessary
+ var moreItemCount = Math.round(screen.height / popup.firstChild.getBoundingClientRect().height);
+ for (var t = 1; t <= moreItemCount; t++) {
+ var menu = document.createElement("menuitem");
+ menu.setAttribute("label", "More" + t);
+ popup.appendChild(menu);
+ }
+ }
+ else if (gTestIndex == 4) {
+ // remove the items added in test 2 above
+ while (popup.childNodes.length > 15)
+ popup.removeChild(popup.lastChild);
+ }
+
+ window.requestAnimationFrame(function() {
+ setTimeout(
+ function() {
+ popup.openPopupAtScreen(100, y, false);
+ }, 0);
+ });
+}
+
+function popupShown()
+{
+ if (gTests[gTestIndex] == "menu movement")
+ return testPopupMovement();
+
+ if (gContextMenuTests)
+ return contextMenuPopupShown();
+
+ var popup = document.getElementById("popup");
+ var rect = popup.getBoundingClientRect();
+ var sbo = document.getAnonymousNodes(popup)[0].scrollBoxObject;
+ var expectedScrollPos = 0;
+
+ if (gTestIndex == 0) {
+ // the popup should be in the center of the screen
+ // note that if the height is odd, the y-offset will have been rounded
+ // down when we pass the fractional value to openPopupAtScreen above.
+ is(Math.round(rect.top) + gScreenY, Math.floor(screen.height / 2),
+ gTests[gTestIndex] + " top");
+ ok(Math.round(rect.bottom) + gScreenY < screen.height,
+ gTests[gTestIndex] + " bottom");
+ ok(!gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow")
+ }
+ else if (gTestIndex == 1) {
+ // the popup was supposed to open 100 pixels from the bottom, but that
+ // would put it off screen so ...
+ if (platformIsMac()) {
+ // On OSX the popup is constrained so it remains within the
+ // bounds of the screen
+ ok(Math.round(rect.top) + gScreenY >= screen.top, gTests[gTestIndex] + " top");
+ is(Math.round(rect.bottom) + gScreenY, screen.availTop + screen.availHeight, gTests[gTestIndex] + " bottom");
+ ok(!gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow");
+ }
+ else {
+ // On other platforms the menu should be flipped to have its bottom
+ // edge 100 pixels from the bottom
+ ok(Math.round(rect.top) + gScreenY >= screen.top, gTests[gTestIndex] + " top");
+ is(Math.round(rect.bottom) + gScreenY, screen.height - 100,
+ gTests[gTestIndex] + " bottom");
+ ok(!gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow");
+ }
+ }
+ else if (gTestIndex == 2) {
+ // the popup is too large so ensure that it is on screen
+ ok(Math.round(rect.top) + gScreenY >= screen.top, gTests[gTestIndex] + " top");
+ ok(Math.round(rect.bottom) + gScreenY <= screen.height, gTests[gTestIndex] + " bottom");
+ ok(gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow")
+
+ sbo.scrollTo(0, 40);
+ expectedScrollPos = 40;
+ }
+ else if (gTestIndex == 3) {
+ expectedScrollPos = 40;
+ }
+ else if (gTestIndex == 4) {
+ // note that if the height is odd, the y-offset will have been rounded
+ // down when we pass the fractional value to openPopupAtScreen above.
+ is(Math.round(rect.top) + gScreenY, Math.floor(screen.height / 2),
+ gTests[gTestIndex] + " top");
+ ok(Math.round(rect.bottom) + gScreenY < screen.height,
+ gTests[gTestIndex] + " bottom");
+ ok(!gOverflowed && gUnderflowed, gTests[gTestIndex] + " overflow");
+ }
+
+ is(sbo.positionY, expectedScrollPos, "menu scroll position");
+
+ hidePopup();
+}
+
+function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
+function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
+
+var oldx, oldy, waitSteps = 0;
+function moveWindowTo(x, y, callback, arg)
+{
+ if (!waitSteps) {
+ oldx = window.screenX;
+ oldy = window.screenY;
+ window.moveTo(x, y);
+
+ waitSteps++;
+ setTimeout(moveWindowTo, 100, x, y, callback, arg);
+ return;
+ }
+
+ if (window.screenX == oldx && window.screenY == oldy) {
+ if (waitSteps++ > 10) {
+ ok(false, "Window never moved properly to " + x + "," + y);
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ window.close();
+ }
+
+ setTimeout(moveWindowTo, 100, x, y, callback, arg);
+ }
+ else {
+ waitSteps = 0;
+ callback(arg);
+ }
+}
+
+function popupHidden()
+{
+ gTestIndex++;
+ if (gTestIndex == gTests.length) {
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ window.close();
+ }
+ else if (gTests[gTestIndex] == "context menu enough space below") {
+ gContextMenuTests = true;
+ moveWindowTo(window.screenX, screen.availTop + 10,
+ () => synthesizeMouse(document.getElementById("label"), 4, 4, { type: "contextmenu", button: 2 }));
+ }
+ else if (gTests[gTestIndex] == "menu movement") {
+ document.getElementById("popup").openPopup(
+ document.getElementById("label"), "after_start", 0, 0, false, false);
+ }
+ else if (gTests[gTestIndex] == "panel movement") {
+ document.getElementById("panel").openPopup(
+ document.getElementById("label"), "after_start", 0, 0, false, false);
+ }
+ else if (gContextMenuTests) {
+ contextMenuPopupHidden();
+ }
+ else {
+ nextTest();
+ }
+}
+
+function contextMenuPopupShown()
+{
+ var popup = document.getElementById("popup");
+ var rect = popup.getBoundingClientRect();
+ var labelrect = document.getElementById("label").getBoundingClientRect();
+
+ // Click to open popup in popupHidden() occurs at (4,4) in label's coordinate space
+ var clickX = clickY = 4;
+
+ var testPopupAppearedRightOfCursor = true;
+ switch (gTests[gTestIndex]) {
+ case "context menu enough space below":
+ is(rect.top, labelrect.top + clickY + (platformIsMac() ? -6 : 2), gTests[gTestIndex] + " top");
+ break;
+ case "context menu more space above":
+ if (platformIsMac()) {
+ let screenY;
+ [, screenY] = getScreenXY(popup);
+ // Macs constrain their popup menus vertically rather than flip them.
+ is(screenY, screen.availTop + screen.availHeight - rect.height, gTests[gTestIndex] + " top");
+ } else {
+ is(rect.top, labelrect.top + clickY - rect.height - 2, gTests[gTestIndex] + " top");
+ }
+
+ break;
+ case "context menu too big either side":
+ [, gScreenY] = getScreenXY(document.documentElement);
+ // compare against the available size as well as the total size, as some
+ // platforms allow the menu to overlap os chrome and others do not
+ var pos = (screen.availTop + screen.availHeight - rect.height) - gScreenY;
+ var availPos = (screen.top + screen.height - rect.height) - gScreenY;
+ ok(rect.top == pos || rect.top == availPos,
+ gTests[gTestIndex] + " top");
+ break;
+ case "context menu larger than screen":
+ ok(rect.top == -(gScreenY - screen.availTop) || rect.top == -(gScreenY - screen.top), gTests[gTestIndex] + " top");
+ break;
+ case "context menu flips horizontally on osx":
+ testPopupAppearedRightOfCursor = false;
+ if (platformIsMac()) {
+ is(Math.round(rect.right), labelrect.left + clickX - 1, gTests[gTestIndex] + " right");
+ }
+ break;
+ }
+
+ if (testPopupAppearedRightOfCursor) {
+ is(rect.left, labelrect.left + clickX + (platformIsMac() ? 1 : 2), gTests[gTestIndex] + " left");
+ }
+
+ hidePopup();
+}
+
+function contextMenuPopupHidden()
+{
+ var screenAvailBottom = screen.availTop + screen.availHeight;
+
+ if (gTests[gTestIndex] == "context menu more space above") {
+ moveWindowTo(window.screenX, screenAvailBottom - 80, nextContextMenuTest, -1);
+ }
+ else if (gTests[gTestIndex] == "context menu too big either side") {
+ moveWindowTo(window.screenX, screenAvailBottom / 2 - 80, nextContextMenuTest, screenAvailBottom / 2 + 120);
+ }
+ else if (gTests[gTestIndex] == "context menu larger than screen") {
+ nextContextMenuTest(screen.availHeight + 80);
+ }
+ else if (gTests[gTestIndex] == "context menu flips horizontally on osx") {
+ var popup = document.getElementById("popup");
+ var popupWidth = popup.getBoundingClientRect().width;
+ moveWindowTo(screen.availLeft + screen.availWidth - popupWidth, 100, nextContextMenuTest, -1);
+ }
+}
+
+function nextContextMenuTest(desiredHeight)
+{
+ if (desiredHeight >= 0) {
+ var popup = document.getElementById("popup");
+ var height = popup.getBoundingClientRect().height;
+ var itemheight = document.getElementById("firstitem").getBoundingClientRect().height;
+ while (height < desiredHeight) {
+ var menu = document.createElement("menuitem");
+ menu.setAttribute("label", "Item");
+ popup.appendChild(menu);
+ height += itemheight;
+ }
+ }
+
+ synthesizeMouse(document.getElementById("label"), 4, 4, { type: "contextmenu", button: 2 });
+}
+
+function testPopupMovement()
+{
+ var button = document.getElementById("label");
+ var isPanelTest = (gTests[gTestIndex] == "panel movement");
+ var popup = document.getElementById(isPanelTest ? "panel" : "popup");
+
+ var screenX, screenY, buttonScreenX, buttonScreenY;
+ var rect = popup.getBoundingClientRect();
+
+ var overlapOSChrome = !platformIsMac();
+ popup.moveTo(1, 1);
+ [screenX, screenY] = getScreenXY(popup);
+
+ var expectedx = 1, expectedy = 1;
+ if (!isPanelTest && !overlapOSChrome) {
+ if (screen.availLeft >= 1) expectedx = screen.availLeft;
+ if (screen.availTop >= 1) expectedy = screen.availTop;
+ }
+ is(screenX, expectedx, gTests[gTestIndex] + " (1, 1) x");
+ is(screenY, expectedy, gTests[gTestIndex] + " (1, 1) y");
+
+ popup.moveTo(100, 8000);
+ if (isPanelTest) {
+ expectedy = 8000;
+ }
+ else {
+ expectedy = (overlapOSChrome ? screen.height + screen.top : screen.availHeight + screen.availTop) -
+ Math.round(rect.height);
+ }
+
+ [screenX, screenY] = getScreenXY(popup);
+ is(screenX, 100, gTests[gTestIndex] + " (100, 8000) x");
+ is(screenY, expectedy, gTests[gTestIndex] + " (100, 8000) y");
+
+ popup.moveTo(6000, 100);
+
+ if (isPanelTest) {
+ expectedx = 6000;
+ }
+ else {
+ expectedx = (overlapOSChrome ? screen.width + screen.left : screen.availWidth + screen.availLeft) -
+ Math.round(rect.width);
+ }
+
+ [screenX, screenY] = getScreenXY(popup);
+ is(screenX, expectedx, gTests[gTestIndex] + " (6000, 100) x");
+ is(screenY, 100, gTests[gTestIndex] + " (6000, 100) y");
+
+ is(popup.left, "", gTests[gTestIndex] + " left is empty after moving");
+ is(popup.top, "", gTests[gTestIndex] + " top is empty after moving");
+ popup.setAttribute("left", "80");
+ popup.setAttribute("top", "82");
+ [screenX, screenY] = getScreenXY(popup);
+ is(screenX, 80, gTests[gTestIndex] + " set left and top x");
+ is(screenY, 82, gTests[gTestIndex] + " set left and top y");
+ popup.moveTo(95, 98);
+ [screenX, screenY] = getScreenXY(popup);
+ is(screenX, 95, gTests[gTestIndex] + " move after set left and top x");
+ is(screenY, 98, gTests[gTestIndex] + " move after set left and top y");
+ is(popup.left, "95", gTests[gTestIndex] + " left is set after moving");
+ is(popup.top, "98", gTests[gTestIndex] + " top is set after moving");
+ popup.removeAttribute("left");
+ popup.removeAttribute("top");
+
+ popup.moveTo(-1, -1);
+ [screenX, screenY] = getScreenXY(popup);
+
+ expectedx = (overlapOSChrome ? screen.left : screen.availLeft);
+ expectedy = (overlapOSChrome ? screen.top : screen.availTop);
+
+ is(screenX, expectedx, gTests[gTestIndex] + " move after set left and top x to -1");
+ is(screenY, expectedy, gTests[gTestIndex] + " move after set left and top y to -1");
+ is(popup.left, "", gTests[gTestIndex] + " left is not set after moving to -1");
+ is(popup.top, "", gTests[gTestIndex] + " top is not set after moving to -1");
+
+ popup.hidePopup();
+}
+
+function platformIsMac()
+{
+ return navigator.platform.indexOf("Mac") > -1;
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window);
+
+]]>
+</script>
+
+<button id="label" label="OK" context="popup"/>
+<menupopup id="popup" onpopupshown="popupShown();" onpopuphidden="popupHidden();"
+ onoverflow="gOverflowed = true" onunderflow="gUnderflowed = true;">
+ <menuitem id="firstitem" label="1"/>
+ <menuitem label="2"/>
+ <menuitem label="3"/>
+ <menuitem label="4"/>
+ <menuitem label="5"/>
+ <menuitem label="6"/>
+ <menuitem label="7"/>
+ <menuitem label="8"/>
+ <menuitem label="9"/>
+ <menuitem label="10"/>
+ <menuitem label="11"/>
+ <menuitem label="12"/>
+ <menuitem label="13"/>
+ <menuitem label="14"/>
+ <menuitem label="15"/>
+</menupopup>
+
+<panel id="panel" onpopupshown="testPopupMovement();" onpopuphidden="popupHidden();" style="margin: 0">
+ <button label="OK"/>
+</panel>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_panel.xul b/toolkit/content/tests/chrome/window_panel.xul
new file mode 100644
index 000000000..b99b52dfa
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_panel.xul
@@ -0,0 +1,312 @@
+<?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"?>
+<!--
+ XUL Widget Test for panels
+ -->
+<window title="Titlebar" width="200" height="200"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<tree id="tree" seltype="single" width="100" height="100">
+ <treecols>
+ <treecol flex="1"/>
+ <treecol flex="1"/>
+ </treecols>
+ <treechildren id="treechildren">
+ <treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
+ <treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
+ <treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
+ <treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
+ <treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
+ <treeitem><treerow><treecell label="One"/><treecell label="Two"/></treerow></treeitem>
+ </treechildren>
+</tree>
+
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var currentTest = null;
+
+function ok(condition, message) {
+ window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+}
+
+function is(left, right, message) {
+ window.opener.wrappedJSObject.SimpleTest.is(left, right, message);
+}
+
+function test_panels()
+{
+ checkTreeCoords();
+
+ addEventListener("popupshowing", popupShowing, false);
+ addEventListener("popupshown", popupShown, false);
+ addEventListener("popuphidden", nextTest, false);
+ nextTest();
+}
+
+function nextTest()
+{
+ if (!tests.length) {
+ window.close();
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ return;
+ }
+
+ currentTest = tests.shift();
+ var panel = createPanel(currentTest.attrs);
+ currentTest.test(panel);
+}
+
+function popupShowing(event)
+{
+ var rect = event.target.getOuterScreenRect();
+ ok(!rect.left && !rect.top && !rect.width && !rect.height,
+ currentTest.testname + " empty rectangle during popupshowing");
+}
+
+var waitSteps = 0;
+function popupShown(event)
+{
+ var panel = event.target;
+
+ if (waitSteps > 0 && navigator.platform.indexOf("Linux") >= 0 &&
+ panel.boxObject.screenY == 210) {
+ waitSteps--;
+ setTimeout(popupShown, 10, event);
+ return;
+ }
+
+ currentTest.result(currentTest.testname + " ", panel);
+ panel.hidePopup();
+}
+
+function createPanel(attrs)
+{
+ var panel = document.createElement("panel");
+ for (var a in attrs) {
+ panel.setAttribute(a, attrs[a]);
+ }
+
+ var button = document.createElement("button");
+ panel.appendChild(button);
+ button.label = "OK";
+ button.width = 120;
+ button.height = 40;
+ button.setAttribute("style", "-moz-appearance: none; border: 0; margin: 0;");
+ panel.setAttribute("style", "-moz-appearance: none; border: 0; margin: 0;");
+ return document.documentElement.appendChild(panel);
+}
+
+function checkTreeCoords()
+{
+ var tree = $("tree");
+ var treechildren = $("treechildren");
+ tree.currentIndex = 0;
+ tree.treeBoxObject.scrollToRow(0);
+ synthesizeMouse(treechildren, 10, tree.treeBoxObject.rowHeight + 2, { });
+ is(tree.currentIndex, 1, "tree selection");
+
+ tree.treeBoxObject.scrollToRow(2);
+ synthesizeMouse(treechildren, 10, tree.treeBoxObject.rowHeight + 2, { });
+ is(tree.currentIndex, 3, "tree selection after scroll");
+}
+
+var tests = [
+ {
+ testname: "normal panel",
+ attrs: { },
+ test: function(panel) {
+ var screenRect = panel.getOuterScreenRect();
+ is(screenRect.left, 0, this.testname + " screen left before open");
+ is(screenRect.top, 0, this.testname + " screen top before open");
+ is(screenRect.width, 0, this.testname + " screen width before open");
+ is(screenRect.height, 0, this.testname + " screen height before open");
+
+ panel.openPopupAtScreen(200, 210);
+ },
+ result: function(testname, panel) {
+ var panelrect = panel.getBoundingClientRect();
+ is(panelrect.left, 200 - mozInnerScreenX, testname + "left");
+ is(panelrect.top, 210 - mozInnerScreenY, testname + "top");
+ is(panelrect.width, 120, testname + "width");
+ is(panelrect.height, 40, testname + "height");
+
+ var screenRect = panel.getOuterScreenRect();
+ is(screenRect.left, 200, testname + " screen left");
+ is(screenRect.top, 210, testname + " screen top");
+ is(screenRect.width, 120, testname + " screen width");
+ is(screenRect.height, 40, testname + " screen height");
+ }
+ },
+ {
+ // only noautohide panels support titlebars, so one shouldn't be shown here
+ testname: "autohide panel with titlebar",
+ attrs: { titlebar: "normal" },
+ test: function(panel) {
+ var screenRect = panel.getOuterScreenRect();
+ is(screenRect.left, 0, this.testname + " screen left before open");
+ is(screenRect.top, 0, this.testname + " screen top before open");
+ is(screenRect.width, 0, this.testname + " screen width before open");
+ is(screenRect.height, 0, this.testname + " screen height before open");
+
+ panel.openPopupAtScreen(200, 210);
+ },
+ result: function(testname, panel) {
+ var panelrect = panel.getBoundingClientRect();
+ is(panelrect.left, 200 - mozInnerScreenX, testname + "left");
+ is(panelrect.top, 210 - mozInnerScreenY, testname + "top");
+ is(panelrect.width, 120, testname + "width");
+ is(panelrect.height, 40, testname + "height");
+
+ var screenRect = panel.getOuterScreenRect();
+ is(screenRect.left, 200, testname + " screen left");
+ is(screenRect.top, 210, testname + " screen top");
+ is(screenRect.width, 120, testname + " screen width");
+ is(screenRect.height, 40, testname + " screen height");
+ }
+ },
+ {
+ testname: "noautohide panel with titlebar",
+ attrs: { noautohide: true, titlebar: "normal" },
+ test: function(panel) {
+ waitSteps = 25;
+
+ var screenRect = panel.getOuterScreenRect();
+ is(screenRect.left, 0, this.testname + " screen left before open");
+ is(screenRect.top, 0, this.testname + " screen top before open");
+ is(screenRect.width, 0, this.testname + " screen width before open");
+ is(screenRect.height, 0, this.testname + " screen height before open");
+
+ panel.openPopupAtScreen(200, 210);
+ },
+ result: function(testname, panel) {
+ var panelrect = panel.getBoundingClientRect();
+ ok(panelrect.left >= 200 - mozInnerScreenX, testname + "left");
+ if (navigator.platform.indexOf("Linux") < 0) {
+ ok(panelrect.top >= 210 - mozInnerScreenY + 10, testname + "top greater");
+ }
+ ok(panelrect.top <= 210 - mozInnerScreenY + 32, testname + "top less");
+ is(panelrect.width, 120, testname + "width");
+ is(panelrect.height, 40, testname + "height");
+
+ var screenRect = panel.getOuterScreenRect();
+ if (navigator.platform.indexOf("Linux") < 0) {
+ is(screenRect.left, 200, testname + " screen left");
+ is(screenRect.top, 210, testname + " screen top");
+ }
+ ok(screenRect.width >= 120 && screenRect.width <= 140, testname + " screen width");
+ ok(screenRect.height >= 40 && screenRect.height <= 80, testname + " screen height");
+
+ var gotMouseEvent = false;
+ function mouseMoved(event)
+ {
+ is(event.clientY, panelrect.top + 10,
+ "popup clientY");
+ is(event.screenY, panel.boxObject.screenY + 10,
+ "popup screenY");
+ is(event.originalTarget, panel.firstChild, "popup target");
+ gotMouseEvent = true;
+ }
+
+ panel.addEventListener("mousemove", mouseMoved, true);
+ synthesizeMouse(panel, 10, 10, { type: "mousemove" });
+ ok(gotMouseEvent, "mouse event on panel");
+ panel.removeEventListener("mousemove", mouseMoved, true);
+
+ var tree = $("tree");
+ tree.currentIndex = 0;
+ panel.appendChild(tree);
+ checkTreeCoords();
+ }
+ },
+ {
+ testname: "noautohide panel with backdrag",
+ attrs: { noautohide: true, backdrag: "true" },
+ test: function(panel) {
+ var label = document.createElement("label");
+ label.id = "backdragspot";
+ label.setAttribute("value", "Hello There");
+ panel.appendChild(label);
+ panel.openPopupAtScreen(200, 230);
+ },
+ result: function(testname, panel) {
+ var oldrect = panel.getOuterScreenRect();
+
+ // Linux uses native window moving
+ if (navigator.platform.indexOf("Linux") == -1) {
+ var backdragspot = document.getElementById("backdragspot");
+ synthesizeMouse(backdragspot, 5, 5, { type: "mousedown" });
+ synthesizeMouse(backdragspot, 15, 20, { type: "mousemove" });
+ synthesizeMouse(backdragspot, 15, 20, { type: "mouseup" });
+
+ is(panel.getOuterScreenRect().left, 210, testname + "left");
+ is(panel.getOuterScreenRect().top, 245, testname + "top");
+ }
+ }
+ },
+ {
+ // The panel should be allowed to appear and remain offscreen
+ testname: "normal panel with flip='none' off-screen",
+ attrs: { "flip": "none" },
+ test: function(panel) {
+ panel.openPopup(document.documentElement, "", -100 - mozInnerScreenX, -100 - mozInnerScreenY, false, false, null);
+ },
+ result: function(testname, panel) {
+ var panelrect = panel.getBoundingClientRect();
+ is(panelrect.left, -100 - mozInnerScreenX, testname + "left");
+ is(panelrect.top, -100 - mozInnerScreenY, testname + "top");
+ is(panelrect.width, 120, testname + "width");
+ is(panelrect.height, 40, testname + "height");
+
+ var screenRect = panel.getOuterScreenRect();
+ is(screenRect.left, -100, testname + " screen left");
+ is(screenRect.top, -100, testname + " screen top");
+ is(screenRect.width, 120, testname + " screen width");
+ is(screenRect.height, 40, testname + " screen height");
+ }
+ },
+ {
+ // The panel should be allowed to remain offscreen after moving and it should follow the anchor
+ testname: "normal panel with flip='none' moved off-screen",
+ attrs: { "flip": "none" },
+ test: function(panel) {
+ panel.openPopup(document.documentElement, "", -100 - mozInnerScreenX, -100 - mozInnerScreenY, false, false, null);
+ window.moveBy(-50, -50);
+ },
+ result: function(testname, panel) {
+ if (navigator.platform.indexOf("Linux") >= 0) {
+ // The window position doesn't get updated immediately on Linux.
+ return;
+ }
+ var panelrect = panel.getBoundingClientRect();
+ is(panelrect.left, -150 - mozInnerScreenX, testname + "left");
+ is(panelrect.top, -150 - mozInnerScreenY, testname + "top");
+ is(panelrect.width, 120, testname + "width");
+ is(panelrect.height, 40, testname + "height");
+
+ var screenRect = panel.getOuterScreenRect();
+ is(screenRect.left, -150, testname + " screen left");
+ is(screenRect.top, -150, testname + " screen top");
+ is(screenRect.width, 120, testname + " screen width");
+ is(screenRect.height, 40, testname + " screen height");
+ }
+ },
+];
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(test_panels, window);
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_panel_focus.xul b/toolkit/content/tests/chrome/window_panel_focus.xul
new file mode 100644
index 000000000..6ac1abdc0
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_panel_focus.xul
@@ -0,0 +1,132 @@
+<?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="Panel Focus Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<checkbox id="b1" label="Item 1"/>
+
+<!-- Focus should be in this order: 2 6 3 8 1 4 5 7 9 -->
+<panel id="panel" norestorefocus="true" onpopupshown="panelShown()" onpopuphidden="panelHidden()">
+ <button id="t1" label="Button One"/>
+ <button id="t2" tabindex="1" label="Button Two" onblur="gButtonBlur++;"/>
+ <button id="t3" tabindex="2" label="Button Three"/>
+ <button id="t4" tabindex="0" label="Button Four"/>
+ <button id="t5" label="Button Five"/>
+ <button id="t6" tabindex="1" label="Button Six"/>
+ <button id="t7" label="Button Seven"/>
+ <button id="t8" tabindex="4" label="Button Eight"/>
+ <button id="t9" label="Button Nine"/>
+</panel>
+
+<panel id="noautofocusPanel" noautofocus="true"
+ onpopupshown="noautofocusPanelShown()" onpopuphidden="noautofocusPanelHidden()">
+ <textbox id="tb3"/>
+</panel>
+
+<checkbox id="b2" label="Item 2" popup="panel" onblur="gButtonBlur++;"/>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+var gButtonBlur = 0;
+
+function showPanel()
+{
+ // click on the document so that the window has focus
+ synthesizeMouse(document.documentElement, 1, 1, { });
+
+ // focus the button
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("b1"), "focus", "button focus");
+ // tabbing again should skip the popup
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("b2"), "focus", "popup skipped in focus navigation");
+
+ $("panel").openPopup(null, "", 10, 10, false, false);
+}
+
+function panelShown()
+{
+ // the focus on the button should have been removed when the popup was opened
+ is(gButtonBlur, 1, "focus removed when popup opened");
+
+ // press tab numerous times to cycle through the buttons. The t2 button will
+ // be blurred twice, so gButtonBlur will be 3 afterwards.
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t2"), "focus", "tabindex 1");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t6"), "focus", "tabindex 2");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t3"), "focus", "tabindex 3");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t8"), "focus", "tabindex 4");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t1"), "focus", "tabindex 5");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t4"), "focus", "tabindex 6");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t5"), "focus", "tabindex 7");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t7"), "focus", "tabindex 8");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t9"), "focus", "tabindex 9");
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("t2"), "focus", "tabindex 10");
+
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t9"), "focus", "back tabindex 1");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t7"), "focus", "back tabindex 2");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t5"), "focus", "back tabindex 3");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t4"), "focus", "back tabindex 4");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t1"), "focus", "back tabindex 5");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t8"), "focus", "back tabindex 6");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t3"), "focus", "back tabindex 7");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t6"), "focus", "back tabindex 8");
+ synthesizeKeyExpectEvent("VK_TAB", { shiftKey: true }, $("t2"), "focus", "back tabindex 9");
+
+ is(gButtonBlur, 3, "blur events fired within popup");
+
+ synthesizeKey("VK_ESCAPE", { });
+}
+
+function ok(condition, message) {
+ window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
+}
+
+function is(left, right, message) {
+ window.opener.wrappedJSObject.SimpleTest.is(left, right, message);
+}
+
+function panelHidden()
+{
+ // closing the popup should have blurred the focused element
+ is(gButtonBlur, 4, "focus removed when popup closed");
+
+ // now that the panel is hidden, pressing tab should focus the elements in
+ // the main window again
+ synthesizeKeyExpectEvent("VK_TAB", { }, $("b1"), "focus", "focus after popup closed");
+
+ $("noautofocusPanel").openPopup(null, "", 10, 10, false, false);
+}
+
+function noautofocusPanelShown()
+{
+ // with noautofocus="true", the focus should not be removed when the panel is
+ // opened, so key events should still be fired at the checkbox.
+ synthesizeKeyExpectEvent("VK_SPACE", { }, $("b1"), "command", "noautofocus");
+ $("noautofocusPanel").hidePopup();
+}
+
+function noautofocusPanelHidden()
+{
+ window.close();
+ window.opener.wrappedJSObject.SimpleTest.finish();
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(showPanel, window);
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_popup_anchor.xul b/toolkit/content/tests/chrome/window_popup_anchor.xul
new file mode 100644
index 000000000..45f5fe365
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_popup_anchor.xul
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Popup Anchor Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script>
+function runTests()
+{
+ frames[0].openPopup();
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window);
+</script>
+
+<spacer height="13"/>
+<button id="outerbutton" label="Button One" style="margin-left: 6px; -moz-appearance: none;"/>
+<hbox>
+ <spacer width="20"/>
+ <deck>
+ <vbox>
+ <iframe id="frame" style="margin-left: 60px; margin-top: 10px; border-left: 17px solid red; padding-left: 0 !important; padding-top: 3px;"
+ width="250" height="80" src="frame_popup_anchor.xul"/>
+ </vbox>
+ </deck>
+</hbox>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_popup_anchoratrect.xul b/toolkit/content/tests/chrome/window_popup_anchoratrect.xul
new file mode 100644
index 000000000..ff37afee7
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_popup_anchoratrect.xul
@@ -0,0 +1,117 @@
+<?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 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onpopupshown="popupshown(event.target)" onpopuphidden="nextTest()">
+
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<label value="Popup Test"/>
+
+<menupopup id="popup">
+ <menuitem label="One"/>
+ <menuitem label="Two"/>
+</menupopup>
+
+<panel id="panel" noautohide="true" height="20">
+ <label value="OK"/>
+</panel>
+
+<script>
+<![CDATA[
+
+let menupopup;
+
+let tests = [
+ {
+ test: () => menupopup.openPopupAtScreenRect("after_start", 150, 250, 30, 40),
+ verify: popup => {
+ let rect = popup.getOuterScreenRect();
+ is(rect.left, 150, "popup at screen position x");
+ is(rect.top, 290, "popup at screen position y");
+ }
+ },
+ {
+ test: () => menupopup.openPopupAtScreenRect("after_start", 150, 350, 30, 9000),
+ verify: popup => {
+ let rect = popup.getOuterScreenRect();
+ is(rect.left, 150, "flipped popup at screen position x");
+ is(rect.bottom, 350, "flipped popup at screen position y");
+ }
+ },
+ {
+ test: () => menupopup.openPopupAtScreenRect("end_before", 150, 250, 30, 40),
+ verify: popup => {
+ let rect = popup.getOuterScreenRect();
+ is(rect.left, 180, "popup at end_before screen position x");
+ is(rect.top, 250, "popup at end_before screen position y");
+ }
+ },
+ {
+ test: () => $("panel").openPopupAtScreenRect("after_start", 150, 250, 30, 40),
+ verify: popup => {
+ let rect = popup.getOuterScreenRect();
+ is(rect.left, 150, "panel at screen position x");
+ is(rect.top, 290, "panel at screen position y");
+ }
+ },
+ {
+ test: () => $("panel").openPopupAtScreenRect("before_start", 150, 250, 30, 40),
+ verify: popup => {
+ let rect = popup.getOuterScreenRect();
+ is(rect.left, 150, "panel at before_start screen position x");
+ is(rect.bottom, 250, "panel at before_start screen position y");
+ }
+ },
+];
+
+function runTest(id)
+{
+ menupopup = $("popup");
+ nextTest();
+}
+
+function nextTest()
+{
+ if (!tests.length) {
+ window.close();
+ window.opener.SimpleTest.finish();
+ return;
+ }
+
+ tests[0].test();
+}
+
+function popupshown(popup)
+{
+ tests[0].verify(popup);
+ tests.shift();
+ popup.hidePopup();
+}
+
+function is(left, right, message)
+{
+ window.opener.SimpleTest.is(left, right, message);
+}
+
+function ok(value, message)
+{
+ window.opener.SimpleTest.ok(value, message);
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTest, window);
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_popup_attribute.xul b/toolkit/content/tests/chrome/window_popup_attribute.xul
new file mode 100644
index 000000000..9316d31c4
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_popup_attribute.xul
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Popup Attribute Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="popup_shared.js"></script>
+ <script type="application/javascript" src="popup_trigger.js"></script>
+
+<script>
+window.opener.SimpleTest.waitForFocus(runTests, window);
+</script>
+
+<hbox style="margin-left: 200px; margin-top: 270px;">
+ <label id="trigger" popup="thepopup" value="Popup" height="60"/>
+</hbox>
+<!-- this frame is used to check that document.popupNode
+ is inaccessible from different sources -->
+<iframe id="childframe" type="content" width="10" height="10"
+ src="http://sectest2.example.org:80/chrome/toolkit/content/tests/chrome/popup_childframe_node.xul"/>
+
+<menupopup id="thepopup">
+ <menuitem id="item1" label="First"/>
+ <menuitem id="item2" label="Main Item"/>
+ <menuitem id="amenu" label="A Menu" accesskey="M"/>
+ <menuitem id="item3" label="Third"/>
+ <menuitem id="one" label="One"/>
+ <menuitem id="fancier" label="Fancier Menu"/>
+ <menu id="submenu" label="Only Menu">
+ <menupopup id="submenupopup">
+ <menuitem id="submenuitem" label="Test Submenu"/>
+ </menupopup>
+ </menu>
+ <menuitem id="other" disabled="true" label="Other Menu"/>
+ <menuitem id="secondlast" label="Second Last Menu" accesskey="T"/>
+ <menuitem id="last" label="One Other Menu"/>
+</menupopup>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_popup_button.xul b/toolkit/content/tests/chrome/window_popup_button.xul
new file mode 100644
index 000000000..125e6886c
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_popup_button.xul
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Popup Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="popup_shared.js"></script>
+ <script type="application/javascript" src="popup_trigger.js"></script>
+
+<script>
+window.opener.SimpleTest.waitForFocus(runTests, window);
+</script>
+
+<hbox style="margin-left: 200px; margin-top: 270px;">
+ <button id="trigger" type="menu" label="Popup" width="100" height="50">
+ <menupopup id="thepopup">
+ <menuitem id="item1" label="First"/>
+ <menuitem id="item2" label="Main Item"/>
+ <menuitem id="amenu" label="A Menu" accesskey="M"/>
+ <menuitem id="item3" label="Third"/>
+ <menuitem id="one" label="One"/>
+ <menuitem id="fancier" label="Fancier Menu"/>
+ <menu id="submenu" label="Only Menu">
+ <menupopup id="submenupopup">
+ <menuitem id="submenuitem" label="Test Submenu"/>
+ </menupopup>
+ </menu>
+ <menuitem id="other" disabled="true" label="Other Menu"/>
+ <menuitem id="secondlast" label="Second Last Menu" accesskey="T"/>
+ <menuitem id="last" label="One Other Menu"/>
+ </menupopup>
+ </button>
+</hbox>
+
+<!-- this frame is used to check that document.popupNode
+ is inaccessible from different sources -->
+<iframe id="childframe" type="content" width="10" height="10"
+ src="http://sectest2.example.org:80/chrome/toolkit/content/tests/chrome/popup_childframe_node.xul"/>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xul b/toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xul
new file mode 100644
index 000000000..4d10d7fc7
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xul
@@ -0,0 +1,113 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window title="Popup Prevent Default Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<!--
+ This tests checks that preventDefault can be called on a popupshowing
+ event or popuphiding event to prevent the default behaviour.
+ -->
+
+<script>
+
+var gBlockShowing = true;
+var gBlockHiding = true;
+var gShownNotAllowed = true;
+var gHiddenNotAllowed = true;
+
+var fm = Components.classes["@mozilla.org/focus-manager;1"].
+ getService(Components.interfaces.nsIFocusManager);
+
+var is = function(l, r, v) { window.opener.wrappedJSObject.SimpleTest.is(l, r, v); }
+var isnot = function(l, r, v) { window.opener.wrappedJSObject.SimpleTest.isnot(l, r, v); }
+
+function runTest()
+{
+ var menu = document.getElementById("menu");
+
+ is(fm.activeWindow, window, "active window at start");
+ is(fm.focusedWindow, window, "focused window at start");
+
+ is(window.windowState, window.STATE_NORMAL, "window is normal");
+ // the minimizing test sometimes fails on Linux so don't test it there
+ if (navigator.platform.indexOf("Lin") == 0) {
+ menu.open = true;
+ return;
+ }
+ window.minimize();
+ is(window.windowState, window.STATE_MINIMIZED, "window is minimized");
+
+ isnot(fm.activeWindow, window, "active window after minimize");
+ isnot(fm.focusedWindow, window, "focused window after minimize");
+
+ menu.open = true;
+
+ setTimeout(runTestAfterMinimize, 0);
+}
+
+function runTestAfterMinimize()
+{
+ var menu = document.getElementById("menu");
+ is(menu.firstChild.state, "closed", "popup not opened when window minimized");
+
+ window.restore();
+ is(window.windowState, window.STATE_NORMAL, "window is restored");
+
+ is(fm.activeWindow, window, "active window after restore");
+ is(fm.focusedWindow, window, "focused window after restore");
+
+ menu.open = true;
+}
+
+function popupShowing(event)
+{
+ if (gBlockShowing) {
+ event.preventDefault();
+ gBlockShowing = false;
+ setTimeout(function() {
+ gShownNotAllowed = false;
+ document.getElementById("menu").open = true;
+ }, 3000, true);
+ }
+}
+
+function popupShown()
+{
+ window.opener.wrappedJSObject.SimpleTest.ok(!gShownNotAllowed, "popupshowing preventDefault");
+ document.getElementById("menu").open = false;
+}
+
+function popupHiding(event)
+{
+ if (gBlockHiding) {
+ event.preventDefault();
+ gBlockHiding = false;
+ setTimeout(function() {
+ gHiddenNotAllowed = false;
+ document.getElementById("menu").open = false;
+ }, 3000, true);
+ }
+}
+
+function popupHidden()
+{
+ window.opener.wrappedJSObject.SimpleTest.ok(!gHiddenNotAllowed, "popuphiding preventDefault");
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ window.close();
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTest, window);
+</script>
+
+<button id="menu" type="menu" label="Menu">
+ <menupopup onpopupshowing="popupShowing(event);"
+ onpopupshown="popupShown();"
+ onpopuphiding="popupHiding(event);"
+ onpopuphidden="popupHidden();">
+ <menuitem label="Item"/>
+ </menupopup>
+</button>
+
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_preferences.xul b/toolkit/content/tests/chrome/window_preferences.xul
new file mode 100644
index 000000000..25ee4b5b2
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_preferences.xul
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<!--
+ XUL Widget Test for preferences window
+-->
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="preferences window"
+ windowtype="test:preferences"
+ buttons="accept,cancel"
+ onload="RunTest(window.arguments)"
+>
+ <script type="application/javascript">
+ <![CDATA[
+ function RunTest(aArgs)
+ {
+ // run test
+ aArgs[0](this);
+ // close dialog
+ document.documentElement[aArgs[1] ? "acceptDialog" : "cancelDialog"]();
+ }
+ ]]>
+ </script>
+
+ <prefpane id="sample_pane" label="Sample Prefpane">
+ <preferences id="sample_preferences">
+ <!-- one of each type known to <preferences>.valueFromPreferences -->
+ <preference id ="tests.static_preference_int"
+ name="tests.static_preference_int"
+ type="int"/>
+ <preference id ="tests.static_preference_bool"
+ name="tests.static_preference_bool"
+ type="bool"/>
+ <preference id ="tests.static_preference_string"
+ name="tests.static_preference_string"
+ type="string"/>
+ <preference id ="tests.static_preference_wstring"
+ name="tests.static_preference_wstring"
+ type="wstring"/>
+ <preference id ="tests.static_preference_unichar"
+ name="tests.static_preference_unichar"
+ type="unichar"/>
+ <preference id ="tests.static_preference_file"
+ name="tests.static_preference_file"
+ type="file"/>
+ </preferences>
+
+ <!-- one element for each preference type above -->
+ <hbox>
+ <label flex="1" value="int"/>
+ <textbox id="static_element_int" preference="tests.static_preference_int"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="bool"/>
+ <checkbox id="static_element_bool" preference="tests.static_preference_bool"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="string"/>
+ <textbox id="static_element_string" preference="tests.static_preference_string"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="wstring"/>
+ <textbox id="static_element_wstring" preference="tests.static_preference_wstring"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="unichar"/>
+ <textbox id="static_element_unichar" preference="tests.static_preference_unichar"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="file"/>
+ <textbox id="static_element_file" preference="tests.static_preference_file"/>
+ </hbox>
+ </prefpane>
+</prefwindow>
diff --git a/toolkit/content/tests/chrome/window_preferences2.xul b/toolkit/content/tests/chrome/window_preferences2.xul
new file mode 100644
index 000000000..87158c9c7
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_preferences2.xul
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<!--
+ XUL Widget Test for preferences window
+-->
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="preferences window"
+ windowtype="test:preferences2"
+ buttons="accept,cancel"
+ onload="RunTest(window.arguments)"
+>
+ <script type="application/javascript">
+ <![CDATA[
+ function RunTest(aArgs)
+ {
+ // open child
+ document.documentElement.openSubDialog("window_preferences3.xul", "", {test: aArgs[0], accept: aArgs[1]});
+ // close dialog
+ document.documentElement[aArgs[1] ? "acceptDialog" : "cancelDialog"]();
+ }
+ ]]>
+ </script>
+
+ <prefpane id="sample_pane" label="Sample Prefpane"/>
+</prefwindow>
diff --git a/toolkit/content/tests/chrome/window_preferences3.xul b/toolkit/content/tests/chrome/window_preferences3.xul
new file mode 100644
index 000000000..c37893a67
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_preferences3.xul
@@ -0,0 +1,74 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<!--
+ XUL Widget Test for preferences window
+-->
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="preferences window"
+ windowtype="test:preferences3"
+ buttons="accept,cancel"
+ onload="RunTest(window.arguments)"
+ type="child"
+>
+ <script type="application/javascript">
+ <![CDATA[
+ function RunTest(aArgs)
+ {
+ // run test
+ aArgs[0].test(this);
+ // close dialog
+ document.documentElement[aArgs[0].accept ? "acceptDialog" : "cancelDialog"]();
+ }
+ ]]>
+ </script>
+
+ <prefpane id="sample_pane" label="Sample Prefpane">
+ <preferences id="sample_preferences">
+ <!-- one of each type known to <preferences>.valueFromPreferences -->
+ <preference id ="tests.static_preference_int"
+ name="tests.static_preference_int"
+ type="int"/>
+ <preference id ="tests.static_preference_bool"
+ name="tests.static_preference_bool"
+ type="bool"/>
+ <preference id ="tests.static_preference_string"
+ name="tests.static_preference_string"
+ type="string"/>
+ <preference id ="tests.static_preference_wstring"
+ name="tests.static_preference_wstring"
+ type="wstring"/>
+ <preference id ="tests.static_preference_unichar"
+ name="tests.static_preference_unichar"
+ type="unichar"/>
+ <preference id ="tests.static_preference_file"
+ name="tests.static_preference_file"
+ type="file"/>
+ </preferences>
+
+ <!-- one element for each preference type above -->
+ <hbox>
+ <label flex="1" value="int"/>
+ <textbox id="static_element_int" preference="tests.static_preference_int"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="bool"/>
+ <checkbox id="static_element_bool" preference="tests.static_preference_bool"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="string"/>
+ <textbox id="static_element_string" preference="tests.static_preference_string"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="wstring"/>
+ <textbox id="static_element_wstring" preference="tests.static_preference_wstring"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="unichar"/>
+ <textbox id="static_element_unichar" preference="tests.static_preference_unichar"/>
+ </hbox>
+ <hbox>
+ <label flex="1" value="file"/>
+ <textbox id="static_element_file" preference="tests.static_preference_file"/>
+ </hbox>
+ </prefpane>
+</prefwindow>
diff --git a/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul b/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul
new file mode 100644
index 000000000..ba200b614
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<!--
+ XUL Widget Test for preferences window with beforeaccept
+-->
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="preferences window"
+ width="300" height="300"
+ windowtype="test:preferences"
+ buttons="accept,cancel"
+ onbeforeaccept="return beforeAccept();"
+ onload="onDialogLoad();"
+>
+ <script type="application/javascript">
+ <![CDATA[
+ function onDialogLoad() {
+ var pref = document.getElementById("tests.beforeaccept.dialogShown");
+ pref.value = true;
+
+ // call the onload handler we were passed
+ window.arguments[0]();
+ }
+
+ function beforeAccept() {
+ var beforeAcceptPref = document.getElementById("tests.beforeaccept.called");
+ var oldValue = beforeAcceptPref.value;
+ beforeAcceptPref.value = true;
+
+ return !!oldValue;
+ }
+ ]]>
+ </script>
+
+ <prefpane id="sample_pane" label="Sample Prefpane">
+ <preferences id="sample_preferences">
+ <preference id="tests.beforeaccept.called"
+ name="tests.beforeaccept.called"
+ type="bool"/>
+ <preference id="tests.beforeaccept.dialogShown"
+ name="tests.beforeaccept.dialogShown"
+ type="bool"/>
+ </preferences>
+ </prefpane>
+ <label>Test Prefpane</label>
+</prefwindow>
diff --git a/toolkit/content/tests/chrome/window_preferences_commandretarget.xul b/toolkit/content/tests/chrome/window_preferences_commandretarget.xul
new file mode 100644
index 000000000..77c6fd18c
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_preferences_commandretarget.xul
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<!--
+ XUL Widget Test for preferences window. This particular test ensures that
+ a checkbox with a command attribute properly updates even though the command
+ event gets retargeted.
+-->
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="preferences window"
+ windowtype="test:preferences"
+ buttons="accept,cancel"
+ onload="RunTest(window.arguments)">
+ <script type="application/javascript">
+ <![CDATA[
+ function RunTest(aArgs)
+ {
+ aArgs[0](this);
+ document.documentElement.cancelDialog();
+ }
+ ]]>
+ </script>
+
+ <prefpane id="sample_pane" label="Sample Prefpane">
+ <preferences id="sample_preferences">
+ <preference id="tests.static_preference_bool"
+ name="tests.static_preference_bool"
+ type="bool"/>
+ </preferences>
+
+ <commandset>
+ <command id="cmd_test" preference="tests.static_preference_bool"/>
+ </commandset>
+
+ <checkbox id="checkbox" label="Enable Option" preference="tests.static_preference_bool" command="cmd_test"/>
+ </prefpane>
+</prefwindow>
diff --git a/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul b/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul
new file mode 100644
index 000000000..e0366f989
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ - You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!--
+ XUL Widget Test for preferences window with onsyncfrompreference
+ This test ensures that onsyncfrompreference handlers are called after all the
+ values of the corresponding preference element have been set correctly
+-->
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="preferences window"
+ width="300" height="300"
+ windowtype="test:preferences">
+
+ <prefpane id="sample_pane" label="Sample Prefpane">
+ <preferences id="sample_preferences">
+ <preference id="tests.onsyncfrompreference.pref1"
+ name="tests.onsyncfrompreference.pref1"
+ type="int"/>
+ <preference id="tests.onsyncfrompreference.pref2"
+ name="tests.onsyncfrompreference.pref2"
+ type="int"/>
+ <preference id="tests.onsyncfrompreference.pref3"
+ name="tests.onsyncfrompreference.pref3"
+ type="int"/>
+ </preferences>
+ </prefpane>
+ <label>Test Prefpane</label>
+ <checkbox id="check1" label="Label1"
+ preference="tests.onsyncfrompreference.pref1"
+ onsyncfrompreference="return window.arguments[0]();"
+ onsynctopreference="return 1;"/>
+ <checkbox id="check2" label="Label2"
+ preference="tests.onsyncfrompreference.pref2"
+ onsyncfrompreference="return window.arguments[0]();"
+ onsynctopreference="return 1;"/>
+ <checkbox id="check3" label="Label3"
+ preference="tests.onsyncfrompreference.pref3"
+ onsyncfrompreference="return window.arguments[0]();"
+ onsynctopreference="return 1;"/>
+</prefwindow>
diff --git a/toolkit/content/tests/chrome/window_screenPosSize.xul b/toolkit/content/tests/chrome/window_screenPosSize.xul
new file mode 100644
index 000000000..accc10d8f
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_screenPosSize.xul
@@ -0,0 +1,17 @@
+<?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="Window Open Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ screenX="80"
+ screenY="80"
+ height="300"
+ width="300"
+ persist="screenX screenY height width">
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_showcaret.xul b/toolkit/content/tests/chrome/window_showcaret.xul
new file mode 100644
index 000000000..cb26658a1
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_showcaret.xul
@@ -0,0 +1,10 @@
+<?xml version='1.0'?>
+
+<?xml-stylesheet href='chrome://global/skin' type='text/css'?>
+
+<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'>
+
+<hbox style='-moz-user-focus: normal;' width='20' height='20'/>
+<textbox/>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_subframe_origin.xul b/toolkit/content/tests/chrome/window_subframe_origin.xul
new file mode 100644
index 000000000..a060929a6
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_subframe_origin.xul
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window id="window" title="Subframe Origin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<iframe
+ style="margin-left:20px; margin-top:20px; min-height:300px; max-width:300px; max-height:300px; border:solid 1px black;"
+ src="frame_subframe_origin_subframe1.xul"></iframe>
+<caption id="parentcap" label=""/>
+
+<script>
+
+// Fire a mouse move event aimed at this window, and check to be
+// sure the client coords translate from widget to the dom correctly.
+
+function runTests()
+{
+ synthesizeMouse(document.getElementById("window"), 1, 2, { type: "mousemove" });
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window);
+
+function mouseMove(e) {
+ var element = e.target;
+ var el = document.getElementById("parentcap");
+ el.label = "client: (" + e.clientX + "," + e.clientY + ")";
+ window.opener.wrappedJSObject.SimpleTest.is(e.clientX, 1, "mouse event clientX");
+ window.opener.wrappedJSObject.SimpleTest.is(e.clientY, 2, "mouse event clientY");
+ // fire the next test on the sub frame
+ frames[0].runTests();
+}
+
+window.addEventListener("mousemove",mouseMove, false);
+
+</script>
+</window>
diff --git a/toolkit/content/tests/chrome/window_titlebar.xul b/toolkit/content/tests/chrome/window_titlebar.xul
new file mode 100644
index 000000000..e27782153
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_titlebar.xul
@@ -0,0 +1,223 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<!--
+ XUL Widget Test for the titlebar element and window dragging
+ -->
+<window title="Titlebar" width="200" height="200"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <titlebar id="titlebar">
+ <label id="label" value="Titlebar"/>
+ </titlebar>
+
+ <!-- a non-noautohide panel is treated as anchored -->
+ <panel id="panel" onpopupshown="popupshown(this, false)" onpopuphidden="popuphidden('panelnoautohide')">
+ <titlebar>
+ <label id="panellabel" value="Titlebar"/>
+ </titlebar>
+ </panel>
+
+ <panel id="panelnoautohide" noautohide="true"
+ onpopupshown="popupshown(this, false)" onpopuphidden="popuphidden('panelanchored')">
+ <titlebar>
+ <label id="panellabelnoautohide" value="Titlebar"/>
+ </titlebar>
+ </panel>
+
+ <panel id="panelanchored" noautohide="true"
+ onpopupshown="popupshown(this, true)" onpopuphidden="popuphidden('paneltop')">
+ <titlebar>
+ <label id="panellabelanchored" value="Titlebar"/>
+ </titlebar>
+ </panel>
+
+ <panel id="paneltop" noautohide="true" level="top"
+ onpopupshown="popupshown(this, false)" onpopuphidden="popuphidden('panelfloating')">
+ <titlebar>
+ <label id="panellabeltop" value="Titlebar"/>
+ </titlebar>
+ </panel>
+
+ <panel id="panelfloating" noautohide="true" level="floating"
+ onpopupshown="popupshown(this, false)" onpopuphidden="popuphidden('')">
+ <titlebar>
+ <label id="panellabelfloating" value="Titlebar"/>
+ </titlebar>
+ </panel>
+
+ <button id="button" label="OK"/>
+
+<script>
+<![CDATA[
+
+var SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+
+SimpleTest.waitForFocus(test_titlebar, window);
+
+var mouseDownTarget;
+var origoldx, origoldy, oldx, oldy, waitSteps = 0;
+function waitForWindowMove(element, x, y, callback, arg, panel, anchored)
+{
+ var isPanelMove = (element.id != "label");
+
+ if (!waitSteps) {
+ oldx = isPanelMove ? panel.getBoundingClientRect().left : window.screenX;
+ oldy = isPanelMove ? panel.getBoundingClientRect().top : window.screenY;
+ synthesizeMouse(element, x, y, { type: "mousemove" });
+ }
+
+ var newx = isPanelMove ? panel.getBoundingClientRect().left : window.screenX;
+ var newy = isPanelMove ? panel.getBoundingClientRect().top : window.screenY;
+ if (newx == oldx && newy == oldy) {
+ if (waitSteps++ > 10) {
+ SimpleTest.is(window.screenX + "," + window.screenY, oldx + "," + oldy + " ",
+ "Window never moved properly to " + x + "," + y + (panel ? " " + panel.id : ""));
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ window.close();
+ return;
+ }
+
+ setTimeout(waitForWindowMove, 100, element, x, y, callback, arg, panel, anchored);
+ }
+ else {
+ waitSteps = 0;
+
+ // on Linux, we need to wait a bit for the popup to be moved as well
+ if (navigator.platform.indexOf("Linux") >= 0) {
+ setTimeout(callback, 0, arg, panel, anchored);
+ }
+ else {
+ callback(arg, panel, anchored);
+ }
+ }
+}
+
+function test_titlebar()
+{
+ var titlebar = document.getElementById("titlebar");
+ var label = document.getElementById("label");
+
+ origoldx = window.screenX;
+ origoldy = window.screenY;
+
+ var mousedownListener = event => mouseDownTarget = event.originalTarget;
+ window.addEventListener("mousedown", mousedownListener, false);
+ synthesizeMouse(label, 2, 2, { type: "mousedown" });
+ SimpleTest.is(mouseDownTarget, titlebar, "movedown on titlebar");
+ waitForWindowMove(label, 22, 22, test_titlebar_step2, mousedownListener);
+}
+
+function test_titlebar_step2(mousedownListener)
+{
+ var titlebar = document.getElementById("titlebar");
+ var label = document.getElementById("label");
+
+ SimpleTest.is(window.screenX, origoldx + 20, "move window horizontal");
+ SimpleTest.is(window.screenY, origoldy + 20, "move window vertical");
+ synthesizeMouse(label, 22, 22, { type: "mouseup" });
+
+ // with allowEvents set to true, the mouse should target the label instead
+ // and not move the window
+ titlebar.allowEvents = true;
+
+ synthesizeMouse(label, 2, 2, { type: "mousedown" });
+ SimpleTest.is(mouseDownTarget, label, "movedown on titlebar with allowevents");
+ synthesizeMouse(label, 22, 22, { type: "mousemove" });
+ SimpleTest.is(window.screenX, origoldx + 20, "mouse on label move window horizontal");
+ SimpleTest.is(window.screenY, origoldy + 20, "mouse on label move window vertical");
+ synthesizeMouse(label, 22, 22, { type: "mouseup" });
+
+ window.removeEventListener("mousedown", mousedownListener, false);
+
+ document.getElementById("panel").openPopupAtScreen(window.screenX + 50, window.screenY + 60, false);
+}
+
+function popupshown(panel, anchored)
+{
+ var rect = panel.getBoundingClientRect();
+
+ // skip this check for non-noautohide panels
+ if (panel.id == "panel") {
+ var panellabel = panel.firstChild.firstChild;
+ synthesizeMouse(panellabel, 2, 2, { type: "mousedown" });
+ waitForWindowMove(panellabel, 22, 22, popupshown_step3, rect, panel, anchored);
+ return;
+ }
+
+ // now, try moving the window. If anchored, the popup should move with the
+ // window. If not anchored, the popup should remain at its current screen location.
+ window.moveBy(10, 10);
+ waitSteps = 1;
+ waitForWindowMove(document.getElementById("label"), 1, 1, popupshown_step2, rect, panel, anchored);
+}
+
+function popupshown_step2(oldrect, panel, anchored)
+{
+ var newrect = panel.getBoundingClientRect();
+
+ // The window movement that occured long ago at the beginning of the test
+ // on Linux is delayed and there isn't any way to tell when the move
+ // actually happened. This causes the checks here to fail. Instead, just
+ // wait a bit for the test to be ready.
+ if (navigator.platform.indexOf("Linux") >= 0 &&
+ newrect.left != oldrect.left - (anchored ? 0 : 10)) {
+ setTimeout(popupshown_step2, 10, oldrect, panel, anchored);
+ return;
+ }
+
+ // anchored popups should still be at the same offset. Non-anchored popups will
+ // now be offset by 10 pixels less.
+ SimpleTest.is(newrect.left, oldrect.left - (anchored ? 0 : 10),
+ panel.id + " horizontal after window move");
+ SimpleTest.is(newrect.top, oldrect.top - (anchored ? 0 : 10),
+ panel.id + " vertical after window move");
+
+ var panellabel = panel.firstChild.firstChild;
+ synthesizeMouse(panellabel, 2, 2, { type: "mousedown" });
+ waitForWindowMove(panellabel, 22, 22, popupshown_step3, newrect, panel, anchored);
+}
+
+function popupshown_step3(oldrect, panel, anchored)
+{
+ // skip this check on Linux for the same window positioning reasons as above
+ if (navigator.platform.indexOf("Linux") == -1 || (panel.id != "panelanchored" && panel.id != "paneltop")) {
+ // next, drag the titlebar in the panel
+ var newrect = panel.getBoundingClientRect();
+ SimpleTest.is(newrect.left, oldrect.left + 20, panel.id + " move popup horizontal");
+ SimpleTest.is(newrect.top, oldrect.top + 20, panel.id + " move popup vertical");
+ synthesizeMouse(document.getElementById("panellabel"), 22, 22, { type: "mouseup" });
+
+ synthesizeMouse(document.getElementById("button"), 5, 5, { type: "mousemove" });
+ newrect = panel.getBoundingClientRect();
+ SimpleTest.is(newrect.left, oldrect.left + 20, panel.id + " horizontal after mouse on button");
+ SimpleTest.is(newrect.top, oldrect.top + 20, panel.id + " vertical after mouse on button");
+ }
+ else {
+ synthesizeMouse(document.getElementById("panellabel"), 22, 22, { type: "mouseup" });
+ }
+
+ panel.hidePopup();
+}
+
+function popuphidden(nextPopup)
+{
+ if (nextPopup) {
+ var panel = document.getElementById(nextPopup);
+ if (panel.id == "panelnoautohide") {
+ panel.openPopupAtScreen(window.screenX + 50, window.screenY + 60, false);
+ }
+ else {
+ panel.openPopup(document.getElementById("button"), "after_start");
+ }
+ }
+ else
+ window.opener.wrappedJSObject.done(window);
+}
+
+]]>
+</script>
+
+</window>
diff --git a/toolkit/content/tests/chrome/window_tooltip.xul b/toolkit/content/tests/chrome/window_tooltip.xul
new file mode 100644
index 000000000..087c91c3e
--- /dev/null
+++ b/toolkit/content/tests/chrome/window_tooltip.xul
@@ -0,0 +1,311 @@
+<?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="Tooltip Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <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>
+ <script type="application/javascript" src="popup_shared.js"></script>
+
+<tooltip id="thetooltip">
+ <label id="label" value="This is a tooltip"/>
+</tooltip>
+
+<box id="parent" tooltiptext="Box Tooltip" style="margin: 10px">
+ <button id="withtext" label="Tooltip Text" tooltiptext="Button Tooltip"
+ style="-moz-appearance: none; padding: 0;"/>
+ <button id="without" label="No Tooltip" style="-moz-appearance: none; padding: 0;"/>
+ <!-- remove the native theme and borders to avoid some platform
+ specific sizing differences -->
+ <button id="withtooltip" label="Tooltip Element" tooltip="thetooltip"
+ class="plain" style="-moz-appearance: none; padding: 0;"/>
+ <iframe id="childframe" type="content" width="10" height="10"
+ src="http://sectest2.example.org:80/chrome/toolkit/content/tests/chrome/popup_childframe_node.xul"/>
+</box>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+var gOriginalWidth = -1;
+var gOriginalHeight = -1;
+var gButton = null;
+
+function runTest()
+{
+ startPopupTests(popupTests);
+}
+
+function checkCoords(event)
+{
+ // all but one test open the tooltip at the button location offset by 6
+ // in each direction. Test 5 opens it at 4 in each direction.
+ var mod = (gTestIndex == 5) ? 4 : 6;
+
+ var rect = gButton.getBoundingClientRect();
+ var popupstyle = window.getComputedStyle(gButton, "");
+ is(event.clientX, Math.round(rect.left + mod),
+ "step " + (gTestIndex + 1) + " clientX");
+ is(event.clientY, Math.round(rect.top + mod),
+ "step " + (gTestIndex + 1) + " clientY");
+ ok(event.screenX > 0, "step " + (gTestIndex + 1) + " screenX");
+ ok(event.screenY > 0, "step " + (gTestIndex + 1) + " screenY");
+}
+
+var popupTests = [
+{
+ testname: "hover tooltiptext attribute",
+ events: [ "popupshowing #tooltip", "popupshown #tooltip" ],
+ test: function() {
+ gButton = document.getElementById("withtext");
+ disableNonTestMouse(true);
+ synthesizeMouse(gButton, 2, 2, { type: "mouseover" });
+ synthesizeMouse(gButton, 4, 4, { type: "mousemove" });
+ synthesizeMouse(gButton, 6, 6, { type: "mousemove" });
+ disableNonTestMouse(false);
+ }
+},
+{
+ testname: "close tooltip",
+ events: [ "popuphiding #tooltip", "popuphidden #tooltip",
+ "DOMMenuInactive #tooltip" ],
+ test: function() {
+ disableNonTestMouse(true);
+ synthesizeMouse(document.documentElement, 2, 2, { type: "mousemove" });
+ disableNonTestMouse(false);
+ }
+},
+{
+ testname: "hover inherited tooltip",
+ events: [ "popupshowing #tooltip", "popupshown #tooltip" ],
+ test: function() {
+ gButton = document.getElementById("without");
+ disableNonTestMouse(true);
+ synthesizeMouse(gButton, 2, 2, { type: "mouseover" });
+ synthesizeMouse(gButton, 4, 4, { type: "mousemove" });
+ synthesizeMouse(gButton, 6, 6, { type: "mousemove" });
+ disableNonTestMouse(false);
+ }
+},
+{
+ testname: "hover tooltip attribute",
+ events: [ "popuphiding #tooltip", "popuphidden #tooltip",
+ "DOMMenuInactive #tooltip",
+ "popupshowing thetooltip", "popupshown thetooltip" ],
+ test: function() {
+ gButton = document.getElementById("withtooltip");
+ gExpectedTriggerNode = gButton;
+ disableNonTestMouse(true);
+ synthesizeMouse(gButton, 2, 2, { type: "mouseover" });
+ synthesizeMouse(gButton, 4, 4, { type: "mousemove" });
+ synthesizeMouse(gButton, 6, 6, { type: "mousemove" });
+ disableNonTestMouse(false);
+ },
+ result: function(testname) {
+ var tooltip = document.getElementById("thetooltip");
+ gExpectedTriggerNode = null;
+ is(tooltip.triggerNode, gButton, testname + " triggerNode");
+ is(document.popupNode, null, testname + " document.popupNode");
+ is(document.tooltipNode, gButton, testname + " document.tooltipNode");
+
+ var child = $("childframe").contentDocument;
+ var evt = child.createEvent("Event");
+ evt.initEvent("click", true, true);
+ child.documentElement.dispatchEvent(evt);
+ is(child.documentElement.getAttribute("data"), "xnull",
+ "cannot get tooltipNode from other document");
+
+ var buttonrect = document.getElementById("withtooltip").getBoundingClientRect();
+ var rect = tooltip.getBoundingClientRect();
+ var popupstyle = window.getComputedStyle(document.getElementById("thetooltip"), "");
+
+ is(Math.round(rect.left),
+ Math.round(buttonrect.left + parseFloat(popupstyle.marginLeft) + 6),
+ testname + " left position of tooltip");
+ is(Math.round(rect.top),
+ Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 6),
+ testname + " top position of tooltip");
+
+ var labelrect = document.getElementById("label").getBoundingClientRect();
+ ok(labelrect.right < rect.right, testname + " tooltip width");
+ ok(labelrect.bottom < rect.bottom, testname + " tooltip height");
+
+ gOriginalWidth = rect.right - rect.left;
+ gOriginalHeight = rect.bottom - rect.top;
+ }
+},
+{
+ testname: "click to close tooltip",
+ events: [ "popuphiding thetooltip", "popuphidden thetooltip",
+ "command withtooltip", "DOMMenuInactive thetooltip" ],
+ test: function() {
+ gButton = document.getElementById("withtooltip");
+ synthesizeMouse(gButton, 2, 2, { });
+ },
+ result: function(testname) {
+ var tooltip = document.getElementById("thetooltip");
+ is(tooltip.triggerNode, null, testname + " triggerNode");
+ is(document.popupNode, null, testname + " document.popupNode");
+ is(document.tooltipNode, null, testname + " document.tooltipNode");
+ }
+},
+{
+ testname: "hover tooltip after size increased",
+ events: [ "popupshowing thetooltip", "popupshown thetooltip" ],
+ test: function() {
+ var label = document.getElementById("label");
+ label.removeAttribute("value");
+ label.textContent = "This is a longer tooltip than before\nIt has multiple lines\nIt is testing tooltip sizing\n";
+ gButton = document.getElementById("withtooltip");
+ disableNonTestMouse(true);
+ synthesizeMouse(gButton, 2, 2, { type: "mouseover" });
+ synthesizeMouse(gButton, 6, 6, { type: "mousemove" });
+ synthesizeMouse(gButton, 4, 4, { type: "mousemove" });
+ disableNonTestMouse(false);
+ },
+ result: function(testname) {
+ var buttonrect = document.getElementById("withtooltip").getBoundingClientRect();
+ var rect = document.getElementById("thetooltip").getBoundingClientRect();
+ var popupstyle = window.getComputedStyle(document.getElementById("thetooltip"), "");
+ var buttonstyle = window.getComputedStyle(document.getElementById("withtooltip"), "");
+
+ is(Math.round(rect.left),
+ Math.round(buttonrect.left + parseFloat(popupstyle.marginLeft) + 4),
+ testname + " left position of tooltip");
+ is(Math.round(rect.top),
+ Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 4),
+ testname + " top position of tooltip");
+
+ var labelrect = document.getElementById("label").getBoundingClientRect();
+ ok(labelrect.right < rect.right, testname + " tooltip width");
+ ok(labelrect.bottom < rect.bottom, testname + " tooltip height");
+
+ // make sure that the tooltip is larger than it was before by just
+ // checking against the original height plus an arbitrary 15 pixels
+ ok(gOriginalWidth + 15 < rect.right - rect.left, testname + " tooltip is wider");
+ ok(gOriginalHeight + 15 < rect.bottom - rect.top, testname + " tooltip is taller");
+ }
+},
+{
+ testname: "close tooltip with hidePopup",
+ events: [ "popuphiding thetooltip", "popuphidden thetooltip",
+ "DOMMenuInactive thetooltip" ],
+ test: function() {
+ document.getElementById("thetooltip").hidePopup();
+ },
+},
+{
+ testname: "hover tooltip after size decreased",
+ events: [ "popupshowing thetooltip", "popupshown thetooltip" ],
+ autohide: "thetooltip",
+ test: function() {
+ var label = document.getElementById("label");
+ label.value = "This is a tooltip";
+ gButton = document.getElementById("withtooltip");
+ disableNonTestMouse(true);
+ synthesizeMouse(gButton, 2, 2, { type: "mouseover" });
+ synthesizeMouse(gButton, 4, 4, { type: "mousemove" });
+ synthesizeMouse(gButton, 6, 6, { type: "mousemove" });
+ disableNonTestMouse(false);
+ },
+ result: function(testname) {
+ var buttonrect = document.getElementById("withtooltip").getBoundingClientRect();
+ var rect = document.getElementById("thetooltip").getBoundingClientRect();
+ var popupstyle = window.getComputedStyle(document.getElementById("thetooltip"), "");
+ var buttonstyle = window.getComputedStyle(document.getElementById("withtooltip"), "");
+
+ is(Math.round(rect.left),
+ Math.round(buttonrect.left + parseFloat(popupstyle.marginLeft) + 6),
+ testname + " left position of tooltip");
+ is(Math.round(rect.top),
+ Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 6),
+ testname + " top position of tooltip");
+
+ var labelrect = document.getElementById("label").getBoundingClientRect();
+ ok(labelrect.right < rect.right, testname + " tooltip width");
+ ok(labelrect.bottom < rect.bottom, testname + " tooltip height");
+
+ is(gOriginalWidth, rect.right - rect.left, testname + " tooltip is original width");
+ is(gOriginalHeight, rect.bottom - rect.top, testname + " tooltip is original height");
+ }
+},
+{
+ testname: "hover tooltip at bottom edge of screen",
+ events: [ "popupshowing thetooltip", "popupshown thetooltip" ],
+ autohide: "thetooltip",
+ condition: function() {
+ // Only checking OSX here because on other platforms popups and tooltips behave the same way
+ // when there's not enough space to show them below (by flipping vertically)
+ // However, on OSX most popups are not flipped but tooltips are.
+ return navigator.platform.indexOf("Mac") > -1;
+ },
+ test: function() {
+ var buttonRect = document.getElementById("withtext").getBoundingClientRect();
+ var windowY = screen.height -
+ (window.mozInnerScreenY - window.screenY ) - buttonRect.bottom;
+
+ moveWindowTo(window.screenX, windowY, function() {
+ gButton = document.getElementById("withtooltip");
+ disableNonTestMouse(true);
+ synthesizeMouse(gButton, 2, 2, { type: "mouseover" });
+ synthesizeMouse(gButton, 6, 6, { type: "mousemove" });
+ synthesizeMouse(gButton, 4, 4, { type: "mousemove" });
+ disableNonTestMouse(false);
+ });
+ },
+ result: function(testname) {
+ var buttonrect = document.getElementById("withtooltip").getBoundingClientRect();
+ var rect = document.getElementById("thetooltip").getBoundingClientRect();
+ var popupstyle = window.getComputedStyle(document.getElementById("thetooltip"), "");
+
+ is(Math.round(rect.y + rect.height),
+ Math.round(buttonrect.top + 4 - parseFloat(popupstyle.marginTop)),
+ testname + " position of tooltip above button");
+ }
+}
+
+];
+
+var waitSteps = 0;
+function moveWindowTo(x, y, callback, arg)
+{
+ if (!waitSteps) {
+ oldx = window.screenX;
+ oldy = window.screenY;
+ window.moveTo(x, y);
+
+ waitSteps++;
+ setTimeout(moveWindowTo, 100, x, y, callback, arg);
+ return;
+ }
+
+ if (window.screenX == oldx && window.screenY == oldy) {
+ if (waitSteps++ > 10) {
+ ok(false, "Window never moved properly to " + x + "," + y);
+ window.opener.wrappedJSObject.SimpleTest.finish();
+ window.close();
+ }
+
+ setTimeout(moveWindowTo, 100, x, y, callback, arg);
+ }
+ else {
+ waitSteps = 0;
+ callback(arg);
+ }
+}
+
+window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTest, window);
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>
diff --git a/toolkit/content/tests/chrome/xul_selectcontrol.js b/toolkit/content/tests/chrome/xul_selectcontrol.js
new file mode 100644
index 000000000..d6518c150
--- /dev/null
+++ b/toolkit/content/tests/chrome/xul_selectcontrol.js
@@ -0,0 +1,390 @@
+// This script is used to test elements that implement
+// nsIDOMXULSelectControlElement. This currently is the following elements:
+// listbox, menulist, radiogroup, richlistbox, tabs
+//
+// flag behaviours that differ for certain elements
+// allow-other-value - alternate values for the value property may be used
+// besides those in the list
+// other-value-clears-selection - alternative values for the value property
+// clears the selected item
+// selection-required - an item must be selected in the list, unless there
+// aren't any to select
+// activate-disabled-menuitem - disabled menuitems can be highlighted
+// select-keynav-wraps - key navigation over a selectable list wraps
+// select-extended-keynav - home, end, page up and page down keys work to
+// navigate over a selectable list
+// keynav-leftright - key navigation is left/right rather than up/down
+// The win:, mac: and gtk: or other prefixes may be used for platform specific behaviour
+var behaviours = {
+ menu: "win:activate-disabled-menuitem activate-disabled-menuitem-mousemove select-keynav-wraps select-extended-keynav",
+ menulist: "allow-other-value other-value-clears-selection",
+ listbox: "select-extended-keynav",
+ richlistbox: "select-extended-keynav",
+ radiogroup: "select-keynav-wraps dont-select-disabled allow-other-value",
+ tabs: "select-extended-keynav mac:select-keynav-wraps allow-other-value selection-required keynav-leftright"
+};
+
+function behaviourContains(tag, behaviour)
+{
+ var platform = "none:";
+ if (navigator.platform.indexOf("Mac") >= 0)
+ platform = "mac:";
+ else if (navigator.platform.indexOf("Win") >= 0)
+ platform = "win:";
+ else if (navigator.platform.indexOf("X") >= 0)
+ platform = "gtk:";
+
+ var re = new RegExp("\\s" + platform + behaviour + "\\s|\\s" + behaviour + "\\s");
+ return re.test(" " + behaviours[tag] + " ");
+}
+
+function test_nsIDOMXULSelectControlElement(element, childtag, testprefix)
+{
+ var testid = (testprefix) ? testprefix + " " : "";
+ testid += element.localName + " nsIDOMXULSelectControlElement ";
+
+ // editable menulists use the label as the value instead
+ var firstvalue = "first", secondvalue = "second", fourthvalue = "fourth";
+ if (element.localName == "menulist" && element.editable) {
+ firstvalue = "First Item";
+ secondvalue = "Second Item"
+ fourthvalue = "Fourth Item";
+ }
+
+ // 'initial' - check if the initial state of the element is correct
+ test_nsIDOMXULSelectControlElement_States(element, testid + "initial", 0, null, -1, "");
+
+ test_nsIDOMXULSelectControlElement_init(element, testid);
+
+ // 'appendItem' - check if appendItem works to add a new item
+ var firstitem = element.appendItem("First Item", "first");
+ is(firstitem.localName, childtag,
+ testid + "appendItem - first item is " + childtag);
+ test_nsIDOMXULSelectControlElement_States(element, testid + "appendItem", 1, null, -1, "");
+
+ is(firstitem.control, element, testid + "control");
+
+ // 'selectedIndex' - check if an item may be selected
+ element.selectedIndex = 0;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "selectedIndex", 1, firstitem, 0, firstvalue);
+
+ // 'appendItem 2' - check if a second item may be added
+ var seconditem = element.appendItem("Second Item", "second");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "appendItem 2", 2, firstitem, 0, firstvalue);
+
+ // 'selectedItem' - check if the second item may be selected
+ element.selectedItem = seconditem;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "selectedItem", 2, seconditem, 1, secondvalue);
+
+ // 'selectedIndex 2' - check if selectedIndex may be set to -1 to deselect items
+ var selectionRequired = behaviourContains(element.localName, "selection-required");
+ element.selectedIndex = -1;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "selectedIndex 2", 2,
+ selectionRequired ? seconditem : null, selectionRequired ? 1 : -1,
+ selectionRequired ? secondvalue : "");
+
+ // 'selectedItem 2' - check if the selectedItem property may be set to null
+ element.selectedIndex = 1;
+ element.selectedItem = null;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "selectedItem 2", 2,
+ selectionRequired ? seconditem : null, selectionRequired ? 1 : -1,
+ selectionRequired ? secondvalue : "");
+
+ // 'getIndexOfItem' - check if getIndexOfItem returns the right index
+ is(element.getIndexOfItem(firstitem), 0, testid + "getIndexOfItem - first item at index 0");
+ is(element.getIndexOfItem(seconditem), 1, testid + "getIndexOfItem - second item at index 1");
+
+ var otheritem = element.ownerDocument.createElement(childtag);
+ is(element.getIndexOfItem(otheritem), -1, testid + "getIndexOfItem - other item not found");
+
+ // 'getItemAtIndex' - check if getItemAtIndex returns the right item
+ is(element.getItemAtIndex(0), firstitem, testid + "getItemAtIndex - index 0 is first item");
+ is(element.getItemAtIndex(1), seconditem, testid + "getItemAtIndex - index 0 is second item");
+ is(element.getItemAtIndex(-1), null, testid + "getItemAtIndex - index -1 is null");
+ is(element.getItemAtIndex(2), null, testid + "getItemAtIndex - index 2 is null");
+
+ // check if setting the value changes the selection
+ element.value = firstvalue;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "set value 1", 2, firstitem, 0, firstvalue);
+ element.value = secondvalue;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "set value 2", 2, seconditem, 1, secondvalue);
+ // setting the value attribute to one not in the list doesn't change the selection.
+ // The value is only changed for elements which support having a value other than the
+ // selection.
+ element.value = "other";
+ var allowOtherValue = behaviourContains(element.localName, "allow-other-value");
+ var otherValueClearsSelection = behaviourContains(element.localName, "other-value-clears-selection");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "set value other", 2,
+ otherValueClearsSelection ? null : seconditem,
+ otherValueClearsSelection ? -1 : 1,
+ allowOtherValue ? "other" : secondvalue);
+ if (allowOtherValue)
+ element.value = "";
+
+ // 'removeItemAt' - check if removeItemAt removes the right item
+ if (selectionRequired)
+ element.value = secondvalue;
+ else
+ element.selectedIndex = -1;
+
+ var removeditem = element.removeItemAt(0);
+ is(removeditem, firstitem, testid + "removeItemAt return value");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "removeItemAt", 1,
+ selectionRequired ? seconditem : null, selectionRequired ? 0 : -1,
+ selectionRequired ? secondvalue : "");
+
+ is(removeditem.control, undefined, testid + "control not set");
+
+ var thirditem = element.appendItem("Third Item", "third");
+ var fourthitem = element.appendItem("Fourth Item", fourthvalue);
+ var fifthitem = element.appendItem("Fifth Item", "fifth");
+
+ // 'removeItemAt 2' - check if removeItemAt removes the selected item and
+ // adjusts the selection to the next item
+ element.selectedItem = thirditem;
+ is(element.removeItemAt(1), thirditem, testid + "removeItemAt 2 return value");
+
+ // radio buttons don't handle removing quite right due to XBL issues,
+ // so disable testing some of these remove tests for now - bug 367400
+ var isnotradio = (element.localName != "radiogroup");
+ // XXXndeakin disable these tests for all widgets for now. They require bug 331513.
+ isnotradio = false;
+ if (isnotradio)
+ test_nsIDOMXULSelectControlElement_States(element, testid + "removeItemAt 2", 3, fourthitem, 1, fourthvalue);
+
+ // 'removeItemAt 3' - check if removeItemAt adjusts the selection
+ // if an earlier item is removed
+ element.selectedItem = fourthitem;
+ element.removeItemAt(0);
+ test_nsIDOMXULSelectControlElement_States(element, testid + "removeItemAt 3", 2, fourthitem, 0, fourthvalue);
+
+ // 'removeItemAt 4' - check if removeItemAt adjusts the selection if the
+ // last item is selected and removed
+ element.selectedItem = fifthitem;
+ element.removeItemAt(1);
+ if (isnotradio)
+ test_nsIDOMXULSelectControlElement_States(element, testid + "removeItemAt 4", 1, fourthitem, 0, fourthvalue);
+
+ // 'removeItemAt 5' - check that removeItemAt doesn't fail when removing invalid items
+ is(element.removeItemAt(-1), null, testid + "removeItemAt 5 return value");
+ if (isnotradio)
+ test_nsIDOMXULSelectControlElement_States(element, testid + "removeItemAt 5", 1, fourthitem, 0, fourthvalue);
+
+ // 'removeItemAt 6' - check that removeItemAt doesn't fail when removing invalid items
+ is(element.removeItemAt(1), null, testid + "removeItemAt 6 return value");
+ is("item removed", "item removed", testid + "removeItemAt 6");
+ if (isnotradio)
+ test_nsIDOMXULSelectControlElement_States(element, testid + "removeItemAt 6", 1, fourthitem, 0, fourthvalue);
+
+ // 'insertItemAt' - check if insertItemAt inserts items at the right locations
+ element.selectedIndex = 0;
+ test_nsIDOMXULSelectControlElement_insertItemAt(element, 0, 0, testid, 5);
+ test_nsIDOMXULSelectControlElement_insertItemAt(element, 2, 2, testid, 6);
+ test_nsIDOMXULSelectControlElement_insertItemAt(element, -1, 3, testid, 7);
+ test_nsIDOMXULSelectControlElement_insertItemAt(element, 6, 4, testid, 8);
+
+ element.selectedIndex = 0;
+ fourthitem.disabled = true;
+ element.selectedIndex = 1;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "selectedIndex disabled", 5, fourthitem, 1, fourthvalue);
+
+ element.selectedIndex = 0;
+ element.selectedItem = fourthitem;
+ test_nsIDOMXULSelectControlElement_States(element, testid + "selectedIndex disabled", 5, fourthitem, 1, fourthvalue);
+
+ // 'removeall' - check if all items are removed
+ while (element.itemCount)
+ element.removeItemAt(0);
+ if (isnotradio)
+ test_nsIDOMXULSelectControlElement_States(element, testid + "remove all", 0, null, -1,
+ allowOtherValue ? "number8" : "");
+}
+
+function test_nsIDOMXULSelectControlElement_init(element, testprefix)
+{
+ // editable menulists use the label as the value
+ var isEditable = (element.localName == "menulist" && element.editable);
+
+ var id = element.id;
+ element = document.getElementById(id + "-initwithvalue");
+ if (element) {
+ var seconditem = element.getItemAtIndex(1);
+ test_nsIDOMXULSelectControlElement_States(element, testprefix + " value initialization",
+ 3, seconditem, 1,
+ isEditable ? seconditem.label : seconditem.value);
+ }
+
+ element = document.getElementById(id + "-initwithselected");
+ if (element) {
+ var thirditem = element.getItemAtIndex(2);
+ test_nsIDOMXULSelectControlElement_States(element, testprefix + " selected initialization",
+ 3, thirditem, 2,
+ isEditable ? thirditem.label : thirditem.value);
+ }
+}
+
+function test_nsIDOMXULSelectControlElement_States(element, testid,
+ expectedcount, expecteditem,
+ expectedindex, expectedvalue)
+{
+ // need an itemCount property here
+ var count = element.itemCount;
+ is(count, expectedcount, testid + " item count");
+ is(element.selectedItem, expecteditem, testid + " selectedItem");
+ is(element.selectedIndex, expectedindex, testid + " selectedIndex");
+ is(element.value, expectedvalue, testid + " value");
+ if (element.selectedItem) {
+ is(element.selectedItem.selected, true,
+ testid + " selectedItem marked as selected");
+ }
+}
+
+function test_nsIDOMXULSelectControlElement_insertItemAt(element, index, expectedindex, testid, number)
+{
+ var expectedCount = element.itemCount;
+ var expectedSelItem = element.selectedItem;
+ var expectedSelIndex = element.selectedIndex;
+ var expectedSelValue = element.value;
+
+ var newitem = element.insertItemAt(index, "Item " + number, "number" + number);
+ is(element.getIndexOfItem(newitem), expectedindex,
+ testid + "insertItemAt " + expectedindex + " - get inserted item");
+ expectedCount++;
+ if (expectedSelIndex >= expectedindex)
+ expectedSelIndex++;
+
+ test_nsIDOMXULSelectControlElement_States(element, testid + "insertItemAt " + index,
+ expectedCount, expectedSelItem,
+ expectedSelIndex, expectedSelValue);
+ return newitem;
+}
+
+/** test_nsIDOMXULSelectControlElement_UI
+ *
+ * Test the UI aspects of an element which implements nsIDOMXULSelectControlElement
+ *
+ * Parameters:
+ * element - element to test
+ */
+function test_nsIDOMXULSelectControlElement_UI(element, testprefix)
+{
+ var testid = (testprefix) ? testprefix + " " : "";
+ testid += element.localName + " nsIDOMXULSelectControlElement UI ";
+
+ while (element.itemCount)
+ element.removeItemAt(0);
+
+ var firstitem = element.appendItem("First Item", "first");
+ var seconditem = element.appendItem("Second Item", "second");
+
+ // 'mouse select' - check if clicking an item selects it
+ synthesizeMouseExpectEvent(firstitem, 2, 2, {}, element, "select", testid + "mouse select");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "mouse select", 2, firstitem, 0, "first");
+
+ synthesizeMouseExpectEvent(seconditem, 2, 2, {}, element, "select", testid + "mouse select 2");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "mouse select 2", 2, seconditem, 1, "second");
+
+ // make sure the element is focused so keyboard navigation will apply
+ element.selectedIndex = 1;
+ element.focus();
+
+ var navLeftRight = behaviourContains(element.localName, "keynav-leftright");
+ var backKey = navLeftRight ? "VK_LEFT" : "VK_UP";
+ var forwardKey = navLeftRight ? "VK_RIGHT" : "VK_DOWN";
+
+ // 'key select' - check if keypresses move between items
+ synthesizeKeyExpectEvent(backKey, {}, element, "select", testid + "key up");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key up", 2, firstitem, 0, "first");
+
+ var keyWrap = behaviourContains(element.localName, "select-keynav-wraps");
+
+ var expectedItem = keyWrap ? seconditem : firstitem;
+ var expectedIndex = keyWrap ? 1 : 0;
+ var expectedValue = keyWrap ? "second" : "first";
+ synthesizeKeyExpectEvent(backKey, {}, keyWrap ? element : null, "select", testid + "key up 2");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key up 2", 2,
+ expectedItem, expectedIndex, expectedValue);
+
+ element.selectedIndex = 0;
+ synthesizeKeyExpectEvent(forwardKey, {}, element, "select", testid + "key down");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key down", 2, seconditem, 1, "second");
+
+ expectedItem = keyWrap ? firstitem : seconditem;
+ expectedIndex = keyWrap ? 0 : 1;
+ expectedValue = keyWrap ? "first" : "second";
+ synthesizeKeyExpectEvent(forwardKey, {}, keyWrap ? element : null, "select", testid + "key down 2");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key down 2", 2,
+ expectedItem, expectedIndex, expectedValue);
+
+ var thirditem = element.appendItem("Third Item", "third");
+ var fourthitem = element.appendItem("Fourth Item", "fourth");
+ if (behaviourContains(element.localName, "select-extended-keynav")) {
+ var fifthitem = element.appendItem("Fifth Item", "fifth");
+ var sixthitem = element.appendItem("Sixth Item", "sixth");
+
+ synthesizeKeyExpectEvent("VK_END", {}, element, "select", testid + "key end");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key end", 6, sixthitem, 5, "sixth");
+
+ synthesizeKeyExpectEvent("VK_HOME", {}, element, "select", testid + "key home");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key home", 6, firstitem, 0, "first");
+
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", {}, element, "select", testid + "key page down");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key page down", 6, fourthitem, 3, "fourth");
+ synthesizeKeyExpectEvent("VK_PAGE_DOWN", {}, element, "select", testid + "key page down to end");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key page down to end", 6, sixthitem, 5, "sixth");
+
+ synthesizeKeyExpectEvent("VK_PAGE_UP", {}, element, "select", testid + "key page up");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key page up", 6, thirditem, 2, "third");
+ synthesizeKeyExpectEvent("VK_PAGE_UP", {}, element, "select", testid + "key page up to start");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key page up to start", 6, firstitem, 0, "first");
+
+ element.removeItemAt(5);
+ element.removeItemAt(4);
+ }
+
+ // now test whether a disabled item works.
+ element.selectedIndex = 0;
+ seconditem.disabled = true;
+
+ var dontSelectDisabled = (behaviourContains(element.localName, "dont-select-disabled"));
+
+ // 'mouse select' - check if clicking an item selects it
+ synthesizeMouseExpectEvent(seconditem, 2, 2, {}, element,
+ dontSelectDisabled ? "!select" : "select",
+ testid + "mouse select disabled");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "mouse select disabled", 4,
+ dontSelectDisabled ? firstitem: seconditem, dontSelectDisabled ? 0 : 1,
+ dontSelectDisabled ? "first" : "second");
+
+ if (dontSelectDisabled) {
+ // test whether disabling an item won't allow it to be selected
+ synthesizeKeyExpectEvent(forwardKey, {}, element, "select", testid + "key down disabled");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key down disabled", 4, thirditem, 2, "third");
+
+ synthesizeKeyExpectEvent(backKey, {}, element, "select", testid + "key up disabled");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key up disabled", 4, firstitem, 0, "first");
+
+ element.selectedIndex = 2;
+ firstitem.disabled = true;
+
+ synthesizeKeyExpectEvent(backKey, {}, keyWrap ? element : null, "select", testid + "key up disabled 2");
+ expectedItem = keyWrap ? fourthitem : thirditem;
+ expectedIndex = keyWrap ? 3 : 2;
+ expectedValue = keyWrap ? "fourth" : "third";
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key up disabled 2", 4,
+ expectedItem, expectedIndex, expectedValue);
+ }
+ else {
+ // in this case, disabled items should behave the same as non-disabled items.
+ element.selectedIndex = 0;
+ synthesizeKeyExpectEvent(forwardKey, {}, element, "select", testid + "key down disabled");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key down disabled", 4, seconditem, 1, "second");
+ synthesizeKeyExpectEvent(forwardKey, {}, element, "select", testid + "key down disabled again");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key down disabled again", 4, thirditem, 2, "third");
+
+ synthesizeKeyExpectEvent(backKey, {}, element, "select", testid + "key up disabled");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key up disabled", 4, seconditem, 1, "second");
+ synthesizeKeyExpectEvent(backKey, {}, element, "select", testid + "key up disabled again");
+ test_nsIDOMXULSelectControlElement_States(element, testid + "key up disabled again", 4, firstitem, 0, "first");
+ }
+}