mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
4045 lines
116 KiB
JavaScript
4045 lines
116 KiB
JavaScript
/* 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/. */
|
|
'use strict';
|
|
|
|
let { Cc, Ci } = require("chrome");
|
|
|
|
require("sdk/context-menu");
|
|
|
|
const { Loader } = require('sdk/test/loader');
|
|
const timer = require("sdk/timers");
|
|
const { merge } = require("sdk/util/object");
|
|
|
|
// These should match the same constants in the module.
|
|
const ITEM_CLASS = "addon-context-menu-item";
|
|
const SEPARATOR_CLASS = "addon-context-menu-separator";
|
|
const OVERFLOW_THRESH_DEFAULT = 10;
|
|
const OVERFLOW_THRESH_PREF =
|
|
"extensions.addon-sdk.context-menu.overflowThreshold";
|
|
const OVERFLOW_MENU_CLASS = "addon-content-menu-overflow-menu";
|
|
const OVERFLOW_POPUP_CLASS = "addon-content-menu-overflow-popup";
|
|
|
|
const TEST_DOC_URL = module.uri.replace(/\.js$/, ".html");
|
|
const data = require("./fixtures");
|
|
|
|
// Tests that when present the separator is placed before the separator from
|
|
// the old context-menu module
|
|
exports.testSeparatorPosition = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
// Create the old separator
|
|
let oldSeparator = test.contextMenuPopup.ownerDocument.createElement("menuseparator");
|
|
oldSeparator.id = "jetpack-context-menu-separator";
|
|
test.contextMenuPopup.appendChild(oldSeparator);
|
|
|
|
// Create an item.
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
assert.equal(test.contextMenuSeparator.nextSibling.nextSibling, oldSeparator,
|
|
"New separator should appear before the old one");
|
|
test.contextMenuPopup.removeChild(oldSeparator);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
// Destroying items that were previously created should cause them to be absent
|
|
// from the menu.
|
|
exports.testConstructDestroy = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
// Create an item.
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
assert.equal(item.parentMenu, loader.cm.contentContextMenu,
|
|
"item's parent menu should be correct");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// It should be present when the menu is shown.
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
// Destroy the item. Multiple destroys should be harmless.
|
|
item.destroy();
|
|
item.destroy();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// It should be removed from the menu.
|
|
test.checkMenu([item], [], [item]);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Destroying an item twice should not cause an error.
|
|
exports.testDestroyTwice = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
item.destroy();
|
|
item.destroy();
|
|
|
|
test.pass("Destroying an item twice should not cause an error.");
|
|
test.done();
|
|
};
|
|
|
|
|
|
// CSS selector contexts should cause their items to be present in the menu
|
|
// when the menu is invoked on nodes that match the selectors.
|
|
exports.testSelectorContextMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
data: "item",
|
|
context: loader.cm.SelectorContext("img")
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// CSS selector contexts should cause their items to be present in the menu
|
|
// when the menu is invoked on nodes that have ancestors that match the
|
|
// selectors.
|
|
exports.testSelectorAncestorContextMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
data: "item",
|
|
context: loader.cm.SelectorContext("a[href]")
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("span-link"), function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// CSS selector contexts should cause their items to be absent from the menu
|
|
// when the menu is not invoked on nodes that match or have ancestors that
|
|
// match the selectors.
|
|
exports.testSelectorContextNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
data: "item",
|
|
context: loader.cm.SelectorContext("img")
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Page contexts should cause their items to be present in the menu when the
|
|
// menu is not invoked on an active element.
|
|
exports.testPageContextMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
new loader.cm.Item({
|
|
label: "item 0"
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 1",
|
|
context: undefined
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
context: loader.cm.PageContext()
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 3",
|
|
context: [loader.cm.PageContext()]
|
|
})
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Page contexts should cause their items to be absent from the menu when the
|
|
// menu is invoked on an active element.
|
|
exports.testPageContextNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
new loader.cm.Item({
|
|
label: "item 0"
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 1",
|
|
context: undefined
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
context: loader.cm.PageContext()
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 3",
|
|
context: [loader.cm.PageContext()]
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, items, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Selection contexts should cause items to appear when a selection exists.
|
|
exports.testSelectionContextMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectionContext()
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
window.getSelection().selectAllChildren(doc.body);
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Selection contexts should cause items to appear when a selection exists in
|
|
// a text field.
|
|
exports.testSelectionContextMatchInTextField = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectionContext()
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let textfield = doc.getElementById("textfield");
|
|
textfield.setSelectionRange(0, textfield.value.length);
|
|
test.showMenu(textfield, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Selection contexts should not cause items to appear when a selection does
|
|
// not exist in a text field.
|
|
exports.testSelectionContextNoMatchInTextField = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectionContext()
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let textfield = doc.getElementById("textfield");
|
|
textfield.setSelectionRange(0, 0);
|
|
test.showMenu(textfield, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Selection contexts should not cause items to appear when a selection does
|
|
// not exist.
|
|
exports.testSelectionContextNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectionContext()
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Selection contexts should cause items to appear when a selection exists even
|
|
// for newly opened pages
|
|
exports.testSelectionContextInNewTab = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectionContext()
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let link = doc.getElementById("targetlink");
|
|
link.click();
|
|
|
|
test.delayedEventListener(this.tabBrowser, "load", function () {
|
|
let browser = test.tabBrowser.selectedBrowser;
|
|
let window = browser.contentWindow;
|
|
let doc = browser.contentDocument;
|
|
window.getSelection().selectAllChildren(doc.body);
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
test.tabBrowser.removeTab(test.tabBrowser.selectedTab);
|
|
test.tabBrowser.selectedTab = test.tab;
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
});
|
|
}, true);
|
|
});
|
|
};
|
|
|
|
|
|
// Selection contexts should work when right clicking a form button
|
|
exports.testSelectionContextButtonMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectionContext()
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
window.getSelection().selectAllChildren(doc.body);
|
|
let button = doc.getElementById("button");
|
|
test.showMenu(button, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
//Selection contexts should work when right clicking a form button
|
|
exports.testSelectionContextButtonNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectionContext()
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let button = doc.getElementById("button");
|
|
test.showMenu(button, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// URL contexts should cause items to appear on pages that match.
|
|
exports.testURLContextMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
loader.cm.Item({
|
|
label: "item 0",
|
|
context: loader.cm.URLContext(TEST_DOC_URL)
|
|
}),
|
|
loader.cm.Item({
|
|
label: "item 1",
|
|
context: loader.cm.URLContext([TEST_DOC_URL, "*.bogus.com"])
|
|
}),
|
|
loader.cm.Item({
|
|
label: "item 2",
|
|
context: loader.cm.URLContext([new RegExp(".*\\.html")])
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// URL contexts should not cause items to appear on pages that do not match.
|
|
exports.testURLContextNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
loader.cm.Item({
|
|
label: "item 0",
|
|
context: loader.cm.URLContext("*.bogus.com")
|
|
}),
|
|
loader.cm.Item({
|
|
label: "item 1",
|
|
context: loader.cm.URLContext(["*.bogus.com", "*.gnarly.com"])
|
|
}),
|
|
loader.cm.Item({
|
|
label: "item 2",
|
|
context: loader.cm.URLContext([new RegExp(".*\\.js")])
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, items, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Removing a non-matching URL context after its item is created and the page is
|
|
// loaded should cause the item's content script to be evaluated when the
|
|
// context menu is next opened.
|
|
exports.testURLContextRemove = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let shouldBeEvaled = false;
|
|
let context = loader.cm.URLContext("*.bogus.com");
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
context: context,
|
|
contentScript: 'self.postMessage("ok"); self.on("context", function () true);',
|
|
onMessage: function (msg) {
|
|
assert.ok(shouldBeEvaled,
|
|
"content script should be evaluated when expected");
|
|
assert.equal(msg, "ok", "Should have received the right message");
|
|
shouldBeEvaled = false;
|
|
}
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
|
|
item.context.remove(context);
|
|
|
|
shouldBeEvaled = true;
|
|
|
|
test.hideMenu(function () {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
|
|
assert.ok(!shouldBeEvaled,
|
|
"content script should have been evaluated");
|
|
|
|
test.hideMenu(function () {
|
|
// Shouldn't get evaluated again
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
// Loading a new page in the same tab should correctly start a new worker for
|
|
// any content scripts
|
|
exports.testPageReload = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({
|
|
label: "Item",
|
|
contentScript: "var doc = document; self.on('context', function(node) doc.body.getAttribute('showItem') == 'true');"
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
// Set a flag on the document that the item uses
|
|
doc.body.setAttribute("showItem", "true");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// With the attribute true the item should be visible in the menu
|
|
test.checkMenu([item], [], []);
|
|
test.hideMenu(function() {
|
|
let browser = this.tabBrowser.getBrowserForTab(this.tab)
|
|
test.delayedEventListener(browser, "load", function() {
|
|
test.delayedEventListener(browser, "load", function() {
|
|
window = browser.contentWindow;
|
|
doc = window.document;
|
|
|
|
// Set a flag on the document that the item uses
|
|
doc.body.setAttribute("showItem", "false");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// In the new document with the attribute false the item should be
|
|
// hidden, but if the contentScript hasn't been reloaded it will
|
|
// still see the old value
|
|
test.checkMenu([item], [item], []);
|
|
|
|
test.done();
|
|
});
|
|
}, true);
|
|
browser.loadURI(TEST_DOC_URL, null, null);
|
|
}, true);
|
|
// Required to make sure we load a new page in history rather than
|
|
// just reloading the current page which would unload it
|
|
browser.loadURI("about:blank", null, null);
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
// Closing a page after it's been used with a worker should cause the worker
|
|
// to be destroyed
|
|
/*exports.testWorkerDestroy = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let loadExpected = false;
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.postMessage("loaded"); self.on("detach", function () { console.log("saw detach"); self.postMessage("detach") });',
|
|
onMessage: function (msg) {
|
|
switch (msg) {
|
|
case "loaded":
|
|
assert.ok(loadExpected, "Should have seen the load event at the right time");
|
|
loadExpected = false;
|
|
break;
|
|
case "detach":
|
|
test.done();
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
loadExpected = true;
|
|
test.showMenu(null, function (popup) {
|
|
assert.ok(!loadExpected, "Should have seen a message");
|
|
|
|
test.checkMenu([item], [], []);
|
|
|
|
test.closeTab();
|
|
});
|
|
});
|
|
};*/
|
|
|
|
|
|
// Content contexts that return true should cause their items to be present
|
|
// in the menu.
|
|
exports.testContentContextMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () true);'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Content contexts that return false should cause their items to be absent
|
|
// from the menu.
|
|
exports.testContentContextNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () false);'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Content contexts that return undefined should cause their items to be absent
|
|
// from the menu.
|
|
exports.testContentContextUndefined = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () {});'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Content contexts that return an empty string should cause their items to be
|
|
// absent from the menu and shouldn't wipe the label
|
|
exports.testContentContextEmptyString = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () "");'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
assert.equal(item.label, "item", "Label should still be correct");
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// If any content contexts returns true then their items should be present in
|
|
// the menu.
|
|
exports.testMultipleContentContextMatch1 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () true); ' +
|
|
'self.on("context", function () false);',
|
|
onMessage: function() {
|
|
test.fail("Should not have called the second context listener");
|
|
}
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// If any content contexts returns true then their items should be present in
|
|
// the menu.
|
|
exports.testMultipleContentContextMatch2 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () false); ' +
|
|
'self.on("context", function () true);'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// If any content contexts returns a string then their items should be present
|
|
// in the menu.
|
|
exports.testMultipleContentContextString1 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () "new label"); ' +
|
|
'self.on("context", function () false);'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
assert.equal(item.label, "new label", "Label should have changed");
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// If any content contexts returns a string then their items should be present
|
|
// in the menu.
|
|
exports.testMultipleContentContextString2 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () false); ' +
|
|
'self.on("context", function () "new label");'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
assert.equal(item.label, "new label", "Label should have changed");
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// If many content contexts returns a string then the first should take effect
|
|
exports.testMultipleContentContextString3 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function () "new label 1"); ' +
|
|
'self.on("context", function () "new label 2");'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
assert.equal(item.label, "new label 1", "Label should have changed");
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Content contexts that return true should cause their items to be present
|
|
// in the menu when context clicking an active element.
|
|
exports.testContentContextMatchActiveElement = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
new loader.cm.Item({
|
|
label: "item 1",
|
|
contentScript: 'self.on("context", function () true);'
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
context: undefined,
|
|
contentScript: 'self.on("context", function () true);'
|
|
}),
|
|
// These items will always be hidden by the declarative usage of PageContext
|
|
new loader.cm.Item({
|
|
label: "item 3",
|
|
context: loader.cm.PageContext(),
|
|
contentScript: 'self.on("context", function () true);'
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 4",
|
|
context: [loader.cm.PageContext()],
|
|
contentScript: 'self.on("context", function () true);'
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, [items[2], items[3]], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Content contexts that return false should cause their items to be absent
|
|
// from the menu when context clicking an active element.
|
|
exports.testContentContextNoMatchActiveElement = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
new loader.cm.Item({
|
|
label: "item 1",
|
|
contentScript: 'self.on("context", function () false);'
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
context: undefined,
|
|
contentScript: 'self.on("context", function () false);'
|
|
}),
|
|
// These items will always be hidden by the declarative usage of PageContext
|
|
new loader.cm.Item({
|
|
label: "item 3",
|
|
context: loader.cm.PageContext(),
|
|
contentScript: 'self.on("context", function () false);'
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 4",
|
|
context: [loader.cm.PageContext()],
|
|
contentScript: 'self.on("context", function () false);'
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, items, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Content contexts that return undefined should cause their items to be absent
|
|
// from the menu when context clicking an active element.
|
|
exports.testContentContextNoMatchActiveElement = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
new loader.cm.Item({
|
|
label: "item 1",
|
|
contentScript: 'self.on("context", function () {});'
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
context: undefined,
|
|
contentScript: 'self.on("context", function () {});'
|
|
}),
|
|
// These items will always be hidden by the declarative usage of PageContext
|
|
new loader.cm.Item({
|
|
label: "item 3",
|
|
context: loader.cm.PageContext(),
|
|
contentScript: 'self.on("context", function () {});'
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 4",
|
|
context: [loader.cm.PageContext()],
|
|
contentScript: 'self.on("context", function () {});'
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, items, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Content contexts that return a string should cause their items to be present
|
|
// in the menu and the items' labels to be updated.
|
|
exports.testContentContextMatchString = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "first label",
|
|
contentScript: 'self.on("context", function () "second label");'
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
assert.equal(item.label, "second label",
|
|
"item's label should be updated");
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Ensure that contentScriptFile is working correctly
|
|
exports.testContentScriptFile = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
// Reject remote files
|
|
assert.throws(function() {
|
|
new loader.cm.Item({
|
|
label: "item",
|
|
contentScriptFile: "http://mozilla.com/context-menu.js"
|
|
});
|
|
},
|
|
new RegExp("The 'contentScriptFile' option must be a local file URL " +
|
|
"or an array of local file URLs."),
|
|
"Item throws when contentScriptFile is a remote URL");
|
|
|
|
// But accept files from data folder
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScriptFile: data.url("test-context-menu.js")
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// The args passed to context listeners should be correct.
|
|
exports.testContentContextArgs = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
let callbacks = 0;
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'self.on("context", function (node) {' +
|
|
' self.postMessage(node.tagName);' +
|
|
' return false;' +
|
|
'});',
|
|
onMessage: function (tagName) {
|
|
assert.equal(tagName, "HTML", "node should be an HTML element");
|
|
if (++callbacks == 2) test.done();
|
|
}
|
|
});
|
|
|
|
test.showMenu(null, function () {
|
|
if (++callbacks == 2) test.done();
|
|
});
|
|
};
|
|
|
|
// Multiple contexts imply intersection, not union, and content context
|
|
// listeners should not be called if all declarative contexts are not current.
|
|
exports.testMultipleContexts = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
context: [loader.cm.SelectorContext("a[href]"), loader.cm.PageContext()],
|
|
contentScript: 'self.on("context", function () self.postMessage());',
|
|
onMessage: function () {
|
|
test.fail("Context listener should not be called");
|
|
}
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("span-link"), function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Once a context is removed, it should no longer cause its item to appear.
|
|
exports.testRemoveContext = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let ctxt = loader.cm.SelectorContext("img");
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
context: ctxt
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
|
|
// The item should be present at first.
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
// Remove the img context and check again.
|
|
item.context.remove(ctxt);
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu([item], [item], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Lots of items should overflow into the overflow submenu.
|
|
exports.testOverflow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [];
|
|
for (let i = 0; i < OVERFLOW_THRESH_DEFAULT + 1; i++) {
|
|
let item = new loader.cm.Item({ label: "item " + i });
|
|
items.push(item);
|
|
}
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Module unload should cause all items to be removed.
|
|
exports.testUnload = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain the item.
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
// Unload the module.
|
|
loader.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The item should be removed from the menu.
|
|
test.checkMenu([item], [], [item]);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Using multiple module instances to add items without causing overflow should
|
|
// work OK. Assumes OVERFLOW_THRESH_DEFAULT >= 2.
|
|
exports.testMultipleModulesAdd = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
// Use each module to add an item, then unload each module in turn.
|
|
let item0 = new loader0.cm.Item({ label: "item 0" });
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain both items.
|
|
test.checkMenu([item0, item1], [], []);
|
|
popup.hidePopup();
|
|
|
|
// Unload the first module.
|
|
loader0.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The first item should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0]);
|
|
popup.hidePopup();
|
|
|
|
// Unload the second module.
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// Both items should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0, item1]);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Using multiple module instances to add items causing overflow should work OK.
|
|
exports.testMultipleModulesAddOverflow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
// Use module 0 to add OVERFLOW_THRESH_DEFAULT items.
|
|
let items0 = [];
|
|
for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i++) {
|
|
let item = new loader0.cm.Item({ label: "item 0 " + i });
|
|
items0.push(item);
|
|
}
|
|
|
|
// Use module 1 to add one item.
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
let allItems = items0.concat(item1);
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain all items in overflow.
|
|
test.checkMenu(allItems, [], []);
|
|
popup.hidePopup();
|
|
|
|
// Unload the first module.
|
|
loader0.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The first items should be removed from the menu, which should not
|
|
// overflow.
|
|
test.checkMenu(allItems, [], items0);
|
|
popup.hidePopup();
|
|
|
|
// Unload the second module.
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// All items should be removed from the menu.
|
|
test.checkMenu(allItems, [], allItems);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Using multiple module instances to modify the menu without causing overflow
|
|
// should work OK. This test creates two loaders and:
|
|
// loader0 create item -> loader1 create item -> loader0.unload ->
|
|
// loader1.unload
|
|
exports.testMultipleModulesDiffContexts1 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let item0 = new loader0.cm.Item({
|
|
label: "item 0",
|
|
context: loader0.cm.SelectorContext("img")
|
|
});
|
|
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain item1.
|
|
test.checkMenu([item0, item1], [item0], []);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 0.
|
|
loader0.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// item0 should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0]);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 1.
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// Both items should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0, item1]);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Using multiple module instances to modify the menu without causing overflow
|
|
// should work OK. This test creates two loaders and:
|
|
// loader1 create item -> loader0 create item -> loader0.unload ->
|
|
// loader1.unload
|
|
exports.testMultipleModulesDiffContexts2 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
let item0 = new loader0.cm.Item({
|
|
label: "item 0",
|
|
context: loader0.cm.SelectorContext("img")
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain item1.
|
|
test.checkMenu([item0, item1], [item0], []);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 0.
|
|
loader0.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// item0 should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0]);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 1.
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// Both items should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0, item1]);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Using multiple module instances to modify the menu without causing overflow
|
|
// should work OK. This test creates two loaders and:
|
|
// loader0 create item -> loader1 create item -> loader1.unload ->
|
|
// loader0.unload
|
|
exports.testMultipleModulesDiffContexts3 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let item0 = new loader0.cm.Item({
|
|
label: "item 0",
|
|
context: loader0.cm.SelectorContext("img")
|
|
});
|
|
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain item1.
|
|
test.checkMenu([item0, item1], [item0], []);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 1.
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// item1 should be removed from the menu.
|
|
test.checkMenu([item0, item1], [item0], [item1]);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 0.
|
|
loader0.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// Both items should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0, item1]);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Using multiple module instances to modify the menu without causing overflow
|
|
// should work OK. This test creates two loaders and:
|
|
// loader1 create item -> loader0 create item -> loader1.unload ->
|
|
// loader0.unload
|
|
exports.testMultipleModulesDiffContexts4 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
let item0 = new loader0.cm.Item({
|
|
label: "item 0",
|
|
context: loader0.cm.SelectorContext("img")
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain item1.
|
|
test.checkMenu([item0, item1], [item0], []);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 1.
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// item1 should be removed from the menu.
|
|
test.checkMenu([item0, item1], [item0], [item1]);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 0.
|
|
loader0.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// Both items should be removed from the menu.
|
|
test.checkMenu([item0, item1], [], [item0, item1]);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test interactions between a loaded module, unloading another module, and the
|
|
// menu separator and overflow submenu.
|
|
exports.testMultipleModulesAddRemove = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let item = new loader0.cm.Item({ label: "item" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain the item.
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
// Remove the item.
|
|
item.destroy();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The item should be removed from the menu.
|
|
test.checkMenu([item], [], [item]);
|
|
popup.hidePopup();
|
|
|
|
// Unload module 1.
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// There shouldn't be any errors involving the menu separator or
|
|
// overflow submenu.
|
|
test.checkMenu([item], [], [item]);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that the order of menu items is correct when adding/removing across
|
|
// multiple modules. All items from a single module should remain in a group
|
|
exports.testMultipleModulesOrder = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
// Use each module to add an item, then unload each module in turn.
|
|
let item0 = new loader0.cm.Item({ label: "item 0" });
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain both items.
|
|
test.checkMenu([item0, item1], [], []);
|
|
popup.hidePopup();
|
|
|
|
let item2 = new loader0.cm.Item({ label: "item 2" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The new item should be grouped with the same items from loader0.
|
|
test.checkMenu([item0, item2, item1], [], []);
|
|
popup.hidePopup();
|
|
|
|
let item3 = new loader1.cm.Item({ label: "item 3" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// Same again
|
|
test.checkMenu([item0, item2, item1, item3], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that the order of menu items is correct when adding/removing across
|
|
// multiple modules when overflowing. All items from a single module should
|
|
// remain in a group
|
|
exports.testMultipleModulesOrderOverflow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let prefs = loader0.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 0);
|
|
|
|
// Use each module to add an item, then unload each module in turn.
|
|
let item0 = new loader0.cm.Item({ label: "item 0" });
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The menu should contain both items.
|
|
test.checkMenu([item0, item1], [], []);
|
|
popup.hidePopup();
|
|
|
|
let item2 = new loader0.cm.Item({ label: "item 2" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// The new item should be grouped with the same items from loader0.
|
|
test.checkMenu([item0, item2, item1], [], []);
|
|
popup.hidePopup();
|
|
|
|
let item3 = new loader1.cm.Item({ label: "item 3" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// Same again
|
|
test.checkMenu([item0, item2, item1, item3], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that if a module's items are all hidden then the overflow menu doesn't
|
|
// get hidden
|
|
exports.testMultipleModulesOverflowHidden = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let prefs = loader0.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 0);
|
|
|
|
// Use each module to add an item, then unload each module in turn.
|
|
let item0 = new loader0.cm.Item({ label: "item 0" });
|
|
let item1 = new loader1.cm.Item({
|
|
label: "item 1",
|
|
context: loader1.cm.SelectorContext("a")
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// One should be hidden
|
|
test.checkMenu([item0, item1], [item1], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that if a module's items are all hidden then the overflow menu doesn't
|
|
// get hidden (reverse order to above)
|
|
exports.testMultipleModulesOverflowHidden2 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let prefs = loader0.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 0);
|
|
|
|
// Use each module to add an item, then unload each module in turn.
|
|
let item0 = new loader0.cm.Item({
|
|
label: "item 0",
|
|
context: loader0.cm.SelectorContext("a")
|
|
});
|
|
let item1 = new loader1.cm.Item({ label: "item 1" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// One should be hidden
|
|
test.checkMenu([item0, item1], [item0], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that we don't overflow if there are more items than the overflow
|
|
// threshold but not all of them are visible
|
|
exports.testOverflowIgnoresHidden = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let prefs = loader.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 2);
|
|
|
|
let allItems = [
|
|
new loader.cm.Item({
|
|
label: "item 0"
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 1"
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
context: loader.cm.SelectorContext("a")
|
|
})
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// One should be hidden
|
|
test.checkMenu(allItems, [allItems[2]], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that we don't overflow if there are more items than the overflow
|
|
// threshold but not all of them are visible
|
|
exports.testOverflowIgnoresHiddenMultipleModules1 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let prefs = loader0.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 2);
|
|
|
|
let allItems = [
|
|
new loader0.cm.Item({
|
|
label: "item 0"
|
|
}),
|
|
new loader0.cm.Item({
|
|
label: "item 1"
|
|
}),
|
|
new loader1.cm.Item({
|
|
label: "item 2",
|
|
context: loader1.cm.SelectorContext("a")
|
|
}),
|
|
new loader1.cm.Item({
|
|
label: "item 3",
|
|
context: loader1.cm.SelectorContext("a")
|
|
})
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// One should be hidden
|
|
test.checkMenu(allItems, [allItems[2], allItems[3]], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that we don't overflow if there are more items than the overflow
|
|
// threshold but not all of them are visible
|
|
exports.testOverflowIgnoresHiddenMultipleModules2 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let prefs = loader0.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 2);
|
|
|
|
let allItems = [
|
|
new loader0.cm.Item({
|
|
label: "item 0"
|
|
}),
|
|
new loader0.cm.Item({
|
|
label: "item 1",
|
|
context: loader0.cm.SelectorContext("a")
|
|
}),
|
|
new loader1.cm.Item({
|
|
label: "item 2"
|
|
}),
|
|
new loader1.cm.Item({
|
|
label: "item 3",
|
|
context: loader1.cm.SelectorContext("a")
|
|
})
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// One should be hidden
|
|
test.checkMenu(allItems, [allItems[1], allItems[3]], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that we don't overflow if there are more items than the overflow
|
|
// threshold but not all of them are visible
|
|
exports.testOverflowIgnoresHiddenMultipleModules3 = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let prefs = loader0.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 2);
|
|
|
|
let allItems = [
|
|
new loader0.cm.Item({
|
|
label: "item 0",
|
|
context: loader0.cm.SelectorContext("a")
|
|
}),
|
|
new loader0.cm.Item({
|
|
label: "item 1",
|
|
context: loader0.cm.SelectorContext("a")
|
|
}),
|
|
new loader1.cm.Item({
|
|
label: "item 2"
|
|
}),
|
|
new loader1.cm.Item({
|
|
label: "item 3"
|
|
})
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// One should be hidden
|
|
test.checkMenu(allItems, [allItems[0], allItems[1]], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Tests that we transition between overflowing to non-overflowing to no items
|
|
// and back again
|
|
exports.testOverflowTransition = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let prefs = loader.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 2);
|
|
|
|
let pItems = [
|
|
new loader.cm.Item({
|
|
label: "item 0",
|
|
context: loader.cm.SelectorContext("p")
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 1",
|
|
context: loader.cm.SelectorContext("p")
|
|
})
|
|
];
|
|
|
|
let aItems = [
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
context: loader.cm.SelectorContext("a")
|
|
}),
|
|
new loader.cm.Item({
|
|
label: "item 3",
|
|
context: loader.cm.SelectorContext("a")
|
|
})
|
|
];
|
|
|
|
let allItems = pItems.concat(aItems);
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("link"), function (popup) {
|
|
// The menu should contain all items and will overflow
|
|
test.checkMenu(allItems, [], []);
|
|
popup.hidePopup();
|
|
|
|
test.showMenu(doc.getElementById("text"), function (popup) {
|
|
// Only contains hald the items and will not overflow
|
|
test.checkMenu(allItems, aItems, []);
|
|
popup.hidePopup();
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// None of the items will be visible
|
|
test.checkMenu(allItems, allItems, []);
|
|
popup.hidePopup();
|
|
|
|
test.showMenu(doc.getElementById("text"), function (popup) {
|
|
// Only contains hald the items and will not overflow
|
|
test.checkMenu(allItems, aItems, []);
|
|
popup.hidePopup();
|
|
|
|
test.showMenu(doc.getElementById("link"), function (popup) {
|
|
// The menu should contain all items and will overflow
|
|
test.checkMenu(allItems, [], []);
|
|
popup.hidePopup();
|
|
|
|
test.showMenu(null, function (popup) {
|
|
// None of the items will be visible
|
|
test.checkMenu(allItems, allItems, []);
|
|
popup.hidePopup();
|
|
|
|
test.showMenu(doc.getElementById("link"), function (popup) {
|
|
// The menu should contain all items and will overflow
|
|
test.checkMenu(allItems, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// An item's command listener should work.
|
|
exports.testItemCommand = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
data: "item data",
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function (data) {
|
|
assert.equal(this, item, "`this` inside onMessage should be item");
|
|
assert.equal(data.tagName, "HTML", "node should be an HTML element");
|
|
assert.equal(data.data, item.data, "data should be item data");
|
|
test.done();
|
|
}
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
let elt = test.getItemElt(popup, item);
|
|
|
|
// create a command event
|
|
let evt = elt.ownerDocument.createEvent('Event');
|
|
evt.initEvent('command', true, true);
|
|
elt.dispatchEvent(evt);
|
|
});
|
|
};
|
|
|
|
|
|
// A menu's click listener should work and receive bubbling 'command' events from
|
|
// sub-items appropriately. This also tests menus and ensures that when a CSS
|
|
// selector context matches the clicked node's ancestor, the matching ancestor
|
|
// is passed to listeners as the clicked node.
|
|
exports.testMenuCommand = function (assert, done) {
|
|
// Create a top-level menu, submenu, and item, like this:
|
|
// topMenu -> submenu -> item
|
|
// Click the item and make sure the click bubbles.
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "submenu item",
|
|
data: "submenu item data",
|
|
context: loader.cm.SelectorContext("a"),
|
|
});
|
|
|
|
let submenu = new loader.cm.Menu({
|
|
label: "submenu",
|
|
context: loader.cm.SelectorContext("a"),
|
|
items: [item]
|
|
});
|
|
|
|
let topMenu = new loader.cm.Menu({
|
|
label: "top menu",
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function (data) {
|
|
assert.equal(this, topMenu, "`this` inside top menu should be menu");
|
|
assert.equal(data.tagName, "A", "Clicked node should be anchor");
|
|
assert.equal(data.data, item.data,
|
|
"Clicked item data should be correct");
|
|
test.done();
|
|
},
|
|
items: [submenu],
|
|
context: loader.cm.SelectorContext("a")
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("span-link"), function (popup) {
|
|
test.checkMenu([topMenu], [], []);
|
|
let topMenuElt = test.getItemElt(popup, topMenu);
|
|
let topMenuPopup = topMenuElt.firstChild;
|
|
let submenuElt = test.getItemElt(topMenuPopup, submenu);
|
|
let submenuPopup = submenuElt.firstChild;
|
|
let itemElt = test.getItemElt(submenuPopup, item);
|
|
|
|
// create a command event
|
|
let evt = itemElt.ownerDocument.createEvent('Event');
|
|
evt.initEvent('command', true, true);
|
|
itemElt.dispatchEvent(evt);
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Click listeners should work when multiple modules are loaded.
|
|
exports.testItemCommandMultipleModules = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let item0 = loader0.cm.Item({
|
|
label: "loader 0 item",
|
|
contentScript: 'self.on("click", self.postMessage);',
|
|
onMessage: function () {
|
|
test.fail("loader 0 item should not emit click event");
|
|
}
|
|
});
|
|
let item1 = loader1.cm.Item({
|
|
label: "loader 1 item",
|
|
contentScript: 'self.on("click", self.postMessage);',
|
|
onMessage: function () {
|
|
test.pass("loader 1 item clicked as expected");
|
|
test.done();
|
|
}
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item0, item1], [], []);
|
|
let item1Elt = test.getItemElt(popup, item1);
|
|
|
|
// create a command event
|
|
let evt = item1Elt.ownerDocument.createEvent('Event');
|
|
evt.initEvent('command', true, true);
|
|
item1Elt.dispatchEvent(evt);
|
|
});
|
|
};
|
|
|
|
|
|
|
|
|
|
// An item's click listener should work.
|
|
exports.testItemClick = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
data: "item data",
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function (data) {
|
|
assert.equal(this, item, "`this` inside onMessage should be item");
|
|
assert.equal(data.tagName, "HTML", "node should be an HTML element");
|
|
assert.equal(data.data, item.data, "data should be item data");
|
|
test.done();
|
|
}
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
let elt = test.getItemElt(popup, item);
|
|
elt.click();
|
|
});
|
|
};
|
|
|
|
|
|
// A menu's click listener should work and receive bubbling clicks from
|
|
// sub-items appropriately. This also tests menus and ensures that when a CSS
|
|
// selector context matches the clicked node's ancestor, the matching ancestor
|
|
// is passed to listeners as the clicked node.
|
|
exports.testMenuClick = function (assert, done) {
|
|
// Create a top-level menu, submenu, and item, like this:
|
|
// topMenu -> submenu -> item
|
|
// Click the item and make sure the click bubbles.
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "submenu item",
|
|
data: "submenu item data",
|
|
context: loader.cm.SelectorContext("a"),
|
|
});
|
|
|
|
let submenu = new loader.cm.Menu({
|
|
label: "submenu",
|
|
context: loader.cm.SelectorContext("a"),
|
|
items: [item]
|
|
});
|
|
|
|
let topMenu = new loader.cm.Menu({
|
|
label: "top menu",
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function (data) {
|
|
assert.equal(this, topMenu, "`this` inside top menu should be menu");
|
|
assert.equal(data.tagName, "A", "Clicked node should be anchor");
|
|
assert.equal(data.data, item.data,
|
|
"Clicked item data should be correct");
|
|
test.done();
|
|
},
|
|
items: [submenu],
|
|
context: loader.cm.SelectorContext("a")
|
|
});
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("span-link"), function (popup) {
|
|
test.checkMenu([topMenu], [], []);
|
|
let topMenuElt = test.getItemElt(popup, topMenu);
|
|
let topMenuPopup = topMenuElt.firstChild;
|
|
let submenuElt = test.getItemElt(topMenuPopup, submenu);
|
|
let submenuPopup = submenuElt.firstChild;
|
|
let itemElt = test.getItemElt(submenuPopup, item);
|
|
itemElt.click();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Click listeners should work when multiple modules are loaded.
|
|
exports.testItemClickMultipleModules = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let item0 = loader0.cm.Item({
|
|
label: "loader 0 item",
|
|
contentScript: 'self.on("click", self.postMessage);',
|
|
onMessage: function () {
|
|
test.fail("loader 0 item should not emit click event");
|
|
}
|
|
});
|
|
let item1 = loader1.cm.Item({
|
|
label: "loader 1 item",
|
|
contentScript: 'self.on("click", self.postMessage);',
|
|
onMessage: function () {
|
|
test.pass("loader 1 item clicked as expected");
|
|
test.done();
|
|
}
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item0, item1], [], []);
|
|
let item1Elt = test.getItemElt(popup, item1);
|
|
item1Elt.click();
|
|
});
|
|
};
|
|
|
|
|
|
// Adding a separator to a submenu should work OK.
|
|
exports.testSeparator = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let menu = new loader.cm.Menu({
|
|
label: "submenu",
|
|
items: [new loader.cm.Separator()]
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// The parentMenu option should work
|
|
exports.testParentMenu = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let menu = new loader.cm.Menu({
|
|
label: "submenu",
|
|
items: [loader.cm.Item({ label: "item 1" })],
|
|
parentMenu: loader.cm.contentContextMenu
|
|
});
|
|
|
|
let item = loader.cm.Item({
|
|
label: "item 2",
|
|
parentMenu: menu,
|
|
});
|
|
|
|
assert.equal(menu.items[1], item, "Item should be in the sub menu");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Existing context menu modifications should apply to new windows.
|
|
exports.testNewWindow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
|
|
test.withNewWindow(function () {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// When a new window is opened, items added by an unloaded module should not
|
|
// be present in the menu.
|
|
exports.testNewWindowMultipleModules = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
loader.unload();
|
|
test.withNewWindow(function () {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], [item]);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Existing context menu modifications should not apply to new private windows.
|
|
exports.testNewPrivateWindow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
test.withNewPrivateWindow(function () {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Existing context menu modifications should apply to new private windows when
|
|
// private browsing support is enabled.
|
|
exports.testNewPrivateEnabledWindow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newPrivateLoader();
|
|
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
test.withNewPrivateWindow(function () {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Existing context menu modifications should apply to new private windows when
|
|
// private browsing support is enabled unless unloaded.
|
|
exports.testNewPrivateEnabledWindowUnloaded = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newPrivateLoader();
|
|
|
|
let item = new loader.cm.Item({ label: "item" });
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
popup.hidePopup();
|
|
|
|
loader.unload();
|
|
|
|
test.withNewPrivateWindow(function () {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Items in the context menu should be sorted according to locale.
|
|
exports.testSorting = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
// Make an unsorted items list. It'll look like this:
|
|
// item 1, item 0, item 3, item 2, item 5, item 4, ...
|
|
let items = [];
|
|
for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i += 2) {
|
|
items.push(new loader.cm.Item({ label: "item " + (i + 1) }));
|
|
items.push(new loader.cm.Item({ label: "item " + i }));
|
|
}
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Items in the overflow menu should be sorted according to locale.
|
|
exports.testSortingOverflow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
// Make an unsorted items list. It'll look like this:
|
|
// item 1, item 0, item 3, item 2, item 5, item 4, ...
|
|
let items = [];
|
|
for (let i = 0; i < OVERFLOW_THRESH_DEFAULT * 2; i += 2) {
|
|
items.push(new loader.cm.Item({ label: "item " + (i + 1) }));
|
|
items.push(new loader.cm.Item({ label: "item " + i }));
|
|
}
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Multiple modules shouldn't interfere with sorting.
|
|
exports.testSortingMultipleModules = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader0 = test.newLoader();
|
|
let loader1 = test.newLoader();
|
|
|
|
let items0 = [];
|
|
let items1 = [];
|
|
for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i++) {
|
|
if (i % 2) {
|
|
let item = new loader0.cm.Item({ label: "item " + i });
|
|
items0.push(item);
|
|
}
|
|
else {
|
|
let item = new loader1.cm.Item({ label: "item " + i });
|
|
items1.push(item);
|
|
}
|
|
}
|
|
let allItems = items0.concat(items1);
|
|
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// All items should be present and sorted.
|
|
test.checkMenu(allItems, [], []);
|
|
popup.hidePopup();
|
|
loader0.unload();
|
|
loader1.unload();
|
|
test.showMenu(null, function (popup) {
|
|
|
|
// All items should be removed.
|
|
test.checkMenu(allItems, [], allItems);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Content click handlers and context handlers should be able to communicate,
|
|
// i.e., they're eval'ed in the same worker and sandbox.
|
|
exports.testContentCommunication = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript: 'var potato;' +
|
|
'self.on("context", function () {' +
|
|
' potato = "potato";' +
|
|
' return true;' +
|
|
'});' +
|
|
'self.on("click", function () {' +
|
|
' self.postMessage(potato);' +
|
|
'});',
|
|
});
|
|
|
|
item.on("message", function (data) {
|
|
assert.equal(data, "potato", "That's a lot of potatoes!");
|
|
test.done();
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
let elt = test.getItemElt(popup, item);
|
|
elt.click();
|
|
});
|
|
};
|
|
|
|
|
|
// When the context menu is invoked on a tab that was already open when the
|
|
// module was loaded, it should contain the expected items and content workers
|
|
// should function as expected.
|
|
exports.testLoadWithOpenTab = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
test.withTestDoc(function (window, doc) {
|
|
let loader = test.newLoader();
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
contentScript:
|
|
'self.on("click", function () self.postMessage("click"));',
|
|
onMessage: function (msg) {
|
|
if (msg === "click")
|
|
test.done();
|
|
}
|
|
});
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.getItemElt(popup, item).click();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Bug 732716: Ensure that the node given in `click` event works fine
|
|
// (i.e. is correctly wrapped)
|
|
exports.testDrawImageOnClickNode = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
test.withTestDoc(function (window, doc) {
|
|
let loader = test.newLoader();
|
|
let item = new loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.SelectorContext("img"),
|
|
contentScript: "new " + function() {
|
|
self.on("click", function (img, data) {
|
|
let ctx = document.createElement("canvas").getContext("2d");
|
|
ctx.drawImage(img, 1, 1, 1, 1);
|
|
self.postMessage("done");
|
|
});
|
|
},
|
|
onMessage: function (msg) {
|
|
if (msg === "done")
|
|
test.done();
|
|
}
|
|
});
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.getItemElt(popup, item).click();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Setting an item's label before the menu is ever shown should correctly change
|
|
// its label.
|
|
exports.testSetLabelBeforeShow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
new loader.cm.Item({ label: "a" }),
|
|
new loader.cm.Item({ label: "b" })
|
|
]
|
|
items[0].label = "z";
|
|
assert.equal(items[0].label, "z");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Setting an item's label after the menu is shown should correctly change its
|
|
// label.
|
|
exports.testSetLabelAfterShow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
new loader.cm.Item({ label: "a" }),
|
|
new loader.cm.Item({ label: "b" })
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
popup.hidePopup();
|
|
|
|
items[0].label = "z";
|
|
assert.equal(items[0].label, "z");
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Setting an item's label before the menu is ever shown should correctly change
|
|
// its label.
|
|
exports.testSetLabelBeforeShowOverflow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let prefs = loader.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 0);
|
|
|
|
let items = [
|
|
new loader.cm.Item({ label: "a" }),
|
|
new loader.cm.Item({ label: "b" })
|
|
]
|
|
items[0].label = "z";
|
|
assert.equal(items[0].label, "z");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Setting an item's label after the menu is shown should correctly change its
|
|
// label.
|
|
exports.testSetLabelAfterShowOverflow = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let prefs = loader.loader.require("sdk/preferences/service");
|
|
prefs.set(OVERFLOW_THRESH_PREF, 0);
|
|
|
|
let items = [
|
|
new loader.cm.Item({ label: "a" }),
|
|
new loader.cm.Item({ label: "b" })
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
popup.hidePopup();
|
|
|
|
items[0].label = "z";
|
|
assert.equal(items[0].label, "z");
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Setting the label of an item in a Menu should work.
|
|
exports.testSetLabelMenuItem = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let menu = loader.cm.Menu({
|
|
label: "menu",
|
|
items: [loader.cm.Item({ label: "a" })]
|
|
});
|
|
menu.items[0].label = "z";
|
|
|
|
assert.equal(menu.items[0].label, "z");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Menu.addItem() should work.
|
|
exports.testMenuAddItem = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let menu = loader.cm.Menu({
|
|
label: "menu",
|
|
items: [
|
|
loader.cm.Item({ label: "item 0" })
|
|
]
|
|
});
|
|
menu.addItem(loader.cm.Item({ label: "item 1" }));
|
|
menu.addItem(loader.cm.Item({ label: "item 2" }));
|
|
|
|
assert.equal(menu.items.length, 3,
|
|
"menu should have correct number of items");
|
|
for (let i = 0; i < 3; i++) {
|
|
assert.equal(menu.items[i].label, "item " + i,
|
|
"item label should be correct");
|
|
assert.equal(menu.items[i].parentMenu, menu,
|
|
"item's parent menu should be correct");
|
|
}
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Adding the same item twice to a menu should work as expected.
|
|
exports.testMenuAddItemTwice = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let menu = loader.cm.Menu({
|
|
label: "menu",
|
|
items: []
|
|
});
|
|
let subitem = loader.cm.Item({ label: "item 1" })
|
|
menu.addItem(subitem);
|
|
menu.addItem(loader.cm.Item({ label: "item 0" }));
|
|
menu.addItem(subitem);
|
|
|
|
assert.equal(menu.items.length, 2,
|
|
"menu should have correct number of items");
|
|
for (let i = 0; i < 2; i++) {
|
|
assert.equal(menu.items[i].label, "item " + i,
|
|
"item label should be correct");
|
|
}
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Menu.removeItem() should work.
|
|
exports.testMenuRemoveItem = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let subitem = loader.cm.Item({ label: "item 1" });
|
|
let menu = loader.cm.Menu({
|
|
label: "menu",
|
|
items: [
|
|
loader.cm.Item({ label: "item 0" }),
|
|
subitem,
|
|
loader.cm.Item({ label: "item 2" })
|
|
]
|
|
});
|
|
|
|
// Removing twice should be harmless.
|
|
menu.removeItem(subitem);
|
|
menu.removeItem(subitem);
|
|
|
|
assert.equal(subitem.parentMenu, null,
|
|
"item's parent menu should be correct");
|
|
|
|
assert.equal(menu.items.length, 2,
|
|
"menu should have correct number of items");
|
|
assert.equal(menu.items[0].label, "item 0",
|
|
"item label should be correct");
|
|
assert.equal(menu.items[1].label, "item 2",
|
|
"item label should be correct");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Adding an item currently contained in one menu to another menu should work.
|
|
exports.testMenuItemSwap = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let subitem = loader.cm.Item({ label: "item" });
|
|
let menu0 = loader.cm.Menu({
|
|
label: "menu 0",
|
|
items: [subitem]
|
|
});
|
|
let menu1 = loader.cm.Menu({
|
|
label: "menu 1",
|
|
items: []
|
|
});
|
|
menu1.addItem(subitem);
|
|
|
|
assert.equal(menu0.items.length, 0,
|
|
"menu should have correct number of items");
|
|
|
|
assert.equal(menu1.items.length, 1,
|
|
"menu should have correct number of items");
|
|
assert.equal(menu1.items[0].label, "item",
|
|
"item label should be correct");
|
|
|
|
assert.equal(subitem.parentMenu, menu1,
|
|
"item's parent menu should be correct");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu0, menu1], [menu0], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Destroying an item should remove it from its parent menu.
|
|
exports.testMenuItemDestroy = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let subitem = loader.cm.Item({ label: "item" });
|
|
let menu = loader.cm.Menu({
|
|
label: "menu",
|
|
items: [subitem]
|
|
});
|
|
subitem.destroy();
|
|
|
|
assert.equal(menu.items.length, 0,
|
|
"menu should have correct number of items");
|
|
assert.equal(subitem.parentMenu, null,
|
|
"item's parent menu should be correct");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [menu], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Setting Menu.items should work.
|
|
exports.testMenuItemsSetter = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let menu = loader.cm.Menu({
|
|
label: "menu",
|
|
items: [
|
|
loader.cm.Item({ label: "old item 0" }),
|
|
loader.cm.Item({ label: "old item 1" })
|
|
]
|
|
});
|
|
menu.items = [
|
|
loader.cm.Item({ label: "new item 0" }),
|
|
loader.cm.Item({ label: "new item 1" }),
|
|
loader.cm.Item({ label: "new item 2" })
|
|
];
|
|
|
|
assert.equal(menu.items.length, 3,
|
|
"menu should have correct number of items");
|
|
for (let i = 0; i < 3; i++) {
|
|
assert.equal(menu.items[i].label, "new item " + i,
|
|
"item label should be correct");
|
|
assert.equal(menu.items[i].parentMenu, menu,
|
|
"item's parent menu should be correct");
|
|
}
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Setting Item.data should work.
|
|
exports.testItemDataSetter = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item = loader.cm.Item({ label: "old item 0", data: "old" });
|
|
item.data = "new";
|
|
|
|
assert.equal(item.data, "new", "item should have correct data");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Open the test doc, load the module, make sure items appear when context-
|
|
// clicking the iframe.
|
|
exports.testAlreadyOpenIframe = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
test.withTestDoc(function (window, doc) {
|
|
let loader = test.newLoader();
|
|
let item = new loader.cm.Item({
|
|
label: "item"
|
|
});
|
|
test.showMenu(doc.getElementById("iframe"), function (popup) {
|
|
test.checkMenu([item], [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Tests that a missing label throws an exception
|
|
exports.testItemNoLabel = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
try {
|
|
new loader.cm.Item({});
|
|
assert.ok(false, "Should have seen exception");
|
|
}
|
|
catch (e) {
|
|
assert.ok(true, "Should have seen exception");
|
|
}
|
|
|
|
try {
|
|
new loader.cm.Item({ label: null });
|
|
assert.ok(false, "Should have seen exception");
|
|
}
|
|
catch (e) {
|
|
assert.ok(true, "Should have seen exception");
|
|
}
|
|
|
|
try {
|
|
new loader.cm.Item({ label: undefined });
|
|
assert.ok(false, "Should have seen exception");
|
|
}
|
|
catch (e) {
|
|
assert.ok(true, "Should have seen exception");
|
|
}
|
|
|
|
try {
|
|
new loader.cm.Item({ label: "" });
|
|
assert.ok(false, "Should have seen exception");
|
|
}
|
|
catch (e) {
|
|
assert.ok(true, "Should have seen exception");
|
|
}
|
|
|
|
test.done();
|
|
}
|
|
|
|
|
|
// Tests that items can have an empty data property
|
|
exports.testItemNoData = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
function checkData(data) {
|
|
assert.equal(data, undefined, "Data should be undefined");
|
|
}
|
|
|
|
let item1 = new loader.cm.Item({
|
|
label: "item 1",
|
|
contentScript: 'self.on("click", function(node, data) self.postMessage(data))',
|
|
onMessage: checkData
|
|
});
|
|
let item2 = new loader.cm.Item({
|
|
label: "item 2",
|
|
data: null,
|
|
contentScript: 'self.on("click", function(node, data) self.postMessage(data))',
|
|
onMessage: checkData
|
|
});
|
|
let item3 = new loader.cm.Item({
|
|
label: "item 3",
|
|
data: undefined,
|
|
contentScript: 'self.on("click", function(node, data) self.postMessage(data))',
|
|
onMessage: checkData
|
|
});
|
|
|
|
assert.equal(item1.data, undefined, "Should be no defined data");
|
|
assert.equal(item2.data, null, "Should be no defined data");
|
|
assert.equal(item3.data, undefined, "Should be no defined data");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item1, item2, item3], [], []);
|
|
|
|
let itemElt = test.getItemElt(popup, item1);
|
|
itemElt.click();
|
|
|
|
test.hideMenu(function() {
|
|
test.showMenu(null, function (popup) {
|
|
let itemElt = test.getItemElt(popup, item2);
|
|
itemElt.click();
|
|
|
|
test.hideMenu(function() {
|
|
test.showMenu(null, function (popup) {
|
|
let itemElt = test.getItemElt(popup, item3);
|
|
itemElt.click();
|
|
|
|
test.done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
// Tests that items without an image don't attempt to show one
|
|
exports.testItemNoImage = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let item1 = new loader.cm.Item({ label: "item 1" });
|
|
let item2 = new loader.cm.Item({ label: "item 2", image: null });
|
|
let item3 = new loader.cm.Item({ label: "item 3", image: undefined });
|
|
|
|
assert.equal(item1.image, undefined, "Should be no defined image");
|
|
assert.equal(item2.image, null, "Should be no defined image");
|
|
assert.equal(item3.image, undefined, "Should be no defined image");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item1, item2, item3], [], []);
|
|
|
|
test.done();
|
|
});
|
|
}
|
|
|
|
|
|
// Test image support.
|
|
exports.testItemImage = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let imageURL = data.url("moz_favicon.ico");
|
|
let item = new loader.cm.Item({ label: "item", image: imageURL });
|
|
let menu = new loader.cm.Menu({ label: "menu", image: imageURL, items: [
|
|
loader.cm.Item({ label: "subitem" })
|
|
]});
|
|
assert.equal(item.image, imageURL, "Should have set the image correctly");
|
|
assert.equal(menu.image, imageURL, "Should have set the image correctly");
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([item, menu], [], []);
|
|
|
|
let imageURL2 = data.url("dummy.ico");
|
|
item.image = imageURL2;
|
|
menu.image = imageURL2;
|
|
assert.equal(item.image, imageURL2, "Should have set the image correctly");
|
|
assert.equal(menu.image, imageURL2, "Should have set the image correctly");
|
|
test.checkMenu([item, menu], [], []);
|
|
|
|
item.image = null;
|
|
menu.image = null;
|
|
assert.equal(item.image, null, "Should have set the image correctly");
|
|
assert.equal(menu.image, null, "Should have set the image correctly");
|
|
test.checkMenu([item, menu], [], []);
|
|
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
// Test image URL validation.
|
|
exports.testItemImageValidURL = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
assert.throws(function(){
|
|
new loader.cm.Item({
|
|
label: "item 1",
|
|
image: "foo"
|
|
})
|
|
}, /Image URL validation failed/
|
|
);
|
|
|
|
assert.throws(function(){
|
|
new loader.cm.Item({
|
|
label: "item 2",
|
|
image: false
|
|
})
|
|
}, /Image URL validation failed/
|
|
);
|
|
|
|
assert.throws(function(){
|
|
new loader.cm.Item({
|
|
label: "item 3",
|
|
image: 0
|
|
})
|
|
}, /Image URL validation failed/
|
|
);
|
|
|
|
let imageURL = data.url("moz_favicon.ico");
|
|
let item4 = new loader.cm.Item({ label: "item 4", image: imageURL });
|
|
let item5 = new loader.cm.Item({ label: "item 5", image: null });
|
|
let item6 = new loader.cm.Item({ label: "item 6", image: undefined });
|
|
|
|
assert.equal(item4.image, imageURL, "Should be proper image URL");
|
|
assert.equal(item5.image, null, "Should be null image");
|
|
assert.equal(item6.image, undefined, "Should be undefined image");
|
|
|
|
test.done();
|
|
};
|
|
|
|
|
|
// Menu.destroy should destroy the item tree rooted at that menu.
|
|
exports.testMenuDestroy = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let menu = loader.cm.Menu({
|
|
label: "menu",
|
|
items: [
|
|
loader.cm.Item({ label: "item 0" }),
|
|
loader.cm.Menu({
|
|
label: "item 1",
|
|
items: [
|
|
loader.cm.Item({ label: "subitem 0" }),
|
|
loader.cm.Item({ label: "subitem 1" }),
|
|
loader.cm.Item({ label: "subitem 2" })
|
|
]
|
|
}),
|
|
loader.cm.Item({ label: "item 2" })
|
|
]
|
|
});
|
|
menu.destroy();
|
|
|
|
/*let numRegistryEntries = 0;
|
|
loader.globalScope.browserManager.browserWins.forEach(function (bwin) {
|
|
for (let itemID in bwin.items)
|
|
numRegistryEntries++;
|
|
});
|
|
assert.equal(numRegistryEntries, 0, "All items should be unregistered.");*/
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([menu], [], [menu]);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
// Checks that if a menu contains sub items that are hidden then the menu is
|
|
// hidden too. Also checks that content scripts and contexts work for sub items.
|
|
exports.testSubItemContextNoMatchHideMenu = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
loader.cm.Menu({
|
|
label: "menu 1",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 1",
|
|
context: loader.cm.SelectorContext(".foo")
|
|
})
|
|
]
|
|
}),
|
|
loader.cm.Menu({
|
|
label: "menu 2",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 2",
|
|
contentScript: 'self.on("context", function () false);'
|
|
})
|
|
]
|
|
}),
|
|
loader.cm.Menu({
|
|
label: "menu 3",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 3",
|
|
context: loader.cm.SelectorContext(".foo")
|
|
}),
|
|
loader.cm.Item({
|
|
label: "subitem 4",
|
|
contentScript: 'self.on("context", function () false);'
|
|
})
|
|
]
|
|
})
|
|
];
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, items, []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
|
|
// Checks that if a menu contains a combination of hidden and visible sub items
|
|
// then the menu is still visible too.
|
|
exports.testSubItemContextMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let hiddenItems = [
|
|
loader.cm.Item({
|
|
label: "subitem 3",
|
|
context: loader.cm.SelectorContext(".foo")
|
|
}),
|
|
loader.cm.Item({
|
|
label: "subitem 6",
|
|
contentScript: 'self.on("context", function () false);'
|
|
})
|
|
];
|
|
|
|
let items = [
|
|
loader.cm.Menu({
|
|
label: "menu 1",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 1",
|
|
context: loader.cm.URLContext(TEST_DOC_URL)
|
|
})
|
|
]
|
|
}),
|
|
loader.cm.Menu({
|
|
label: "menu 2",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 2",
|
|
contentScript: 'self.on("context", function () true);'
|
|
})
|
|
]
|
|
}),
|
|
loader.cm.Menu({
|
|
label: "menu 3",
|
|
items: [
|
|
hiddenItems[0],
|
|
loader.cm.Item({
|
|
label: "subitem 4",
|
|
contentScript: 'self.on("context", function () true);'
|
|
})
|
|
]
|
|
}),
|
|
loader.cm.Menu({
|
|
label: "menu 4",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 5",
|
|
context: loader.cm.URLContext(TEST_DOC_URL)
|
|
}),
|
|
hiddenItems[1]
|
|
]
|
|
}),
|
|
loader.cm.Menu({
|
|
label: "menu 5",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 7",
|
|
context: loader.cm.URLContext(TEST_DOC_URL)
|
|
}),
|
|
loader.cm.Item({
|
|
label: "subitem 8",
|
|
contentScript: 'self.on("context", function () true);'
|
|
})
|
|
]
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, hiddenItems, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Child items should default to visible, not to PageContext
|
|
exports.testSubItemDefaultVisible = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [
|
|
loader.cm.Menu({
|
|
label: "menu 1",
|
|
context: loader.cm.SelectorContext("img"),
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 1"
|
|
}),
|
|
loader.cm.Item({
|
|
label: "subitem 2",
|
|
context: loader.cm.SelectorContext("img")
|
|
}),
|
|
loader.cm.Item({
|
|
label: "subitem 3",
|
|
context: loader.cm.SelectorContext("a")
|
|
})
|
|
]
|
|
})
|
|
];
|
|
|
|
// subitem 3 will be hidden
|
|
let hiddenItems = [items[0].items[2]];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, hiddenItems, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Tests that the click event on sub menuitem
|
|
// tiggers the click event for the sub menuitem and the parent menu
|
|
exports.testSubItemClick = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let state = 0;
|
|
|
|
let items = [
|
|
loader.cm.Menu({
|
|
label: "menu 1",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 1",
|
|
data: "foobar",
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function(msg) {
|
|
assert.equal(msg.tagName, "HTML", "should have seen the right node");
|
|
assert.equal(msg.data, "foobar", "should have seen the right data");
|
|
assert.equal(state, 0, "should have seen the event at the right time");
|
|
state++;
|
|
}
|
|
})
|
|
],
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function(msg) {
|
|
assert.equal(msg.tagName, "HTML", "should have seen the right node");
|
|
assert.equal(msg.data, "foobar", "should have seen the right data");
|
|
assert.equal(state, 1, "should have seen the event at the right time");
|
|
|
|
test.done();
|
|
}
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
|
|
let topMenuElt = test.getItemElt(popup, items[0]);
|
|
let topMenuPopup = topMenuElt.firstChild;
|
|
let itemElt = test.getItemElt(topMenuPopup, items[0].items[0]);
|
|
itemElt.click();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Tests that the command event on sub menuitem
|
|
// tiggers the click event for the sub menuitem and the parent menu
|
|
exports.testSubItemCommand = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let state = 0;
|
|
|
|
let items = [
|
|
loader.cm.Menu({
|
|
label: "menu 1",
|
|
items: [
|
|
loader.cm.Item({
|
|
label: "subitem 1",
|
|
data: "foobar",
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function(msg) {
|
|
assert.equal(msg.tagName, "HTML", "should have seen the right node");
|
|
assert.equal(msg.data, "foobar", "should have seen the right data");
|
|
assert.equal(state, 0, "should have seen the event at the right time");
|
|
state++;
|
|
}
|
|
})
|
|
],
|
|
contentScript: 'self.on("click", function (node, data) {' +
|
|
' self.postMessage({' +
|
|
' tagName: node.tagName,' +
|
|
' data: data' +
|
|
' });' +
|
|
'});',
|
|
onMessage: function(msg) {
|
|
assert.equal(msg.tagName, "HTML", "should have seen the right node");
|
|
assert.equal(msg.data, "foobar", "should have seen the right data");
|
|
assert.equal(state, 1, "should have seen the event at the right time");
|
|
state++
|
|
|
|
test.done();
|
|
}
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
|
|
let topMenuElt = test.getItemElt(popup, items[0]);
|
|
let topMenuPopup = topMenuElt.firstChild;
|
|
let itemElt = test.getItemElt(topMenuPopup, items[0].items[0]);
|
|
|
|
// create a command event
|
|
let evt = itemElt.ownerDocument.createEvent('Event');
|
|
evt.initEvent('command', true, true);
|
|
itemElt.dispatchEvent(evt);
|
|
});
|
|
});
|
|
};
|
|
|
|
// Tests that opening a context menu for an outer frame when an inner frame
|
|
// has a selection doesn't activate the SelectionContext
|
|
exports.testSelectionInInnerFrameNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let state = 0;
|
|
|
|
let items = [
|
|
loader.cm.Item({
|
|
label: "test item",
|
|
context: loader.cm.SelectionContext()
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let frame = doc.getElementById("iframe");
|
|
frame.contentWindow.getSelection().selectAllChildren(frame.contentDocument.body);
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, items, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Tests that opening a context menu for an inner frame when the inner frame
|
|
// has a selection does activate the SelectionContext
|
|
exports.testSelectionInInnerFrameMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let state = 0;
|
|
|
|
let items = [
|
|
loader.cm.Item({
|
|
label: "test item",
|
|
context: loader.cm.SelectionContext()
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let frame = doc.getElementById("iframe");
|
|
frame.contentWindow.getSelection().selectAllChildren(frame.contentDocument.body);
|
|
|
|
test.showMenu(frame.contentDocument.getElementById("text"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Tests that opening a context menu for an inner frame when the outer frame
|
|
// has a selection doesn't activate the SelectionContext
|
|
exports.testSelectionInOuterFrameNoMatch = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let state = 0;
|
|
|
|
let items = [
|
|
loader.cm.Item({
|
|
label: "test item",
|
|
context: loader.cm.SelectionContext()
|
|
})
|
|
];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let frame = doc.getElementById("iframe");
|
|
window.getSelection().selectAllChildren(doc.body);
|
|
|
|
test.showMenu(frame.contentDocument.getElementById("text"), function (popup) {
|
|
test.checkMenu(items, items, []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test that the return value of the predicate function determines if
|
|
// item is shown
|
|
exports.testPredicateContextControl = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let itemTrue = loader.cm.Item({
|
|
label: "visible",
|
|
context: loader.cm.PredicateContext(function () { return true; })
|
|
});
|
|
|
|
let itemFalse = loader.cm.Item({
|
|
label: "hidden",
|
|
context: loader.cm.PredicateContext(function () { return false; })
|
|
});
|
|
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu([itemTrue, itemFalse], [itemFalse], []);
|
|
test.done();
|
|
});
|
|
};
|
|
|
|
// Test that the data object has the correct document type
|
|
exports.testPredicateContextDocumentType = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.equal(data.documentType, 'text/html');
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object has the correct document URL
|
|
exports.testPredicateContextDocumentURL = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.equal(data.documentURL, TEST_DOC_URL);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test that the data object has the correct element name
|
|
exports.testPredicateContextTargetName = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.targetName, "input");
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("button"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test that the data object has the correct ID
|
|
exports.testPredicateContextTargetIDSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.targetID, "button");
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("button"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object has the correct ID
|
|
exports.testPredicateContextTargetIDNotSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.targetID, null);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementsByClassName("predicate-test-a")[0], function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object is showing editable correctly for regular text inputs
|
|
exports.testPredicateContextTextBoxIsEditable = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.isEditable, true);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("textbox"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object is showing editable correctly for readonly text inputs
|
|
exports.testPredicateContextReadonlyTextBoxIsNotEditable = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.isEditable, false);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("readonly-textbox"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object is showing editable correctly for disabled text inputs
|
|
exports.testPredicateContextDisabledTextBoxIsNotEditable = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.isEditable, false);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("disabled-textbox"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object is showing editable correctly for text areas
|
|
exports.testPredicateContextTextAreaIsEditable = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.isEditable, true);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("textfield"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that non-text inputs are not considered editable
|
|
exports.testPredicateContextButtonIsNotEditable = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.isEditable, false);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("button"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test that the data object is showing editable correctly
|
|
exports.testPredicateContextNonInputIsNotEditable = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.isEditable, false);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test that the data object is showing editable correctly for HTML contenteditable elements
|
|
exports.testPredicateContextEditableElement = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.isEditable, true);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("editable"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test that the data object does not have a selection when there is none
|
|
exports.testPredicateContextNoSelectionInPage = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.selectionText, null);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object includes the selected page text
|
|
exports.testPredicateContextSelectionInPage = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
// since we might get whitespace
|
|
assert.ok(data.selectionText && data.selectionText.search(/^\s*Some text.\s*$/) != -1,
|
|
'Expected "Some text.", got "' + data.selectionText + '"');
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
window.getSelection().selectAllChildren(doc.getElementById("text"));
|
|
test.showMenu(null, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object includes the selected input text
|
|
exports.testPredicateContextSelectionInTextBox = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
// since we might get whitespace
|
|
assert.strictEqual(data.selectionText, "t v");
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
let textbox = doc.getElementById("textbox");
|
|
textbox.focus();
|
|
textbox.setSelectionRange(3, 6);
|
|
test.showMenu(textbox, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object has the correct src for an image
|
|
exports.testPredicateContextTargetSrcSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
let image;
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.srcURL, image.src);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
image = doc.getElementById("image");
|
|
test.showMenu(image, function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object has no src for a link
|
|
exports.testPredicateContextTargetSrcNotSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.srcURL, null);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("link"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// Test that the data object has the correct link set
|
|
exports.testPredicateContextTargetLinkSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
let image;
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.linkURL, TEST_DOC_URL + "#test");
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementsByClassName("predicate-test-a")[0], function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object has no link for an image
|
|
exports.testPredicateContextTargetLinkNotSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.linkURL, null);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object has the value for an input textbox
|
|
exports.testPredicateContextTargetValueSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
let image;
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.value, "test value");
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("textbox"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
// Test that the data object has no value for an image
|
|
exports.testPredicateContextTargetValueNotSet = function (assert, done) {
|
|
let test = new TestHelper(assert, done);
|
|
let loader = test.newLoader();
|
|
|
|
let items = [loader.cm.Item({
|
|
label: "item",
|
|
context: loader.cm.PredicateContext(function (data) {
|
|
assert.strictEqual(data.value, null);
|
|
return true;
|
|
})
|
|
})];
|
|
|
|
test.withTestDoc(function (window, doc) {
|
|
test.showMenu(doc.getElementById("image"), function (popup) {
|
|
test.checkMenu(items, [], []);
|
|
test.done();
|
|
});
|
|
});
|
|
};
|
|
|
|
|
|
// NO TESTS BELOW THIS LINE! ///////////////////////////////////////////////////
|
|
|
|
// This makes it easier to run tests by handling things like opening the menu,
|
|
// opening new windows, making assertions, etc. Methods on |test| can be called
|
|
// on instances of this class. Don't forget to call done() to end the test!
|
|
// WARNING: This looks up items in popups by comparing labels, so don't give two
|
|
// items the same label.
|
|
function TestHelper(assert, done) {
|
|
this.assert = assert;
|
|
this.end = done;
|
|
this.loaders = [];
|
|
this.browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"].
|
|
getService(Ci.nsIWindowMediator).
|
|
getMostRecentWindow("navigator:browser");
|
|
this.overflowThreshValue = require("sdk/preferences/service").
|
|
get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT);
|
|
}
|
|
|
|
TestHelper.prototype = {
|
|
get contextMenuPopup() {
|
|
return this.browserWindow.document.getElementById("contentAreaContextMenu");
|
|
},
|
|
|
|
get contextMenuSeparator() {
|
|
return this.browserWindow.document.querySelector("." + SEPARATOR_CLASS);
|
|
},
|
|
|
|
get overflowPopup() {
|
|
return this.browserWindow.document.querySelector("." + OVERFLOW_POPUP_CLASS);
|
|
},
|
|
|
|
get overflowSubmenu() {
|
|
return this.browserWindow.document.querySelector("." + OVERFLOW_MENU_CLASS);
|
|
},
|
|
|
|
get tabBrowser() {
|
|
return this.browserWindow.gBrowser;
|
|
},
|
|
|
|
// Methods on the wrapped test can be called on this object.
|
|
__noSuchMethod__: function (methodName, args) {
|
|
this.assert[methodName].apply(this.assert, args);
|
|
},
|
|
|
|
// Asserts that elt, a DOM element representing item, looks OK.
|
|
checkItemElt: function (elt, item) {
|
|
let itemType = this.getItemType(item);
|
|
|
|
switch (itemType) {
|
|
case "Item":
|
|
this.assert.equal(elt.localName, "menuitem",
|
|
"Item DOM element should be a xul:menuitem");
|
|
if (typeof(item.data) === "string") {
|
|
this.assert.equal(elt.getAttribute("value"), item.data,
|
|
"Item should have correct data");
|
|
}
|
|
break
|
|
case "Menu":
|
|
this.assert.equal(elt.localName, "menu",
|
|
"Menu DOM element should be a xul:menu");
|
|
let subPopup = elt.firstChild;
|
|
this.assert.ok(subPopup, "xul:menu should have a child");
|
|
this.assert.equal(subPopup.localName, "menupopup",
|
|
"xul:menu's first child should be a menupopup");
|
|
break;
|
|
case "Separator":
|
|
this.assert.equal(elt.localName, "menuseparator",
|
|
"Separator DOM element should be a xul:menuseparator");
|
|
break;
|
|
}
|
|
|
|
if (itemType === "Item" || itemType === "Menu") {
|
|
this.assert.equal(elt.getAttribute("label"), item.label,
|
|
"Item should have correct title");
|
|
if (typeof(item.image) === "string") {
|
|
this.assert.equal(elt.getAttribute("image"), item.image,
|
|
"Item should have correct image");
|
|
if (itemType === "Menu")
|
|
this.assert.ok(elt.classList.contains("menu-iconic"),
|
|
"Menus with images should have the correct class")
|
|
else
|
|
this.assert.ok(elt.classList.contains("menuitem-iconic"),
|
|
"Items with images should have the correct class")
|
|
}
|
|
else {
|
|
this.assert.ok(!elt.getAttribute("image"),
|
|
"Item should not have image");
|
|
this.assert.ok(!elt.classList.contains("menu-iconic") && !elt.classList.contains("menuitem-iconic"),
|
|
"The iconic classes should not be present")
|
|
}
|
|
}
|
|
},
|
|
|
|
// Asserts that the context menu looks OK given the arguments. presentItems
|
|
// are items that have been added to the menu. absentItems are items that
|
|
// shouldn't match the current context. removedItems are items that have been
|
|
// removed from the menu.
|
|
checkMenu: function (presentItems, absentItems, removedItems) {
|
|
// Count up how many top-level items there are
|
|
let total = 0;
|
|
for (let item of presentItems) {
|
|
if (absentItems.indexOf(item) < 0 && removedItems.indexOf(item) < 0)
|
|
total++;
|
|
}
|
|
|
|
let separator = this.contextMenuSeparator;
|
|
if (total == 0) {
|
|
this.assert.ok(!separator || separator.hidden,
|
|
"separator should not be present");
|
|
}
|
|
else {
|
|
this.assert.ok(separator && !separator.hidden,
|
|
"separator should be present");
|
|
}
|
|
|
|
let mainNodes = this.browserWindow.document.querySelectorAll("#contentAreaContextMenu > ." + ITEM_CLASS);
|
|
let overflowNodes = this.browserWindow.document.querySelectorAll("." + OVERFLOW_POPUP_CLASS + " > ." + ITEM_CLASS);
|
|
|
|
this.assert.ok(mainNodes.length == 0 || overflowNodes.length == 0,
|
|
"Should only see nodes at the top level or in overflow");
|
|
|
|
let overflow = this.overflowSubmenu;
|
|
if (this.shouldOverflow(total)) {
|
|
this.assert.ok(overflow && !overflow.hidden,
|
|
"overflow menu should be present");
|
|
this.assert.equal(mainNodes.length, 0,
|
|
"should be no items in the main context menu");
|
|
}
|
|
else {
|
|
this.assert.ok(!overflow || overflow.hidden,
|
|
"overflow menu should not be present");
|
|
// When visible nodes == 0 they could be in overflow or top level
|
|
if (total > 0) {
|
|
this.assert.equal(overflowNodes.length, 0,
|
|
"should be no items in the overflow context menu");
|
|
}
|
|
}
|
|
|
|
// Iterate over wherever the nodes have ended up
|
|
let nodes = mainNodes.length ? mainNodes : overflowNodes;
|
|
this.checkNodes(nodes, presentItems, absentItems, removedItems)
|
|
let pos = 0;
|
|
},
|
|
|
|
// Recurses through the item hierarchy of presentItems comparing it to the
|
|
// node hierarchy of nodes. Any items in removedItems will be skipped (so
|
|
// should not exist in the XUL), any items in absentItems must exist and be
|
|
// hidden
|
|
checkNodes: function (nodes, presentItems, absentItems, removedItems) {
|
|
let pos = 0;
|
|
for (let item of presentItems) {
|
|
// Removed items shouldn't be in the list
|
|
if (removedItems.indexOf(item) >= 0)
|
|
continue;
|
|
|
|
if (nodes.length <= pos) {
|
|
this.assert.ok(false, "Not enough nodes");
|
|
return;
|
|
}
|
|
|
|
let hidden = absentItems.indexOf(item) >= 0;
|
|
|
|
this.checkItemElt(nodes[pos], item);
|
|
this.assert.equal(nodes[pos].hidden, hidden,
|
|
"hidden should be set correctly");
|
|
|
|
// The contents of hidden menus doesn't matter so much
|
|
if (!hidden && this.getItemType(item) == "Menu") {
|
|
this.assert.equal(nodes[pos].firstChild.localName, "menupopup",
|
|
"menu XUL should contain a menupopup");
|
|
this.checkNodes(nodes[pos].firstChild.childNodes, item.items, absentItems, removedItems);
|
|
}
|
|
|
|
if (pos > 0)
|
|
this.assert.equal(nodes[pos].previousSibling, nodes[pos - 1],
|
|
"nodes should all be in the same group");
|
|
pos++;
|
|
}
|
|
|
|
this.assert.equal(nodes.length, pos,
|
|
"should have checked all the XUL nodes");
|
|
},
|
|
|
|
// Attaches an event listener to node. The listener is automatically removed
|
|
// when it's fired (so it's assumed it will fire), and callback is called
|
|
// after a short delay. Since the module we're testing relies on the same
|
|
// event listeners to do its work, this is to give them a little breathing
|
|
// room before callback runs. Inside callback |this| is this object.
|
|
// Optionally you can pass a function to test if the event is the event you
|
|
// want.
|
|
delayedEventListener: function (node, event, callback, useCapture, isValid) {
|
|
const self = this;
|
|
node.addEventListener(event, function handler(evt) {
|
|
if (isValid && !isValid(evt))
|
|
return;
|
|
node.removeEventListener(event, handler, useCapture);
|
|
timer.setTimeout(function () {
|
|
try {
|
|
callback.call(self, evt);
|
|
}
|
|
catch (err) {
|
|
self.assert.fail(err);
|
|
self.end();
|
|
}
|
|
}, 20);
|
|
}, useCapture);
|
|
},
|
|
|
|
// Call to finish the test.
|
|
done: function () {
|
|
const self = this;
|
|
function commonDone() {
|
|
this.closeTab();
|
|
|
|
while (this.loaders.length) {
|
|
this.loaders[0].unload();
|
|
}
|
|
|
|
require("sdk/preferences/service").set(OVERFLOW_THRESH_PREF, self.overflowThreshValue);
|
|
|
|
this.end();
|
|
}
|
|
|
|
function closeBrowserWindow() {
|
|
if (this.oldBrowserWindow) {
|
|
this.delayedEventListener(this.browserWindow, "unload", commonDone,
|
|
false);
|
|
this.browserWindow.close();
|
|
this.browserWindow = this.oldBrowserWindow;
|
|
delete this.oldBrowserWindow;
|
|
}
|
|
else {
|
|
commonDone.call(this);
|
|
}
|
|
};
|
|
|
|
if (this.contextMenuPopup.state == "closed") {
|
|
closeBrowserWindow.call(this);
|
|
}
|
|
else {
|
|
this.delayedEventListener(this.contextMenuPopup, "popuphidden",
|
|
function () closeBrowserWindow.call(this),
|
|
false);
|
|
this.contextMenuPopup.hidePopup();
|
|
}
|
|
},
|
|
|
|
closeTab: function() {
|
|
if (this.tab) {
|
|
this.tabBrowser.removeTab(this.tab);
|
|
this.tabBrowser.selectedTab = this.oldSelectedTab;
|
|
this.tab = null;
|
|
}
|
|
},
|
|
|
|
// Returns the DOM element in popup corresponding to item.
|
|
// WARNING: The element is found by comparing labels, so don't give two items
|
|
// the same label.
|
|
getItemElt: function (popup, item) {
|
|
let nodes = popup.childNodes;
|
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
if (this.getItemType(item) === "Separator") {
|
|
if (nodes[i].localName === "menuseparator")
|
|
return nodes[i];
|
|
}
|
|
else if (nodes[i].getAttribute("label") === item.label)
|
|
return nodes[i];
|
|
}
|
|
return null;
|
|
},
|
|
|
|
// Returns "Item", "Menu", or "Separator".
|
|
getItemType: function (item) {
|
|
// Could use instanceof here, but that would require accessing the loader
|
|
// that created the item, and I don't want to A) somehow search through the
|
|
// this.loaders list to find it, and B) assume there are any live loaders at
|
|
// all.
|
|
return /^\[object (Item|Menu|Separator)/.exec(item.toString())[1];
|
|
},
|
|
|
|
// Returns a wrapper around a new loader: { loader, cm, unload, globalScope }.
|
|
// loader is a Cuddlefish sandboxed loader, cm is the context menu module,
|
|
// globalScope is the context menu module's global scope, and unload is a
|
|
// function that unloads the loader and associated resources.
|
|
newLoader: function () {
|
|
const self = this;
|
|
let loader = Loader(module);
|
|
let wrapper = {
|
|
loader: loader,
|
|
cm: loader.require("sdk/context-menu"),
|
|
globalScope: loader.sandbox("sdk/context-menu"),
|
|
unload: function () {
|
|
loader.unload();
|
|
let idx = self.loaders.indexOf(wrapper);
|
|
if (idx < 0)
|
|
throw new Error("Test error: tried to unload nonexistent loader");
|
|
self.loaders.splice(idx, 1);
|
|
}
|
|
};
|
|
this.loaders.push(wrapper);
|
|
return wrapper;
|
|
},
|
|
|
|
// As above but the loader has private-browsing support enabled.
|
|
newPrivateLoader: function() {
|
|
let base = require("@loader/options");
|
|
|
|
// Clone current loader's options adding the private-browsing permission
|
|
let options = merge({}, base, {
|
|
metadata: merge({}, base.metadata || {}, {
|
|
permissions: merge({}, base.metadata.permissions || {}, {
|
|
'private-browsing': true
|
|
})
|
|
})
|
|
});
|
|
|
|
const self = this;
|
|
let loader = Loader(module, null, options);
|
|
let wrapper = {
|
|
loader: loader,
|
|
cm: loader.require("sdk/context-menu"),
|
|
globalScope: loader.sandbox("sdk/context-menu"),
|
|
unload: function () {
|
|
loader.unload();
|
|
let idx = self.loaders.indexOf(wrapper);
|
|
if (idx < 0)
|
|
throw new Error("Test error: tried to unload nonexistent loader");
|
|
self.loaders.splice(idx, 1);
|
|
}
|
|
};
|
|
this.loaders.push(wrapper);
|
|
return wrapper;
|
|
},
|
|
|
|
// Returns true if the count crosses the overflow threshold.
|
|
shouldOverflow: function (count) {
|
|
return count >
|
|
(this.loaders.length ?
|
|
this.loaders[0].loader.require("sdk/preferences/service").
|
|
get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT) :
|
|
OVERFLOW_THRESH_DEFAULT);
|
|
},
|
|
|
|
// Opens the context menu on the current page. If targetNode is null, the
|
|
// menu is opened in the top-left corner. onShowncallback is passed the
|
|
// popup.
|
|
showMenu: function(targetNode, onshownCallback) {
|
|
function sendEvent() {
|
|
this.delayedEventListener(this.browserWindow, "popupshowing",
|
|
function (e) {
|
|
let popup = e.target;
|
|
onshownCallback.call(this, popup);
|
|
}, false);
|
|
|
|
let rect = targetNode ?
|
|
targetNode.getBoundingClientRect() :
|
|
{ left: 0, top: 0, width: 0, height: 0 };
|
|
let contentWin = targetNode ? targetNode.ownerDocument.defaultView
|
|
: this.browserWindow.content;
|
|
contentWin.
|
|
QueryInterface(Ci.nsIInterfaceRequestor).
|
|
getInterface(Ci.nsIDOMWindowUtils).
|
|
sendMouseEvent("contextmenu",
|
|
rect.left + (rect.width / 2),
|
|
rect.top + (rect.height / 2),
|
|
2, 1, 0);
|
|
}
|
|
|
|
// If a new tab or window has not yet been opened, open a new tab now. For
|
|
// some reason using the tab already opened when the test starts causes
|
|
// leaks. See bug 566351 for details.
|
|
if (!targetNode && !this.oldSelectedTab && !this.oldBrowserWindow) {
|
|
this.oldSelectedTab = this.tabBrowser.selectedTab;
|
|
this.tab = this.tabBrowser.addTab("about:blank");
|
|
let browser = this.tabBrowser.getBrowserForTab(this.tab);
|
|
|
|
this.delayedEventListener(browser, "load", function () {
|
|
this.tabBrowser.selectedTab = this.tab;
|
|
sendEvent.call(this);
|
|
}, true);
|
|
}
|
|
else
|
|
sendEvent.call(this);
|
|
},
|
|
|
|
hideMenu: function(onhiddenCallback) {
|
|
this.delayedEventListener(this.browserWindow, "popuphidden", onhiddenCallback);
|
|
|
|
this.contextMenuPopup.hidePopup();
|
|
},
|
|
|
|
// Opens a new browser window. The window will be closed automatically when
|
|
// done() is called.
|
|
withNewWindow: function (onloadCallback) {
|
|
let win = this.browserWindow.OpenBrowserWindow();
|
|
this.delayedEventListener(win, "load", onloadCallback, true);
|
|
this.oldBrowserWindow = this.browserWindow;
|
|
this.browserWindow = win;
|
|
},
|
|
|
|
// Opens a new private browser window. The window will be closed
|
|
// automatically when done() is called.
|
|
withNewPrivateWindow: function (onloadCallback) {
|
|
let win = this.browserWindow.OpenBrowserWindow({private: true});
|
|
this.delayedEventListener(win, "load", onloadCallback, true);
|
|
this.oldBrowserWindow = this.browserWindow;
|
|
this.browserWindow = win;
|
|
},
|
|
|
|
// Opens a new tab with our test page in the current window. The tab will
|
|
// be closed automatically when done() is called.
|
|
withTestDoc: function (onloadCallback) {
|
|
this.oldSelectedTab = this.tabBrowser.selectedTab;
|
|
this.tab = this.tabBrowser.addTab(TEST_DOC_URL);
|
|
let browser = this.tabBrowser.getBrowserForTab(this.tab);
|
|
|
|
this.delayedEventListener(browser, "load", function () {
|
|
this.tabBrowser.selectedTab = this.tab;
|
|
onloadCallback.call(this, browser.contentWindow, browser.contentDocument);
|
|
}, true, function(evt) {
|
|
return evt.target.location == TEST_DOC_URL;
|
|
});
|
|
}
|
|
};
|
|
|
|
require('sdk/test').run(exports);
|