diff options
author | Kris Maglione <maglione.k@gmail.com> | 2011-01-26 16:22:29 -0500 |
---|---|---|
committer | Kris Maglione <maglione.k@gmail.com> | 2011-01-26 16:22:29 -0500 |
commit | 218562e21b0ab73b58102653543c5107ee23c2bc (patch) | |
tree | c5fe08c6e4c7675179fbb31b38cb10547417d473 /common | |
parent | a6fe97b787007bba0ea5e310aa70fc5853ce4173 (diff) | |
download | pentadactyl-218562e21b0ab73b58102653543c5107ee23c2bc.tar.gz |
Fix tab number updates in FF36. Closes issue 300.
Diffstat (limited to 'common')
47 files changed, 400 insertions, 8580 deletions
diff --git a/common/content/browser.js b/common/content/browser.js index fd00987e..ac647fee 100644 --- a/common/content/browser.js +++ b/common/content/browser.js @@ -65,7 +65,7 @@ var Browser = Module("browser", { mappings: function () { mappings.add([modes.NORMAL], - ["y"], "Yank current location to the clipboard", + ["y", "<yank-location>"], "Yank current location to the clipboard", function () { dactyl.clipboardWrite(buffer.uri.spec, true); }); // opening websites diff --git a/common/content/buffer.js b/common/content/buffer.js index 1bbaab99..05223fe4 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -1651,7 +1651,7 @@ var Buffer = Module("buffer", { mappings: function () { var myModes = config.browserModes; - mappings.add(myModes, ["."], + mappings.add(myModes, [".", "<repeat-key>"], "Repeat the last key event", function (args) { if (mappings.repeat) { @@ -1670,31 +1670,31 @@ var Buffer = Module("buffer", { function () { ex.stop(); }); // scrolling - mappings.add(myModes, ["j", "<Down>", "<C-e>"], + mappings.add(myModes, ["j", "<Down>", "<C-e>", "<scroll-down-line>"], "Scroll document down", function (args) { buffer.scrollVertical("lines", Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, ["k", "<Up>", "<C-y>"], + mappings.add(myModes, ["k", "<Up>", "<C-y>", "<scroll-up-line>"], "Scroll document up", function (args) { buffer.scrollVertical("lines", -Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, dactyl.has("mail") ? ["h"] : ["h", "<Left>"], + mappings.add(myModes, dactyl.has("mail") ? ["h", "<scroll-left-column>"] : ["h", "<Left>", "<scroll-left-column>"], "Scroll document to the left", function (args) { buffer.scrollHorizontal("columns", -Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, dactyl.has("mail") ? ["l"] : ["l", "<Right>"], + mappings.add(myModes, dactyl.has("mail") ? ["l", "<scroll-right-column>"] : ["l", "<Right>", "<scroll-right-column>"], "Scroll document to the right", function (args) { buffer.scrollHorizontal("columns", Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, ["0", "^"], + mappings.add(myModes, ["0", "^", "<scroll-begin>"], "Scroll to the absolute left of the document", function () { buffer.scrollToPercent(0, null); }); - mappings.add(myModes, ["$"], + mappings.add(myModes, ["$", "<scroll-end>"], "Scroll to the absolute right of the document", function () { buffer.scrollToPercent(100, null); }); @@ -1708,7 +1708,7 @@ var Buffer = Module("buffer", { function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 100); }, { count: true }); - mappings.add(myModes, ["%"], + mappings.add(myModes, ["%", "<scroll-percent>"], "Scroll to {count} percent of the document", function (args) { dactyl.assert(args.count > 0 && args.count <= 100); @@ -1716,59 +1716,59 @@ var Buffer = Module("buffer", { }, { count: true }); - mappings.add(myModes, ["<C-d>"], + mappings.add(myModes, ["<C-d>", "<scroll-down>"], "Scroll window downwards in the buffer", function (args) { buffer._scrollByScrollSize(args.count, true); }, { count: true }); - mappings.add(myModes, ["<C-u>"], + mappings.add(myModes, ["<C-u>", "<scroll-up>"], "Scroll window upwards in the buffer", function (args) { buffer._scrollByScrollSize(args.count, false); }, { count: true }); - mappings.add(myModes, ["<C-b>", "<PageUp>", "<S-Space>"], + mappings.add(myModes, ["<C-b>", "<PageUp>", "<S-Space>", "<scroll-page-up>"], "Scroll up a full page", function (args) { buffer.scrollVertical("pages", -Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, ["<C-f>", "<PageDown>", "<Space>"], + mappings.add(myModes, ["<C-f>", "<PageDown>", "<Space>", "<scroll-page-down>"], "Scroll down a full page", function (args) { buffer.scrollVertical("pages", Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, ["]f"], + mappings.add(myModes, ["]f", "<previous-frame>"], "Focus next frame", function (args) { buffer.shiftFrameFocus(Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, ["[f"], + mappings.add(myModes, ["[f", "<next-frame>"], "Focus previous frame", function (args) { buffer.shiftFrameFocus(-Math.max(args.count, 1)); }, { count: true }); - mappings.add(myModes, ["]]"], + mappings.add(myModes, ["]]", "<next-page>"], "Follow the link labeled 'next' or '>' if it exists", function (args) { buffer.findLink("next", options["nextpattern"], (args.count || 1) - 1, true); }, { count: true }); - mappings.add(myModes, ["[["], + mappings.add(myModes, ["[[", "<previous-page>"], "Follow the link labeled 'prev', 'previous' or '<' if it exists", function (args) { buffer.findLink("previous", options["previouspattern"], (args.count || 1) - 1, true); }, { count: true }); - mappings.add(myModes, ["gf"], + mappings.add(myModes, ["gf", "<view-source>"], "Toggle between rendered and source view", function () { buffer.viewSource(null, false); }); - mappings.add(myModes, ["gF"], + mappings.add(myModes, ["gF", "<view-source-externally>"], "View source with an external editor", function () { buffer.viewSource(null, true); }); - mappings.add(myModes, ["gi"], + mappings.add(myModes, ["gi", "<focus-input>"], "Focus last used input field", function (args) { let elem = buffer.lastInputField; @@ -1808,7 +1808,7 @@ var Buffer = Module("buffer", { dactyl.open(url, { from: "paste", where: dactyl.NEW_TAB, background: true }); }); - mappings.add(myModes, ["p", "<MiddleMouse>"], + mappings.add(myModes, ["p", "<MiddleMouse>", "<open-clipboard-url>"], "Open (put) a URL based on the current clipboard contents in the current buffer", function () { let url = dactyl.clipboardRead(); @@ -1816,7 +1816,7 @@ var Buffer = Module("buffer", { dactyl.open(url); }); - mappings.add(myModes, ["P"], + mappings.add(myModes, ["P", "<tab-open-clipboard-url>"], "Open (put) a URL based on the current clipboard contents in a new buffer", function () { let url = dactyl.clipboardRead(); @@ -1825,16 +1825,16 @@ var Buffer = Module("buffer", { }); // reloading - mappings.add(myModes, ["r"], + mappings.add(myModes, ["r", "<reload>"], "Reload the current web page", function () { tabs.reload(tabs.getTab(), false); }); - mappings.add(myModes, ["R"], + mappings.add(myModes, ["R", "<full-reload>"], "Reload while skipping the cache", function () { tabs.reload(tabs.getTab(), true); }); // yanking - mappings.add(myModes, ["Y"], + mappings.add(myModes, ["Y", "<yank-word>"], "Copy selected text or current word", function () { let sel = buffer.getCurrentWord(); @@ -1843,62 +1843,62 @@ var Buffer = Module("buffer", { }); // zooming - mappings.add(myModes, ["zi", "+"], + mappings.add(myModes, ["zi", "+", "<text-zoom-in>"], "Enlarge text zoom of current web page", function (args) { buffer.zoomIn(Math.max(args.count, 1), false); }, { count: true }); - mappings.add(myModes, ["zm"], + mappings.add(myModes, ["zm", "<text-zoom-more>"], "Enlarge text zoom of current web page by a larger amount", function (args) { buffer.zoomIn(Math.max(args.count, 1) * 3, false); }, { count: true }); - mappings.add(myModes, ["zo", "-"], + mappings.add(myModes, ["zo", "-", "<text-zoom-out>"], "Reduce text zoom of current web page", function (args) { buffer.zoomOut(Math.max(args.count, 1), false); }, { count: true }); - mappings.add(myModes, ["zr"], + mappings.add(myModes, ["zr", "<text-zoom-reduce>"], "Reduce text zoom of current web page by a larger amount", function (args) { buffer.zoomOut(Math.max(args.count, 1) * 3, false); }, { count: true }); - mappings.add(myModes, ["zz"], + mappings.add(myModes, ["zz", "<text-zoom>"], "Set text zoom value of current web page", function (args) { buffer.setZoom(args.count > 1 ? args.count : 100, false); }, { count: true }); - mappings.add(myModes, ["ZI", "zI"], + mappings.add(myModes, ["ZI", "zI", "<full-zoom-in>"], "Enlarge full zoom of current web page", function (args) { buffer.zoomIn(Math.max(args.count, 1), true); }, { count: true }); - mappings.add(myModes, ["ZM", "zM"], + mappings.add(myModes, ["ZM", "zM", "<full-zoom-more>"], "Enlarge full zoom of current web page by a larger amount", function (args) { buffer.zoomIn(Math.max(args.count, 1) * 3, true); }, { count: true }); - mappings.add(myModes, ["ZO", "zO"], + mappings.add(myModes, ["ZO", "zO", "<full-zoom-out>"], "Reduce full zoom of current web page", function (args) { buffer.zoomOut(Math.max(args.count, 1), true); }, { count: true }); - mappings.add(myModes, ["ZR", "zR"], + mappings.add(myModes, ["ZR", "zR", "<full-zoom-reduce>"], "Reduce full zoom of current web page by a larger amount", function (args) { buffer.zoomOut(Math.max(args.count, 1) * 3, true); }, { count: true }); - mappings.add(myModes, ["zZ"], + mappings.add(myModes, ["zZ", "<full-zoom>"], "Set full zoom value of current web page", function (args) { buffer.setZoom(args.count > 1 ? args.count : 100, true); }, { count: true }); // page info - mappings.add(myModes, ["<C-g>"], + mappings.add(myModes, ["<C-g>", "<page-info>"], "Print the current file name", function () { buffer.showPageInfo(false); }); - mappings.add(myModes, ["g<C-g>"], + mappings.add(myModes, ["g<C-g>", "<more-page-info>"], "Print file information", function () { buffer.showPageInfo(true); }); }, diff --git a/common/content/commandline.js b/common/content/commandline.js index 77a11e4d..08f091ff 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -148,12 +148,6 @@ var CommandWidgets = Class("CommandWidgets", { return this.commandbar; } }); - - let fontSize = util.computedStyle(document.documentElement).fontSize; - styles.system.add("font-size", "dactyl://content/buffer.xhtml", - "body { font-size: " + fontSize + "; } \ - html|html > xul|scrollbar { visibility: collapse !important; }", - true); }, addElement: function addElement(obj) { const self = this; @@ -301,18 +295,10 @@ var CommandMode = Class("CommandMode", { this.keepCommand = userContext.hidden_option_command_afterimage; if (this.historyKey) - this.history = CommandLine.History(commandline.widgets.active.command.inputField, this.historyKey); + this.history = CommandLine.History(commandline.widgets.active.command.inputField, this.historyKey, this); if (this.complete) - this.completions = CommandLine.Completions(commandline.widgets.active.command.inputField); - - this.autocompleteTimer = Timer(200, 500, function autocompleteTell(tabPressed) { - if (!events.feedingKeys && this.completions && options["autocomplete"].length) { - this.completions.complete(true, false); - if (this.completions) - this.completions.itemList.visible = true; - } - }, this); + this.completions = CommandLine.Completions(commandline.widgets.active.command.inputField, this); }, open: function (command) { @@ -335,17 +321,14 @@ var CommandMode = Class("CommandMode", { commandline.commandSession = this; if (this.command || stack.pop && commandline.command) { this.onChange(commandline.command); - this.autocompleteTimer.flush(true); + if (this.completions) + this.completions.autocompleteTimer.flush(true); } }, leave: function (stack) { - this.autocompleteTimer.reset(); - - if (this.completions) { - this.completions.previewClear(); - this.completions.tabTimer.reset(); - } + if (this.completions) + this.completions.cleanup(); if (this.history) this.history.save(); @@ -368,9 +351,9 @@ var CommandMode = Class("CommandMode", { if (this.completions) { this.resetCompletions(); - this.autocompleteTimer.tell(false); + this.completions.autocompleteTimer.tell(false); if (!this.completions.itemList.visible) - this.autocompleteTimer.flush(); + this.completions.autocompleteTimer.flush(); } this.onChange(commandline.command); }, @@ -614,8 +597,10 @@ var CommandLine = Module("commandline", { if (this.widgets.message && this.widgets.message[1] === this._lastClearable) this.widgets.message = null; - if (modes.main != modes.COMMAND_LINE) + if (!this.commandSession) { this.widgets.command = null; + this.hideCompletions(); + } if (modes.main == modes.OUTPUT_MULTILINE && !mow.isScrollable(1)) modes.pop(); @@ -866,10 +851,11 @@ var CommandLine = Module("commandline", { * @param {string} mode The mode for which we need history. */ History: Class("History", { - init: function init(inputField, mode) { + init: function init(inputField, mode, session) { this.mode = mode; this.input = inputField; this.reset(); + this.session = session; }, get store() commandline._store.get(this.mode, []), set store(ary) { commandline._store.set(this.mode, ary); }, @@ -915,8 +901,9 @@ var CommandLine = Module("commandline", { */ replace: function replace(val) { delete this.input.dactylKeyPress; + if (this.completions) + this.completions.previewClear(); this.input.value = val; - commandline.commandSession.onChange(val, "history"); }, /** @@ -928,8 +915,8 @@ var CommandLine = Module("commandline", { */ select: function select(backward, matchCurrent) { // always reset the tab completion if we use up/down keys - if (commandline._completions) - commandline._completions.reset(); + if (this.session.completions) + this.session.completions.reset(); let diff = backward ? -1 : 1; @@ -976,22 +963,36 @@ var CommandLine = Module("commandline", { * @param {Object} input */ Completions: Class("Completions", { - init: function init(input) { + init: function init(input, session) { this.context = CompletionContext(input.QueryInterface(Ci.nsIDOMNSEditableElement).editor); this.context.onUpdate = this.closure._reset; this.editor = input.editor; this.input = input; + this.session = session; this.selected = null; this.wildmode = options.get("wildmode"); this.wildtypes = this.wildmode.value; this.itemList = commandline.completionList; this.itemList.setItems(this.context); + this.autocompleteTimer = Timer(200, 500, function autocompleteTell(tabPressed) { + if (!events.feedingKeys && options["autocomplete"].length) { + this.complete(true, false); + this.itemList.visible = true; + } + }, this); this.tabTimer = Timer(0, 0, function tabTell(event) { this.tab(event.shiftKey, event.altKey && options["altwildmode"]); }, this); }, + cleanup: function () { + this.previewClear(); + this.tabTimer.reset(); + this.autocompleteTimer.reset(); + this.itemList.visible = false; + }, + UP: {}, DOWN: {}, PAGE_UP: {}, @@ -1038,7 +1039,7 @@ var CommandLine = Module("commandline", { complete: function complete(show, tabPressed) { this.context.reset(); this.context.tabPressed = tabPressed; - commandline.commandSession.complete(this.context); + this.session.complete(this.context); this.context.updateAsync = true; this.reset(show, tabPressed); this.wildIndex = 0; @@ -1204,7 +1205,7 @@ var CommandLine = Module("commandline", { tabs: [], tab: function tab(reverse, wildmode) { - commandline.commandSession.autocompleteTimer.flush(); + this.autocompleteTimer.flush(); if (this._caret != this.caret) this.reset(); diff --git a/common/content/dactyl.js b/common/content/dactyl.js index bb5aa362..3183f37f 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -110,10 +110,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { get menuItems() Dactyl.getMenuItems(), // Global constants - CURRENT_TAB: [], - NEW_TAB: [], - NEW_BACKGROUND_TAB: [], - NEW_WINDOW: [], + CURRENT_TAB: "here", + NEW_TAB: "tab", + NEW_BACKGROUND_TAB: "background-tab", + NEW_WINDOW: "window", forceNewTab: false, forceNewWindow: false, @@ -173,7 +173,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { let filters = args.map(function (arg) RegExp("\\b" + util.regexp.escape(arg) + "\\b", "i")); if (filters.length) - results = results.filter(function (item) filters.every(function (re) re.test(item.name + item.description))); + results = results.filter(function (item) filters.every(function (re) re.test(item.name + " " + item.description))); commandline.commandOutput( template.usage(results, params.format)); @@ -380,15 +380,16 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }, userEval: function (str, context, fileName, lineNumber) { + let ctxt; if (jsmodules.__proto__ != window) str = "with (window) { with (modules) { (this.eval || eval)(" + str.quote() + ") } }"; if (fileName == null) if (io.sourcing && io.sourcing.file[0] !== "[") - ({ file: fileName, line: lineNumber }) = io.sourcing; + ({ file: fileName, line: lineNumber, context: ctxt }) = io.sourcing; else try { if (!context) - context = userContext; + context = userContext || ctxt; context[EVAL_ERROR] = null; context[EVAL_STRING] = str; @@ -411,7 +412,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { } if (!context) - context = _userContext; + context = _userContext || ctxt; return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber); }, @@ -560,9 +561,14 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { * @private */ initDocument: function initDocument(doc) { - if (doc.location.protocol === "dactyl:") { - dactyl.initHelp(); - config.styleHelp(); + try { + if (doc.location.protocol === "dactyl:") { + dactyl.initHelp(); + config.styleHelp(); + } + } + catch (e) { + util.reportError(e); } }, @@ -662,9 +668,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { let re = util.regexp(<![CDATA[ ^ (?P<space> \s*) - (?P<char> [-*+]) \x20 + (?P<char> [-*+]) \ // (?P<content> .*\n - (?: \1\x20\x20.*\n | \s*\n)* ) + (?: \1\ \ .*\n | \s*\n)* ) | (?P<par> (?: ^ [^\S\n]* @@ -676,30 +682,55 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { (?: ^ [^\S\n]* \n) + ]]>, "gmy"); + let betas = util.regexp(/\[(b\d)\]/, "g"); + + let beta = array(betas.iterate(NEWS)) + .map(function (m) m[1]).uniq().slice(-1)[0]; + default xml namespace = NS; - function rec(text, level) { + function rec(text, level, li) { let res = <></>; - let list, space; + let list, space, i = 0; for (let match in re.iterate(text)) { if (match.char) { if (!list) res += list = <ul/>; - list.* += <li>{rec(match.content.replace(RegExp("^" + match.space, "gm"), ""), level + 1)}</li>; + let li = <li/>; + li.* += rec(match.content.replace(RegExp("^" + match.space, "gm"), ""), level + 1, li) + list.* += li; } else if (match.par) { + let [, par, tags] = /([^]*?)\s*((?:\[[^\]]+\])*)\n*$/.exec(match.par); + let t = tags; + tags = array(betas.iterate(tags)).map(function (m) m[1]); + + let group = tags.length && !tags.some(function (t) t == beta) ? "HelpNewsOld" : ""; + if (i === 0 && li) { + li.@highlight = group; + group = ""; + } + list = null; - if (level == 0 && /^.*:\n$/.test(match.par)) - res += <h2>{template.linkifyHelp(match.par.slice(0, -1), true)}</h2>; + if (level == 0 && /^.*:\n$/.test()) + var elem = <h2>{template.linkifyHelp(par.slice(0, -1), true)}</h2>; else { - let [, a, b] = /^(IMPORTANT:?)?([^]*)/.exec(match.par); - res += <p>{ + let [, a, b] = /^(IMPORTANT:?)?([^]*)/.exec(par); + res += <p highlight={group + " HelpNews"}>{ + !tags.length ? "" : + <hl key="HelpNewsTag">{tags.join(" ")}</hl> + }{ a ? <hl key="HelpWarning">{a}</hl> : "" }{ template.linkifyHelp(b, true) }</p>; } } + i++; + } + for each (let attr in res..@highlight) { + attr.parent().@NS::highlight = attr; + delete attr.parent().@highlight; } return res; } @@ -710,7 +741,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { '<?xml-stylesheet type="text/xsl" href="dactyl://content/help.xsl"?>\n' + '<!DOCTYPE document SYSTEM "resource://dactyl-content/dactyl.dtd">\n' + unescape(encodeURI( // UTF-8 handling hack. - <document xmlns={NS} + <document xmlns={NS} xmlns:dactyl={NS} name="versions" title={config.appName + " Versions"}> <h1 tag="versions news">{config.appName} Versions</h1> <toc start="2"/> diff --git a/common/content/events.js b/common/content/events.js index b0cfecee..c70b9cb3 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -11,12 +11,14 @@ var ProcessorStack = Class("ProcessorStack", { init: function (mode, hives, keyModes) { this.main = mode.main; + this._actions = []; this.actions = []; this.buffer = ""; this.events = []; this.processors = keyModes.map(function (m) hives.map(function (h) KeyProcessor(m, h))) .flatten().array; + this.ownsBuffer = !this.processors.some(function (p) p.main.ownsBuffer); for (let [i, input] in Iterator(this.processors)) { let params = input.main.params; @@ -31,9 +33,70 @@ var ProcessorStack = Class("ProcessorStack", { } }, + notify: function () { + this.execute(Events.KILL, true); + }, + + execute: function execute(result, force) { + + if (force && this.actions.length) + this.processors.length = 0; + + if (this.ownsBuffer) + statusline.updateInputBuffer(this.processors.length ? this.buffer : ""); + + if (this.processors.length) { + result = Events.KILL; + if (this.actions.length && options["timeout"]) + this.timer = services.Timer(this, options["timeoutlen"], services.Timer.TYPE_ONE_SHOT); + } + else if (this.actions.length) { + if (this._actions.length == 0) { + dactyl.beep(); + events.feedingKeys = false; + } + + for (var res = this.actions[0]; callable(res);) + res = res(); + result = res === Events.PASS ? Events.PASS : Events.KILL; + } + else if (result !== Events.KILL && !this.actions.length && + this.processors.some(function (p) !p.main.passUnknown)) { + result = Events.KILL; + dactyl.beep(); + events.feedingKeys = false; + } + else if (result === undefined) + result = Events.PASS; + + if (result !== Events.PASS) + Events.kill(this.events[this.events.length - 1]); + + if (result === Events.PASS || result === Events.ABORT) + this.events.filter(function (e) e.getPreventDefault()) + .forEach(function (event, i) { + let elem = event.originalTarget; + if (event.originalTarget) { + let doc = elem.ownerDocument || elem.document || elem; + let evt = events.create(doc, event.type, event); + events.dispatch(elem, evt, { skipmap: true, isMacro: true, isReplay: true }); + } + else if (i > 0) + events.events.keypress.call(events, event); + }); + + if (force && this.processors.length === 0) + events.processor = null; + + return this.processors.length == 0; + }, + process: function process(event) { function dbg() {} + if (this.timer) + this.timer.cancel(); + let key = events.toString(event); this.events.push(event); @@ -70,9 +133,7 @@ var ProcessorStack = Class("ProcessorStack", { dbg("ACTIONS: " + actions.length + " " + this.actions.length); dbg("PROCESSORS:", processors); - if (!processors.some(function (p) p.main.ownsBuffer)) - statusline.updateInputBuffer(processors.length ? this.buffer : ""); - + this._actions = actions; this.actions = actions.concat(this.actions); if (result === Events.KILL) @@ -87,42 +148,7 @@ var ProcessorStack = Class("ProcessorStack", { this.processors = processors; - if (processors.length) - result = Events.KILL; - else if (this.actions.length) { - if (actions.length == 0) - dactyl.beep(); - - if (modes.replaying && !events.waitForPageLoad()) - result = Events.KILL; - else { - for (var res = this.actions[0]; callable(res);) - res = res(); - result = res === Events.PASS ? Events.PASS : Events.KILL; - } - } - else if (result !== Events.KILL && !this.actions.length && - processors.some(function (p) !p.main.passUnknown)) { - result = Events.KILL; - dactyl.beep(); - } - else if (result === undefined) - result = Events.PASS; - - if (result !== Events.PASS) - Events.kill(event); - - if (result === Events.PASS || result === Events.ABORT) - this.events.filter(function (e) e.getPreventDefault()) - .forEach(function (event, i) { - if (event.originalTarget) { - let evt = events.create(event.originalTarget.ownerDocument, event.type, event); - events.dispatch(event.originalTarget, evt, { skipmap: true, isMacro: true }); - } - else if (i > 0) - events.events.keypress.call(events, event); - }); - return this.processors.length == 0; + return this.execute(result, options["timeout"] && options["timeoutlen"] === 0) } }); @@ -491,6 +517,7 @@ var Events = Module("events", { util.threadYield(1, true); for (let [, evt_obj] in Iterator(events.fromString(keys))) { + let now = Date.now(); for (let type in values(["keydown", "keyup", "keypress"])) { let evt = update({}, evt_obj, { type: type }); @@ -511,10 +538,6 @@ var Events = Module("events", { if (!this.feedingKeys) break; - - // Stop feeding keys if page loading failed. - if (modes.replaying && !this.waitForPageLoad()) - break; } } catch (e) { @@ -594,9 +617,14 @@ var Events = Module("events", { * of x. * * @param {string} keys Messy form. + * @param {boolean} unknownOk Whether unknown keys are passed + * through rather than being converted to <lt>keyname>. + * @default false * @returns {string} Canonical form. */ canonicalKeys: function (keys, unknownOk) { + if (arguments.length === 1) + unknownOk = true; return events.fromString(keys, unknownOk).map(events.closure.toString).join(""); }, @@ -651,11 +679,17 @@ var Events = Module("events", { * <S-@> where @ is a non-case-changeable, non-space character. * * @param {string} keys The string to parse. + * @param {boolean} unknownOk Whether unknown keys are passed + * through rather than being converted to <lt>keyname>. + * @default false * @returns {Array[Object]} */ fromString: function (input, unknownOk) { - let out = []; + if (arguments.length === 1) + unknownOk = true; + + let out = []; let re = RegExp("<.*?>?>|[^<]|<(?!.*>)", "g"); let match; while ((match = re.exec(input))) { @@ -862,10 +896,7 @@ var Events = Module("events", { isContentNode: function isContentNode(node) { let win = (node.ownerDocument || node).defaultView || node; - for (; win; win = win.parent != win && win.parent) - if (win == content) - return true; - return false; + return XPCNativeWrapper(win).top == content; }, /** @@ -874,39 +905,24 @@ var Events = Module("events", { * * @returns {boolean} */ - waitForPageLoad: function () { + waitForPageLoad: function (time) { util.threadYield(true); // clear queue - if (buffer.loaded == 1) + if (buffer.loaded) return true; - const maxWaitTime = 25; - let start = Date.now(); - let end = start + (maxWaitTime * 1000); // maximum time to wait - TODO: add option - let now; - while (now = Date.now(), now < end) { - util.threadYield(); + dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE); - if (!events.feedingKeys) - return false; + const maxWaitTime = (time || 25); + let start = Date.now(); + let end = start + (maxWaitTime * 1000); - if (buffer.loaded > 0) { - util.sleep(250); - break; - } - else - dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE); - } + util.waitFor(function () !events.feedingKeys || buffer.loaded || Date.now() > end); commandline.clear(); - // TODO: allow macros to be continued when page does not fully load with an option if (!buffer.loaded) dactyl.echoerr("Page did not load completely in " + maxWaitTime + " seconds. Macro stopped."); - // sometimes the input widget had focus when replaying a macro - // maybe this call should be moved somewhere else? - // dactyl.focusContent(true); - return buffer.loaded; }, @@ -1000,7 +1016,8 @@ var Events = Module("events", { */ input: function onInput(event) { - delete event.originalTarget.dactylKeyPress; + if ("dactylKeyPress" in event.originalTarget) + delete event.originalTarget.dactylKeyPress; }, // this keypress handler gets always called first, even if e.g. @@ -1024,18 +1041,17 @@ var Events = Module("events", { let duringFeed = this.duringFeed || []; this.duringFeed = []; try { - if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) { + if (this.feedingEvent) for (let [k, v] in Iterator(this.feedingEvent)) if (!(k in event)) event[k] = v; - this.feedingEvent = null; - } + this.feedingEvent = null; let key = events.toString(event); if (!key) return null; - if (modes.recording && (!this._input || !mappings.user.hasMap(modes.main, this._input.buffer + key))) + if (modes.recording && !event.isReplay) events._macroKeys.push(key); // feedingKeys needs to be separate from interrupted so @@ -1043,8 +1059,6 @@ var Events = Module("events", { // interrupting whatever it's started and a real <C-c> // interrupting our playback. if (events.feedingKeys && !event.isMacro) { - if (!event.originalTarget) - util.dumpStack(); if (key == "<C-c>") { events.feedingKeys = false; if (modes.replaying) { @@ -1177,10 +1191,6 @@ var Events = Module("events", { // access to the real focus target // Huh? --djk onFocusChange: function onFocusChange(event) { - // command line has its own focus change handler - if (modes.main.input) - return; - function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument let win = window.document.commandDispatcher.focusedWindow; @@ -1202,7 +1212,7 @@ var Events = Module("events", { } if (Events.isInputElement(elem)) { - if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL))) + if (!modes.main.input) modes.push(modes.INSERT); if (hasHTMLDocument(win)) @@ -1216,7 +1226,7 @@ var Events = Module("events", { if (modes.main == modes.VISUAL && elem.selectionEnd == elem.selectionStart) modes.pop(); - if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL))) + if (!modes.main.input) if (options["insertmode"]) modes.push(modes.INSERT); else { @@ -1323,11 +1333,11 @@ var Events = Module("events", { }, mappings: function () { mappings.add(modes.all, - ["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings", + ["<C-z>", "<pass-all-keys>"], "Temporarily ignore all " + config.appName + " key bindings", function () { modes.push(modes.PASS_THROUGH); }); mappings.add(modes.all, - ["<C-v>"], "Pass through next key", + ["<C-v>", "<pass-next-key>"], "Pass through next key", function () { if (modes.main == modes.QUOTE) return Events.PASS; @@ -1340,7 +1350,7 @@ var Events = Module("events", { // macros mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity), - ["q"], "Record a key sequence into a macro", + ["q", "<record-macro>"], "Record a key sequence into a macro", function ({ arg }) { events._macroKeys.pop(); events[modes.recording ? "finishRecording" : "startRecording"](arg); @@ -1348,13 +1358,33 @@ var Events = Module("events", { { get arg() !modes.recording }); mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity), - ["@"], "Play a macro", + ["@", "<play-macro>"], "Play a macro", function ({ arg, count }) { count = Math.max(count, 1); while (count-- && events.playMacro(arg)) ; }, { arg: true, count: true }); + + mappings.add([modes.COMMAND], + ["<A-m>s", "<sleep>"], "Sleep for {count} milliseconds before continuing macro playback", + function ({ command, count }) { + let now = Date.now(); + dactyl.assert(count, "Count required for " + command); + if (events.feedingKeys) + util.sleep(count); + }, + { count: true }); + + mappings.add([modes.COMMAND], + ["<A-m>l", "<wait-for-page-load>"], "Wait for the current page to finish loading before continuing macro playback", + function ({ count }) { + if (events.feedingKeys && !events.waitForPageLoad(count)) { + util.interrupted = true; + throw Error("Interrupted"); + } + }, + { count: true }); }, options: function () { options.add(["passkeys", "pk"], @@ -1375,9 +1405,18 @@ var Events = Module("events", { return values; } }); + options.add(["strictfocus", "sf"], "Prevent scripts from focusing input elements without user intervention", "boolean", true); + + options.add(["timeout", "tmo"], + "Whether to execute a shorter key command after a timeout when a longer command exists", + "boolean", true); + + options.add(["timeoutlen", "tmol"], + "Maximum time (milliseconds) to wait for a longer key command when a shorter one exists", + "number", 1000); }, sanitizer: function () { sanitizer.addItem("macros", { diff --git a/common/content/mappings.js b/common/content/mappings.js index b5255d77..3e86257c 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -113,9 +113,17 @@ var Map = Class("Map", { if (this.executing) util.dumpStack("Attempt to execute mapping recursively: " + args.command); dactyl.assert(!this.executing, "Attempt to execute mapping recursively: " + args.command); - this.executing = true; - let res = dactyl.trapErrors(repeat); - this.executing = false; + + try { + this.executing = true; + var res = repeat(); + } + catch (e) { + events.feedingKeys = false; + } + finally { + this.executing = false; + } return res; } @@ -507,7 +515,7 @@ var Mappings = Module("mappings", { description: "Accept a count before the requisite key press" }, { - names: ["-description", "-d"], + names: ["-description", "-desc", "-d"], description: "A description of this mapping", default: "User-defined mapping", type: CommandOption.STRING diff --git a/common/content/mow.js b/common/content/mow.js index bccff26c..6a8ff4d7 100644 --- a/common/content/mow.js +++ b/common/content/mow.js @@ -8,6 +8,12 @@ var MOW = Module("mow", { init: function () { + let fontSize = util.computedStyle(document.documentElement).fontSize; + styles.system.add("font-size", "dactyl://content/buffer.xhtml", + "body { font-size: " + fontSize + "; } \ + html|html > xul|scrollbar { visibility: collapse !important; }", + true); + XML.ignoreWhitespace = true; util.overlayWindow(window, { objects: { diff --git a/common/content/tabs.js b/common/content/tabs.js index 87a91e7d..b76509ed 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -867,9 +867,11 @@ var Tabs = Module("tabs", { }, events: function () { let tabContainer = config.tabbrowser.mTabContainer; - ["TabMove", "TabOpen", "TabClose"].forEach(function (event) { - events.addSessionListener(tabContainer, event, this.closure.updateTabCount, false); - }, this); + function callback() { + tabs.timeout(function () { this.updateTabCount(); }); + } + for (let event in values(["TabMove", "TabOpen", "TabClose"])) + events.addSessionListener(tabContainer, event, callback, false); events.addSessionListener(tabContainer, "TabSelect", this.closure._onTabSelect, false); }, mappings: function () { diff --git a/common/locale/en-US/browsing.xml b/common/locale/en-US/browsing.xml index fb48cf46..03011a37 100644 --- a/common/locale/en-US/browsing.xml +++ b/common/locale/en-US/browsing.xml @@ -20,7 +20,7 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to &dactyl.host; or to a web page, you have two options: <item> - <tags><![CDATA[pass-through <C-z> CTRL-Z]]></tags> + <tags><![CDATA[pass-through <pass-all-keys> <C-z> CTRL-Z]]></tags> <spec><C-z></spec> <description> <p> @@ -33,7 +33,7 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to </item> <item> - <tags><![CDATA[send-key <C-v> CTRL-V]]></tags> + <tags><![CDATA[send-key <pass-next-key> <C-v> CTRL-V]]></tags> <spec><C-v></spec> <description> <p> @@ -171,7 +171,7 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to </item> <item> - <tags><![CDATA[<MiddleMouse> p]]></tags> + <tags><![CDATA[<open-clipboard-url> <MiddleMouse> p]]></tags> <strut/> <spec>p</spec> <description> @@ -185,7 +185,7 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to </item> <item> - <tags>P</tags> + <tags><tab-open-clipboard-url> P</tags> <strut/> <spec>P</spec> <description> @@ -343,7 +343,7 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to <h2 tag="reloading">Reloading</h2> <item> - <tags>r</tags> + <tags><reload> r</tags> <spec>r</spec> <description short="true"> <p>Reload the current web page.</p> @@ -351,7 +351,7 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to </item> <item> - <tags>R</tags> + <tags><full-reload> R</tags> <spec>R</spec> <description short="true"> <p>Reload the current web page without using the cache.</p> diff --git a/common/locale/en-US/buffer.xml b/common/locale/en-US/buffer.xml index 5dbcfae5..66d0d978 100644 --- a/common/locale/en-US/buffer.xml +++ b/common/locale/en-US/buffer.xml @@ -22,7 +22,7 @@ <h2 tag="buffer-information">Buffer information</h2> <item> - <tags><![CDATA[<C-g>]]></tags> + <tags><![CDATA[<page-info> <C-g>]]></tags> <strut/> <spec><C-g></spec> <description> @@ -35,7 +35,7 @@ </item> <item> - <tags><![CDATA[g<C-g>]]></tags> + <tags><![CDATA[<more-page-info> g<C-g>]]></tags> <spec>g<C-g></spec> <description short="true"> <p>Print file information. Same as <ex>:pa<oa>geinfo</oa></ex>.</p> @@ -95,7 +95,7 @@ <h2 tag="motion scrolling">Motion commands</h2> <item> - <tags>^ 0</tags> + <tags><scroll-begin> ^ 0</tags> <strut/> <spec>0</spec> <description> @@ -107,7 +107,7 @@ </item> <item> - <tags>$</tags> + <tags><scroll-end> $</tags> <spec>$</spec> <description short="true"> <p>Scroll to the absolute right of the document</p> @@ -140,7 +140,7 @@ </item> <item> - <tags>N%</tags> + <tags><scroll-percent> N%</tags> <spec><a>count</a>%</spec> <description short="true"> <p>Scroll to <a>count</a> percent of the document.</p> @@ -148,7 +148,7 @@ </item> <item> - <tags><![CDATA[<Left> h]]></tags> + <tags><![CDATA[<scroll-column-left> <Left> h]]></tags> <strut/> <spec><oa>count</oa>h</spec> <description> @@ -160,7 +160,7 @@ </item> <item> - <tags><![CDATA[<C-e> <Down> j]]></tags> + <tags><![CDATA[<scroll-line-down> <C-e> <Down> j]]></tags> <strut/> <spec><oa>count</oa>j</spec> <description> @@ -172,7 +172,7 @@ </item> <item> - <tags><![CDATA[<C-y> <Up> k]]></tags> + <tags><![CDATA[<scroll-line-up> <C-y> <Up> k]]></tags> <strut/> <spec><oa>count</oa>k</spec> <description> @@ -184,7 +184,7 @@ </item> <item> - <tags><![CDATA[<Right> l]]></tags> + <tags><![CDATA[<scroll-column-right> <Right> l]]></tags> <strut/> <spec><oa>count</oa>l</spec> <description> @@ -196,7 +196,7 @@ </item> <item> - <tags><![CDATA[<C-d>]]></tags> + <tags><![CDATA[<scroll-down> <C-d>]]></tags> <strut/> <spec><oa>count</oa><C-d></spec> <description> @@ -209,7 +209,7 @@ </item> <item> - <tags><![CDATA[<C-u>]]></tags> + <tags><![CDATA[<scroll-up> <C-u>]]></tags> <strut/> <spec><oa>count</oa><C-u></spec> <description> @@ -222,7 +222,7 @@ </item> <item> - <tags><![CDATA[<S-Space> <PageUp> <C-b>]]></tags> + <tags><![CDATA[<scroll-page-up> <S-Space> <PageUp> <C-b>]]></tags> <strut/> <spec><oa>count</oa><C-b></spec> <description> @@ -234,7 +234,7 @@ </item> <item> - <tags><![CDATA[<Space> <PageDown> <C-f>]]></tags> + <tags><![CDATA[<scroll-page-down> <Space> <PageDown> <C-f>]]></tags> <strut/> <spec><oa>count</oa><C-f></spec> <description> @@ -264,7 +264,7 @@ </item> <item> - <tags>gi</tags> + <tags><focus-input> gi</tags> <strut/> <spec><oa>count</oa>gi</spec> <description> @@ -277,7 +277,7 @@ </item> <item> - <tags>]f</tags> + <tags><next-frame> ]f</tags> <strut/> <spec><oa>count</oa>]f</spec> <description> @@ -290,7 +290,7 @@ </item> <item> - <tags>[f</tags> + <tags><previous-frame> [f</tags> <strut/> <spec><oa>count</oa>[f</spec> <description> @@ -303,7 +303,7 @@ </item> <item> - <tags>]]</tags> + <tags><next-page> ]]</tags> <strut/> <spec><oa>count</oa>]]</spec> <description> @@ -316,7 +316,7 @@ </item> <item> - <tags>[[</tags> + <tags><previous-page> [[</tags> <strut/> <spec><oa>count</oa>[[</spec> <description> @@ -361,7 +361,7 @@ </note> <item> - <tags>+ zi</tags> + <tags><![CDATA[<text-zoom-in> + zi]]></tags> <spec><oa>count</oa>zi</spec> <description short="true"> <p>Enlarge text zoom of current web page. Mnemonic: zoom in.</p> @@ -369,7 +369,7 @@ </item> <item> - <tags>zm</tags> + <tags><![CDATA[<text-zoom-more> zm]]></tags> <strut/> <spec><oa>count</oa>zm</spec> <description> @@ -378,7 +378,7 @@ </item> <item> - <tags>- zo</tags> + <tags><![CDATA[<text-zoom-out> - zo]]></tags> <spec><oa>count</oa>zo</spec> <description short="true"> <p>Reduce text zoom of current web page. Mnemonic: zoom out.</p> @@ -386,7 +386,7 @@ </item> <item> - <tags>zr</tags> + <tags><![CDATA[<text-zoom-reduce> zr]]></tags> <spec><oa>count</oa>zr</spec> <description short="true"> <p>Reduce text zoom of current web page by a larger amount. Mnemonic: zoom reduce.</p> @@ -394,7 +394,7 @@ </item> <item> - <tags>zz</tags> + <tags><![CDATA[<text-zoom> zz]]></tags> <strut/> <spec><oa>count</oa>zz</spec> <description> @@ -407,7 +407,7 @@ </item> <item> - <tags>ZI zI</tags> + <tags><![CDATA[<full-zoom-in> ZI zI]]></tags> <spec><oa>count</oa>ZI</spec> <description short="true"> <p>Enlarge full zoom of current web page. Mnemonic: zoom in.</p> @@ -415,7 +415,7 @@ </item> <item> - <tags>ZM zM</tags> + <tags><![CDATA[<full-zoom-more> ZM zM]]></tags> <strut/> <spec><oa>count</oa>ZM</spec> <description> @@ -424,7 +424,7 @@ </item> <item> - <tags>ZO zO</tags> + <tags><![CDATA[<full-zoom-out> ZO zO]]></tags> <spec><oa>count</oa>ZO</spec> <description short="true"> <p>Reduce full zoom of current web page. Mnemonic: zoom out.</p> @@ -432,7 +432,7 @@ </item> <item> - <tags>ZR zR</tags> + <tags><![CDATA[<full-zoom-reduce> ZR zR]]></tags> <spec><oa>count</oa>ZR</spec> <description short="true"> <p>Reduce full zoom of current web page by a larger amount. Mnemonic: zoom reduce.</p> @@ -440,7 +440,7 @@ </item> <item> - <tags>zZ</tags> + <tags><![CDATA[<full-zoom> zZ]]></tags> <strut/> <spec><oa>count</oa>zZ</spec> <description> @@ -489,7 +489,7 @@ </p> <item> - <tags>y</tags> + <tags><yank-location> y</tags> <spec>y</spec> <description short="true"> <p>Yank current location to the clipboard.</p> @@ -497,7 +497,7 @@ </item> <item> - <tags>Y</tags> + <tags><yank-word> Y</tags> <spec>Y</spec> <description short="true"> <p>Copy currently selected text to the system clipboard.</p> diff --git a/common/locale/en-US/map.xml b/common/locale/en-US/map.xml index 24ff91ba..2a0bfd21 100644 --- a/common/locale/en-US/map.xml +++ b/common/locale/en-US/map.xml @@ -217,6 +217,14 @@ </description> </item> +<h3 tag=":map-timeout map-timeout">Mapping timeout</h3> +<p> + When &dactyl.appName; receives a key event that has a separate binding and + at the same time is part of a key chain, values of the <o>timeout</o> and + <o>timeoutlen</o> options are used to decide what to do. See the + documentation of those options for more information. +</p> + <h3 tag=":map-arguments">Special arguments</h3> <tags>:map-<silent></tags> diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml index 5016950d..c11a047a 100644 --- a/common/locale/en-US/options.xml +++ b/common/locale/en-US/options.xml @@ -1392,6 +1392,34 @@ </item> <item> + <tags>'tmo' 'timeout'</tags> + <spec>'timeout' 'tmo'</spec> + <type>boolean</type> + <default>true</default> + <description> + <p> + When this option is set and a key sequence interpretable both as a + complete command and as a start of a longer command is typed, + execute the shorter command after <o>timeoutlen</o> milliseconds. + </p> + </description> +</item> + +<item> + <tags>'tmol' 'timeoutlen'</tags> + <spec>'timeoutlen' 'tmol'</spec> + <type>number</type> + <default>1000</default> + <description> + <p> + Maximum number of milliseconds to wait for a longer key command + when a shorter one exists. Only effective when <o>timeout</o> is + set. + </p> + </description> +</item> + +<item> <tags>'titlestring'</tags> <spec>'titlestring'</spec> <type>string</type> diff --git a/common/locale/en-US/repeat.xml b/common/locale/en-US/repeat.xml index 753bc48f..d9470eff 100644 --- a/common/locale/en-US/repeat.xml +++ b/common/locale/en-US/repeat.xml @@ -21,7 +21,7 @@ <h2 tag="single-repeat">Single repeats</h2> <item> - <tags>.</tags> + <tags><repeat-key> .</tags> <strut/> <spec><oa>count</oa>.</spec> <description> @@ -45,7 +45,7 @@ <h2 tag="macros complex-repeat">Macros</h2> <item> - <tags>q</tags> + <tags><record-macro> q</tags> <strut/> <spec>q<a>0-9a-zA-Z</a></spec> <description> @@ -82,7 +82,7 @@ </item> <item> - <tags>@</tags> + <tags><play-macro> @</tags> <spec><oa>count</oa>@<a>a-z0-9</a></spec> <description> <p> @@ -100,6 +100,39 @@ </description> </item> +<h2 tag="macro-utilities">Macro utilities</h2> + +<p> + The following key bindings facilitate the recording of efficient + macros. They have no effect when typed normally, but are + recorded and take effect during macro playback. +</p> + +<item> + <tags><sleep> <A-m>s</tags> + <strut/> + <spec><a>count</a><m>s</spec> + <description> + <p> + Sleep for <a>count</a> milliseconds before resuming playback. + </p> + </description> +</item> + +<item> + <tags><![CDATA[<wait-for-page-load> <A-m>l]]></tags> + <strut/> + <spec><oa>count</oa><![CDATA[<A-m>l]]></spec> + <description> + <p> + Wait for the current page to finish loading before resuming + playback. If <oa>count</oa> is given, wait no more than + <oa>count</oa> seconds. Otherwise wait no more than 25 seconds. + </p> + </description> +</item> + + <h2 tag="using-scripts">Using scripts</h2> <item> diff --git a/common/modules/base.jsm b/common/modules/base.jsm index a7279244..efdbd106 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -1219,6 +1219,15 @@ update(iter, { func.call(self, val); }, + indexOf: function indexOf(iter, elem) { + let i = 0; + for (let item in iter) { + if (item == elem) + return i; + i++; + } + }, + /** * Returns the array that results from applying *func* to each property of * *obj*. diff --git a/common/modules/config.jsm b/common/modules/config.jsm index 0e818d3f..71d25426 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -613,6 +613,9 @@ var ConfigBase = Class("ConfigBase", { HelpString[delim]::before content: attr(delim); HelpString[delim]::after content: attr(delim); + HelpNews position: relative; + HelpNewsOld opacity: .7; + HelpNewsTag position: absolute; left: 100%; padding-left: 1em; color: #527BBD; opacity: .6; white-space: pre; HelpHead;html|h1,html|h2,html|h3,html|h4;dactyl://help/* { font-weight: bold; diff --git a/common/modules/finder.jsm b/common/modules/finder.jsm index 80525f53..52b1b540 100644 --- a/common/modules/finder.jsm +++ b/common/modules/finder.jsm @@ -174,13 +174,13 @@ var RangeFinder = Module("rangefinder", { description: "Forward Find mode, active when typing search input", bases: [modes.FIND], input: true - }, { history: "search" }); + }); modes.addMode("FIND_BACKWARD", { extended: true, description: "Backward Find mode, active when typing search input", bases: [modes.FIND], input: true - }, { history: "search" }); + }); }, commands: function (dactyl, modules, window) { const { commands, rangefinder } = modules; diff --git a/common/modules/io.jsm b/common/modules/io.jsm index d49f2349..e8fb057f 100644 --- a/common/modules/io.jsm +++ b/common/modules/io.jsm @@ -185,8 +185,10 @@ var IO = Module("io", { else if (/\.css$/.test(filename)) styles.registerSheet(uri.spec, false, true); else { + if (!(file.path in plugins)) + plugins[file.path] = modules.newContext(modules.userContext); modules.commands.execute(file.read(), null, silent || "loud", null, - { file: file.path, line: 1 }); + { file: file.path, line: 1, context: plugins[file.path] }); } if (this._scriptNames.indexOf(file.path) == -1) diff --git a/common/modules/javascript.jsm b/common/modules/javascript.jsm index ab76a98a..9d83a52f 100644 --- a/common/modules/javascript.jsm +++ b/common/modules/javascript.jsm @@ -478,7 +478,7 @@ var JavaScript = Module("javascript", { if (obj.length) { let func = obj[0][0][funcName]; if (callable(func)) { - let [, prefix, args] = /^(function .*?)\((.*)?\)/.exec(Function.prototype.toString.call(func)); + let [, prefix, args] = /^(function .*?)\((.*?)\)/.exec(Function.prototype.toString.call(func)); let n = this._get(i).comma.length; args = template.map(Iterator(args.split(", ")), function ([i, arg]) <span highlight={i == n ? "Filter" : ""}>{arg}</span>, diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 1c145f1c..01fce1ae 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -1200,7 +1200,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), } if (post) return [url, elems.join('&'), charset, elems]; - return [url + "?" + elems.join('&'), null, charset]; + return [url + "?" + elems.join('&'), null, charset, elems]; }, /** @@ -1270,8 +1270,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), if (tokens) expr = String.replace(expr, /(\(?P)?<(\w+)>/g, function (m, n1, n2) !n1 && set.has(tokens, n2) ? tokens[n2].dactylSource || tokens[n2].source || tokens[n2] : m); - expr = String.replace(expr, /\/\/[^\n]*|\/\*[^]*?\*\//gm, "") - .replace(/\s+/g, ""); + expr = String.replace(expr, /(\\.)|\/\/[^\n]*|\/\*[^]*?\*\/|\s+/gm, function (m, m1) m1 || ""); if (/\(\?P</.test(expr)) { var source = expr; diff --git a/common/tests/functional/README b/common/tests/functional/README deleted file mode 100644 index 3f1c84c6..00000000 --- a/common/tests/functional/README +++ /dev/null @@ -1 +0,0 @@ -- shared-modules should be synced with http://hg.mozilla.org/qa/mozmill-tests/ diff --git a/common/tests/functional/dactyl.js b/common/tests/functional/dactyl.js deleted file mode 100644 index 8adf268c..00000000 --- a/common/tests/functional/dactyl.js +++ /dev/null @@ -1,140 +0,0 @@ -var elementslib = {}; Components.utils.import("resource://mozmill/modules/elementslib.js", elementslib); -var jumlib = {}; Components.utils.import("resource://mozmill/modules/jum.js", jumlib); - -/** - * A controller for simulating Dactyl related user actions and for making - * assertions about the expected outcomes of such actions. - * - * @param {MozMillController} controller The browser's MozMill controller. - */ -function Controller(controller) { - this.controller = controller; - this._dactyl = controller.window.dactyl.modules; -} - -Controller.prototype = { - - /** - * Asserts that the output message line text content matches *text*. - * - * @param {string|RegExp} text The expected text of the expected message line. - * @param {string} message The message to display upon assertion failure. - */ - assertMessageLine: function (text, message) { - let value = this.readMessageLine(); - jumlib.assertTrue(typeof text == "string" ? text == value : text.test(value), message); - }, - - /** - * Asserts that the output message window text content matches *text*. - * - * @param {string|RegExp} text The expected text of the message window. - * @param {string} message The message to display upon assertion failure. - */ - assertMessageWindow: function (text, message) { - let value = this.readMessageWindow(); - jumlib.assertTrue(typeof text == "string" ? text == value : text.test(value), message); - }, - - /** - * Asserts that an error message has been echoed to the message line or - * appended to the message window with the given *text*. - * - * @param {string|RegExp} text The expected text of the error message. - * @param {string} message The message to display upon assertion failure. - */ - // TODO: test against the tail of the MOW too. - assertErrorMessage: function (text, message) { - this.controller.sleep(0); // XXX - let messageBox = new elementslib.ID(this.controller.window.document, "dactyl-message").getNode(); - jumlib.assertTrue(messageBox.value == text && /\bErrorMsg\b/.test(messageBox.getAttribute("highlight")), message); - }, - - /** - * Asserts that the current window selection matches *text*. - * - * @param {string|RegExp} text The expected text of the current selection. - * @param {string} message The message to display upon assertion failure. - */ - assertSelection: function (text, message) { - let selection = String(this.controller.window.content.getSelection()); - jumlib.assertTrue(typeof text == "string" ? text == selection : text.test(selection), message); - }, - - /** - * Runs a Vi command. - * - * @param {string|Array} keys Either a string of simple keys suitable for - * {@link MozMillController#type} or an array of keysym - modifier - * pairs suitable for {@link MozMillController#keypress}. - */ - runViCommand: function (keys) { - if (typeof keys == "string") - keys = [[k] for each (k in keys)]; - let self = this; - keys.forEach(function ([key, modifiers]) { self.controller.keypress(null, key, modifiers || {}); }); - }, - - /** - * Runs an Ex command. - * - * @param {string} cmd The Ex command string as entered on the command - * line. - */ - runExCommand: function (cmd) { - this.controller.keypress(null, ":", {}); - this.controller.type(null, cmd); - this.controller.keypress(null, "VK_RETURN", {}); - }, - - /** - * Returns the text content of the output message line. - * - * @returns {string} The message line text content. - */ - readMessageLine: function () { - this.controller.sleep(0); // XXX - return new elementslib.ID(this.controller.window.document, "dactyl-message").getNode().value; - }, - - /** - * Returns the text content of the output message window. - * - * @returns {string} The message window text content. - */ - readMessageWindow: function () { - let messageWindow = new elementslib.ID(this.controller.window.document, "dactyl-multiline-output").getNode(); - try { - this.controller.waitForEval("subject.collapsed == false", 1000, 100, messageWindow.parentNode); - return messageWindow.contentDocument.body.textContent; - } - catch (e) { - return ""; - } - }, - - /** - * Opens the output message window by echoing a single newline character. - */ - openMessageWindow: function() { - //this.runExCommand("echo '\\n'"); - this.runExCommand("echo " + "\n".quote()); - }, - - /** - * Closes the output message window if open. - */ - closeMessageWindow: function() { - if (!this._dactyl.commandline.widgets.mowContainer.collapsed) // XXX - this.runViCommand([["VK_RETURN"]]); - }, - - /** - * @property {string} The specific Dactyl application. Eg. Pentadactyl - */ - get applicationName() this._dactyl.config.appName // XXX -}; - -exports.Controller = Controller; - -// vim: sw=4 ts=8 et: diff --git a/common/tests/functional/data/find.html b/common/tests/functional/data/find.html deleted file mode 100644 index 6752df19..00000000 --- a/common/tests/functional/data/find.html +++ /dev/null @@ -1,13 +0,0 @@ -<title>Test Find Commands</title> - -<p> -A (play /ˈeɪ/; named a, plural aes) is the first letter and a vowel in the basic modern Latin alphabet. It is similar to the Ancient Greek letter Alpha, from which it derives. -</p> - -<p> -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -</p> - -<p> -π (sometimes written pi) is a mathematical constant whose value is the ratio of any circle's circumference to its diameter in the Euclidean plane; this is the same value as the ratio of a circle's area to the square of its radius. It is approximately equal to 3.14159265 in the usual decimal notation. Many formulae from mathematics, science, and engineering involve π, which makes it one of the most important mathematical constants. -</p> diff --git a/common/tests/functional/shared-modules/addons.js b/common/tests/functional/shared-modules/addons.js deleted file mode 100644 index ef558377..00000000 --- a/common/tests/functional/shared-modules/addons.js +++ /dev/null @@ -1,1284 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Geo Mealer <gmealer@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Include required modules -var domUtils = require("dom-utils"); -var prefs = require("prefs"); -var tabs = require("tabs"); -var utils = require("utils"); - - -const TIMEOUT = 5000; -const TIMEOUT_DOWNLOAD = 15000; -const TIMEOUT_SEARCH = 30000; - -var pm = Cc["@mozilla.org/permissionmanager;1"]. - getService(Ci.nsIPermissionManager); - -// AMO Preview site -const AMO_PREVIEW_DOMAIN = "addons.allizom.org"; -const AMO_PREVIEW_SITE = "https://" + AMO_PREVIEW_DOMAIN; - -// Available search filters -const SEARCH_FILTER = [ - "local", - "remote" -]; - -// Preferences which have to be changed to make sure we do not interact with the -// official AMO page but the preview site instead -const AMO_PREFERENCES = [ - {name: "extensions.getAddons.browseAddons", old: "addons.mozilla.org", new: AMO_PREVIEW_DOMAIN}, - {name: "extensions.getAddons.recommended.browseURL", old: "addons.mozilla.org", new: AMO_PREVIEW_DOMAIN}, - {name: "extensions.getAddons.recommended.url", old: "services.addons.mozilla.org", new: AMO_PREVIEW_DOMAIN}, - {name: "extensions.getAddons.search.browseURL", old: "addons.mozilla.org", new: AMO_PREVIEW_DOMAIN}, - {name: "extensions.getAddons.search.url", old: "services.addons.mozilla.org", new: AMO_PREVIEW_DOMAIN}, - {name: "extensions.getMoreThemesURL", old: "addons.mozilla.org", new: AMO_PREVIEW_DOMAIN} -]; - -/** - * Constructor - */ -function addonsManager(aController) { - this._controller = aController; - this._tabBrowser = new tabs.tabBrowser(this._controller); -} - -/** - * Addons Manager class - */ -addonsManager.prototype = { - - /////////////////////////////// - // Global section - /////////////////////////////// - - /** - * Get the controller of the window - * - * @returns Mozmill Controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns URL's of external DTD files - * @type {array of string} - */ - get dtds() { - var dtds = [ - "chrome://mozapps/locale/extensions/extensions.dtd", - "chrome://browser/locale/browser.dtd" - ]; - - return dtds; - }, - - /** - * Open the Add-ons Manager - * - * @param {object} aSpec - * Information how to open the Add-ons Manager - * Elements: type - Event, can be menu, or shortcut - * [optional - default: menu] - * waitFor - Wait until the Add-ons Manager has been opened - * [optional - default: true] - * - * - * @returns Reference the tab with the Add-ons Manager open - * @type {object} - * Elements: controller - Mozmill Controller of the window - * index - Index of the tab - */ - open : function addonsManager_open(aSpec) { - var spec = aSpec || { }; - var type = (spec.type == undefined) ? "menu" : spec.type; - var waitFor = (spec.waitFor == undefined) ? true : spec.waitFor; - - switch (type) { - case "menu": - var menuItem = new elementslib.Elem(this._controller. - menus["tools-menu"].menu_openAddons); - this._controller.click(menuItem); - break; - case "shortcut": - var cmdKey = utils.getEntity(this.dtds, "addons.commandkey"); - this._controller.keypress(null, cmdKey, {accelKey: true, shiftKey: true}); - break; - default: - throw new Error(arguments.callee.name + ": Unknown event type - " + - event.type); - } - - return waitFor ? this.waitForOpened() : null; - }, - - /** - * Check if the Add-ons Manager is open - * - * @returns True if the Add-ons Manager is open - * @type {boolean} - */ - get isOpen() { - return (this.getTabs().length > 0); - }, - - /** - * Waits until the Addons Manager has been opened and returns its controller - * - * @param {object} aSpec - * Object with parameters for customization - * Elements: timeout - Duration to wait for the target state - * [optional - default: 5s] - * - * @returns Currently selected tab - */ - waitForOpened : function addonsManager_waitforOpened(aSpec) { - var spec = aSpec || { }; - var timeout = (spec.timeout == undefined) ? TIMEOUT : spec.timeout; - - // TODO: restore after 1.5.1 has landed - // var self = this; - // - // mozmill.utils.waitFor(function() { - // return self.isOpen; - // }, timeout, 100, "Add-ons Manager has been opened"); - - mozmill.utils.waitForEval("subject.isOpen", timeout, 100, this); - - // The first tab found will be the selected one - var tab = this.getTabs()[0]; - tab.controller.waitForPageLoad(); - - return tab; - }, - - /** - * Close the Addons Manager - * - * @param {object} aSpec - * Information about the event to send - * Elements: type - Event type (closeButton, menu, middleClick, shortcut) - */ - close : function addonsManager_close(aSpec) { - this._tabBrowser.closeTab(aSpec); - }, - - /** - * Retrieves the list of open add-ons manager tabs - * - * @returns List of open tabs - * @type {array of object} - * Elements: controller - MozMillController - * index - Index of the tab - */ - getTabs : function addonsManager_getTabs() { - return tabs.getTabsWithURL("about:addons"); - }, - - /** - * Opens the utils button menu and clicks the specified menu entry - * - * @param {object} aSpec - * Information about the menu - * Elements: item - menu item to click (updateNow, viewUpdates, - * installFromFile, autoUpdateDefault, - * resetAddonUpdatesToAutomatic, - * resetAddonUpdatesToManual) - */ - handleUtilsButton : function addonsManager_handleUtilsButton(aSpec) { - var spec = aSpec || { }; - var item = spec.item; - - if (!item) - throw new Error(arguments.callee.name + ": Menu item not specified."); - - var button = this.getElement({type: "utilsButton"}); - var menu = this.getElement({type: "utilsButton_menu"}); - - try { - this._controller.click(button); - - // Click the button and wait until menu has been opened - - // TODO: restore after 1.5.1 has landed - // mozmill.utils.waitFor(function() { - // return menu.getNode() && menu.getNode().state == "open"; - // }, TIMEOUT, 100, "Menu of utils button has been opened."); - - mozmill.utils.waitForEval("subject && subject.state == 'open'", - TIMEOUT, 100, menu.getNode()); - - // Click the given menu entry and make sure the - var menuItem = this.getElement({ - type: "utilsButton_menuItem", - value: "#utils-" + item - }); - - this._controller.click(menuItem); - } finally { - // Make sure the menu has been closed - this._controller.keypress(menu, "VK_ESCAPE", {}); - - // TODO: restore after 1.5.1 has landed - // mozmill.utils.waitFor(function() { - // return menu.getNode() && menu.getNode().state == "closed"; - // }, TIMEOUT, 100, "Menu of utils button has been closed."); - - mozmill.utils.waitForEval("subject && subject.state == 'closed'", - TIMEOUT, 100, menu.getNode()); - } - }, - - - /////////////////////////////// - // Add-on section - /////////////////////////////// - - /** - * Check if the specified add-on is compatible - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - * - * @returns True if the add-on is compatible - * @type {ElemBase} - */ - isAddonCompatible : function addonsManager_isAddonCompatible(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - - if (!addon) - throw new Error(arguments.callee.name + ": Add-on not specified."); - - // XXX: Bug 599702 doens't give enough information which type of notification - return addon.getNode().getAttribute("notification") != "warning"; - }, - - /** - * Check if the specified add-on is enabled - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - * - * @returns True if the add-on is enabled - * @type {ElemBase} - */ - isAddonEnabled : function addonsManager_isAddonEnabled(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - - if (!addon) - throw new Error(arguments.callee.name + ": Add-on not specified."); - - return addon.getNode().getAttribute("active") == "true"; - }, - - /** - * Check if the specified add-on is installed - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - * - * @returns True if the add-on is installed - * @type {ElemBase} - */ - isAddonInstalled : function addonsManager_isAddonInstalled(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - - if (!addon) - throw new Error(arguments.callee.name + ": Add-on not specified."); - - // Bug 600502 : Add-ons in search view are not initialized correctly - return addon.getNode().getAttribute("remote") == "false" && - addon.getNode().getAttribute("status") == "installed"; - }, - - /** - * Enables the specified add-on - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - */ - enableAddon : function addonsManager_enableAddon(aSpec) { - var spec = aSpec || { }; - spec.button = "enable"; - - var button = this.getAddonButton(spec); - this._controller.click(button); - }, - - /** - * Disables the specified add-on - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - */ - disableAddon : function addonsManager_disableAddon(aSpec) { - var spec = aSpec || { }; - spec.button = "disable"; - - var button = this.getAddonButton(spec); - this._controller.click(button); - }, - - /** - * Installs the specified add-on - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - * waitFor - Wait until the category has been selected - * [optional - default: true] - * timeout - Duration to wait for the download - * [optional - default: 15s] - */ - installAddon : function addonsManager_installAddon(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - var timeout = spec.timeout; - var button = "install"; - var waitFor = (spec.waitFor == undefined) ? true : spec.waitFor; - - var button = this.getAddonButton({addon: addon, button: button}); - this._controller.click(button); - - if (waitFor) - this.waitForDownloaded({addon: addon, timeout: timeout}); - }, - - /** - * Removes the specified add-on - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - */ - removeAddon : function addonsManager_removeAddon(aSpec) { - var spec = aSpec || { }; - spec.button = "remove"; - - var button = this.getAddonButton(spec); - this._controller.click(button); - }, - - /** - * Undo the last action performed for the given add-on - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - */ - undo : function addonsManager_undo(aSpec) { - var spec = aSpec || { }; - spec.link = "undo"; - - var link = this.getAddonLink(spec); - this._controller.click(link); - }, - - /** - * Returns the addons from the currently selected view which match the - * filter criteria - * - * @param {object} aSpec - * Information about the filter to apply - * Elements: attribute - DOM attribute of the wanted addon - * [optional - default: ""] - * value - Value of the DOM attribute - * [optional - default: ""] - * - * @returns List of addons - * @type {array of ElemBase} - */ - getAddons : function addonsManager_addons(aSpec) { - var spec = aSpec || {}; - - return this.getElements({ - type: "addons", - subtype: spec.attribute, - value: spec.value, - parent: this.selectedView - }); - }, - - /** - * Returns the element of the specified add-ons button - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - * button - Button (disable, enable, preferences, remove) - * - * @returns Add-on button - * @type {ElemBase} - */ - getAddonButton : function addonsManager_getAddonButton(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - var button = spec.button; - - if (!button) - throw new Error(arguments.callee.name + ": Button not specified."); - - return this.getAddonChildElement({addon: addon, type: button + "Button"}); - }, - - /** - * Returns the element of the specified add-ons link - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - * link - Link - * List view (more, restart, undo) - * Detail view (findUpdates, restart, undo) - * - * @return Add-on link - * @type {ElemBase} - */ - getAddonLink : function addonsManager_getAddonLink(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - var link = spec.link; - - if (!link) - throw new Error(arguments.callee.name + ": Link not specified."); - - return this.getAddonChildElement({addon: addon, type: link + "Link"}); - }, - - /** - * Returns the element of the specified add-ons radio group - * - * @param {object} aSpec - * Information on which add-on to operate on - * Elements: addon - Add-on element - * radiogroup - Radiogroup - * Detail View (autoUpdate) - * - * @returns Add-on radiogroup - * @type {ElemBase} - */ - getAddonRadiogroup : function addonsManager_getAddonRadiogroup(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - var radiogroup = spec.radiogroup; - - if (!radiogroup) - throw new Error(arguments.callee.name + ": Radiogroup not specified."); - - return this.getAddonChildElement({addon: addon, type: radiogroup + "Radiogroup"}); - }, - - /** - * Retrieve the given child element of the specified add-on - * - * @param {object} aSpec - * Information for getting the add-ons child node - * Elements: addon - Add-on element - * type - Type of the element - * [optional - default: use attribute/value] - * attribute - DOM attribute of the node - * value - Value of the DOM attribute - * - * @returns Element - * @type {ElemBase} - */ - getAddonChildElement : function addonsManager_getAddonChildElement(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - var attribute = spec.attribute; - var value = spec.value; - var type = spec.type; - - if (!addon) - throw new Error(arguments.callee.name + ": Add-on not specified."); - - // If no type has been set retrieve a general element which needs an - // attribute and value - if (!type) { - type = "element"; - - if (!attribute) - throw new Error(arguments.callee.name + ": DOM attribute not specified."); - if (!value) - throw new Error(arguments.callee.name + ": Value not specified."); - } - - // For the details view the elements don't have anonymous nodes - if (this.selectedView.getNode().id == "detail-view") { - return this.getElement({ - type: "detailView_" + type, - subtype: attribute, - value: value - }); - } else { - return this.getElement({ - type: "listView_" + type, - subtype: attribute, - value: value, - parent: addon - }); - } - }, - - /** - * Wait until the specified add-on has been downloaded - * - * @param {object} aSpec - * Object with parameters for customization - * Elements: addon - Add-on element to wait for being downloaded - * timeout - Duration to wait for the target state - * [optional - default: 15s] - */ - waitForDownloaded : function addonsManager_waitForDownloaded(aSpec) { - var spec = aSpec || { }; - var addon = spec.addon; - var timeout = (spec.timeout == undefined) ? TIMEOUT_DOWNLOAD : spec.timeout; - - if (!addon) - throw new Error(arguments.callee.name + ": Add-on not specified."); - - var self = this; - var node = addon.getNode(); - - // TODO: restore after 1.5.1 has landed - // mozmill.utils.waitFor(function () { - // return node.getAttribute("pending") == "install" && - // node.getAttribute("status") != "installing"; - // }, timeout, 100, "'" + node.getAttribute("name") + "' has been downloaded"); - - mozmill.utils.waitForEval("subject.getAttribute('pending') == 'install' &&" + - "subject.getAttribute('status') != 'installing'", - timeout, 100, node); - }, - - - /////////////////////////////// - // Category section - /////////////////////////////// - - /** - * Retrieve the currently selected category - * - * @returns Element which represents the currently selected category - * @type {ElemBase} - */ - get selectedCategory() { - return this.getCategories({attribute: "selected", value: "true"})[0]; - }, - - /** - * Returns the categories which match the filter criteria - * - * @param {object} aSpec - * Information about the filter to apply - * Elements: attribute - DOM attribute of the wanted category - * [optional - default: ""] - * value - Value of the DOM attribute - * [optional - default: ""] - * - * @returns List of categories - * @type {array of ElemBase} - */ - getCategories : function addonsManager_categories(aSpec) { - var spec = aSpec || { }; - - var categories = this.getElements({ - type: "categories", - subtype: spec.attribute, - value: spec.value - }); - - if (categories.length == 0) - throw new Error(arguments.callee.name + ": Categories could not be found."); - - return categories; - }, - - /** - * Get the category element for the specified id - * - * @param {object} aSpec - * Information for getting a category - * Elements: id - Category id (search, discover, languages, - * searchengines, extensions, themes, plugins, - * availableUpdates, recentUpdates) - * - * @returns Category - * @type {ElemBase} - */ - getCategoryById : function addonsManager_getCategoryById(aSpec) { - var spec = aSpec || { }; - var id = spec.id; - - if (!id) - throw new Error(arguments.callee.name + ": Category ID not specified."); - - return this.getCategories({ - attribute: "id", - value: "category-" + id - })[0]; - }, - - /** - * Get the ID of the given category element - * - * @param {object} aSpec - * Information for getting a category - * Elements: category - Category to get the id from - * - * @returns Category Id - * @type {string} - */ - getCategoryId : function addonsManager_getCategoryId(aSpec) { - var spec = aSpec || { }; - var category = spec.category; - - if (!category) - throw new Error(arguments.callee.name + ": Category not specified."); - - return category.getNode().id; - }, - - /** - * Select the given category - * - * @param {object} aSpec - * Information for selecting a category - * Elements: category - Category element - * waitFor - Wait until the category has been selected - * [optional - default: true] - */ - setCategory : function addonsManager_setCategory(aSpec) { - var spec = aSpec || { }; - var category = spec.category; - var waitFor = (spec.waitFor == undefined) ? true : spec.waitFor; - - if (!category) - throw new Error(arguments.callee.name + ": Category not specified."); - - this._controller.click(category); - - if (waitFor) - this.waitForCategory({category: category}); - }, - - /** - * Select the category with the given id - * - * @param {object} aSpec - * Information for selecting a category - * Elements: id - Category id (search, discover, languages, - * searchengines, extensions, themes, plugins, - * availableUpdates, recentUpdates) - * waitFor - Wait until the category has been selected - * [optional - default: true] - */ - setCategoryById : function addonsManager_setCategoryById(aSpec) { - var spec = aSpec || { }; - var id = spec.id; - var waitFor = (spec.waitFor == undefined) ? true : spec.waitFor; - - if (!id) - throw new Error(arguments.callee.name + ": Category ID not specified."); - - // Retrieve the category and set it as active - var category = this.getCategoryById({id: id}); - if (category) - this.setCategory({category: category, waitFor: waitFor}); - else - throw new Error(arguments.callee.name + ": Category '" + id + " not found."); - }, - - /** - * Wait until the specified category has been selected - * - * @param {object} aSpec - * Object with parameters for customization - * Elements: category - Category element to wait for - * timeout - Duration to wait for the target state - * [optional - default: 5s] - */ - waitForCategory : function addonsManager_waitForCategory(aSpec) { - var spec = aSpec || { }; - var category = spec.category; - var timeout = (spec.timeout == undefined) ? TIMEOUT : spec.timeout; - - if (!category) - throw new Error(arguments.callee.name + ": Category not specified."); - - // TODO: restore after 1.5.1 has landed - // var self = this; - // mozmill.utils.waitFor(function () { - // return self.selectedCategory.getNode() == category.getNode(); - // }, timeout, 100, "Category '" + category.getNode().id + "' has been set"); - - mozmill.utils.waitForEval("subject.self.selectedCategory.getNode() == subject.aCategory.getNode()", - timeout, 100, - {self: this, aCategory: category}); - }, - - /////////////////////////////// - // Search section - /////////////////////////////// - - /** - * Clear the search field - */ - clearSearchField : function addonsManager_clearSearchField() { - var textbox = this.getElement({type: "search_textbox"}); - var cmdKey = utils.getEntity(this.dtds, "selectAllCmd.key"); - - this._controller.keypress(textbox, cmdKey, {accelKey: true}); - this._controller.keypress(textbox, 'VK_DELETE', {}); - }, - - /** - * Search for a specified add-on - * - * @param {object} aSpec - * Information to execute the search - * Elements: value - Search term - * timeout - Duration to wait for search results - * [optional - default: 30s] - * waitFor - Wait until the search has been finished - * [optional - default: true] - */ - search : function addonsManager_search(aSpec) { - var spec = aSpec || { }; - var value = spec.value; - var timeout = (spec.timeout == undefined) ? TIMEOUT_SEARCH : spec.timeout; - var waitFor = (spec.waitFor == undefined) ? true : spec.waitFor; - - if (!value) - throw new Error(arguments.callee.name + ": Search term not specified."); - - var textbox = this.getElement({type: "search_textbox"}); - - this.clearSearchField(); - this._controller.type(textbox, value); - this._controller.keypress(textbox, "VK_RETURN", {}); - - if (waitFor) - this.waitForSearchFinished(); - }, - - /** - * Check if a search is active - * - * @returns State of the search - * @type {boolean} - */ - get isSearching() { - var throbber = this.getElement({type: "search_throbber"}); - return throbber.getNode().hasAttribute("active"); - }, - - /** - * Retrieve the currently selected search filter - * - * @returns Element which represents the currently selected search filter - * @type {ElemBase} - */ - get selectedSearchFilter() { - var filter = this.getSearchFilter({attribute: "selected", value: "true"}); - - return (filter.length > 0) ? filter[0] : undefined; - }, - - /** - * Set the currently selected search filter status - * - * @param {string} aValue - * Filter for the search results (local, remote) - */ - set selectedSearchFilter(aValue) { - var filter = this.getSearchFilter({attribute: "value", value: aValue}); - - if (SEARCH_FILTER.indexOf(aValue) == -1) - throw new Error(arguments.callee.name + ": '" + aValue + - "' is not a valid search filter"); - - if (filter.length > 0) { - this._controller.click(filter[0]); - this.waitForSearchFilter({filter: filter[0]}); - } - }, - - /** - * Returns the available search filters which match the filter criteria - * - * @param {object} aSpec - * Information about the filter to apply - * Elements: attribute - DOM attribute of the wanted filter - * [optional - default: ""] - * value - Value of the DOM attribute - * [optional - default: ""] - * - * @returns List of search filters - * @type {array of ElemBase} - */ - getSearchFilter : function addonsManager_getSearchFilter(aSpec) { - var spec = aSpec || { }; - - return this.getElements({ - type: "search_filterRadioButtons", - subtype: spec.attribute, - value: spec.value - }); - }, - - /** - * Get the search filter element for the specified value - * - * @param {string} aValue - * Search filter value (local, remote) - * - * @returns Search filter element - * @type {ElemBase} - */ - getSearchFilterByValue : function addonsManager_getSearchFilterByValue(aValue) { - if (!aValue) - throw new Error(arguments.callee.name + ": Search filter value not specified."); - - return this.getElement({ - type: "search_filterRadioGroup", - subtype: "value", - value: aValue - }); - }, - - /** - * Get the value of the given search filter element - * - * @param {object} aSpec - * Information for getting the views matched by the criteria - * Elements: filter - Filter element - * - * @returns Value of the search filter - * @type {string} - */ - getSearchFilterValue : function addonsManager_getSearchFilterValue(aSpec) { - var spec = aSpec || { }; - var filter = spec.filter; - - if (!filter) - throw new Error(arguments.callee.name + ": Search filter not specified."); - - return filter.getNode().value; - }, - - /** - * Waits until the specified search filter has been selected - * - * @param {object} aSpec - * Object with parameters for customization - * Elements: filter - Filter element to wait for - * timeout - Duration to wait for the target state - * [optional - default: 5s] - */ - waitForSearchFilter : function addonsManager_waitForSearchFilter(aSpec) { - var spec = aSpec || { }; - var filter = spec.filter; - var timeout = (spec.timeout == undefined) ? TIMEOUT : spec.timeout; - - if (!filter) - throw new Error(arguments.callee.name + ": Search filter not specified."); - - // TODO: restore after 1.5.1 has landed - // var self = this; - // - // mozmill.utils.waitFor(function () { - // return self.selectedSearchFilter.getNode() == filter.getNode(); - // }, timeout, 100, "Search filter '" + filter.getNode().value + "' has been set"); - - mozmill.utils.waitForEval("subject.self.selectedSearchFilter.getNode() == subject.aFilter.getNode()", - timeout, 100, - {self: this, aFilter: filter}); - }, - - /** - * Returns the list of add-ons found by the selected filter - * - * @returns List of add-ons - * @type {ElemBase} - */ - getSearchResults : function addonsManager_getSearchResults() { - var filterValue = this.getSearchFilterValue({ - filter: this.selectedSearchFilter - }); - - switch (filterValue) { - case "local": - return this.getAddons({attribute: "status", value: "installed"}); - case "remote": - return this.getAddons({attribute: "remote", value: "true"}); - default: - throw new Error(arguments.callee.name + ": Unknown search filter '" + - filterValue + "' selected"); - } - }, - - /** - * Waits until the active search has been finished - * - * @param {object} aSpec - * Object with parameters for customization - * Elements: timeout - Duration to wait for the target state - */ - waitForSearchFinished : function addonsManager_waitForSearchFinished(aSpec) { - var spec = aSpec || { }; - var timeout = (spec.timeout == undefined) ? TIMEOUT_SEARCH : spec.timeout; - - // TODO: restore after 1.5.1 has landed - // var self = this; - // - // mozmill.utils.waitFor(function () { - // return self.isSearching == false; - // }, timeout, 100, "Search has been finished"); - - mozmill.utils.waitForEval("subject.isSearching == false", - timeout, 100, this); - }, - - /////////////////////////////// - // View section - /////////////////////////////// - - /** - * Returns the views which match the filter criteria - * - * @param {object} aSpec - * Information for getting the views matched by the criteria - * Elements: attribute - DOM attribute of the node - * [optional - default: ""] - * value - Value of the DOM attribute - * [optional - default: ""] - * - * @returns Filtered list of views - * @type {array of ElemBase} - */ - getViews : function addonsManager_getViews(aSpec) { - var spec = aSpec || { }; - var attribute = spec.attribute; - var value = spec.value; - - return this.getElements({type: "views", subtype: attribute, value: value}); - }, - - /** - * Check if the details view is active - * - * @returns True if the default view is selected - * @type {boolean} - */ - get isDetailViewActive() { - return (this.selectedView.getNode().id == "detail-view"); - }, - - /** - * Retrieve the currently used view - * - * @returns Element which represents the currently selected view - * @type {ElemBase} - */ - get selectedView() { - var viewDeck = this.getElement({type: "viewDeck"}); - var views = this.getViews(); - - return views[viewDeck.getNode().selectedIndex]; - }, - - - /////////////////////////////// - // UI Elements section - /////////////////////////////// - - /** - * Retrieve an UI element based on the given specification - * - * @param {object} aSpec - * Information of the UI elements which should be retrieved - * Elements: type - Identifier of the element - * subtype - Attribute of the element to filter - * [optional - default: ""] - * value - Value of the attribute to filter - * [optional - default: ""] - * parent - Parent of the to find element - * [optional - default: document] - * - * @returns Element which has been found - * @type {ElemBase} - */ - getElement : function addonsManager_getElement(aSpec) { - var elements = this.getElements(aSpec); - - return (elements.length > 0) ? elements[0] : undefined; - }, - - /** - * Retrieve list of UI elements based on the given specification - * - * @param {object} aSpec - * Information of the UI elements which should be retrieved - * Elements: type - Identifier of the element - * subtype - Attribute of the element to filter - * [optional - default: ""] - * value - Value of the attribute to filter - * [optional - default: ""] - * parent - Parent of the to find element - * [optional - default: document] - * - * @returns Elements which have been found - * @type {array of ElemBase} - */ - getElements : function addonsManager_getElements(aSpec) { - var spec = aSpec || { }; - var type = spec.type; - var subtype = spec.subtype; - var value = spec.value; - var parent = spec.parent; - - var root = parent ? parent.getNode() : this._controller.tabs.activeTab; - var nodeCollector = new domUtils.nodeCollector(root); - - switch (type) { - // Add-ons - case "addons": - nodeCollector.queryNodes(".addon").filterByDOMProperty(subtype, value); - break; - case "addonsList": - nodeCollector.queryNodes("#addon-list"); - break; - // Categories - case "categoriesList": - nodeCollector.queryNodes("#categories"); - break; - case "categories": - nodeCollector.queryNodes(".category").filterByDOMProperty(subtype, value); - break; - // Detail view - case "detailView_element": - nodeCollector.queryNodes(value); - break; - case "detailView_disableButton": - nodeCollector.queryNodes("#detail-disable"); - break; - case "detailView_enableButton": - nodeCollector.queryNodes("#detail-enable"); - break; - case "detailView_installButton": - nodeCollector.queryNodes("#detail-install"); - break; - case "detailView_preferencesButton": - nodeCollector.queryNodes("#detail-prefs"); - break; - case "detailView_removeButton": - nodeCollector.queryNodes("#detail-uninstall"); - break; - case "detailView_findUpdatesLink": - nodeCollector.queryNodes("#detail-findUpdates"); - break; - // Bug 599771 - button-link's are missing id or anonid - //case "detailView_restartLink": - // nodeCollector.queryNodes("#detail-restart"); - // break; - case "detailView_undoLink": - nodeCollector.queryNodes("#detail-undo"); - break; - case "detailView_findUpdatesRadiogroup": - nodeCollector.queryNodes("#detail-findUpdates"); - break; - // List view - case "listView_element": - nodeCollector.queryAnonymousNodes(subtype, value); - break; - case "listView_disableButton": - nodeCollector.queryAnonymousNodes("anonid", "disable-btn"); - break; - case "listView_enableButton": - nodeCollector.queryAnonymousNodes("anonid", "enable-btn"); - break; - case "listView_installButton": - // There is another binding we will have to skip - nodeCollector.queryAnonymousNodes("anonid", "install-status"); - nodeCollector.root = nodeCollector.nodes[0]; - nodeCollector.queryAnonymousNodes("anonid", "install-remote"); - break; - case "listView_preferencesButton": - nodeCollector.queryAnonymousNodes("anonid", "preferences-btn"); - break; - case "listView_removeButton": - nodeCollector.queryAnonymousNodes("anonid", "remove-btn"); - break; - case "listView_moreLink": - // Bug 599771 - button-link's are missing id or anonid - nodeCollector.queryAnonymousNodes("class", "details button-link"); - break; - // Bug 599771 - button-link's are missing id or anonid - //case "listView_restartLink": - // nodeCollector.queryAnonymousNodes("anonid", "restart"); - // break; - case "listView_undoLink": - nodeCollector.queryAnonymousNodes("anonid", "undo"); - break; - case "listView_cancelDownload": - // There is another binding we will have to skip - nodeCollector.queryAnonymousNodes("anonid", "install-status"); - nodeCollector.root = nodeCollector.nodes[0]; - nodeCollector.queryAnonymousNodes("anonid", "cancel"); - break; - case "listView_pauseDownload": - // There is another binding we will have to skip - nodeCollector.queryAnonymousNodes("anonid", "install-status"); - nodeCollector.root = nodeCollector.nodes[0]; - nodeCollector.queryAnonymousNodes("anonid", "pause"); - break; - case "listView_progressDownload": - // There is another binding we will have to skip - nodeCollector.queryAnonymousNodes("anonid", "install-status"); - nodeCollector.root = nodeCollector.nodes[0]; - nodeCollector.queryAnonymousNodes("anonid", "progress"); - break; - // Search - // Bug 599775 - Controller needs to handle radio groups correctly - // Means for now we have to use the radio buttons - case "search_filterRadioButtons": - nodeCollector.queryNodes(".search-filter-radio").filterByDOMProperty(subtype, value); - break; - case "search_filterRadioGroup": - nodeCollector.queryNodes("#search-filter-radiogroup"); - break; - case "search_textbox": - nodeCollector.queryNodes("#header-search"); - break; - case "search_throbber": - nodeCollector.queryNodes("#header-searching"); - break; - // Utils - case "utilsButton": - nodeCollector.queryNodes("#header-utils-btn"); - break; - case "utilsButton_menu": - nodeCollector.queryNodes("#utils-menu"); - break; - case "utilsButton_menuItem": - nodeCollector.queryNodes(value); - break; - // Views - case "viewDeck": - nodeCollector.queryNodes("#view-port"); - break; - case "views": - nodeCollector.queryNodes(".view-pane").filterByDOMProperty(subtype, value); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return nodeCollector.elements; - } -}; - -/** - * Whitelist permission for the specified domain - * @param {string} aDomain - * The domain to add the permission for - */ -function addToWhiteList(aDomain) { - pm.add(utils.createURI(aDomain), - "install", - Ci.nsIPermissionManager.ALLOW_ACTION); -} - -/** - * Remove whitelist permission for the specified host - * @param {string} aHost - * The host whose permission will be removed - */ -function removeFromWhiteList(aHost) { - pm.remove(aHost, "install"); -} - -/** - * Reset all preferences which point to the preview sub domain - */ -function resetAmoPreviewUrls() { - var prefSrv = prefs.preferences; - - for each (var preference in AMO_PREFERENCES) { - prefSrv.clearUserPref(preference.name); - } -} - -/** - * Updates all necessary preferences to the preview sub domain - */ -function useAmoPreviewUrls() { - var prefSrv = prefs.preferences; - - for each (var preference in AMO_PREFERENCES) { - var pref = prefSrv.getPref(preference.name, ""); - prefSrv.setPref(preference.name, - pref.replace(preference.old, preference.new)); - } -} - -// Export of variables -exports.AMO_PREVIEW_DOMAIN = AMO_PREVIEW_DOMAIN; -exports.AMO_PREVIEW_SITE = AMO_PREVIEW_SITE; - -// Export of functions -exports.addToWhiteList = addToWhiteList; -exports.removeFromWhiteList = removeFromWhiteList; -exports.resetAmoPreviewUrls = resetAmoPreviewUrls; -exports.useAmoPreviewUrls = useAmoPreviewUrls; - -// Export of classes -exports.addonsManager = addonsManager; diff --git a/common/tests/functional/shared-modules/dom-utils.js b/common/tests/functional/shared-modules/dom-utils.js deleted file mode 100644 index c24fe7fe..00000000 --- a/common/tests/functional/shared-modules/dom-utils.js +++ /dev/null @@ -1,685 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Adrian Kalla <akalla@aviary.pl> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Include required modules -var modalDialog = require("modal-dialog"); -var utils = require("utils"); - - -/** - * Unwraps a node which is wrapped into a XPCNativeWrapper or XrayWrapper - * - * @param {DOMnode} Wrapped DOM node - * @returns {DOMNode} Unwrapped DOM node - */ -function unwrapNode(aNode) { - var node = aNode; - - if (node) { - // unwrap is not available on older branches (3.5 and 3.6) - Bug 533596 - if ("unwrap" in XPCNativeWrapper) { - node = XPCNativeWrapper.unwrap(node); - } - else if ("wrappedJSObject" in node) { - node = node.wrappedJSObject; - } - } - - return node; -} - - -/** - * DOMWalker Constructor - * - * @param {MozMillController} controller - * MozMill controller of the window to operate on. - * @param {Function} callbackFilter - * callback-method to filter nodes - * @param {Function} callbackNodeTest - * callback-method to test accepted nodes - * @param {Function} callbackResults - * callback-method to process the results - * [optional - default: undefined] - */ -function DOMWalker(controller, callbackFilter, callbackNodeTest, - callbackResults) { - - this._controller = controller; - this._callbackFilter = callbackFilter; - this._callbackNodeTest = callbackNodeTest; - this._callbackResults = callbackResults; -} - -DOMWalker.FILTER_ACCEPT = 1; -DOMWalker.FILTER_REJECT = 2; -DOMWalker.FILTER_SKIP = 3; - -DOMWalker.GET_BY_ID = "id"; -DOMWalker.GET_BY_SELECTOR = "selector"; - -DOMWalker.WINDOW_CURRENT = 1; -DOMWalker.WINDOW_MODAL = 2; -DOMWalker.WINDOW_NEW = 4; - -DOMWalker.prototype = { - /** - * Returns the filter-callback - * - * @returns Function - */ - get callbackFilter() { - return this._callbackFilter; - }, - - /** - * Returns the node-testing-callback - * - * @returns Function - */ - get callbackNodeTest() { - return this._callbackNodeTest; - }, - - /** - * Returns the results-callback - * - * @returns Function - */ - get callbackResults() { - return this._callbackResults; - }, - - /** - * Returns the MozMill controller - * - * @returns Mozmill controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * The main DOMWalker function. - * - * It start's the _walk-method for a given window or other dialog, runs - * a callback to process the results for that window/dialog. - * After that switches to provided new windows/dialogs. - * - * @param {array of objects} ids - * Contains informations on the elements to open while - * Object-elements: getBy - attribute-name of the attribute - * containing the identification - * information for the opener-element - * subContent - array of ids of the opener-elements - * in the window with the value of - * the above getBy-attribute - * target - information, where the new - * elements will be opened - * [1|2|4] - * title - title of the opened dialog/window - * waitFunction - The function used as an argument - * for MozmillController.waitFor to - * wait before starting the walk. - * [optional - default: no waiting] - * windowHandler - Window instance - * [only needed for some tests] - * - * @param {Node} root - * Node to start testing from - * [optional - default: this._controller.window.document.documentElement] - * @param {Function} waitFunction - * The function used as an argument for MozmillController.waitFor to - * wait before starting the walk. - * [optional - default: no waiting] - */ - walk : function DOMWalker_walk(ids, root, waitFunction) { - if (typeof waitFunction == 'function') - this._controller.waitFor(waitFunction()); - - if (!root) - root = this._controller.window.document.documentElement; - - var resultsArray = this._walk(root); - - if (typeof this._callbackResults == 'function') - this._callbackResults(this._controller, resultsArray); - - if (ids) - this._prepareTargetWindows(ids); - }, - - /** - * DOMWalker_filter filters a given node by submitting it to the - * this._callbackFilter method to decide, if it should be submitted to - * a provided this._callbackNodeTest method for testing (that hapens in case - * of FILTER_ACCEPT). - * In case of FILTER_ACCEPT and FILTER_SKIP, the children of such a node - * will be filtered recursively. - * Nodes with the nodeStatus "FILTER_REJECT" and their descendants will be - * completetly ignored. - * - * @param {Node} node - * Node to filter - * @param {array of elements} collectedResults - * An array with gathered all results from testing a given element - * @returns An array with gathered all results from testing a given element - * @type {array of elements} - */ - _filter : function DOMWalker_filter(node, collectedResults) { - var nodeStatus = this._callbackFilter(node); - - var nodeTestResults = []; - - switch (nodeStatus) { - case DOMWalker.FILTER_ACCEPT: - nodeTestResults = this._callbackNodeTest(node); - collectedResults = collectedResults.concat(nodeTestResults); - // no break here as we have to perform the _walk below too - case DOMWalker.FILTER_SKIP: - nodeTestResults = this._walk(node); - break; - default: - break; - } - - collectedResults = collectedResults.concat(nodeTestResults); - - return collectedResults; - }, - - /** - * Retrieves and returns a wanted node based on the provided identification - * set. - * - * @param {array of objects} idSet - * Contains informations on the elements to open while - * Object-elements: getBy - attribute-name of the attribute - * containing the identification - * information for the opener-element - * subContent - array of ids of the opener-elements - * in the window with the value of - * the above getBy-attribute - * target - information, where the new - * elements will be opened - * [1|2|4] - * title - title of the opened dialog/window - * waitFunction - The function used as an argument - * for MozmillController.waitFor to - * wait before starting the walk. - * [optional - default: no waiting] - * windowHandler - Window instance - * [only needed for some tests] - * - * @returns Node - * @type {Node} - */ - _getNode : function DOMWalker_getNode(idSet) { - var doc = this._controller.window.document; - - // QuerySelector seems to be unusuale for id's in this case: - // https://developer.mozilla.org/En/Code_snippets/QuerySelector - switch (idSet.getBy) { - case DOMWalker.GET_BY_ID: - return doc.getElementById(idSet[idSet.getBy]); - case DOMWalker.GET_BY_SELECTOR: - return doc.querySelector(idSet[idSet.getBy]); - default: - throw new Error("Not supported getBy-attribute: " + idSet.getBy); - } - }, - - /** - * Main entry point to open new elements like windows, tabpanels, prefpanes, - * dialogs - * - * @param {array of objects} ids - * Contains informations on the elements to open while - * Object-elements: getBy - attribute-name of the attribute - * containing the identification - * information for the opener-element - * subContent - array of ids of the opener-elements - * in the window with the value of - * the above getBy-attribute - * target - information, where the new - * elements will be opened - * [1|2|4] - * title - title of the opened dialog/window - * waitFunction - The function used as an argument - * for MozmillController.waitFor to - * wait before starting the walk. - * [optional - default: no waiting] - * windowHandler - Window instance - * [only needed for some tests] - */ - _prepareTargetWindows : function DOMWalker_prepareTargetWindows(ids) { - var doc = this._controller.window.document; - - // Go through all the provided ids - for (var i = 0; i < ids.length; i++) { - var node = this._getNode(ids[i]); - - // Go further only, if the needed element exists - if (node) { - var idSet = ids[i]; - - // Decide if what we want to open is a new normal/modal window or if it - // will be opened in the current window. - switch (idSet.target) { - case DOMWalker.WINDOW_CURRENT: - this._processNode(node, idSet); - break; - case DOMWalker.WINDOW_MODAL: - // Modal windows have to be able to access that informations - var modalInfos = {ids : idSet.subContent, - callbackFilter : this._callbackFilter, - callbackNodeTest : this._callbackNodeTest, - callbackResults : this._callbackResults, - waitFunction : idSet.waitFunction} - persisted.modalInfos = modalInfos; - - var md = new modalDialog.modalDialog(this._controller.window); - md.start(this._modalWindowHelper); - - this._processNode(node, idSet); - md.waitForDialog(); - break; - case DOMWalker.WINDOW_NEW: - this._processNode(node, idSet); - - // Get the new non-modal window controller - var controller = utils.handleWindow('title', idSet.title, - undefined, false); - - // Start a new DOMWalker instance - let domWalker = new DOMWalker(controller, this._callbackFilter, - this._callbackNodeTest, - this._callbackResults); - domWalker.walk(idSet.subContent, - controller.window.document.documentElement, - idSet.waitFunction); - - // Close the window - controller.window.close(); - break; - default: - throw new Error("Node does not exist: " + ids[i][ids[i].getBy]); - } - } - } - }, - - /** - * Opens new windows/dialog and starts the DOMWalker.walk() in case of dialogs - * in existing windows. - * - * @param {Node} activeNode - * Node that holds the information which way - * to open the new window/dialog - * @param {object} idSet - * ID set for the element to open - */ - _processNode: function DOMWalker_processNode(activeNode, idSet) { - var doc = this._controller.window.document; - var nodeToProcess = this._getNode(idSet); - - // Opens a new window/dialog through a menulist and runs DOMWalker.walk() - // for it. - // If the wanted window/dialog is already selected, just run this function - // recursively for it's descendants. - if (activeNode.localName == "menulist") { - if (nodeToProcess.value != idSet.value) { - var dropDown = new elementslib.Elem(nodeToProcess); - this._controller.waitForElement(dropDown); - - this._controller.select(dropDown, null, null, idSet.value); - - this._controller.waitFor(function() { - return nodeToProcess.value == idSet.value; - }, "The menu item did not load in time: " + idSet.value); - - // If the target is a new modal/non-modal window, this.walk() has to be - // started by the method opening that window. If not, we do it here. - if (idSet.target == DOMWalker.WINDOW_CURRENT) - this.walk(idSet.subContent, null, idSet.waitFunction); - } else if (nodeToProcess.selected && idSet.subContent && - idSet.subContent.length > 0) { - this._prepareTargetWindows(idSet.subContent); - } - } - - // Opens a new prefpane using a provided windowHandler object - // and runs DOMWalker.walk() for it. - // If the wanted prefpane is already selected, just run this function - // recursively for it's descendants. - else if (activeNode.localName == "prefpane") { - var windowHandler = idSet.windowHandler; - - if (windowHandler.paneId != idSet.id) { - windowHandler.paneId = idSet.id; - - // Wait for the pane's content to load and to be fully displayed - this._controller.waitFor(function() { - return (nodeToProcess.loaded && - (!mozmill.isMac || - nodeToProcess.style.opacity == 1 || - nodeToProcess.style.opacity == null)); - }, "The pane did not load in time: " + idSet.id); - - // If the target is a new modal/non-modal window, this.walk() has to be - // started by the method opening that window. If not, we do it here. - if (idSet.target == DOMWalker.WINDOW_CURRENT) - this.walk(idSet.subContent, null, idSet.waitFunction); - } else if (windowHandler.paneId == idSet.id && idSet.subContent && - idSet.subContent.length > 0) { - this._prepareTargetWindows(idSet.subContent); - } - } - - // Switches to another tab and runs DOMWalker.walk() for it. - // If the wanted tabpanel is already selected, just run this function - // recursively for it's descendants. - else if (activeNode.localName == "tab") { - if (nodeToProcess.selected != true) { - this._controller.click(new elementslib.Elem(nodeToProcess)); - - // If the target is a new modal/non-modal window, this.walk() has to be - // started by the method opening that window. If not, we do it here. - if (idSet.target == DOMWalker.WINDOW_CURRENT) - this.walk(idSet.subContent, null, idSet.waitFunction); - } else if (nodeToProcess.selected && idSet.subContent - && idSet.subContent.length > 0) { - this._prepareTargetWindows(idSet.subContent); - } - } - - // Opens a new dialog/window by clicking on an object and runs - // DOMWalker.walk() for it. - else { - this._controller.click(new elementslib.Elem(nodeToProcess)); - - // If the target is a new modal/non-modal window, this.walk() has to be - // started by the method opening that window. If not, we do it here. - if (idSet.target == DOMWalker.WINDOW_CURRENT) - this.walk(idSet.subContent, null, idSet.waitFunction); - } - }, - - /** - * DOMWalker_walk goes recursively through the DOM, starting with a provided - * root-node and filters the nodes using the this._filter method. - * - * @param {Node} root - * Node to start testing from - * [optional - default: this._controller.window.document.documentElement] - * @returns An array with gathered all results from testing a given element - * @type {array of elements} - */ - _walk : function DOMWalker__walk(root) { - if (!root.childNodes) - throw new Error("root.childNodes does not exist"); - - var collectedResults = []; - - // There seems to be no other way to get to the nodes hidden in the - // "_buttons" object (see Bug 614949) - if (root._buttons) { - for each (button in root._buttons) { - collectedResults = this._filter(button, collectedResults); - } - } - - for (var i = 0; i < root.childNodes.length; i++) { - collectedResults = this._filter(root.childNodes[i], collectedResults); - } - - return collectedResults; - }, - - /** - * Callback function to handle new windows - * - * @param {MozMillController} controller - * MozMill controller of the new window to operate on. - */ - _modalWindowHelper: function DOMWalker_modalWindowHelper(controller) { - let domWalker = new DOMWalker(controller, - persisted.modalInfos.callbackFilter, - persisted.modalInfos.callbackNodeTest, - persisted.modalInfos.callbackResults); - domWalker.walk(persisted.modalInfos.ids, - controller.window.document.documentElement, - persisted.modalInfos.waitFunction); - - delete persisted.modalInfos; - - controller.window.close(); - } -} - -/** - * Default constructor - * - * @param {object} aRoot - * Root node in the DOM to use as parent - */ -function nodeCollector(aRoot) { - this._root = aRoot.wrappedJSObject ? aRoot.wrappedJSObject : aRoot; - this._document = this._root.ownerDocument ? this._root.ownerDocument : this._root; - this._nodes = [ ]; -} - -/** - * Node collector class - */ -nodeCollector.prototype = { - /** - * Converts current nodes to elements - * - * @returns List of elements - * @type {array of ElemBase} - */ - get elements() { - var elements = [ ]; - - Array.forEach(this._nodes, function(element) { - elements.push(new elementslib.Elem(element)); - }); - - return elements; - }, - - /** - * Get the current list of DOM nodes - * - * @returns List of nodes - * @type {array of object} - */ - get nodes() { - return this._nodes; - }, - - /** - * Sets current nodes to entries from the node list - * - * @param {array of objects} aNodeList - * List of DOM nodes to set - */ - set nodes(aNodeList) { - if (aNodeList) { - this._nodes = [ ]; - - Array.forEach(aNodeList, function(node) { - this._nodes.push(node); - }, this); - } - }, - - /** - * Get the root node used as parent for a node collection - * - * @returns Current root node - * @type {object} - */ - get root() { - return this._root; - }, - - /** - * Sets root node to the specified DOM node - * - * @param {object} aRoot - * DOM node to use as root for node collection - */ - set root(aRoot) { - if (aRoot) { - this._root = aRoot; - this._nodes = [ ]; - } - }, - - /** - * Filter nodes given by the specified callback function - * - * @param {function} aCallback - * Function to test each element of the array. - * Elements: node, index (optional) , array (optional) - * @param {object} aThisObject - * Object to use as 'this' when executing callback. - * [optional - default: function scope] - * - * @returns The class instance - * @type {object} - */ - filter : function nodeCollector_filter(aCallback, aThisObject) { - if (!aCallback) - throw new Error(arguments.callee.name + ": No callback specified"); - - this.nodes = Array.filter(this.nodes, aCallback, aThisObject); - - return this; - }, - - /** - * Filter nodes by DOM property and its value - * - * @param {string} aProperty - * Property to filter for - * @param {string} aValue - * Expected value of the DOM property - * [optional - default: n/a] - * - * @returns The class instance - * @type {object} - */ - filterByDOMProperty : function nodeCollector_filterByDOMProperty(aProperty, aValue) { - return this.filter(function(node) { - if (aProperty && aValue) - return node.getAttribute(aProperty) == aValue; - else if (aProperty) - return node.hasAttribute(aProperty); - else - return true; - }); - }, - - /** - * Filter nodes by JS property and its value - * - * @param {string} aProperty - * Property to filter for - * @param {string} aValue - * Expected value of the JS property - * [optional - default: n/a] - * - * @returns The class instance - * @type {object} - */ - filterByJSProperty : function nodeCollector_filterByJSProperty(aProperty, aValue) { - return this.filter(function(node) { - if (aProperty && aValue) - return node.aProperty == aValue; - else if (aProperty) - return node.aProperty !== undefined; - else - return true; - }); - }, - - /** - * Find anonymouse nodes with the specified attribute and value - * - * @param {string} aAttribute - * DOM attribute of the wanted node - * @param {string} aValue - * Value of the DOM attribute - * - * @returns The class instance - * @type {object} - */ - queryAnonymousNodes : function nodeCollector_queryAnonymousNodes(aAttribute, aValue) { - var node = this._document.getAnonymousElementByAttribute(this._root, - aAttribute, - aValue); - this.nodes = node ? [node] : [ ]; - - return this; - }, - - /** - * Find nodes with the specified selector - * - * @param {string} aSelector - * jQuery like element selector string - * - * @returns The class instance - * @type {object} - */ - queryNodes : function nodeCollector_queryNodes(aSelector) { - this.nodes = this._root.querySelectorAll(aSelector); - - return this; - } -} - -// Exports of functions -exports.unwrapNode = unwrapNode; - -// Exports of classes -exports.DOMWalker = DOMWalker; -exports.nodeCollector = nodeCollector; diff --git a/common/tests/functional/shared-modules/downloads.js b/common/tests/functional/shared-modules/downloads.js deleted file mode 100644 index d06cba09..00000000 --- a/common/tests/functional/shared-modules/downloads.js +++ /dev/null @@ -1,411 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Anthony Hughes <anthony.s.hughes@gmail.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The DownloadsAPI adds support for download related functions. It also gives - * access to the Download Manager. - * - * @version 1.0.1 - */ - -// Include required modules -var utils = require("utils"); - -const gTimeout = 5000; - -/** - * List of available download states - */ -const downloadState = { - notStarted : -1, - downloading : 0, - finished : 1, - failed : 2, - canceled : 3, - paused : 4, - queued : 5, - blockedParental : 6, - scanning : 7, - dirty : 8, - blockedPolicy : 9 -} - -/** - * Constructor - */ -function downloadManager() { - this._controller = null; - this.downloadState = downloadState; - - this._dms = Cc["@mozilla.org/download-manager;1"]. - getService(Ci.nsIDownloadManager); -} - -/** - * Download Manager class - */ -downloadManager.prototype = { - /** - * Returns the controller of the current window - * - * @returns Mozmill Controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Returns the number of currently active downloads - * - * @returns Number of active downloads - * @type {number} - */ - get activeDownloadCount() { - return this._dms.activeDownloadCount; - }, - - /** - * Cancel all active downloads - */ - cancelActiveDownloads : function downloadManager_cancelActiveDownloads() { - // Get a list of all active downloads (nsISimpleEnumerator) - var downloads = this._dms.activeDownloads; - - // Iterate through each active download and cancel it - while (downloads.hasMoreElements()) { - var download = downloads.getNext().QueryInterface(Ci.nsIDownload); - this._dms.cancelDownload(download.id); - } - }, - - /** - * Remove all downloads from the database - */ - cleanUp : function downloadManager_cleanUp() - { - this._dms.cleanUp(); - }, - - /** - * Cancel any active downloads, remove the files, and clean - * up the Download Manager database - * - * @param {Array of download} downloads - * Downloaded files which should be deleted (optional) - */ - cleanAll : function downloadManager_cleanAll(downloads) { - // Cancel any active downloads - this.cancelActiveDownloads(); - - // If no downloads have been specified retrieve the list from the database - if (downloads === undefined || downloads.length == 0) - downloads = this.getAllDownloads(); - else - downloads = downloads.concat(this.getAllDownloads()); - - // Delete all files referred to in the Download Manager - this.deleteDownloadedFiles(downloads); - - // Clean any entries from the Download Manager database - this.cleanUp(); - }, - - /** - * Close the download manager - * - * @param {boolean} force - * Force the closing of the DM window - */ - close : function downloadManager_close(force) { - var windowCount = mozmill.utils.getWindows().length; - - if (this._controller) { - // Check if we should force the closing of the DM window - if (force) { - this._controller.window.close(); - } else { - var cmdKey = utils.getEntity(this.getDtds(), "cmd.close.commandKey"); - this._controller.keypress(null, cmdKey, {accelKey: true}); - } - - this._controller.waitForEval("subject.getWindows().length == " + (windowCount - 1), - gTimeout, 100, mozmill.utils); - this._controller = null; - } - }, - - /** - * Delete all downloads from the local drive - * - * @param {download} downloads - * List of downloaded files - */ - deleteDownloadedFiles : function downloadManager_deleteDownloadedFiles(downloads) { - downloads.forEach(function(download) { - try { - var file = getLocalFileFromNativePathOrUrl(download.target); - file.remove(false); - } catch (ex) { - } - }); - }, - - /** - * Get the list of all downloaded files in the database - * - * @returns List of downloads - * @type {Array of download} - */ - getAllDownloads : function downloadManager_getAllDownloads() { - var dbConn = this._dms.DBConnection; - var stmt = null; - - if (dbConn.schemaVersion < 3) - return new Array(); - - // Run a SQL query and iterate through all results which have been found - var downloads = []; - stmt = dbConn.createStatement("SELECT * FROM moz_downloads"); - while (stmt.executeStep()) { - downloads.push({ - id: stmt.row.id, name: stmt.row.name, target: stmt.row.target, - tempPath: stmt.row.tempPath, startTime: stmt.row.startTime, - endTime: stmt.row.endTime, state: stmt.row.state, - referrer: stmt.row.referrer, entityID: stmt.row.entityID, - currBytes: stmt.row.currBytes, maxBytes: stmt.row.maxBytes, - mimeType : stmt.row.mimeType, autoResume: stmt.row.autoResume, - preferredApplication: stmt.row.preferredApplication, - preferredAction: stmt.row.preferredAction - }); - }; - stmt.reset(); - - return downloads; - }, - - /** - * Gets the download state of the given download - * - * @param {ElemBase} download - * Download which state should be checked - */ - getDownloadState : function downloadManager_getDownloadState(download) { - return download.getNode().getAttribute('state'); - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function downloadManager_getDtds() { - var dtds = ["chrome://browser/locale/browser.dtd", - "chrome://mozapps/locale/downloads/downloads.dtd"]; - return dtds; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type {ElemBase} - */ - getElement : function downloadManager_getElement(spec) { - var elem = null; - - switch(spec.type) { - /** - * subtype: subtype of property to match - * value: value of property to match - */ - case "download": - // Use a temporary lookup to get the download item - var download = new elementslib.Lookup(this._controller.window.document, - '/id("downloadManager")/id("downloadView")/' + - '{"' + spec.subtype + '":"' + spec.value + '"}'); - this._controller.waitForElement(download, gTimeout); - - // Use its download id to construct the real lookup expression - elem = new elementslib.Lookup(this._controller.window.document, - '/id("downloadManager")/id("downloadView")/' + - 'id("' + download.getNode().getAttribute('id') + '")'); - break; - - /** - * subtype: Identifier of the specified download button (cancel, pause, resume, retry) - * value: Entry (download) of the download list - */ - case "download_button": - // XXX: Bug 555347 - There are outstanding events to process - this._controller.sleep(0); - - elem = new elementslib.Lookup(this._controller.window.document, spec.value.expression + - '/anon({"flex":"1"})/[1]/[1]/{"cmd":"cmd_' + spec.subtype + '"}'); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Open the Download Manager - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @param {boolean} shortcut - * If true the keyboard shortcut is used - */ - open : function downloadManager_open(controller, shortcut) { - if (shortcut) { - if (mozmill.isLinux) { - var cmdKey = utils.getEntity(this.getDtds(), "downloadsUnix.commandkey"); - controller.keypress(null, cmdKey, {ctrlKey: true, shiftKey: true}); - } else { - var cmdKey = utils.getEntity(this.getDtds(), "downloads.commandkey"); - controller.keypress(null, cmdKey, {accelKey: true}); - } - } else { - controller.click(new elementslib.Elem(controller.menus["tools-menu"].menu_openDownloads)); - } - - controller.sleep(500); - this.waitForOpened(controller); - }, - - /** - * Wait for the given download state - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @param {downloadState} state - * Expected state of the download - * @param {number} timeout - * Timeout for waiting for the download state (optional) - */ - waitForDownloadState : function downloadManager_waitForDownloadState(download, state, timeout) { - this._controller.waitForEval("subject.manager.getDownloadState(subject.download) == subject.state", timeout, 100, - {manager: this, download: download, state: state}); - }, - - /** - * Wait until the Download Manager has been opened - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - */ - waitForOpened : function downloadManager_waitForOpened(controller) { - this._controller = utils.handleWindow("type", "Download:Manager", - undefined, false); - } -}; - -/** - * Download the file of unkown type from the given location by saving it - * automatically to disk - * - * @param {MozMillController} controller - * MozMillController of the browser window - * @param {string} url - * URL of the file which has to be downloaded - */ -var downloadFileOfUnknownType = function(controller, url) { - controller.open(url); - - // Wait until the unknown content type dialog has been opened - controller.waitForEval("subject.getMostRecentWindow('').document.documentElement.id == 'unknownContentType'", - gTimeout, 100, mozmill.wm); - - utils.handleWindow("type", "", function (controller) { - // Select to save the file directly - var saveFile = new elementslib.ID(controller.window.document, "save"); - controller.waitThenClick(saveFile, gTimeout); - controller.waitForEval("subject.selected == true", gTimeout, 100, - saveFile.getNode()); - - // Wait until the OK button has been enabled and click on it - var button = new elementslib.Lookup(controller.window.document, - '/id("unknownContentType")/anon({"anonid":"buttons"})/{"dlgtype":"accept"}'); - controller.waitForElement(button, gTimeout); - controller.waitForEval("subject.okButton.hasAttribute('disabled') == false", gTimeout, 100, - {okButton: button.getNode()}); - controller.click(button); - }); -} - -/** - * Get a local file from a native path or URL - * - * @param {string} aPathOrUrl - * Native path or URL of the file - * @see http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/downloads/content/downloads.js#1309 - */ -function getLocalFileFromNativePathOrUrl(aPathOrUrl) { - if (aPathOrUrl.substring(0,7) == "file://") { - // if this is a URL, get the file from that - let ioSvc = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); - - // XXX it's possible that using a null char-set here is bad - const fileUrl = ioSvc.newURI(aPathOrUrl, null, null) - .QueryInterface(Ci.nsIFileURL); - return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile); - } else { - // if it's a pathname, create the nsILocalFile directly - var f = new nsLocalFile(aPathOrUrl); - return f; - } -} - -// Export of variables -exports.downloadState = downloadState; - -// Export of functions -exports.downloadFileOfUnknownType = downloadFileOfUnknownType; -exports.getLocalFileFromNativePathOrUrl = getLocalFileFromNativePathOrUrl; - -// Export of classes -exports.downloadManager = downloadManager; diff --git a/common/tests/functional/shared-modules/localization.js b/common/tests/functional/shared-modules/localization.js deleted file mode 100644 index fd405abb..00000000 --- a/common/tests/functional/shared-modules/localization.js +++ /dev/null @@ -1,307 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Adrian Kalla <akalla@aviary.pl> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Include required modules -var domUtils = require("dom-utils"); -var screenshot = require("screenshot"); -var utils = require("utils"); - -const jumlib = {}; -Components.utils.import("resource://mozmill/modules/jum.js", jumlib); - -/** - * Callback function for parsing the results of testing for duplicated - * access keys. - * - * This function processes the access keys found in one access keys scope - * looking for access keys that are listed more than one time. - * At the end, it calls the screenshot.create to create a screenshot with the - * elements containing the broken access keys highlighted. - * - * @param {array of array of object} accessKeysSet - * @param {MozmillController} controller - */ -function checkAccessKeysResults(controller, accessKeysSet) { - // Sort the access keys to have them in a A->Z order - var accessKeysList = accessKeysSet.sort(); - - // List of access keys - var aKeysList = []; - - // List of values to identify the access keys - var valueList = []; - - // List of rectangles of nodes containing access keys - var rects = []; - - // List of rectangles of nodes with broken access keys - var badRects = []; - - // Makes lists of all access keys and the values the access keys are in - for (var i = 0; i < accessKeysList.length; i++) { - var accessKey = accessKeysList[i][0]; - var node = accessKeysList[i][1]; - - // Set the id and label to be shown in the console - var id = node.id || "(id is undefined)"; - var label = node.label || "(label is undefined)"; - - var box = node.boxObject; - - var innerIds = []; - var innerRects = []; - - // if the access key is already in our list, take it out to replace it - // later - if (accessKey == aKeysList[aKeysList.length-1]) { - innerIds = valueList.pop(); - innerRects = rects.pop(); - } else { - aKeysList.push([accessKey]); - } - innerIds.push("[id: " + id + ", label: " + label + "]"); - valueList.push(innerIds); - innerRects.push([box.x, box.y, box.width, box.height]); - rects.push(innerRects); - } - - // Go through all access keys and find the duplicated ones - for (var i = 0; i < valueList.length; i++) { - // Only access keys contained in more than one node are the ones we are - // looking for - if (valueList[i].length > 1) { - for (var j = 0; j < rects[i].length; j++) { - badRects.push(rects[i][j]); - } - jumlib.assert(false, 'accessKey: ' + aKeysList[i] + - ' found in string\'s: ' + valueList[i].join(", ")); - } - } - - // If we have found broken access keys, make a screenshot - if (badRects.length > 0) { - screenshot.create(controller, badRects); - } -} - -/** - * Callback function for testing for cropped elements. - * - * Checks if the XUL boxObject has screen coordinates outside of - * the screen coordinates of its parent. If there's no parent, return. - * - * @param {node} child - * @returns List of boxes that can be highlighted on a screenshot - * @type {array of array of int} - */ -function checkDimensions(child) { - if (!child.boxObject) - return []; - var childBox = child.boxObject; - var parent = childBox.parentBox; - - // toplevel element or hidden elements, like script tags - if (!parent || parent == child.element || !parent.boxObject) { - return []; - } - var parentBox = parent.boxObject; - - var badRects = []; - - // check width - if (childBox.height && childBox.screenX < parentBox.screenX) { - badRects.push([childBox.x, childBox.y, parentBox.x - childBox.x, - childBox.height]); - jumlib.assert(false, 'Node is cut off at the left: ' + - _reportNode(child) + '. Parent node: ' + _reportNode(parent)); - } - if (childBox.height && childBox.screenX + childBox.width > - parentBox.screenX + parentBox.width) { - badRects.push([parentBox.x + parentBox.width, childBox.y, - childBox.x + childBox.width - parentBox.x - parentBox.width, - childBox.height]); - jumlib.assert(false, 'Node is cut off at the right: ' + - _reportNode(child) + '. Parent node: ' + _reportNode(parent)); - } - - // check height - // We don't want to test menupopup's, as they always report the full height - // of all items in the popup - if (child.nodeName != 'menupopup' && parent.nodeName != 'menupopup') { - if (childBox.width && childBox.screenY < parentBox.screenY) { - badRects.push([childBox.x, childBox.y, parentBox.y - childBox.y, - childBox.width]); - jumlib.assert(false, 'Node is cut off at the top: ' + - _reportNode(child) + '. Parent node: ' + _reportNode(parent)); - } - if (childBox.width && childBox.screenY + childBox.height > - parentBox.screenY + parentBox.height) { - badRects.push([childBox.x, parentBox.y + parentBox.height, - childBox.width, - childBox.y + childBox.height - parentBox.y - parentBox.height]); - jumlib.assert(false, 'Node is cut off at the bottom: ' + - _reportNode(child) + '. Parent node: ' + _reportNode(parent)); - } - } - - return badRects; -} - -/** - * Filters out nodes which should not be tested because they are not in the - * current access key scope. - * - * @param {node} node - * @returns Filter status of the given node - * @type {array of array of int} - */ -function filterAccessKeys(node) { - // Menus will need a separate filter set - var notAllowedLocalNames = ["menu", "menubar", "menupopup", "popupset"]; - - if (!node.disabled && !node.collapsed && !node.hidden && - notAllowedLocalNames.indexOf(node.localName) == -1) { - // Code specific to the preferences panes to reject out not visible nodes - // in the panes. - if (node.parentNode && (node.parentNode.localName == "prefwindow" && - node.parentNode.currentPane.id != node.id) || - ((node.parentNode.localName == "tabpanels" || - node.parentNode.localName == "deck") && - node.parentNode.selectedPanel.id != node.id)) { - return domUtils.DOMWalker.FILTER_REJECT; - // end of the specific code - } else if (node.accessKey) { - return domUtils.DOMWalker.FILTER_ACCEPT; - } else { - return domUtils.DOMWalker.FILTER_SKIP; - } - } else { - // we don't want to test not visible elements - return domUtils.DOMWalker.FILTER_REJECT; - } -} - -/** - * Filters out nodes which should not be tested because they are not visible - * - * @param {node} node - * @returns Filter status of the given node - * @type {array of array of int} - */ -function filterCroppedNodes(node) { - if (!node.boxObject) { - return domUtils.DOMWalker.FILTER_SKIP; - } else { - if (!node.disabled && !node.collapsed && !node.hidden) { - // Code specific to the preferences panes to reject out not visible nodes - // in the panes. - if (node.parentNode && (node.parentNode.localName == "prefwindow" && - node.parentNode.currentPane.id != node.id) || - ((node.parentNode.localName == "tabpanels" || - node.parentNode.localName == "deck") && - node.parentNode.selectedPanel.id != node.id)) { - return domUtils.DOMWalker.FILTER_REJECT; - // end of the specific code - } else { - return domUtils.DOMWalker.FILTER_ACCEPT; - } - } else { - // we don't want to test not visible elements - return domUtils.DOMWalker.FILTER_REJECT; - } - } -} - -/** - * Callback function for testing access keys. To be used with the DOMWalker. - * - * It packs a submitted node and its access key into a double array - * - * @param {node} node Node containing the access key - * @returns lower-cased access key and its node in a nested array - * @type {array of array} - */ -function prepareAccessKey(node) { - return [[node.accessKey.toLowerCase(), node]]; -} - -/** - * Callback function for parsing the results of testing for cropped elements. - * - * This function calls the screenshot.create method if there is at least one - * box. - * - * @param {array of array of int} boxes - * @param {MozmillController} controller - */ -function processDimensionsResults(controller, boxes) { - if (boxes && boxes.length > 0) { - screenshot.create(controller, boxes); - } -} - -/** - * Tries to return a useful string identificator of the given node - * - * @param {node} node - * @returns Identificator of the node - * @type {String} - */ -function _reportNode(node) { - if (node.id) { - return "id: " + node.id; - } else if (node.label) { - return "label: " + node.label; - } else if (node.value) { - return "value: " + node.value; - } else if (node.hasAttributes()) { - var attrs = "node attributes: "; - for (var i = node.attributes.length - 1; i >= 0; i--) { - attrs += node.attributes[i].name + "->" + node.attributes[i].value + ";"; - } - return attrs; - } else { - return "anonymous node"; - } -} - -// Export of functions -exports.checkAccessKeysResults = checkAccessKeysResults; -exports.checkDimensions = checkDimensions; -exports.filterAccessKeys = filterAccessKeys; -exports.filterCroppedNodes = filterCroppedNodes; -exports.prepareAccessKey = prepareAccessKey; -exports.processDimensionsResults = processDimensionsResults; diff --git a/common/tests/functional/shared-modules/modal-dialog.js b/common/tests/functional/shared-modules/modal-dialog.js deleted file mode 100644 index 5ba5a9df..00000000 --- a/common/tests/functional/shared-modules/modal-dialog.js +++ /dev/null @@ -1,236 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Clint Talbert <ctalbert@mozilla.com> - * Henrik Skupin <hskupin@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Include required modules -var domUtils = require("dom-utils"); - -const TIMEOUT_MODAL_DIALOG = 5000; -const DELAY_CHECK = 100; - -/** - * Observer object to find the modal dialog spawned by a controller - * - * @constructor - * @class Observer used to find a modal dialog - * - * @param {object} aOpener - * Window which is the opener of the modal dialog - * @param {function} aCallback - * The callback handler to use to interact with the modal dialog - */ -function mdObserver(aOpener, aCallback) { - this._opener = aOpener; - this._callback = aCallback; - this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); -} - -mdObserver.prototype = { - - /** - * Set our default values for our internal properties - */ - _opener : null, - _callback: null, - _timer: null, - exception: null, - finished: false, - - /** - * Check if the modal dialog has been opened - * - * @returns {object} The modal dialog window found, or null. - */ - findWindow : function mdObserver_findWindow() { - // If a window has been opened from content, it has to be unwrapped. - var window = domUtils.unwrapNode(mozmill.wm.getMostRecentWindow('')); - - // Get the WebBrowserChrome and check if it's a modal window - var chrome = window.QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIWebNavigation). - QueryInterface(Ci.nsIDocShellTreeItem). - treeOwner. - QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIWebBrowserChrome); - if (!chrome.isWindowModal()) { - return null; - } - - // Opening a modal dialog from a modal dialog would fail, if we wouldn't - // check for the opener of the modal dialog - var found = false; - if (window.opener) { - // XXX Bug 614757 - an already unwrapped node returns a wrapped node - var opener = domUtils.unwrapNode(window.opener); - found = (mozmill.utils.getChromeWindow(opener) == this._opener); - } - else { - // Also note that it could happen that dialogs don't have an opener - // (i.e. clear recent history). In such a case make sure that the most - // recent window is not the passed in reference opener - found = (window != this._opener); - } - - return (found ? window : null); - }, - - /** - * Called by the timer in the given interval to check if the modal dialog has - * been opened. Once it has been found the callback gets executed - * - * @param {object} aSubject Not used. - * @param {string} aTopic Not used. - * @param {string} aData Not used. - */ - observe : function mdObserver_observe(aSubject, aTopic, aData) { - // Once the window has been found and loaded we can execute the callback - var window = this.findWindow(); - if (window && ("documentLoaded" in window)) { - try { - this._callback(new mozmill.controller.MozMillController(window)); - } - catch (ex) { - // Store the exception, so it can be forwarded if a modal dialog has - // been opened by another modal dialog - this.exception = ex; - } - - if (window) { - window.close(); - } - - this.finished = true; - this.stop(); - } - else { - // otherwise try again in a bit - this._timer.init(this, DELAY_CHECK, Ci.nsITimer.TYPE_ONE_SHOT); - } - }, - - /** - * Stop the timer which checks for new modal dialogs - */ - stop : function mdObserver_stop() { - delete this._timer; - } -}; - - -/** - * Creates a new instance of modalDialog. - * - * @constructor - * @class Handler for modal dialogs - * - * @param {object} aWindow [optional - default: null] - * Window which is the opener of the modal dialog - */ -function modalDialog(aWindow) { - this._window = aWindow || null; -} - -modalDialog.prototype = { - - /** - * Simply checks if the modal dialog has been processed - * - * @returns {boolean} True, if the dialog has been processed - */ - get finished() { - return (!this._observer || this._observer.finished); - }, - - /** - * Start timer to wait for the modal dialog. - * - * @param {function} aCallback - * The callback handler to use to interact with the modal dialog - */ - start : function modalDialog_start(aCallback) { - if (!aCallback) - throw new Error(arguments.callee.name + ": Callback not specified."); - - this._observer = new mdObserver(this._window, aCallback); - - this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this._timer.init(this._observer, DELAY_CHECK, Ci.nsITimer.TYPE_ONE_SHOT); - }, - - /** - * Stop the timer which checks for new modal dialogs - */ - stop : function modalDialog_stop() { - delete this._timer; - - if (this._observer) { - this._observer.stop(); - this._observer = null; - } - }, - - /** - * Wait until the modal dialog has been processed. - * - * @param {Number} aTimeout (optional - default 5s) - * Duration to wait - */ - waitForDialog : function modalDialog_waitForDialog(aTimeout) { - var timeout = aTimeout || TIMEOUT_MODAL_DIALOG; - - if (!this._observer) { - return; - } - - try { - mozmill.utils.waitFor(function () { - return this.finished; - }, "Modal dialog has been found and processed", timeout, undefined, this); - - // Forward the raised exception so we can detect failures in modal dialogs - if (this._observer.exception) { - throw this._observer.exception; - } - } - finally { - this.stop(); - } - } -} - - -// Export of classes -exports.modalDialog = modalDialog; diff --git a/common/tests/functional/shared-modules/performance.js b/common/tests/functional/shared-modules/performance.js deleted file mode 100644 index 14dd4a62..00000000 --- a/common/tests/functional/shared-modules/performance.js +++ /dev/null @@ -1,208 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Geo Mealer <gmealer@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Paths for mapped memory and allocated memory, respectively. Use as -// keys to access the appropriate memory reporters. -const PATH_MAPPED = "malloc/mapped"; -const PATH_ALLOCATED = "malloc/allocated"; - -// Returning this as a numeric constant to simplify memory calculations -// Neither allocated nor mapped should be 0 in real life. -const MEMORY_UNAVAILABLE = "0"; - -// INITIALIZE MEMORY REPORTERS - -// gMemReporters will be a dictionary, key=path and val=reporter -// See initMemReporters() for how it's used. -var gMemReporters = {}; - -/** - * Initialize the static memory reporters - * - * Called during module initialization, below. - * See also aboutMemory.js in Firefox code - */ -function initMemReporters() { - var memMgr = Cc["@mozilla.org/memory-reporter-manager;1"]. - getService(Ci.nsIMemoryReporterManager); - - // Grab all the memory reporters, load into gMemReporters as a dictionary - var e = memMgr.enumerateReporters(); - while (e.hasMoreElements()) { - var memReporter = e.getNext().QueryInterface(Ci.nsIMemoryReporter); - gMemReporters[memReporter.path] = memReporter; - } -} - -initMemReporters(); - -/** - * PERFORMANCE TRACER - * - * Keeps a trace log of both actions and performance statistics - * throughout a test run. - * - * Performance stats currently include mapped and allocated memory. - * More stats will be added as methods to read them are discovered. - * - * Usage: - * Before test, create a new PerfTracer named after the test. - * Ex: var perf = new performance.PerfTracer("MyTestFunc"); - * - * During test, after notable actions call PerfTracer.addCheckpoint(label) - * Ex: perf.addCheckpoint("Opened preferences dialog"); - * - * After test, call PerfTracer.finish() - * Ex: perf.finish(); - */ - -/** - * PerfTracer constructor - * - * @param {string} name - * Name of the tracer, currently used in the output title - */ -function PerfTracer(name) { - if (!name) { - throw new Error(arguments.callee.name + ": name not supplied."); - } - - this.clearLog(); - this._name = name; -} - -PerfTracer.prototype = { - // UTILITY METHODS - - /** - * Format a single result for printing - * - * @param {object} result - * Result as created by addCheckpoint() - * Elements: timestamp {Date} - date/time - * allocated {number} - allocated memory - * mapped {number} - mapped memory - * label {string} - label for result - * - * @returns Result string formatted for output - * @type {string} - */ - _formatResult : function PerfTracer_formatResult(result) { - var resultString = result.timestamp.toUTCString() + " | " + - result.allocated + " | " + - result.mapped + " | " + - result.label + "\n"; - - return resultString; - }, - - // PUBLIC INTERFACE - - /** - * Get a memory value from a reporter - * - * @param {string} path - * Path of memory reporter (e.g. PATH_MAPPED) - * @returns Memory value from requested reporter, MEMORY_UNAVAILABLE if - * not found - * @type {number} - */ - getMemory : function PerfTracer_getMemory(path) { - var val = MEMORY_UNAVAILABLE; - if (path in gMemReporters) { - val = gMemReporters[path].memoryUsed; - } - - return val; - }, - - /** - * Clears the tracker log and starts over - */ - clearLog : function PerfTracer_clearLog() { - this._log = new Array(); - }, - - /** - * Adds a checkpoint to the tracker log, with time and performance info - * - * @param {string} aLabel - * Label attached to performance results. Typically should be - * whatever the test just did. - */ - addCheckpoint : function PerfTracer_addCheckpoint(aLabel) { - var result = { - label: aLabel, - timestamp: new Date(), - mapped: this.getMemory(PATH_MAPPED), - allocated: this.getMemory(PATH_ALLOCATED) - }; - - this._log.push(result); - }, - - /** - * Prints all results to console. - * XXX: make this work with output files - */ - finish : function PerfTracer_finish() { - // Title - var title = "Performance Trace (" + this._name + ")"; - - // Separator - var sep = ""; - for(var i = 0; i < title.length; i++) { - sep += "="; - } - - dump(sep + "\n"); - dump(title + "\n"); - dump(sep + "\n"); - - // Log - for(i = 0; i < this._log.length; i++) { - dump(this._formatResult(this._log[i])); - } - } -} - -// Exported constants -exports.PATH_MAPPED = PATH_MAPPED; -exports.PATH_ALLOCATED = PATH_ALLOCATED; -exports.MEMORY_UNAVAILABLE = MEMORY_UNAVAILABLE; - -// Exported class -exports.PerfTracer = PerfTracer; diff --git a/common/tests/functional/shared-modules/places.js b/common/tests/functional/shared-modules/places.js deleted file mode 100644 index e0f1b795..00000000 --- a/common/tests/functional/shared-modules/places.js +++ /dev/null @@ -1,192 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Geo Mealer <gmealer@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The ModalDialogAPI adds support for handling modal dialogs. It - * has to be used e.g. for alert boxes and other commonDialog instances. - * - * @version 1.0.2 - */ - -// Include required modules -var utils = require("utils"); - -const gTimeout = 5000; - -// Default bookmarks.html file lives in omni.jar, get via resource URI -const BOOKMARKS_RESOURCE = "resource:///defaults/profile/bookmarks.html"; - -// Bookmarks can take up to ten seconds to restore -const BOOKMARKS_TIMEOUT = 10000; - -// Observer topics we need to watch to know whether we're finished -const TOPIC_BOOKMARKS_RESTORE_SUCCESS = "bookmarks-restore-success"; - -/** - * Instance of the bookmark service to gain access to the bookmark API. - * - * @see http://mxr.mozilla.org/mozilla-central (nsINavBookmarksService.idl) - */ -var bookmarksService = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - -/** - * Instance of the history service to gain access to the history API. - * - * @see http://mxr.mozilla.org/mozilla-central (nsINavHistoryService.idl) - */ -var historyService = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); - -/** - * Instance of the livemark service to gain access to the livemark API - * - * @see http://mxr.mozilla.org/mozilla-central (nsILivemarkService.idl) - */ -var livemarkService = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); - -/** - * Instance of the browser history interface to gain access to - * browser-specific history API - * - * @see http://mxr.mozilla.org/mozilla-central (nsIBrowserHistory.idl) - */ -var browserHistory = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsIBrowserHistory); - -/** - * Instance of the observer service to gain access to the observer API - * - * @see http://mxr.mozilla.org/mozilla-central (nsIObserverService.idl) - */ -var observerService = Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); - -/** - * Check if an URI is bookmarked within the specified folder - * - * @param (nsIURI) uri - * URI of the bookmark - * @param {String} folderId - * Folder in which the search has to take place - * @return Returns if the URI exists in the given folder - * @type Boolean - */ -function isBookmarkInFolder(uri, folderId) -{ - var ids = bookmarksService.getBookmarkIdsForURI(uri, {}); - for (let i = 0; i < ids.length; i++) { - if (bookmarksService.getFolderIdForItem(ids[i]) == folderId) - return true; - } - - return false; -} - -/** - * Restore the default bookmarks for the current profile - */ -function restoreDefaultBookmarks() { - // Set up the observer -- we're only checking for success here, so we'll simply - // time out and throw on failure. It makes the code much clearer than handling - // finished state and success state separately. - var importSuccessful = false; - var importObserver = { - observe: function (aSubject, aTopic, aData) { - if (aTopic == TOPIC_BOOKMARKS_RESTORE_SUCCESS) { - importSuccessful = true; - } - } - } - observerService.addObserver(importObserver, TOPIC_BOOKMARKS_RESTORE_SUCCESS, false); - - try { - // Fire off the import - var bookmarksURI = utils.createURI(BOOKMARKS_RESOURCE); - var importer = Cc["@mozilla.org/browser/places/import-export-service;1"]. - getService(Ci.nsIPlacesImportExportService); - importer.importHTMLFromURI(bookmarksURI, true); - - // Wait for it to be finished--the observer above will flip this flag - mozmill.utils.waitFor(function () { - return importSuccessful; - }, "Default bookmarks have finished importing", BOOKMARKS_TIMEOUT); - } - finally { - // Whatever happens, remove the observer afterwards - observerService.removeObserver(importObserver, TOPIC_BOOKMARKS_RESTORE_SUCCESS); - } -} - -/** - * Synchronous wrapper around browserHistory.removeAllPages() - * Removes history and blocks until done - */ -function removeAllHistory() { - const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished"; - - // Create flag visible to both the eval and the observer object - var finishedFlag = { - state: false - } - - // Set up an observer so we get notified when remove completes - let observer = { - observe: function(aSubject, aTopic, aData) { - observerService.removeObserver(this, TOPIC_EXPIRATION_FINISHED); - finishedFlag.state = true; - } - } - observerService.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false); - - // Remove the pages, then block until we're done or until timeout is reached - browserHistory.removeAllPages(); - mozmill.controller.waitForEval("subject.state == true", gTimeout, 100, finishedFlag); -} - -// Export of variables -exports.bookmarksService = bookmarksService; -exports.historyService = historyService; -exports.livemarkService = livemarkService; -exports.browserHistory = browserHistory; - -// Export of functions -exports.isBookmarkInFolder = isBookmarkInFolder; -exports.restoreDefaultBookmarks = restoreDefaultBookmarks; -exports.removeAllHistory = removeAllHistory; diff --git a/common/tests/functional/shared-modules/prefs.js b/common/tests/functional/shared-modules/prefs.js deleted file mode 100644 index 553c4ec8..00000000 --- a/common/tests/functional/shared-modules/prefs.js +++ /dev/null @@ -1,384 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Clint Talbert <ctalbert@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The PrefsAPI adds support for preferences related functions. It gives access - * to the preferences system and allows to handle the preferences dialog - * - * @version 1.0.1 - */ - -// Include required modules -var modalDialog = require("modal-dialog"); -var utils = require("utils"); - - -const gTimeout = 5000; - -// Preferences dialog element templates -const PREF_DIALOG_BUTTONS = '/{"type":"prefwindow"}/anon({"anonid":"dlg-buttons"})'; -const PREF_DIALOG_DECK = '/{"type":"prefwindow"}/anon({"class":"paneDeckContainer"})/anon({"anonid":"paneDeck"})'; -const PREF_DIALOG_SELECTOR = '/{"type":"prefwindow"}/anon({"orient":"vertical"})/anon({"anonid":"selector"})'; - - -/** - * Constructor - * - * @param {MozMillController} controller - * MozMill controller of the browser window to operate on. - */ -function preferencesDialog(controller) { - this._controller = controller; -} - -/** - * Preferences dialog object to simplify the access to this dialog - */ -preferencesDialog.prototype = { - /** - * Returns the MozMill controller - * - * @returns Mozmill controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Retrieve the currently selected panel - * - * @returns The panel element - * @type {ElemBase} - */ - get selectedPane() { - return this.getElement({type: "deck_pane"}); - }, - - /** - * Get the given pane id - */ - get paneId() { - // Check if the selector and the pane are consistent - var selector = this.getElement({type: "selector"}); - - this._controller.waitForEval("subject.selector.getAttribute('pane') == subject.dlg.selectedPane.getNode().id", gTimeout, 100, - {selector: selector.getNode().selectedItem, dlg: this}); - - return this.selectedPane.getNode().id; - }, - - /** - * Set the given pane by id - * - * @param {string} id of the pane - */ - set paneId(id) { - var button = this.getElement({type: "selector_button", value: id}); - this._controller.waitThenClick(button, gTimeout); - - // Check if the correct selector is selected - var selector = this.getElement({type: "selector"}); - this._controller.waitForEval("subject.selector.getAttribute('pane') == subject.newPane", gTimeout, 100, - {selector: selector.getNode().selectedItem, newPane: id}); - return this.paneId; - }, - - /** - * Close the preferences dialog - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @param {boolean} saveChanges - * (Optional) If true the OK button is clicked on Windows which saves - * the changes. On OS X and Linux changes are applied immediately - */ - close : function preferencesDialog_close(saveChanges) { - saveChanges = (saveChanges == undefined) ? false : saveChanges; - - if (mozmill.isWindows) { - var button = this.getElement({type: "button", subtype: (saveChanges ? "accept" : "cancel")}); - this._controller.click(button); - } else { - this._controller.keypress(null, 'w', {accelKey: true}); - } - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function preferencesDialog_getDtds() { - return null; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type {ElemBase} - */ - getElement : function aboutSessionRestore_getElement(spec) { - var elem = null; - - switch(spec.type) { - case "button": - elem = new elementslib.Lookup(this._controller.window.document, PREF_DIALOG_BUTTONS + - '/{"dlgtype":"' + spec.subtype + '"}'); - break; - case "deck": - elem = new elementslib.Lookup(this._controller.window.document, PREF_DIALOG_DECK); - break; - case "deck_pane": - var deck = this.getElement({type: "deck"}).getNode(); - - // XXX: Bug 390724 - selectedPane is broken. So iterate through all elements - var panel = deck.boxObject.firstChild; - for (var ii = 0; ii < deck.selectedIndex; ii++) - panel = panel.nextSibling; - - elem = new elementslib.Elem(panel); - break; - case "selector": - elem = new elementslib.Lookup(this._controller.window.document, PREF_DIALOG_SELECTOR); - break; - case "selector_button": - elem = new elementslib.Lookup(this._controller.window.document, PREF_DIALOG_SELECTOR + - '/{"pane":"' + spec.value + '"}'); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - } -}; - -/** - * Preferences object to simplify the access to the nsIPrefBranch. - */ -var preferences = { - _prefService : Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService), - - /** - * Use branch to access low level functions of nsIPrefBranch - * - * @return Instance of the preferences branch - * @type nsIPrefBranch - */ - get prefBranch() { - return this._prefService.QueryInterface(Ci.nsIPrefBranch); - }, - - /** - * Use defaultPrefBranch to access low level functions of the default branch - * - * @return Instance of the preferences branch - * @type nsIPrefBranch - */ - get defaultPrefBranch() { - return this._prefService.getDefaultBranch(""); - }, - - /** - * Use prefService to access low level functions of nsIPrefService - * - * @return Instance of the pref service - * @type nsIPrefService - */ - get prefService() { - return this._prefService; - }, - - /** - * Clear a user set preference - * - * @param {string} prefName - * The user-set preference to clear - * @return False if the preference had the default value - * @type boolean - **/ - clearUserPref : function preferences_clearUserPref(prefName) { - try { - this.prefBranch.clearUserPref(prefName); - return true; - } catch (e) { - return false; - } - }, - - /** - * Retrieve the value of an individual preference. - * - * @param {string} prefName - * The preference to get the value of. - * @param {boolean/number/string} defaultValue - * The default value if preference cannot be found. - * @param {boolean/number/string} defaultBranch - * If true the value will be read from the default branch (optional) - * @param {string} interfaceType - * Interface to use for the complex value (optional) - * (nsILocalFile, nsISupportsString, nsIPrefLocalizedString) - * - * @return The value of the requested preference - * @type boolean/int/string/complex - */ - getPref : function preferences_getPref(prefName, defaultValue, defaultBranch, - interfaceType) { - try { - branch = defaultBranch ? this.defaultPrefBranch : this.prefBranch; - - // If interfaceType has been set, handle it differently - if (interfaceType != undefined) { - return branch.getComplexValue(prefName, interfaceType); - } - - switch (typeof defaultValue) { - case ('boolean'): - return branch.getBoolPref(prefName); - case ('string'): - return branch.getCharPref(prefName); - case ('number'): - return branch.getIntPref(prefName); - default: - return undefined; - } - } catch(e) { - return defaultValue; - } - }, - - /** - * Set the value of an individual preference. - * - * @param {string} prefName - * The preference to set the value of. - * @param {boolean/number/string/complex} value - * The value to set the preference to. - * @param {string} interfaceType - * Interface to use for the complex value - * (nsILocalFile, nsISupportsString, nsIPrefLocalizedString) - * - * @return Returns if the value was successfully set. - * @type boolean - */ - setPref : function preferences_setPref(prefName, value, interfaceType) { - try { - switch (typeof value) { - case ('boolean'): - this.prefBranch.setBoolPref(prefName, value); - break; - case ('string'): - this.prefBranch.setCharPref(prefName, value); - break; - case ('number'): - this.prefBranch.setIntPref(prefName, value); - break; - default: - this.prefBranch.setComplexValue(prefName, interfaceType, value); - } - } catch(e) { - return false; - } - - return true; - } -}; - -/** - * Open the preferences dialog and call the given handler - * - * @param {MozMillController} controller - * MozMillController which is the opener of the preferences dialog - * @param {function} callback - * The callback handler to use to interact with the preference dialog - * @param {function} launcher - * (Optional) A callback handler to launch the preference dialog - */ -function openPreferencesDialog(controller, callback, launcher) { - if (!controller) - throw new Error("No controller given for Preferences Dialog"); - if (typeof callback != "function") - throw new Error("No callback given for Preferences Dialog"); - - if (mozmill.isWindows) { - // Preference dialog is modal on windows, set up our callback - var prefModal = new modalDialog.modalDialog(controller.window); - prefModal.start(callback); - } - - // Launch the preference dialog - if (launcher) { - launcher(); - } else { - mozmill.getPreferencesController(); - } - - if (mozmill.isWindows) { - prefModal.waitForDialog(); - } else { - // Get the window type of the preferences window depending on the application - var prefWindowType = null; - switch (mozmill.Application) { - case "Thunderbird": - prefWindowType = "Mail:Preferences"; - break; - default: - prefWindowType = "Browser:Preferences"; - } - - utils.handleWindow("type", prefWindowType, callback); - } -} - -// Export of variables -exports.preferences = preferences; - -// Export of functions -exports.openPreferencesDialog = openPreferencesDialog; - -// Export of classes -exports.preferencesDialog = preferencesDialog; diff --git a/common/tests/functional/shared-modules/private-browsing.js b/common/tests/functional/shared-modules/private-browsing.js deleted file mode 100644 index 12344d6b..00000000 --- a/common/tests/functional/shared-modules/private-browsing.js +++ /dev/null @@ -1,237 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The PrivateBrowsingAPI adds support for handling the private browsing mode. - * - * @version 1.0.0 - */ - -// Include required modules -var modalDialog = require("modal-dialog"); -var prefs = require("prefs"); -var utils = require("utils"); - -// Preference for confirmation dialog when entering Private Browsing mode -const PB_NO_PROMPT_PREF = 'browser.privatebrowsing.dont_prompt_on_enter'; - -const gTimeout = 5000; - -/** - * Create a new privateBrowsing instance. - * - * @class This class adds support for the Private Browsing mode - * @param {MozMillController} controller - * MozMillController to use for the modal entry dialog - */ -function privateBrowsing(controller) { - this._controller = controller; - this._handler = null; - - /** - * Menu item in the main menu to enter/leave Private Browsing mode - * @private - */ - this._pbMenuItem = new elementslib.Elem(this._controller.menus['tools-menu'].privateBrowsingItem); - this._pbTransitionItem = new elementslib.ID(this._controller.window.document, "Tools:PrivateBrowsing"); - - this.__defineGetter__('_pbs', function() { - delete this._pbs; - return this._pbs = Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService); - }); -} - -/** - * Prototype definition of the privateBrowsing class - */ -privateBrowsing.prototype = { - /** - * Returns the controller of the current window - * - * @returns Mozmill Controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Checks the state of the Private Browsing mode - * - * @returns Enabled state - * @type {boolean} - */ - get enabled() { - return this._pbs.privateBrowsingEnabled; - }, - - /** - * Sets the state of the Private Browsing mode - * - * @param {boolean} value - * New state of the Private Browsing mode - */ - set enabled(value) { - this._pbs.privateBrowsingEnabled = value; - }, - - /** - * Sets the callback handler for the confirmation dialog - * - * @param {function} callback - * Callback handler for the confirmation dialog - */ - set handler(callback) { - this._handler = callback; - }, - - /** - * Gets the enabled state of the confirmation dialog - * - * @returns Enabled state - * @type {boolean} - */ - get showPrompt() { - return !prefs.preferences.getPref(PB_NO_PROMPT_PREF, true); - }, - - /** - * Sets the enabled state of the confirmation dialog - * - * @param {boolean} value - * New enabled state of the confirmation dialog - */ - set showPrompt(value){ - prefs.preferences.setPref(PB_NO_PROMPT_PREF, !value); - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function downloadManager_getDtds() { - var dtds = ["chrome://branding/locale/brand.dtd", - "chrome://browser/locale/browser.dtd", - "chrome://browser/locale/aboutPrivateBrowsing.dtd"]; - return dtds; - }, - - /** - * Turn off Private Browsing mode and reset all changes - */ - reset : function privateBrowsing_reset() { - try { - this.stop(true); - } catch (ex) { - // Do a hard reset - this.enabled = false; - } - - this.showPrompt = true; - }, - - /** - * Start the Private Browsing mode - * - * @param {boolean} useShortcut - * Use the keyboard shortcut if true otherwise the menu entry is used - */ - start: function privateBrowsing_start(useShortcut) { - var dialog = null; - - if (this.enabled) - return; - - if (this.showPrompt) { - dialog = new modalDialog.modalDialog(this._controller.window); - dialog.start(this._handler); - } - - if (useShortcut) { - var cmdKey = utils.getEntity(this.getDtds(), "privateBrowsingCmd.commandkey"); - this._controller.keypress(null, cmdKey, {accelKey: true, shiftKey: true}); - } else { - this._controller.click(this._pbMenuItem); - } - - if (dialog) { - dialog.waitForDialog(); - } - this.waitForTransistionComplete(true); - }, - - /** - * Stop the Private Browsing mode - * - * @param {boolean} useShortcut - * Use the keyboard shortcut if true otherwise the menu entry is used - */ - stop: function privateBrowsing_stop(useShortcut) - { - if (!this.enabled) - return; - - if (useShortcut) { - var privateBrowsingCmdKey = utils.getEntity(this.getDtds(), "privateBrowsingCmd.commandkey"); - this._controller.keypress(null, privateBrowsingCmdKey, {accelKey: true, shiftKey: true}); - } else { - this._controller.click(this._pbMenuItem); - } - - this.waitForTransistionComplete(false); - }, - - /** - * Waits until the transistion into or out of the Private Browsing mode happened - * - * @param {boolean} state - * Expected target state of the Private Browsing mode - */ - waitForTransistionComplete : function privateBrowsing_waitForTransitionComplete(state) { - // We have to wait until the transition has been finished - this._controller.waitForEval("subject.hasAttribute('disabled') == false", gTimeout, 100, - this._pbTransitionItem.getNode()); - this._controller.waitForEval("subject.privateBrowsing.enabled == subject.state", gTimeout, 100, - {privateBrowsing: this, state: state}); - } -} - -// Export of classes -exports.privateBrowsing = privateBrowsing; diff --git a/common/tests/functional/shared-modules/readme.txt b/common/tests/functional/shared-modules/readme.txt deleted file mode 100644 index 9931d1ca..00000000 --- a/common/tests/functional/shared-modules/readme.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Shared Modules # - -Many common elements are referenced across the Mozmill tests. To make it easier -to work with these elements and execute common actions, shared modules have been -implemented. These modules contain helper classes and helper functions with a -focus on user interface. Some of these shared modules are unique to Firefox, -while others can also be used in other applications based on the Gecko platform. - -For more information on Shared Modules visit: -https://developer.mozilla.org/en/Mozmill_Tests/Shared_Modules diff --git a/common/tests/functional/shared-modules/screenshot.js b/common/tests/functional/shared-modules/screenshot.js deleted file mode 100644 index 19751897..00000000 --- a/common/tests/functional/shared-modules/screenshot.js +++ /dev/null @@ -1,131 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Adrian Kalla <akalla@aviary.pl> - * Axel Hecht <axel@pike.org> - * Henrik Skupin <hskupin@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Include the required modules -var utils = require("utils"); - -/** - * This function creates a screenshot of the window provided in the given - * controller and highlights elements from the coordinates provided in the - * given boxes-array. - * - * @param {array of array of int} boxes - * @param {MozmillController} controller - */ -function create(controller, boxes) { - var doc = controller.window.document; - var maxWidth = doc.documentElement.boxObject.width; - var maxHeight = doc.documentElement.boxObject.height; - var rect = []; - for (var i = 0, j = boxes.length; i < j; ++i) { - rect = boxes[i]; - if (rect[0] + rect[2] > maxWidth) maxWidth = rect[0] + rect[2]; - if (rect[1] + rect[3] > maxHeight) maxHeight = rect[1] + rect[3]; - } - var canvas = doc.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); - var width = doc.documentElement.boxObject.width; - var height = doc.documentElement.boxObject.height; - canvas.width = maxWidth; - canvas.height = maxHeight; - var ctx = canvas.getContext("2d"); - ctx.clearRect(0,0, canvas.width, canvas.height); - ctx.save(); - ctx.drawWindow(controller.window, 0, 0, width, height, "rgb(0,0,0)"); - ctx.restore(); - ctx.save(); - ctx.fillStyle = "rgba(255,0,0,0.4)"; - for (var i = 0, j = boxes.length; i < j; ++i) { - rect = boxes[i]; - ctx.fillRect(rect[0], rect[1], rect[2], rect[3]); - } - ctx.restore(); - - _saveCanvas(canvas); -} - -/** - * Saves a given Canvas object to a file. - * The path to save the file under should be given on the command line. If not, - * it will be saved in the temporary folder of the system. - * - * @param {canvas} canvas - */ -function _saveCanvas(canvas) { - // Use the path given on the command line and saved under - // persisted.screenshotPath, if available. If not, use the path to the - // temporary folder as a fallback. - var file = null; - if ("screenshotPath" in persisted) { - file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); - file.initWithPath(persisted.screenshotPath); - } - else { - file = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties). - get("TmpD", Ci.nsIFile); - } - - var fileName = utils.appInfo.name + "-" + - utils.appInfo.locale + "." + - utils.appInfo.version + "." + - utils.appInfo.buildID + "." + - utils.appInfo.os + ".png"; - file.append(fileName); - - // if a file already exists, don't overwrite it and create a new name - file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0666", 8)); - - // create a data url from the canvas and then create URIs of the source - // and targets - var io = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); - var source = io.newURI(canvas.toDataURL("image/png", ""), "UTF8", null); - var target = io.newFileURI(file) - - // prepare to save the canvas data - var wbPersist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]. - createInstance(Ci.nsIWebBrowserPersist); - - wbPersist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; - wbPersist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; - - // save the canvas data to the file - wbPersist.saveURI(source, null, null, null, null, file); -} - -// Export of functions -exports.create = create; diff --git a/common/tests/functional/shared-modules/search.js b/common/tests/functional/shared-modules/search.js deleted file mode 100644 index 0d40b321..00000000 --- a/common/tests/functional/shared-modules/search.js +++ /dev/null @@ -1,836 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The SearchAPI adds support for search related functions like the search bar. - */ - -// Include required modules -var modalDialog = require("modal-dialog"); -var utils = require("utils"); -var widgets = require("widgets"); - -const TIMEOUT = 5000; -const TIMEOUT_REQUEST_SUGGESTIONS = 750; - -// Helper lookup constants for the engine manager elements -const MANAGER_BUTTONS = '/id("engineManager")/anon({"anonid":"buttons"})'; - -// Helper lookup constants for the search bar elements -const NAV_BAR = '/id("main-window")/id("tab-view-deck")/{"flex":"1"}' + - '/id("navigator-toolbox")/id("nav-bar")'; -const SEARCH_BAR = NAV_BAR + '/id("search-container")/id("searchbar")'; -const SEARCH_TEXTBOX = SEARCH_BAR + '/anon({"anonid":"searchbar-textbox"})'; -const SEARCH_DROPDOWN = SEARCH_TEXTBOX + '/[0]/anon({"anonid":"searchbar-engine-button"})'; -const SEARCH_POPUP = SEARCH_DROPDOWN + '/anon({"anonid":"searchbar-popup"})'; -const SEARCH_INPUT = SEARCH_TEXTBOX + '/anon({"class":"autocomplete-textbox-container"})' + - '/anon({"anonid":"textbox-input-box"})' + - '/anon({"anonid":"input"})'; -const SEARCH_CONTEXT = SEARCH_TEXTBOX + '/anon({"anonid":"textbox-input-box"})' + - '/anon({"anonid":"input-box-contextmenu"})'; -const SEARCH_GO_BUTTON = SEARCH_TEXTBOX + '/anon({"class":"search-go-container"})' + - '/anon({"class":"search-go-button"})'; -const SEARCH_AUTOCOMPLETE = '/id("main-window")/id("mainPopupSet")/id("PopupAutoComplete")'; - -/** - * Constructor - * - * @param {MozMillController} controller - * MozMillController of the engine manager - */ -function engineManager(controller) -{ - this._controller = controller; -} - -/** - * Search Manager class - */ -engineManager.prototype = { - /** - * Get the controller of the associated engine manager dialog - * - * @returns Controller of the browser window - * @type MozMillController - */ - get controller() - { - return this._controller; - }, - - /** - * Gets the list of search engines - * - * @returns List of engines - * @type object - */ - get engines() { - var engines = [ ]; - var tree = this.getElement({type: "engine_list"}).getNode(); - - for (var ii = 0; ii < tree.view.rowCount; ii ++) { - engines.push({name: tree.view.getCellText(ii, tree.columns.getColumnAt(0)), - keyword: tree.view.getCellText(ii, tree.columns.getColumnAt(1))}); - } - - return engines; - }, - - /** - * Gets the name of the selected search engine - * - * @returns Name of the selected search engine - * @type string - */ - get selectedEngine() { - var treeNode = this.getElement({type: "engine_list"}).getNode(); - - if(this.selectedIndex != -1) { - return treeNode.view.getCellText(this.selectedIndex, - treeNode.columns.getColumnAt(0)); - } else { - return null; - } - }, - - /** - * Select the engine with the given name - * - * @param {string} name - * Name of the search engine to select - */ - set selectedEngine(name) { - var treeNode = this.getElement({type: "engine_list"}).getNode(); - - for (var ii = 0; ii < treeNode.view.rowCount; ii ++) { - if (name == treeNode.view.getCellText(ii, treeNode.columns.getColumnAt(0))) { - this.selectedIndex = ii; - break; - } - } - }, - - /** - * Gets the index of the selected search engine - * - * @returns Index of the selected search engine - * @type number - */ - get selectedIndex() { - var tree = this.getElement({type: "engine_list"}); - var treeNode = tree.getNode(); - - return treeNode.view.selection.currentIndex; - }, - - /** - * Select the engine with the given index - * - * @param {number} index - * Index of the search engine to select - */ - set selectedIndex(index) { - var tree = this.getElement({type: "engine_list"}); - var treeNode = tree.getNode(); - - if (index < treeNode.view.rowCount) { - widgets.clickTreeCell(this._controller, tree, index, 0, {}); - } - - this._controller.waitForEval("subject.manager.selectedIndex == subject.newIndex", TIMEOUT, 100, - {manager: this, newIndex: index}); - }, - - /** - * Gets the suggestions enabled state - */ - get suggestionsEnabled() { - var checkbox = this.getElement({type: "suggest"}); - - return checkbox.getNode().checked; - }, - - /** - * Sets the suggestions enabled state - */ - set suggestionsEnabled(state) { - var checkbox = this.getElement({type: "suggest"}); - this._controller.check(checkbox, state); - }, - - /** - * Close the engine manager - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @param {boolean} saveChanges - * (Optional) If true the OK button is clicked otherwise Cancel - */ - close : function preferencesDialog_close(saveChanges) { - saveChanges = (saveChanges == undefined) ? false : saveChanges; - - var button = this.getElement({type: "button", subtype: (saveChanges ? "accept" : "cancel")}); - this._controller.click(button); - }, - - /** - * Edit the keyword associated to a search engine - * - * @param {string} name - * Name of the engine to remove - * @param {function} handler - * Callback function for Engine Manager - */ - editKeyword : function engineManager_editKeyword(name, handler) - { - // Select the search engine - this.selectedEngine = name; - - // Setup the modal dialog handler - md = new modalDialog.modalDialog(this._controller.window); - md.start(handler); - - var button = this.getElement({type: "engine_button", subtype: "edit"}); - this._controller.click(button); - md.waitForDialog(); - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function engineManager_getDtds() { - var dtds = ["chrome://browser/locale/engineManager.dtd"]; - return dtds; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type ElemBase - */ - getElement : function engineManager_getElement(spec) { - var elem = null; - - switch(spec.type) { - /** - * subtype: subtype to match - * value: value to match - */ - case "more_engines": - elem = new elementslib.ID(this._controller.window.document, "addEngines"); - break; - case "button": - elem = new elementslib.Lookup(this._controller.window.document, MANAGER_BUTTONS + - '/{"dlgtype":"' + spec.subtype + '"}'); - break; - case "engine_button": - switch(spec.subtype) { - case "down": - elem = new elementslib.ID(this._controller.window.document, "dn"); - break; - case "edit": - elem = new elementslib.ID(this._controller.window.document, "edit"); - break; - case "remove": - elem = new elementslib.ID(this._controller.window.document, "remove"); - break; - case "up": - elem = new elementslib.ID(this._controller.window.document, "up"); - break; - } - break; - case "engine_list": - elem = new elementslib.ID(this._controller.window.document, "engineList"); - break; - case "suggest": - elem = new elementslib.ID(this._controller.window.document, "enableSuggest"); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Clicks the "Get more search engines..." link - */ - getMoreSearchEngines : function engineManager_getMoreSearchEngines() { - var link = this.getElement({type: "more_engines"}); - this._controller.click(link); - }, - - /** - * Move down the engine with the given name - * - * @param {string} name - * Name of the engine to remove - */ - moveDownEngine : function engineManager_moveDownEngine(name) { - this.selectedEngine = name; - var index = this.selectedIndex; - - var button = this.getElement({type: "engine_button", subtype: "down"}); - this._controller.click(button); - - this._controller.waitForEval("subject.manager.selectedIndex == subject.oldIndex + 1", TIMEOUT, 100, - {manager: this, oldIndex: index}); - }, - - /** - * Move up the engine with the given name - * - * @param {string} name - * Name of the engine to remove - */ - moveUpEngine : function engineManager_moveUpEngine(name) { - this.selectedEngine = name; - var index = this.selectedIndex; - - var button = this.getElement({type: "engine_button", subtype: "up"}); - this._controller.click(button); - - this._controller.waitForEval("subject.manager.selectedIndex == subject.oldIndex - 1", TIMEOUT, 100, - {manager: this, oldIndex: index}); - }, - - /** - * Remove the engine with the given name - * - * @param {string} name - * Name of the engine to remove - */ - removeEngine : function engineManager_removeEngine(name) { - this.selectedEngine = name; - - var button = this.getElement({type: "engine_button", subtype: "remove"}); - this._controller.click(button); - - this._controller.waitForEval("subject.manager.selectedEngine != subject.removedEngine", TIMEOUT, 100, - {manager: this, removedEngine: name}); - }, - - /** - * Restores the defaults for search engines - */ - restoreDefaults : function engineManager_restoreDefaults() { - var button = this.getElement({type: "button", subtype: "extra2"}); - this._controller.click(button); - } -}; - -/** - * Constructor - * - * @param {MozMillController} controller - * MozMillController of the browser window to operate on - */ -function searchBar(controller) -{ - this._controller = controller; - this._bss = Cc["@mozilla.org/browser/search-service;1"] - .getService(Ci.nsIBrowserSearchService); -} - -/** - * Search Manager class - */ -searchBar.prototype = { - /** - * Get the controller of the associated browser window - * - * @returns Controller of the browser window - * @type MozMillController - */ - get controller() - { - return this._controller; - }, - - /** - * Get the names of all installed engines - */ - get engines() - { - var engines = [ ]; - var popup = this.getElement({type: "searchBar_dropDownPopup"}); - - for (var ii = 0; ii < popup.getNode().childNodes.length; ii++) { - var entry = popup.getNode().childNodes[ii]; - if (entry.className.indexOf("searchbar-engine") != -1) { - engines.push({name: entry.id, - selected: entry.selected, - tooltipText: entry.getAttribute('tooltiptext') - }); - } - } - - return engines; - }, - - /** - * Get the search engines drop down open state - */ - get enginesDropDownOpen() - { - var popup = this.getElement({type: "searchBar_dropDownPopup"}); - return popup.getNode().state != "closed"; - }, - - /** - * Set the search engines drop down open state - */ - set enginesDropDownOpen(newState) - { - if (this.enginesDropDownOpen != newState) { - var button = this.getElement({type: "searchBar_dropDown"}); - this._controller.click(button); - - this._controller.waitForEval("subject.searchBar.enginesDropDownOpen == subject.newState", TIMEOUT, 100, - {searchBar: this, newState: newState }); - this._controller.sleep(0); - } - }, - - /** - * Get the names of all installable engines - */ - get installableEngines() - { - var engines = [ ]; - var popup = this.getElement({type: "searchBar_dropDownPopup"}); - - for (var ii = 0; ii < popup.getNode().childNodes.length; ii++) { - var entry = popup.getNode().childNodes[ii]; - if (entry.className.indexOf("addengine-item") != -1) { - engines.push({name: entry.getAttribute('title'), - selected: entry.selected, - tooltipText: entry.getAttribute('tooltiptext') - }); - } - } - - return engines; - }, - - /** - * Returns the currently selected search engine - * - * @return Name of the currently selected engine - * @type string - */ - get selectedEngine() - { - // Open drop down which updates the list of search engines - var state = this.enginesDropDownOpen; - this.enginesDropDownOpen = true; - - var engine = this.getElement({type: "engine", subtype: "selected", value: "true"}); - this._controller.waitForElement(engine, TIMEOUT); - - this.enginesDropDownOpen = state; - - return engine.getNode().id; - }, - - /** - * Select the search engine with the given name - * - * @param {string} name - * Name of the search engine to select - */ - set selectedEngine(name) { - // Open drop down and click on search engine - this.enginesDropDownOpen = true; - - var engine = this.getElement({type: "engine", subtype: "id", value: name}); - this._controller.waitThenClick(engine, TIMEOUT); - - // Wait until the drop down has been closed - this._controller.waitForEval("subject.searchBar.enginesDropDownOpen == false", TIMEOUT, 100, - {searchBar: this}); - - this._controller.waitForEval("subject.searchBar.selectedEngine == subject.newEngine", TIMEOUT, 100, - {searchBar: this, newEngine: name}); - }, - - /** - * Returns all the visible search engines (API call) - */ - get visibleEngines() - { - return this._bss.getVisibleEngines({}); - }, - - /** - * Checks if the correct target URL has been opened for the search - * - * @param {string} searchTerm - * Text which should be checked for - */ - checkSearchResultPage : function searchBar_checkSearchResultPage(searchTerm) { - // Retrieve the URL which is used for the currently selected search engine - var targetUrl = this._bss.currentEngine.getSubmission(searchTerm, null).uri; - var currentUrl = this._controller.tabs.activeTabWindow.document.location; - - var domainRegex = /[^\.]+\.([^\.]+)\..+$/gi; - var targetDomainName = targetUrl.host.replace(domainRegex, "$1"); - var currentDomainName = currentUrl.host.replace(domainRegex, "$1"); - - this._controller.assert(function () { - return currentDomainName === targetDomainName; - }, "Current domain name matches target domain name - got '" + - currentDomainName + "', expected '" + targetDomainName + "'"); - - // Check if search term is listed in URL - this._controller.assert(function () { - return currentUrl.href.toLowerCase().indexOf(searchTerm.toLowerCase()) != -1; - }, "Current URL contains the search term - got '" + - currentUrl.href.toLowerCase() + "', expected '" + searchTerm.toLowerCase() + "'"); - - }, - - /** - * Clear the search field - */ - clear : function searchBar_clear() - { - var activeElement = this._controller.window.document.activeElement; - - var searchInput = this.getElement({type: "searchBar_input"}); - var cmdKey = utils.getEntity(this.getDtds(), "selectAllCmd.key"); - this._controller.keypress(searchInput, cmdKey, {accelKey: true}); - this._controller.keypress(searchInput, 'VK_DELETE', {}); - - if (activeElement) - activeElement.focus(); - }, - - /** - * Focus the search bar text field - * - * @param {object} event - * Specifies the event which has to be used to focus the search bar - */ - focus : function searchBar_focus(event) - { - var input = this.getElement({type: "searchBar_input"}); - - switch (event.type) { - case "click": - this._controller.click(input); - break; - case "shortcut": - if (mozmill.isLinux) { - var cmdKey = utils.getEntity(this.getDtds(), "searchFocusUnix.commandkey"); - } else { - var cmdKey = utils.getEntity(this.getDtds(), "searchFocus.commandkey"); - } - this._controller.keypress(null, cmdKey, {accelKey: true}); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + event.type); - } - - // Check if the search bar has the focus - var activeElement = this._controller.window.document.activeElement; - this._controller.assertJS("subject.isFocused == true", - {isFocused: input.getNode() == activeElement}); - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function searchBar_getDtds() { - var dtds = ["chrome://browser/locale/browser.dtd"]; - return dtds; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type ElemBase - */ - getElement : function searchBar_getElement(spec) { - var elem = null; - - switch(spec.type) { - /** - * subtype: subtype to match - * value: value to match - */ - case "engine": - // XXX: bug 555938 - Mozmill can't fetch the element via a lookup here. - // That means we have to grab it temporarily by iterating through all childs. - var popup = this.getElement({type: "searchBar_dropDownPopup"}).getNode(); - for (var ii = 0; ii < popup.childNodes.length; ii++) { - var entry = popup.childNodes[ii]; - if (entry.getAttribute(spec.subtype) == spec.value) { - elem = new elementslib.Elem(entry); - break; - } - } - //elem = new elementslib.Lookup(this._controller.window.document, SEARCH_POPUP + - // '/anon({"' + spec.subtype + '":"' + spec.value + '"})'); - break; - case "engine_manager": - // XXX: bug 555938 - Mozmill can't fetch the element via a lookup here. - // That means we have to grab it temporarily by iterating through all childs. - var popup = this.getElement({type: "searchBar_dropDownPopup"}).getNode(); - for (var ii = popup.childNodes.length - 1; ii >= 0; ii--) { - var entry = popup.childNodes[ii]; - if (entry.className == "open-engine-manager") { - elem = new elementslib.Elem(entry); - break; - } - } - //elem = new elementslib.Lookup(this._controller.window.document, SEARCH_POPUP + - // '/anon({"anonid":"open-engine-manager"})'); - break; - case "searchBar": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_BAR); - break; - case "searchBar_autoCompletePopup": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_AUTOCOMPLETE); - break; - case "searchBar_contextMenu": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_CONTEXT); - break; - case "searchBar_dropDown": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_DROPDOWN); - break; - case "searchBar_dropDownPopup": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_POPUP); - break; - case "searchBar_goButton": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_GO_BUTTON); - break; - case "searchBar_input": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_INPUT); - break; - case "searchBar_suggestions": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_AUTOCOMPLETE + - '/anon({"anonid":"tree"})'); - break; - case "searchBar_textBox": - elem = new elementslib.Lookup(this._controller.window.document, SEARCH_TEXTBOX); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Returns the search suggestions for the search term - */ - getSuggestions : function(searchTerm) { - var suggestions = [ ]; - var popup = this.getElement({type: "searchBar_autoCompletePopup"}); - var treeElem = this.getElement({type: "searchBar_suggestions"}); - - // XXX Bug 542990, Bug 392633 - // Typing too fast can cause several issue like the suggestions not to appear. - // Lets type the letters one by one and wait for the popup or the timeout - for (var i = 0; i < searchTerm.length; i++) { - try { - this.type(searchTerm[i]); - this._controller.waitFor(function () { - return popup.getNode().state === 'open'; - }, "", TIMEOUT_REQUEST_SUGGESTIONS); - } - catch (e) { - // We are not interested in handling the timeout for now - } - } - - // After entering the search term the suggestions have to be visible - this._controller.assert(function () { - return popup.getNode().state === 'open'; - }, "Search suggestions are visible"); - this._controller.waitForElement(treeElem, TIMEOUT); - - // Get all suggestions - var tree = treeElem.getNode(); - this._controller.waitForEval("subject.tree.view != null", TIMEOUT, 100, - {tree: tree}); - for (var i = 0; i < tree.view.rowCount; i ++) { - suggestions.push(tree.view.getCellText(i, tree.columns.getColumnAt(0))); - } - - // Close auto-complete popup - this._controller.keypress(popup, "VK_ESCAPE", {}); - this._controller.waitForEval("subject.popup.state == 'closed'", TIMEOUT, 100, - {popup: popup.getNode()}); - - return suggestions; - }, - - /** - * Check if a search engine is installed (API call) - * - * @param {string} name - * Name of the search engine to check - */ - isEngineInstalled : function searchBar_isEngineInstalled(name) - { - var engine = this._bss.getEngineByName(name); - return (engine != null); - }, - - /** - * Open the Engine Manager - * - * @param {function} handler - * Callback function for Engine Manager - */ - openEngineManager : function searchBar_openEngineManager(handler) - { - this.enginesDropDownOpen = true; - var engineManager = this.getElement({type: "engine_manager"}); - - // Setup the modal dialog handler - md = new modalDialog.modalDialog(this._controller.window); - md.start(handler); - - // XXX: Bug 555347 - Process any outstanding events before clicking the entry - this._controller.sleep(0); - this._controller.click(engineManager); - md.waitForDialog(); - - this._controller.assert(function () { - return this.enginesDropDownOpen == false; - }, "The search engine drop down menu has been closed", this); - }, - - /** - * Remove the search engine with the given name (API call) - * - * @param {string} name - * Name of the search engine to remove - */ - removeEngine : function searchBar_removeEngine(name) - { - if (this.isEngineInstalled(name)) { - var engine = this._bss.getEngineByName(name); - this._bss.removeEngine(engine); - } - }, - - /** - * Restore the default set of search engines (API call) - */ - restoreDefaultEngines : function searchBar_restoreDefaults() - { - // XXX: Bug 556477 - Restore default sorting - this.openEngineManager(function(controller) { - var manager = new engineManager(controller); - - // We have to do any action so the restore button gets enabled - manager.moveDownEngine(manager.engines[0].name); - manager.restoreDefaults(); - manager.close(true); - }); - - // Update the visibility status for each engine and reset the default engine - this._bss.restoreDefaultEngines(); - this._bss.currentEngine = this._bss.defaultEngine; - - // Clear any entered search term - this.clear(); - }, - - /** - * Start a search with the given search term and check if the resulting URL - * contains the search term. - * - * @param {object} data - * Object which contains the search term and the action type - */ - search : function searchBar_search(data) - { - var searchBar = this.getElement({type: "searchBar"}); - this.type(data.text); - - switch (data.action) { - case "returnKey": - this._controller.keypress(searchBar, 'VK_RETURN', {}); - break; - case "goButton": - default: - this._controller.click(this.getElement({type: "searchBar_goButton"})); - break; - } - - this._controller.waitForPageLoad(); - this.checkSearchResultPage(data.text); - }, - - /** - * Enter a search term into the search bar - * - * @param {string} searchTerm - * Text which should be searched for - */ - type : function searchBar_type(searchTerm) { - var searchBar = this.getElement({type: "searchBar"}); - this._controller.type(searchBar, searchTerm); - } -}; - -// Export of classes -exports.engineManager = engineManager; -exports.searchBar = searchBar; diff --git a/common/tests/functional/shared-modules/sessionstore.js b/common/tests/functional/shared-modules/sessionstore.js deleted file mode 100644 index 94ab9b1a..00000000 --- a/common/tests/functional/shared-modules/sessionstore.js +++ /dev/null @@ -1,318 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Aaron Train <aaron.train@gmail.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The SessionStoreAPI adds support for accessing session related elements and features - * - * @version 1.0.0 - */ - -// Include required modules -var prefs = require("prefs"); -var utils = require("utils"); -var widgets = require("widgets"); - -// Session Store service -var sessionStoreService = Cc["@mozilla.org/browser/sessionstore;1"] - .getService(Ci.nsISessionStore); - -// Preference for indicating the amount of restorable tabs -const SESSIONSTORE_MAXTABS_PREF = 'browser.sessionstore.max_tabs_undo'; - -const gTimeout = 5000; - -/** - * Constructor - * - * @param {MozMillController} controller - * MozMill controller of the browser window to operate on. - */ -function aboutSessionRestore(controller) -{ - this._controller = controller; -} - -/** - * This class handles the about:sessionrestore page. - */ -aboutSessionRestore.prototype = { - /** - * Returns the MozMill controller - * - * @returns Mozmill controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Returns the tree which contains the windows and tabs - * - * @returns Tree with windows and tabs to restore - * @type {ElemBase} - */ - get tabList() { - return this.getElement({type: "tabList"}); - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function aboutSessionRestore_getDtds() { - var dtds = ["chrome://browser/locale/browser.dtd", - "chrome://browser/locale/aboutSessionRestore.dtd"]; - return dtds; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type {ElemBase} - */ - getElement : function aboutSessionRestore_getElement(spec) { - var elem = null; - - switch(spec.type) { - case "button_restoreSession": - elem = new elementslib.ID(this._controller.tabs.activeTab, "errorTryAgain"); - break; - case "error_longDesc": - elem = new elementslib.ID(this._controller.tabs.activeTab, "errorLongDesc"); - break; - case "error_pageContainer": - elem = new elementslib.ID(this._controller.tabs.activeTab, "errorPageContainer"); - break; - case "error_shortDesc": - elem = new elementslib.ID(this._controller.tabs.activeTab, "errorShortDescText"); - break; - case "error_title": - elem = new elementslib.ID(this._controller.tabs.activeTab, "errorTitleText"); - break; - case "tabList": - elem = new elementslib.ID(this._controller.window.document, "tabList"); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Returns the current restore state of the given element - * - * @param {object} element - * Element which restore state should be retrieved - * @returns True if the element should be restored - * @type {boolean} - * - */ - getRestoreState : function aboutSessionRestore_getRestoreState(element) { - var tree = this.tabList.getNode(); - - return tree.view.getCellValue(element.listIndex, tree.columns.getColumnAt(0)); - }, - - /** - * Get restorable tabs under the given window - * - * @param {object} window - * Window inside the tree - * @returns List of tabs - * @type {array of object} - */ - getTabs : function aboutSessionRestore_getTabs(window) { - var tabs = [ ]; - var tree = this.tabList.getNode(); - - // Add entries when they are tabs (no container) - var ii = window.listIndex + 1; - while (ii < tree.view.rowCount && !tree.view.isContainer(ii)) { - tabs.push({ - index: tabs.length, - listIndex : ii, - restore: tree.view.getCellValue(ii, tree.columns.getColumnAt(0)), - title: tree.view.getCellText(ii, tree.columns.getColumnAt(2)) - }); - ii++; - } - - return tabs; - }, - - /** - * Get restorable windows - * - * @returns List of windows - * @type {array of object} - */ - getWindows : function aboutSessionRestore_getWindows() { - var windows = [ ]; - var tree = this.tabList.getNode(); - - for (var ii = 0; ii < tree.view.rowCount; ii++) { - if (tree.view.isContainer(ii)) { - windows.push({ - index: windows.length, - listIndex : ii, - open: tree.view.isContainerOpen(ii), - restore: tree.view.getCellValue(ii, tree.columns.getColumnAt(0)), - title: tree.view.getCellText(ii, tree.columns.getColumnAt(2)) - }); - } - } - - return windows; - }, - - /** - * Toggles the restore state for the element - * - * @param {object} element - * Specifies the element which restore state should be toggled - */ - toggleRestoreState : function aboutSessionRestore_toggleRestoreState(element) { - var state = this.getRestoreState(element); - - widgets.clickTreeCell(this._controller, this.tabList, element.listIndex, 0, {}); - this._controller.sleep(0); - - this._controller.assertJS("subject.newState != subject.oldState", - {newState : this.getRestoreState(element), oldState : state}); - } -} - -/** - * Resets the list of recently closed tabs by setting and clearing the user preference - */ -function resetRecentlyClosedTabs() -{ - prefs.preferences.setPref(SESSIONSTORE_MAXTABS_PREF, 0); - prefs.preferences.clearUserPref(SESSIONSTORE_MAXTABS_PREF); -} - -/** - * Returns the number of restorable tabs for a given window - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @returns The number of restorable tabs in the window - */ -function getClosedTabCount(controller) -{ - return sessionStoreService.getClosedTabCount(controller.window); -} - -/** - * Restores the tab which has been recently closed - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @param {object} event - * Specifies the event to use to execute the command - */ -function undoClosedTab(controller, event) -{ - var count = sessionStoreService.getClosedTabCount(controller.window); - - switch (event.type) { - case "menu": - throw new Error("Menu gets build dynamically and cannot be accessed."); - break; - case "shortcut": - var cmdKey = utils.getEntity(this.getDtds(), "tabCmd.commandkey"); - controller.keypress(null, cmdKey, {accelKey: true, shiftKey: true}); - break; - } - - if (count > 0) - controller.assertJS("subject.newTabCount < subject.oldTabCount", - { - newTabCount : sessionStoreService.getClosedTabCount(controller.window), - oldTabCount : count - }); -} - -/** - * Restores the window which has been recently closed - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @param {object} event - * Specifies the event to use to execute the command - */ -function undoClosedWindow(controller, event) -{ - var count = sessionStoreService.getClosedWindowCount(controller.window); - - switch (event.type) { - case "menu": - throw new Error("Menu gets build dynamically and cannot be accessed."); - break; - case "shortcut": - var cmdKey = utils.getEntity(this.getDtds(), "newNavigatorCmd.key"); - controller.keypress(null, cmdKey, {accelKey: true, shiftKey: true}); - break; - } - - if (count > 0) - controller.assertJS("subject.newWindowCount < subject.oldWindowCount", - { - newWindowCount : sessionStoreService.getClosedWindowCount(controller.window), - oldWindowCount : count - }); -} - -// Export of functions -exports.getClosedTabCount = getClosedTabCount; -exports.resetRecentlyClosedTabs = resetRecentlyClosedTabs; -exports.undoClosedTab = undoClosedTab; -exports.undoClosedWindow = undoClosedWindow; - -// Export of classes -exports.aboutSessionRestore = aboutSessionRestore; diff --git a/common/tests/functional/shared-modules/software-update.js b/common/tests/functional/shared-modules/software-update.js deleted file mode 100644 index 61239589..00000000 --- a/common/tests/functional/shared-modules/software-update.js +++ /dev/null @@ -1,530 +0,0 @@ -/* * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * **** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The SoftwareUpdateAPI adds support for an easy access to the update process. - */ - -// Include required modules -var prefs = require("prefs"); -var utils = require("utils"); - -const gTimeoutUpdateCheck = 10000; -const gTimeoutUpdateDownload = 360000; - -const PREF_DISABLED_ADDONS = "extensions.disabledAddons"; - -// Helper lookup constants for elements of the software update dialog -const WIZARD = '/id("updates")'; -const WIZARD_BUTTONS = WIZARD + '/anon({"anonid":"Buttons"})'; -const WIZARD_DECK = WIZARD + '/anon({"anonid":"Deck"})'; - -const WIZARD_PAGES = { - dummy: 'dummy', - checking: 'checking', - pluginUpdatesFound: 'pluginupdatesfound', - noUpdatesFound: 'noupdatesfound', - manualUpdate: 'manualUpdate', - incompatibleCheck: 'incompatibleCheck', - updatesFoundBasic: 'updatesfoundbasic', - updatesFoundBillboard: 'updatesfoundbillboard', - license: 'license', - incompatibleList: 'incompatibleList', - downloading: 'downloading', - errors: 'errors', - errorPatching: 'errorpatching', - finished: 'finished', - finishedBackground: 'finishedBackground', - installed: 'installed' -} - -// On Mac there is another DOM structure used as on Windows and Linux -if (mozmill.isMac) { - var WIZARD_BUTTONS_BOX = WIZARD_BUTTONS + - '/anon({"flex":"1"})/{"class":"wizard-buttons-btm"}/'; - var WIZARD_BUTTON = { - back: '{"dlgtype":"back"}', - next: '{"dlgtype":"next"}', - cancel: '{"dlgtype":"cancel"}', - finish: '{"dlgtype":"finish"}', - extra1: '{"dlgtype":"extra1"}', - extra2: '{"dlgtype":"extra2"}' - } -} else { - var WIZARD_BUTTONS_BOX = WIZARD_BUTTONS + - '/anon({"flex":"1"})/{"class":"wizard-buttons-box-2"}/'; - var WIZARD_BUTTON = { - back: '{"dlgtype":"back"}', - next: 'anon({"anonid":"WizardButtonDeck"})/[1]/{"dlgtype":"next"}', - cancel: '{"dlgtype":"cancel"}', - finish: 'anon({"anonid":"WizardButtonDeck"})/[0]/{"dlgtype":"finish"}', - extra1: '{"dlgtype":"extra1"}', - extra2: '{"dlgtype":"extra2"}' - } -} - -/** - * Constructor for software update class - */ -function softwareUpdate() { - this._controller = null; - this._wizard = null; - this._downloadDuration = -1; - - this._aus = Cc["@mozilla.org/updates/update-service;1"]. - getService(Ci.nsIApplicationUpdateService); - this._ums = Cc["@mozilla.org/updates/update-manager;1"]. - getService(Ci.nsIUpdateManager); - this._vc = Cc["@mozilla.org/xpcom/version-comparator;1"]. - getService(Ci.nsIVersionComparator); -} - -/** - * Class for software updates - */ -softwareUpdate.prototype = { - /** - * Returns the active update - * - * @returns The currently selected update - * @type nsIUpdate - */ - get activeUpdate() { - return this._ums.activeUpdate; - }, - - /** - * Check if the user has permissions to run the software update - * - * @returns Status if the user has the permissions. - * @type {boolean} - */ - get allowed() { - return this._aus.canCheckForUpdates && this._aus.canApplyUpdates; - }, - - /** - * Returns information of the current build version - */ - get buildInfo() { - return { - buildid : utils.appInfo.buildID, - disabled_addons : prefs.preferences.getPref(PREF_DISABLED_ADDONS, ''), - locale : utils.appInfo.locale, - user_agent : utils.appInfo.userAgent, - version : utils.appInfo.version - }; - }, - - /** - * Returns the current update channel - */ - get channel() { - return prefs.preferences.getPref('app.update.channel', ''); - }, - - /** - * Get the controller of the associated engine manager dialog - * - * @returns Controller of the browser window - * @type MozMillController - */ - get controller() { - return this._controller; - }, - - /** - * Returns the current step of the software update dialog wizard - */ - get currentPage() { - return this._wizard.getNode().getAttribute('currentpageid'); - }, - - /** - * Returns true if the offered update is a complete update - */ - get isCompleteUpdate() { - // Throw when isCompleteUpdate is called without an update. This should - // never happen except if the test is incorrectly written. - if (!this.activeUpdate) - throw new Error(arguments.callee.name + ": isCompleteUpdate called " + - "when activeUpdate is null!"); - - var patchCount = this.activeUpdate.patchCount; - if ((patchCount < 1) || (patchCount > 2)) { - throw new Error("An update must have one or two patches included."); - } - - // XXX: After Firefox 4 has been released and we do not have to test any - // beta release anymore uncomment out the following code -// if (this.activeUpdate.patchCount == 2) { -// var patch0URL = this.activeUpdate.getPatchAt(0).URL; -// var patch1URL = this.activeUpdate.getPatchAt(1).URL; - // Test that the update snippet created by releng doesn't have the same - // url for both patches (bug 514040). -// controller.assertJS("subject.patch0URL != subject.patch1URL", -// {patch0URL: patch0URL, patch1URL: patch1URL}); -// } - - return (this.activeUpdate.selectedPatch.type == "complete"); - }, - - /** - * Returns information of the active update in the queue. - */ - get patchInfo() { - this._controller.assert(function() { - return !!this.activeUpdate; - }, "An active update is in the queue.", this); - - return { - buildid : this.activeUpdate.buildID, - channel : this.channel, - is_complete : this.isCompleteUpdate, - size : this.activeUpdate.selectedPatch.size, - type : this.activeUpdate.type, - url : this.activeUpdate.selectedPatch.finalURL || "n/a", - download_duration : this._downloadDuration, - version : this.activeUpdate.version - }; - }, - - /** - * Returns the update type (minor or major) - * - * @returns The update type - */ - get updateType() { - return this.activeUpdate.type; - }, - - /** - * Check if updates have been found - */ - get updatesFound() { - return this.currentPage.indexOf("updatesfound") == 0; - }, - - /** - * Checks if an update has been applied correctly - * - * @param {object} updateData - * All the data collected during the update process - */ - assertUpdateApplied : function softwareUpdate_assertUpdateApplied(updateData) { - // Get the information from the last update - var info = updateData.updates[updateData.updateIndex]; - - // The upgraded version should be identical with the version given by - // the update and we shouldn't have run a downgrade - var check = this._vc.compare(info.build_post.version, info.build_pre.version); - this._controller.assert(function () { - return check >= 0; - }, "The version number of the upgraded build is higher or equal."); - - // The build id should be identical with the one from the update - this._controller.assert(function () { - return info.build_post.buildid === info.patch.buildid; - }, "The build id is equal to the build id of the update."); - - // If a target build id has been given, check if it matches the updated build - info.target_buildid = updateData.targetBuildID; - if (info.target_buildid) { - this._controller.assert(function () { - return info.build_post.buildid === info.target_buildid; - }, "Target build id matches id of updated build."); - } - - // An upgrade should not change the builds locale - this._controller.assert(function () { - return info.build_post.locale === info.build_pre.locale; - }, "The locale of the updated build is identical to the original locale."); - - // Check that no application-wide add-ons have been disabled - this._controller.assert(function () { - return info.build_post.disabled_addons === info.build_pre.disabled_addons; - }, "No application-wide add-ons have been disabled by the update."); - }, - - /** - * Close the software update dialog - */ - closeDialog: function softwareUpdate_closeDialog() { - if (this._controller) { - this._controller.keypress(null, "VK_ESCAPE", {}); - this._controller.sleep(500); - this._controller = null; - this._wizard = null; - } - }, - - /** - * Download the update of the given channel and type - * @param {string} channel - * Update channel to use - * @param {boolean} waitForFinish - * Sets if the function should wait until the download has been finished - * @param {number} timeout - * Timeout the download has to stop - */ - download : function softwareUpdate_download(channel, waitForFinish, timeout) { - waitForFinish = waitForFinish ? waitForFinish : true; - - // Check that the correct channel has been set - this._controller.assert(function() { - return channel == this.channel; - }, "The current update channel is identical to the specified one.", this); - - // Retrieve the timestamp, so we can measure the duration of the download - var startTime = Date.now(); - - // Click the next button - var next = this.getElement({type: "button", subtype: "next"}); - this._controller.click(next); - - // Wait for the download page - if it fails the update was already cached - try { - this.waitForWizardPage(WIZARD_PAGES.downloading); - - if (waitForFinish) - this.waitforDownloadFinished(timeout); - } catch (ex) { - this.waitForWizardPage(WIZARD_PAGES.finished); - } - - // Calculate the duration in ms - this._downloadDuration = Date.now() - startTime; - }, - - /** - * Update the update.status file and set the status to 'failed:6' - */ - forceFallback : function softwareUpdate_forceFallback() { - var dirService = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties); - - var updateDir; - var updateStatus; - - // Check the global update folder first - try { - updateDir = dirService.get("UpdRootD", Ci.nsIFile); - updateDir.append("updates"); - updateDir.append("0"); - - updateStatus = updateDir.clone(); - updateStatus.append("update.status"); - } catch (ex) { - } - - if (updateStatus == undefined || !updateStatus.exists()) { - updateDir = dirService.get("XCurProcD", Ci.nsIFile); - updateDir.append("updates"); - updateDir.append("0"); - - updateStatus = updateDir.clone(); - updateStatus.append("update.status"); - } - - var foStream = Cc["@mozilla.org/network/file-output-stream;1"]. - createInstance(Ci.nsIFileOutputStream); - var status = "failed: 6\n"; - foStream.init(updateStatus, 0x02 | 0x08 | 0x20, -1, 0); - foStream.write(status, status.length); - foStream.close(); - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function softwareUpdate_getDtds() { - var dtds = ["chrome://mozapps/locale/update/history.dtd", - "chrome://mozapps/locale/update/updates.dtd"] - return dtds; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type {ElemBase} - */ - getElement : function softwareUpdate_getElement(spec) { - var elem = null; - - switch(spec.type) { - /** - * subtype: subtype to match - * value: value to match - */ - case "button": - elem = new elementslib.Lookup(this._controller.window.document, - WIZARD_BUTTONS_BOX + WIZARD_BUTTON[spec.subtype]); - break; - case "wizard": - elem = new elementslib.Lookup(this._controller.window.document, WIZARD); - break; - case "wizard_page": - elem = new elementslib.Lookup(this._controller.window.document, WIZARD_DECK + - '/id(' + spec.subtype + ')'); - break; - case "download_progress": - elem = new elementslib.ID(this._controller.window.document, "downloadProgress"); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Open software update dialog - * - * @param {MozMillController} browserController - * Mozmill controller of the browser window - */ - openDialog: function softwareUpdate_openDialog(browserController) { - // XXX: After Firefox 4 has been released and we do not have to test any - // beta release anymore uncomment out the following code - - // With version >= 4.0b7pre the update dialog is reachable from within the - // about window now. - var appVersion = utils.appInfo.version; - - if (this._vc.compare(appVersion, "4.0b7pre") >= 0) { - // XXX: We can't open the about window, otherwise a parallel download of - // the update will let us fallback to a complete one all the time - - // Open the about window and check the update button - //var aboutItem = new elementslib.Elem(browserController.menus.helpMenu.aboutName); - //browserController.click(aboutItem); - // - //utils.handleWindow("type", "Browser:About", function(controller) { - // // XXX: Bug 599290 - Check for updates has been completely relocated - // // into the about window. We can't check the in-about ui yet. - // var updateButton = new elementslib.ID(controller.window.document, - // "checkForUpdatesButton"); - // //controller.click(updateButton); - // controller.waitForElement(updateButton, gTimeout); - //}); - - // For now just call the old ui until we have support for the about window. - var updatePrompt = Cc["@mozilla.org/updates/update-prompt;1"]. - createInstance(Ci.nsIUpdatePrompt); - updatePrompt.checkForUpdates(); - } else { - // For builds <4.0b7pre - updateItem = new elementslib.Elem(browserController.menus.helpMenu.checkForUpdates); - browserController.click(updateItem); - } - - this.waitForDialogOpen(browserController); - }, - - /** - * Wait that check for updates has been finished - * @param {number} timeout - */ - waitForCheckFinished : function softwareUpdate_waitForCheckFinished(timeout) { - timeout = timeout ? timeout : gTimeoutUpdateCheck; - - this._controller.waitFor(function() { - return this.currentPage != WIZARD_PAGES.checking; - }, "Check for updates has been completed.", timeout, null, this); - }, - - /** - * Wait for the software update dialog - * - * @param {MozMillController} browserController - * Mozmill controller of the browser window - */ - waitForDialogOpen : function softwareUpdate_waitForDialogOpen(browserController) { - this._controller = utils.handleWindow("type", "Update:Wizard", - undefined, false); - this._wizard = this.getElement({type: "wizard"}); - - this._controller.waitFor(function () { - return this.currentPage !== WIZARD_PAGES.dummy; - }, "Dummy wizard page has been made invisible - got " + this.currentPage, - undefined, undefined, this); - - this._controller.window.focus(); - }, - - /** - * Wait until the download has been finished - * - * @param {number} timeout - * Timeout the download has to stop - */ - waitforDownloadFinished: function softwareUpdate_waitForDownloadFinished(timeout) { - timeout = timeout ? timeout : gTimeoutUpdateDownload; - - var progress = this.getElement({type: "download_progress"}); - this._controller.waitFor(function () { - return progress.getNode().value === '100'; - }, "Update has been finished downloading.", timeout); - - this.waitForWizardPage(WIZARD_PAGES.finished); - }, - - /** - * Waits for the given page of the update dialog wizard - */ - waitForWizardPage : function softwareUpdate_waitForWizardPage(step) { - this._controller.waitFor(function () { - return this.currentPage === step; - }, "New wizard page has been selected - got " + this.currentPage + - ", expected " + step, undefined, undefined, this); - } -} - -// Export of variables -exports.WIZARD_PAGES = WIZARD_PAGES; - -// Export of classes -exports.softwareUpdate = softwareUpdate; diff --git a/common/tests/functional/shared-modules/tabs.js b/common/tests/functional/shared-modules/tabs.js deleted file mode 100644 index b6e75686..00000000 --- a/common/tests/functional/shared-modules/tabs.js +++ /dev/null @@ -1,503 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Anthony Hughes <ahughes@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The TabbedBrowsingAPI adds support for accessing and interacting with tab elements - * - * @version 1.0.0 - */ - -// Include required modules -var utils = require("utils"); -var prefs = require("prefs"); - -const TIMEOUT = 5000; - -const PREF_TABS_ANIMATE = "browser.tabs.animate"; - -const TABS_VIEW = '/id("main-window")/id("tab-view-deck")/{"flex":"1"}'; -const TABS_BROWSER = TABS_VIEW + '/id("browser")/id("appcontent")/id("content")'; -const TABS_TOOLBAR = TABS_VIEW + '/id("navigator-toolbox")/id("TabsToolbar")'; -const TABS_TABS = TABS_TOOLBAR + '/id("tabbrowser-tabs")'; -const TABS_ARROW_SCROLLBOX = TABS_TABS + '/anon({"anonid":"arrowscrollbox"})'; -const TABS_STRIP = TABS_ARROW_SCROLLBOX + '/anon({"anonid":"scrollbox"})/anon({"flex":"1"})'; - -/** - * Close all tabs and open about:blank - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - */ -function closeAllTabs(controller) -{ - var browser = new tabBrowser(controller); - browser.closeAllTabs(); -} - -/** - * Check and return all open tabs with the specified URL - * - * @param {string} aUrl - * URL to check for - * - * @returns Array of tabs - */ -function getTabsWithURL(aUrl) { - var tabs = [ ]; - - var uri = utils.createURI(aUrl, null, null); - - var wm = Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator); - var winEnum = wm.getEnumerator("navigator:browser"); - - // Iterate through all windows - while (winEnum.hasMoreElements()) { - var window = winEnum.getNext(); - - // Don't check windows which are about to close or don't have gBrowser set - if (window.closed || !("gBrowser" in window)) - continue; - - // Iterate through all tabs in the current window - var browsers = window.gBrowser.browsers; - for (var i = 0; i < browsers.length; i++) { - var browser = browsers[i]; - if (browser.currentURI.equals(uri)) { - tabs.push({ - controller : new mozmill.controller.MozMillController(window), - index : i - }); - } - } - } - - return tabs; -} - -/** - * Constructor - * - * @param {MozMillController} controller - * MozMill controller of the window to operate on - */ -function tabBrowser(controller) -{ - this._controller = controller; - this._tabs = this.getElement({type: "tabs"}); -} - -/** - * Tabbed Browser class - */ -tabBrowser.prototype = { - /** - * Returns the MozMill controller - * - * @returns Mozmill controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Get the amount of open tabs - * - * @returns Number of tabs - * @type {number} - */ - get length() { - return this._tabs.getNode().itemCount; - }, - - /** - * Get the currently selected tab index - * - * @returns Index of currently selected tab - * @type {number} - */ - get selectedIndex() { - return this._tabs.getNode().selectedIndex; - }, - - /** - * Select the tab with the given index - * - * @param {number} index - * Index of the tab which should be selected - */ - set selectedIndex(index) { - this._controller.click(this.getTab(index)); - }, - - /** - * Close all tabs of the window except the last one and open a blank page. - */ - closeAllTabs : function tabBrowser_closeAllTabs() - { - while (this._controller.tabs.length > 1) { - this.closeTab({type: "menu"}); - } - - this._controller.open("about:blank"); - this._controller.waitForPageLoad(); - }, - - /** - * Close an open tab - * - * @param {object} aEvent - * The event specifies how to close a tab - * Elements: type - Type of event (closeButton, menu, middleClick, shortcut) - * [optional - default: menu] - */ - closeTab : function tabBrowser_closeTab(aEvent) { - var event = aEvent || { }; - var type = (event.type == undefined) ? "menu" : event.type; - - // Disable tab closing animation for default behavior - prefs.preferences.setPref(PREF_TABS_ANIMATE, false); - - // Add event listener to wait until the tab has been closed - var self = { closed: false }; - function checkTabClosed() { self.closed = true; } - this._controller.window.addEventListener("TabClose", checkTabClosed, false); - - switch (type) { - case "closeButton": - var button = this.getElement({type: "tabs_tabCloseButton", - subtype: "tab", value: this.getTab()}); - this._controller.click(button); - break; - case "menu": - var menuitem = new elementslib.Elem(this._controller.menus['file-menu'].menu_close); - this._controller.click(menuitem); - break; - case "middleClick": - var tab = this.getTab(event.index); - this._controller.middleClick(tab); - break; - case "shortcut": - var cmdKey = utils.getEntity(this.getDtds(), "closeCmd.key"); - this._controller.keypress(null, cmdKey, {accelKey: true}); - break; - default: - throw new Error(arguments.callee.name + ": Unknown event type - " + type); - } - - try { - this._controller.waitForEval("subject.tab.closed == true", TIMEOUT, 100, - {tab: self}); - } finally { - this._controller.window.removeEventListener("TabClose", checkTabClosed, false); - prefs.preferences.clearUserPref(PREF_TABS_ANIMATE); - } - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function tabBrowser_getDtds() { - var dtds = ["chrome://browser/locale/browser.dtd", - "chrome://browser/locale/tabbrowser.dtd", - "chrome://global/locale/global.dtd"]; - return dtds; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type {ElemBase} - */ - getElement : function tabBrowser_getElement(spec) { - var document = this._controller.window.document; - var elem = null; - - switch(spec.type) { - /** - * subtype: subtype to match - * value: value to match - */ - case "tabs": - elem = new elementslib.Lookup(this._controller.window.document, - TABS_TABS); - break; - case "tabs_allTabsButton": - elem = new elementslib.Lookup(this._controller.window.document, - TABS_TOOLBAR + '/id("alltabs-button")'); - break; - case "tabs_allTabsPopup": - elem = new elementslib.Lookup(this._controller.window.document, TABS_TOOLBAR + - '/id("alltabs-button")/id("alltabs-popup")'); - break; - case "tabs_newTabButton": - elem = new elementslib.Lookup(this._controller.window.document, - TABS_ARROW_SCROLLBOX + '/anon({"class":"tabs-newtab-button"})'); - break; - case "tabs_scrollButton": - elem = new elementslib.Lookup(this._controller.window.document, - TABS_ARROW_SCROLLBOX + - '/anon({"anonid":"scrollbutton-' + spec.subtype + '"})'); - break; - case "tabs_strip": - elem = new elementslib.Lookup(this._controller.window.document, TABS_STRIP); - break; - case "tabs_tab": - switch (spec.subtype) { - case "index": - elem = new elementslib.Elem(this._tabs.getNode().getItemAtIndex(spec.value)); - break; - } - break; - case "tabs_tabCloseButton": - var node = document.getAnonymousElementByAttribute( - spec.value.getNode(), - "anonid", - "close-button" - ); - elem = new elementslib.Elem(node); - break; - case "tabs_tabFavicon": - var node = document.getAnonymousElementByAttribute( - spec.value.getNode(), - "class", - "tab-icon-image" - ); - - elem = new elementslib.Elem(node); - break; - case "tabs_tabPanel": - var panelId = spec.value.getNode().getAttribute("linkedpanel"); - elem = new elementslib.Lookup(this._controller.window.document, TABS_BROWSER + - '/anon({"anonid":"tabbox"})/anon({"anonid":"panelcontainer"})' + - '/{"id":"' + panelId + '"}'); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Get the tab at the specified index - * - * @param {number} index - * Index of the tab - * @returns The requested tab - * @type {ElemBase} - */ - getTab : function tabBrowser_getTab(index) { - if (index === undefined) - index = this.selectedIndex; - - return this.getElement({type: "tabs_tab", subtype: "index", value: index}); - }, - - /** - * Creates the child element of the tab's notification bar - * - * @param {number} tabIndex - * (Optional) Index of the tab to check - * @param {string} elemString - * (Optional) Lookup string of the notification bar's child element - * @return The created child element - * @type {ElemBase} - */ - getTabPanelElement : function tabBrowser_getTabPanelElement(tabIndex, elemString) - { - var index = tabIndex ? tabIndex : this.selectedIndex; - var elemStr = elemString ? elemString : ""; - - // Get the tab panel and check if an element has to be fetched - var panel = this.getElement({type: "tabs_tabPanel", subtype: "tab", value: this.getTab(index)}); - var elem = new elementslib.Lookup(this._controller.window.document, panel.expression + elemStr); - - return elem; - }, - - /** - * Open element (link) in a new tab - * - * @param {object} aEvent - * The event specifies how to open the element in a new tab - * Elements: type - Type of event (contextMenu, middleClick) - * [optional - default: middleClick] - * target - Element to click on - * [optional - default: -] - */ - openInNewTab : function tabBrowser_openInNewTab(aEvent) { - var event = aEvent || { }; - var type = (event.type == undefined) ? "middleClick" : event.type; - var target = event.target; - - // Disable tab closing animation for default behavior - prefs.preferences.setPref(PREF_TABS_ANIMATE, false); - - // Add event listener to wait until the tab has been opened - var self = { opened: false }; - function checkTabOpened() { self.opened = true; } - this._controller.window.addEventListener("TabOpen", checkTabOpened, false); - - switch (type) { - case "contextMenu": - var contextMenuItem = new elementslib.ID(this._controller.window.document, - "context-openlinkintab"); - this._controller.rightClick(target); - this._controller.click(contextMenuItem); - utils.closeContentAreaContextMenu(this._controller); - break; - case "middleClick": - this._controller.middleClick(target); - break; - default: - throw new Error(arguments.callee.name + ": Unknown event type - " + type); - } - - try { - this._controller.waitForEval("subject.tab.opened == true", TIMEOUT, 100, - {tab: self}); - } finally { - this._controller.window.removeEventListener("TabOpen", checkTabOpened, false); - prefs.preferences.clearUserPref(PREF_TABS_ANIMATE); - } - }, - - /** - * Open a new tab - * - * @param {object} aEvent - * The event specifies how to open a new tab (menu, shortcut, - * Elements: type - Type of event (menu, newTabButton, shortcut, tabStrip) - * [optional - default: menu] - */ - openTab : function tabBrowser_openTab(aEvent) { - var event = aEvent || { }; - var type = (event.type == undefined) ? "menu" : event.type; - - // Disable tab closing animation for default behavior - prefs.preferences.setPref(PREF_TABS_ANIMATE, false); - - // Add event listener to wait until the tab has been opened - var self = { opened: false }; - function checkTabOpened() { self.opened = true; } - this._controller.window.addEventListener("TabOpen", checkTabOpened, false); - - switch (type) { - case "menu": - var menuitem = new elementslib.Elem(this._controller.menus['file-menu'].menu_newNavigatorTab); - this._controller.click(menuitem); - break; - case "shortcut": - var cmdKey = utils.getEntity(this.getDtds(), "tabCmd.commandkey"); - this._controller.keypress(null, cmdKey, {accelKey: true}); - break; - case "newTabButton": - var newTabButton = this.getElement({type: "tabs_newTabButton"}); - this._controller.click(newTabButton); - break; - case "tabStrip": - var tabStrip = this.getElement({type: "tabs_strip"}); - - // RTL-locales need to be treated separately - if (utils.getEntity(this.getDtds(), "locale.dir") == "rtl") { - // XXX: Workaround until bug 537968 has been fixed - this._controller.click(tabStrip, 100, 3); - // Todo: Calculate the correct x position - this._controller.doubleClick(tabStrip, 100, 3); - } else { - // XXX: Workaround until bug 537968 has been fixed - this._controller.click(tabStrip, tabStrip.getNode().clientWidth - 100, 3); - // Todo: Calculate the correct x position - this._controller.doubleClick(tabStrip, tabStrip.getNode().clientWidth - 100, 3); - } - break; - default: - throw new Error(arguments.callee.name + ": Unknown event type - " + type); - } - - try { - this._controller.waitForEval("subject.tab.opened == true", TIMEOUT, 100, - {tab: self}); - } finally { - this._controller.window.removeEventListener("TabOpen", checkTabOpened, false); - prefs.preferences.clearUserPref(PREF_TABS_ANIMATE); - } - }, - - /** - * Waits for a particular tab panel element to display and stop animating - * - * @param {number} tabIndex - * Index of the tab to check - * @param {string} elemString - * Lookup string of the tab panel element - */ - waitForTabPanel: function tabBrowser_waitForTabPanel(tabIndex, elemString) { - // Get the specified tab panel element - var tabPanel = this.getTabPanelElement(tabIndex, elemString); - - // Get the style information for the tab panel element - var style = this._controller.window.getComputedStyle(tabPanel.getNode(), null); - - // Wait for the top margin to be 0px - ie. has stopped animating - // XXX: A notification bar starts at a negative pixel margin and drops down - // to 0px. This creates a race condition where a test may click - // before the notification bar appears at it's anticipated screen location - this._controller.waitFor(function () { - return style.marginTop == '0px'; - }, "Expected notification bar to be visible: '" + elemString + "' "); - } -} - -// Export of functions -exports.closeAllTabs = closeAllTabs; -exports.getTabsWithURL = getTabsWithURL; - -// Export of classes -exports.tabBrowser = tabBrowser; diff --git a/common/tests/functional/shared-modules/tabview.js b/common/tests/functional/shared-modules/tabview.js deleted file mode 100644 index 8c873058..00000000 --- a/common/tests/functional/shared-modules/tabview.js +++ /dev/null @@ -1,629 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Include required modules -var domUtils = require("dom-utils"); -var tabs = require("tabs"); -var utils = require("utils"); - -const TIMEOUT = 5000; - -/** - * Constructor - */ -function tabView(aController) { - this._controller = aController; - this._tabView = null; - this._tabViewDoc = this._controller.window.document; - this._tabViewObject = this._controller.window.TabView; -} - -/** - * Tab View class - */ -tabView.prototype = { - - /////////////////////////////// - // Global section - /////////////////////////////// - - /** - * Returns the MozMill controller - * - * @returns Mozmill controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Check if the Tab View is open - * - * @returns True if the Tab View is open - * @type {boolean} - */ - get isOpen() { - var deck = this.getElement({type: "deck"}); - return deck.getNode().getAttribute("selectedIndex") == "1"; - }, - - /** - * Open the Tab View - */ - open : function tabView_open() { - var menuitem = new elementslib.Elem(this._controller.menus['view-menu'].menu_tabview); - this._controller.click(menuitem); - this.waitForOpened(); - - this._tabView = this.getElement({type: "tabView"}); - this._tabViewDoc = this._tabView.getNode().webNavigation.document; - }, - - /** - * Reset the Tab View settings for the current window - */ - reset : function tabView_reset() { - // Make sure to close TabView before resetting its ui - if (this.isOpen) { - this.close(); - } - - var self = this; - this._tabViewObject._initFrame(function () { - var contentWindow = self._tabViewObject._window; - contentWindow.UI.reset(); - }); - - // Make sure all tabs will be shown - Array.forEach(this._controller.window.gBrowser.tabs, function (tab) { - this._controller.window.gBrowser.showTab(tab); - }, this); - }, - - /** - * Wait until the Tab View has been opened - */ - waitForOpened : function tabView_waitForOpened() { - // Add event listener to wait until the tabview has been opened - var self = { opened: false }; - function checkOpened() { self.opened = true; } - this._controller.window.addEventListener("tabviewshown", checkOpened, false); - - try { - mozmill.utils.waitFor(function () { - return self.opened == true; - }, "TabView is not open."); - - this._groupItemsObject = this._tabViewObject._window.GroupItems; - this._tabItemsObject = this._tabViewObject._window.TabItems; - } - finally { - this._controller.window.removeEventListener("tabviewshown", checkOpened, false); - } - }, - - /** - * Close the Tab View - */ - close : function tabView_close() { - var menuitem = new elementslib.Elem(this._controller.menus['view-menu'].menu_tabview); - this._controller.click(menuitem); - this.waitForClosed(); - - this._tabView = null; - this._tabViewDoc = this._controller.window.document; - }, - - /** - * Wait until the Tab View has been closed - */ - waitForClosed : function tabView_waitForClosed() { - // Add event listener to wait until the tabview has been closed - var self = { closed: false }; - function checkClosed() { self.closed = true; } - this._controller.window.addEventListener("tabviewhidden", checkClosed, false); - - try { - mozmill.utils.waitFor(function () { - return self.closed == true; - }, "TabView is still open."); - } finally { - this._controller.window.removeEventListener("tabviewhidden", checkClosed, false); - } - - this._groupItemsObject = null; - this._tabItemsObject = null; - }, - - - /////////////////////////////// - // Groups section - /////////////////////////////// - - /** - * Returns the tab groups which match the filter criteria - * - * @param {object} aSpec - * Information about the filter to apply - * Elements: filter - Type of filter to apply - * (active, title) - * [optional - default: ""] - * value - Value of the element - * [optional - default: ""] - * - * @returns List of groups - * @type {array of ElemBase} - */ - getGroups : function tabView_getGroups(aSpec) { - var spec = aSpec || {}; - - return this.getElements({ - type: "groups", - subtype: spec.filter, - value: spec.value - }); - }, - - /** - * Retrieve the group's title box - * - * @param {object} aSpec - * Information on which group to operate on - * Elements: group - Group element - * - * @returns Group title box - * @type {ElemBase} - */ - getGroupTitleBox : function tabView_getGroupTitleBox(aSpec) { - var spec = aSpec || {}; - var group = spec.group; - - if (!group) { - throw new Error(arguments.callee.name + ": Group not specified."); - } - - return this.getElement({ - type: "group_titleBox", - parent: group - }); - }, - - /** - * Close the specified tab group - * - * @param {object} aSpec - * Information on which group to operate on - * Elements: group - Group - */ - closeGroup : function tabView_closeGroup(aSpec) { - var spec = aSpec || {}; - var group = spec.group; - - if (!group) { - throw new Error(arguments.callee.name + ": Group not specified."); - } - - var button = this.getElement({ - type: "group_closeButton", - parent: group - }); - this._controller.click(button); - - this.waitForGroupClosed({group: group}); - }, - - /** - * Wait until the specified tab group has been closed - * - * @param {object} aSpec - * Information on which group to operate on - * Elements: group - Group - */ - waitForGroupClosed : function tabView_waitForGroupClosed(aSpec) { - var spec = aSpec || {}; - var group = spec.group; - var groupObj = null; - - var self = { closed: false }; - function checkClosed() { self.closed = true; } - - if (!group) { - throw new Error(arguments.callee.name + ": Group not specified."); - } - - this._groupItemsObject.groupItems.forEach(function (node) { - if (node.container == group.getNode()) { - groupObj = node; - } - }); - - if (!groupObj) { - throw new Error(arguments.callee.name + ": Group not found."); - } - - try { - groupObj.addSubscriber(groupObj, "groupHidden", checkClosed); - mozmill.utils.waitFor(function () { - return self.closed; - }, "Tab Group has not been closed."); - } - finally { - groupObj.removeSubscriber(groupObj, "groupHidden"); - } - }, - - /** - * Undo the closing of the specified tab group - * - * @param {object} aSpec - * Information on which group to operate on - * Elements: group - Group - */ - undoCloseGroup : function tabView_undoCloseGroup(aSpec) { - var spec = aSpec || {}; - var group = spec.group; - - if (!group) { - throw new Error(arguments.callee.name + ": Group not specified."); - } - - var undo = this.getElement({ - type: "group_undoButton", - parent: group - }); - this._controller.waitThenClick(undo); - - this.waitForGroupUndo({group: group}); - }, - - /** - * Wait until the specified tab group has been reopened - * - * @param {object} aSpec - * Information on which group to operate on - * Elements: group - Group - */ - waitForGroupUndo : function tabView_waitForGroupUndo(aSpec) { - var spec = aSpec || {}; - var group = spec.group; - var groupObj = null; - - var self = { reopened: false }; - function checkClosed() { self.reopened = true; } - - if (!group) { - throw new Error(arguments.callee.name + ": Group not specified."); - } - - var groupObj = null; - this._groupItemsObject.groupItems.forEach(function(node) { - if (node.container == group.getNode()) { - groupObj = node; - } - }); - - if (!groupObj) { - throw new Error(arguments.callee.name + ": Group not found."); - } - - try { - groupObj.addSubscriber(groupObj, "groupShown", checkClosed); - mozmill.utils.waitFor(function () { - return self.reopened; - }, "Tab Group has not been reopened."); - } - finally { - groupObj.removeSubscriber(groupObj, "groupShown"); - } - }, - - - /////////////////////////////// - // Tabs section - /////////////////////////////// - - /** - * Returns the tabs which match the filter criteria - * - * @param {object} aSpec - * Information about the filter to apply - * Elements: filter - Type of filter to apply - * (active, title) - * [optional - default: ""] - * value - Value of the element - * [optional - default: ""] - * - * @returns List of tabs - * @type {array of ElemBase} - */ - getTabs : function tabView_getTabs(aSpec) { - var spec = aSpec || {}; - - return this.getElements({ - type: "tabs", - subtype: spec.filter, - value: spec.value - }); - }, - - /** - * Close a tab - * - * @param {object} aSpec - * Information about the element to operate on - * Elements: tab - Tab to close - */ - closeTab : function tabView_closeTab(aSpec) { - var spec = aSpec || {}; - var tab = spec.tab; - - if (!tab) { - throw new Error(arguments.callee.name + ": Tab not specified."); - } - - var button = this.getElement({ - type: "tab_closeButton", - value: tab} - ); - this._controller.click(button); - }, - - /** - * Retrieve the tab's title box - * - * @param {object} aSpec - * Information on which tab to operate on - * Elements: tab - Tab - * - * @returns Tab title box - * @type {ElemBase} - */ - getTabTitleBox : function tabView_getTabTitleBox(aSpec) { - var spec = aSpec || {}; - var tab = spec.tab; - - if (!tab) { - throw new Error(arguments.callee.name + ": Tab not specified."); - } - - return this.getElement({ - type: "tab_titleBox", - parent: spec.tab - }); - }, - - /** - * Open a new tab in the specified group - * - * @param {object} aSpec - * Information about the element to operate on - * Elements: group - Group to create a new tab in - */ - openTab : function tabView_openTab(aSpec) { - var spec = aSpec || {}; - var group = spec.group; - - if (!group) { - throw new Error(arguments.callee.name + ": Group not specified."); - } - - var button = this.getElement({ - type: "group_newTabButton", - parent: group - }); - - this._controller.click(button); - this.waitForClosed(); - }, - - - /////////////////////////////// - // UI Elements section - /////////////////////////////// - - /** - * Retrieve an UI element based on the given specification - * - * @param {object} aSpec - * Information of the UI elements which should be retrieved - * Elements: type - Identifier of the element - * subtype - Attribute of the element to filter - * [optional - default: ""] - * value - Value of the attribute to filter - * [optional - default: ""] - * parent - Parent of the to find element - * [optional - default: document] - * - * @returns Element which has been found - * @type {ElemBase} - */ - getElement : function tabView_getElement(aSpec) { - var elements = this.getElements(aSpec); - - return (elements.length > 0) ? elements[0] : undefined; - }, - - /** - * Retrieve list of UI elements based on the given specification - * - * @param {object} aSpec - * Information of the UI elements which should be retrieved - * Elements: type - Identifier of the element - * subtype - Attribute of the element to filter - * [optional - default: ""] - * value - Value of the attribute to filter - * [optional - default: ""] - * parent - Parent of the to find element - * [optional - default: document] - * - * @returns Elements which have been found - * @type {array of ElemBase} - */ - getElements : function tabView_getElement(aSpec) { - var spec = aSpec || { }; - var type = spec.type; - var subtype = spec.subtype; - var value = spec.value; - var parent = spec.parent; - - var root = parent ? parent.getNode() : this._tabViewDoc; - var nodeCollector = new domUtils.nodeCollector(root); - - switch(type) { - // Top level elements - case "tabView": - nodeCollector.root = this._controller.window.document; - nodeCollector.queryNodes("#tab-view"); - break; - case "contentArea": - nodeCollector.queryNodes("#content"); - break; - case "deck": - nodeCollector.root = this._controller.window.document; - nodeCollector.queryNodes("#tab-view-deck"); - break; - case "exitButton": - nodeCollector.queryNodes("#exit-button"); - break; - - // Group elements - case "group_appTabs": - nodeCollector.queryNodes(".appTabIcon"); - break; - case "group_closeButton": - nodeCollector.queryNodes(".close"); - break; - case "group_newTabButton": - nodeCollector.queryNodes(".newTabButton"); - break; - case "group_resizer": - nodeCollector.queryNodes(".iq-resizable-handle"); - break; - case "group_stackExpander": - nodeCollector.queryNodes(".stackExpander"); - break; - case "group_titleBox": - nodeCollector.queryNodes(".name"); - break; - case "group_undoButton": - // Bug 596504 - No reference to the undo button - nodeCollector.root = this._tabViewDoc; - nodeCollector.queryNodes(".undo").filter(function (node) { - var groups = this._groupItemsObject.groupItems; - for (var i = 0; i < groups.length; i++) { - var group = groups[i]; - if (group.container == parent.getNode() && - group.$undoContainer.length == 1) { - return true; - } - } - return false; - }, this); - break; - case "groups": - nodeCollector.queryNodes(".groupItem").filter(function (node) { - switch(subtype) { - case "active": - return node.className.indexOf("activeGroup") != -1; - case "title": - // If no title is given the default name is used - if (!value) { - value = utils.getProperty("chrome://browser/locale/tabview.properties", - "tabview.groupItem.defaultName"); - } - var title = node.querySelector(".name"); - return (value == title.value); - default: - return true; - } - }, this); - break; - - // Search elements - case "search_box": - nodeCollector.queryNodes("#searchbox"); - break; - case "search_button": - nodeCollector.queryNodes("#searchbutton"); - break; - - // Tab elements - case "tab_closeButton": - nodeCollector.queryNodes(".tab .close"); - break; - case "tab_favicon": - nodeCollector.queryNodes(".tab .favicon"); - break; - case "tab_titleBox": - nodeCollector.queryNodes(".tab .tab-title"); - break; - case "tabs": - nodeCollector.queryNodes(".tab").filter(function (node) { - switch (subtype) { - case "active": - return (node.className.indexOf("focus") != -1); - case "group": - var group = value ? value.getNode() : null; - if (group) { - var tabs = this._tabItemsObject.getItems(); - for (var i = 0; i < tabs.length; i++) { - var tab = tabs[i]; - if (tab.parent && tab.parent.container == group) { - return true; - } - } - return false; - } - else { - return (node.className.indexOf("tabInGroupItem") == -1); - } - default: - return true; - } - }, this); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + - aSpec.type); - } - - return nodeCollector.elements; - } -} - -// Export of classes -exports.tabView = tabView; diff --git a/common/tests/functional/shared-modules/toolbars.js b/common/tests/functional/shared-modules/toolbars.js deleted file mode 100644 index acfa890b..00000000 --- a/common/tests/functional/shared-modules/toolbars.js +++ /dev/null @@ -1,509 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Aaron Train <atrain@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The ToolbarAPI adds support for accessing and interacting with toolbar elements - * - * @version 1.0.0 - */ - -// Include required modules -var utils = require("utils"); - -const TIMEOUT = 5000; - -const AUTOCOMPLETE_POPUP = '/id("main-window")/id("mainPopupSet")/id("PopupAutoCompleteRichResult")'; -const NOTIFICATION_POPUP = '/id("main-window")/id("mainPopupSet")/id("notification-popup")'; -const URLBAR_CONTAINER = '/id("main-window")/id("tab-view-deck")/{"flex":"1"}' + - '/id("navigator-toolbox")/id("nav-bar")/id("urlbar-container")'; -const URLBAR_INPUTBOX = URLBAR_CONTAINER + '/id("urlbar")/anon({"anonid":"stack"})' + - '/anon({"anonid":"textbox-container"})' + - '/anon({"anonid":"textbox-input-box"})'; -const CONTEXT_MENU = URLBAR_INPUTBOX + '/anon({"anonid":"input-box-contextmenu"})'; - -/** - * Constructor - * - * @param {MozmillController} controller - * MozMillController of the window to operate on - */ -function autoCompleteResults(controller) { - this._controller = controller; - this._popup = this.getElement({type: "popup"}); - this._results = this.getElement({type: "results"}); -} - -/** - * AutoComplete Result class - */ -autoCompleteResults.prototype = { - /** - * Returns all autocomplete results - * - * @returns Autocomplete results - * @type {Array of ElemBase} - */ - get allResults() { - var results = []; - for (ii = 0; ii < this.length; ii++) { - results.push(this.getResult(ii)); - } - return results; - }, - - /** - * Returns the controller of the current window - * - * @returns Mozmill Controller - * @type MozMillController - */ - get controller() { - return this._controller; - }, - - /** - * Check if the autocomplete popup is open - * - * @returns True if the panel is open - * @type {boolean} - */ - get isOpened() { - return (this._popup.getNode().state == 'open'); - }, - - /** - * Return the amount of autocomplete entries - * - * @returns Number of all entries - * @type {number} - */ - get length() { - return this._results.getNode().itemCount; - }, - - /** - * Returns the currently selected index - * - * @returns Selected index - * @type {number} - */ - get selectedIndex() { - return this._results.getNode().selectedIndex; - }, - - /** - * Returns the visible autocomplete results - * - * @returns Results - * @type {Array of ElemBase} - */ - get visibleResults() { - var results = []; - for (ii = 0; ii < this.length; ii++) { - var result = this.getResult(ii); - if (!result.getNode().hasAttribute("collapsed")) - results.push(result); - } - return results; - }, - - /** - * Returns the underlined text of all results from the text or URL - * - * @param {ElemBase} result - * Autocomplete result which has to be checked - * @param {string} type - * Type of element to check (text or url) - * - * @returns An array of substrings which are underlined - * @type {Array of string} - */ - getUnderlinedText : function autoCompleteResults_getUnderlinedText(result, type) { - this._controller.assertJS("subject.resultNode != null", - {resultNode: result.getNode()}); - - // Get the description element of the given title or url - var description = null; - switch (type) { - case "title": - description = result.getNode().boxObject.firstChild.childNodes[1].childNodes[0]; - break; - case "url": - description = result.getNode().boxObject.lastChild.childNodes[2].childNodes[0]; - break; - default: - throw new Error(arguments.callee.name + ": Type unknown - " + type); - } - - let values = [ ]; - for each (node in description.childNodes) { - if (node.nodeName == 'span') { - // Only add underlined text to the results - values.push(node.innerHTML); - } - } - - return values; - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function autoCompleteResults_getDtds() { - return null; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type {ElemBase} - */ - getElement : function autoCompleteResults_getElement(spec) { - var elem = null; - - switch (spec.type) { - /** - * subtype: subtype to match - * value: value to match - */ - case "popup": - elem = new elementslib.Lookup(this._controller.window.document, AUTOCOMPLETE_POPUP); - break; - case "results": - elem = new elementslib.Lookup(this._controller.window.document, - AUTOCOMPLETE_POPUP + '/anon({"anonid":"richlistbox"})'); - break; - case "result": - elem = new elementslib.Elem(this._results.getNode().getItemAtIndex(spec.value)); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Returns the autocomplete result element of the given index - * - * @param {number} index - * Index of the result to return - * @returns Autocomplete result element - * @type {ElemBase} - */ - getResult : function autoCompleteResults_getResult(index) { - return this.getElement({type: "result", value: index}); - }, - - /** - * Close the autocomplete popup - * - * @param {boolean} force - * Force the closing of the autocomplete popup - */ - close : function autoCompleteResults_close(force) { - if (this.isOpened) { - if (force) { - this._popup.getNode().hidePopup(); - } else { - this._controller.keypress(locationBar.urlbar, "VK_ESCAPE", {}); - } - this._controller.waitFor(function () { - return !this.isOpened; - }, "Autocomplete list should not be open."); - } - } -} - -/** - * Constructor - * - * @param {MozmillController} controller - * MozMillController of the window to operate on - */ -function locationBar(controller) -{ - this._controller = controller; - this._autoCompleteResults = new autoCompleteResults(controller); -} - -/** - * Location Bar class - */ -locationBar.prototype = { - /** - * Returns the autocomplete object - * - * @returns Autocomplete object - * @type {object} - */ - get autoCompleteResults() { - return this._autoCompleteResults; - }, - - /** - * Returns the controller of the current window - * - * @returns Mozmill controller - * @type {MozMillController} - */ - get controller() { - return this._controller; - }, - - /** - * Returns the urlbar element - * - * @returns URL bar - * @type {ElemBase} - */ - get urlbar() { - return this.getElement({type: "urlbar"}); - }, - - /** - * Returns the currently shown URL - * - * @returns Text inside the location bar - * @type {string} - */ - get value() { - return this.urlbar.getNode().value; - }, - - /** - * Clear the location bar - */ - clear : function locationBar_clear() { - this.focus({type: "shortcut"}); - this._controller.keypress(this.urlbar, "VK_DELETE", {}); - this._controller.waitForEval("subject.value == ''", - TIMEOUT, 100, this.urlbar.getNode()); - }, - - /** - * Close the context menu of the urlbar input field - */ - closeContextMenu : function locationBar_closeContextMenu() { - var menu = this.getElement({type: "contextMenu"}); - this._controller.keypress(menu, "VK_ESCAPE", {}); - }, - - /** - * Check if the location bar contains the given text - * - * @param {string} text - * Text which should be checked against - */ - contains : function locationBar_contains(text) { - return this.urlbar.getNode().value.indexOf(text) != -1; - }, - - /** - * Focus the location bar - * - * @param {object} event - * Focus the location bar with the given event (click or shortcut) - */ - focus : function locationBar_focus(event) { - switch (event.type) { - case "click": - this._controller.click(this.urlbar); - break; - case "shortcut": - var cmdKey = utils.getEntity(this.getDtds(), "openCmd.commandkey"); - this._controller.keypress(null, cmdKey, {accelKey: true}); - break; - default: - throw new Error(arguments.callee.name + ": Unkown event type - " + event.type); - } - - // Wait until the location bar has been focused - this._controller.waitForEval("subject.getAttribute('focused') == 'true'", - TIMEOUT, 100, this.urlbar.getNode()); - }, - - /** - * Gets all the needed external DTD urls as an array - * - * @returns Array of external DTD urls - * @type [string] - */ - getDtds : function locationBar_getDtds() { - var dtds = ["chrome://branding/locale/brand.dtd", - "chrome://browser/locale/browser.dtd"]; - return dtds; - }, - - /** - * Retrieve an UI element based on the given spec - * - * @param {object} spec - * Information of the UI element which should be retrieved - * type: General type information - * subtype: Specific element or property - * value: Value of the element or property - * @returns Element which has been created - * @type ElemBase - */ - getElement : function locationBar_getElement(spec) { - var elem = null; - - switch(spec.type) { - /** - * subtype: subtype to match - * value: value to match - */ - case "contextMenu": - elem = new elementslib.Lookup(this._controller.window.document, CONTEXT_MENU); - break; - case "contextMenu_entry": - elem = new elementslib.Lookup(this._controller.window.document, CONTEXT_MENU + - '/{"cmd":"cmd_' + spec.subtype + '"}'); - break; - case "favicon": - elem = new elementslib.ID(this._controller.window.document, "page-proxy-favicon"); - break; - case "feedButton": - elem = new elementslib.ID(this._controller.window.document, "feed-button"); - break; - case "goButton": - elem = new elementslib.ID(this._controller.window.document, "urlbar-go-button"); - break; - case "historyDropMarker": - elem = new elementslib.Lookup(this._controller.window.document, - URLBAR_CONTAINER + '/id("urlbar")/anon({"anonid":"historydropmarker"})'); - break; - case "identityBox": - elem = new elementslib.ID(this._controller.window.document, "identity-box"); - break; - case "notification_element": - elem = new elementslib.Lookup(this._controller.window.document, NOTIFICATION_POPUP + - spec.subtype); - break; - case "notification_popup": - elem = new elementslib.Lookup(this._controller.window.document, NOTIFICATION_POPUP); - break; - case "starButton": - elem = new elementslib.ID(this._controller.window.document, "star-button"); - break; - case "stopButton": - elem = new elementslib.ID(this._controller.window.document, "urlbar-stop-button"); - break; - case "urlbar": - elem = new elementslib.ID(this._controller.window.document, "urlbar"); - break; - case "urlbar_input": - elem = new elementslib.Lookup(this._controller.window.document, URLBAR_INPUTBOX + - '/anon({"anonid":"input"})'); - break; - default: - throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type); - } - - return elem; - }, - - /** - * Retrieves the notification popup - * - * @return The notification popup element - * @type {ElemBase} - */ - getNotification : function locationBar_getNotification() { - return this.getElement({type: "notification_popup"}); - }, - - /** - * Retrieves the specified element of the door hanger notification bar - * - * @param {string} aType - * Type of the notification bar to look for - * @param {string} aLookupString - * Lookup string of the notification bar's child element - * [optional - default: ""] - * - * @return The created element - * @type {ElemBase} - */ - getNotificationElement : function locationBar_getNotificationElement(aType, aLookupString) - { - var lookup = '/id("' + aType + '")'; - lookup = aLookupString ? lookup + aLookupString : lookup; - - // Get the notification and fetch the child element if wanted - return this.getElement({type: "notification_element", subtype: lookup}); - }, - - /** - * Load the given URL - * - * @param {string} url - * URL of web page to load - */ - loadURL : function locationBar_loadURL(url) { - this.focus({type: "shortcut"}); - this.type(url); - this._controller.keypress(this.urlbar, "VK_RETURN", {}); - }, - - /** - * Type the given text into the location bar - * - * @param {string} text - * Text to enter into the location bar - */ - type : function locationBar_type(text) { - this._controller.type(this.urlbar, text); - this.contains(text); - } -} - -// Export of classes -exports.locationBar = locationBar; -exports.autoCompleteResults = autoCompleteResults; - diff --git a/common/tests/functional/shared-modules/utils.js b/common/tests/functional/shared-modules/utils.js deleted file mode 100644 index 4e1c7305..00000000 --- a/common/tests/functional/shared-modules/utils.js +++ /dev/null @@ -1,445 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * Anthony Hughes <ahughes@mozilla.com> - * M.-A. Darche <mozdev@cynode.org> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The UtilsAPI offers various helper functions for any other API which is - * not already covered by another shared module. - * - * @version 1.0.3 - */ - -// Include required modules -var prefs = require("prefs"); - -const gTimeout = 5000; - -/** - * Get application specific informations - * @see http://mxr.mozilla.org/mozilla-central/source/xpcom/system/nsIXULAppInfo.idl - */ -var appInfo = { - _service: null, - - /** - * Get the application info service - * @returns XUL runtime object - * @type nsiXULRuntime - */ - get appInfo() { - if (!this._appInfo) { - this._service = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULAppInfo) - .QueryInterface(Ci.nsIXULRuntime); - } - return this._service; - }, - - /** - * Get the build id - * @returns Build id - * @type string - */ - get buildID() this.appInfo.appBuildID, - - /** - * Get the application id - * @returns Application id - * @type string - */ - get ID() this.appInfo.ID, - - /** - * Get the application name - * @returns Application name - * @type string - */ - get name() this.appInfo.name, - - /** - * Get the operation system - * @returns Operation system name - * @type string - */ - get os() this.appInfo.OS, - - /** - * Get the product vendor - * @returns Vendor name - * @type string - */ - get vendor() this.appInfo.vendor, - - /** - * Get the application version - * @returns Application version - * @type string - */ - get version() this.appInfo.version, - - /** - * Get the build id of the Gecko platform - * @returns Platform build id - * @type string - */ - get platformBuildID() this.appInfo.platformBuildID, - - /** - * Get the version of the Gecko platform - * @returns Platform version - * @type string - */ - get platformVersion() this.appInfo.platformVersion, - - /** - * Get the currently used locale - * @returns Current locale - * @type string - */ - get locale() { - var registry = Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIXULChromeRegistry); - return registry.getSelectedLocale("global"); - }, - - /** - * Get the user agent string - * @returns User agent - * @type string - */ - get userAgent() { - var window = mozmill.wm.getMostRecentWindow("navigator:browser"); - if (window) - return window.navigator.userAgent; - return ""; - } -}; - -/** - * Checks the visibility of an element. - * XXX: Mozmill doesn't check if an element is visible and also operates on - * elements which are invisible. (Bug 490548) - * - * @param {MozmillController} controller - * MozMillController of the window to operate on - * @param {ElemBase} elem - * Element to check its visibility - * @param {boolean} expectedVisibility - * Expected visibility state of the element - */ -function assertElementVisible(controller, elem, expectedVisibility) { - var element = elem.getNode(); - var visible; - - switch (element.nodeName) { - case 'panel': - visible = (element.state == 'open'); - break; - default: - var style = controller.window.getComputedStyle(element, ''); - var state = style.getPropertyValue('visibility'); - visible = (state == 'visible'); - } - - controller.assertJS('subject.visible == subject.expectedVisibility', { - visible: visible, - expectedVisibility: expectedVisibility - }); -} - -/** - * Assert if the current URL is identical to the target URL. - * With this function also redirects can be tested. - * - * @param {MozmillController} controller - * MozMillController of the window to operate on - * @param {string} targetURL - * URL to check - */ -function assertLoadedUrlEqual(controller, targetUrl) { - var locationBar = new elementslib.ID(controller.window.document, "urlbar"); - var currentURL = locationBar.getNode().value; - - // Load the target URL - controller.open(targetUrl); - controller.waitForPageLoad(); - - // Check the same web page has been opened - controller.waitFor(function () { - return locationBar.getNode().value === currentURL; - }, "Current URL should be identical to the target URL - got " + - locationBar.getNode().value + ", expected " + currentURL); -} - -/** - * Close the context menu inside the content area of the currently open tab - * - * @param {MozmillController} controller - * MozMillController of the window to operate on - */ -function closeContentAreaContextMenu(controller) { - var contextMenu = new elementslib.ID(controller.window.document, "contentAreaContextMenu"); - controller.keypress(contextMenu, "VK_ESCAPE", {}); -} - -/** - * Run tests against a given search form - * - * @param {MozMillController} controller - * MozMillController of the window to operate on - * @param {ElemBase} searchField - * The HTML input form element to test - * @param {string} searchTerm - * The search term for the test - * @param {ElemBase} submitButton - * (Optional) The forms submit button - * @param {number} timeout - * The timeout value for the single tests - */ -function checkSearchField(controller, searchField, - searchTerm, submitButton, - timeout) { - controller.waitThenClick(searchField, timeout); - controller.type(searchField, searchTerm); - - if (submitButton != undefined) { - controller.waitThenClick(submitButton, timeout); - } -} - -/** - * Create a new URI - * - * @param {string} spec - * The URI string in UTF-8 encoding. - * @param {string} originCharset - * The charset of the document from which this URI string originated. - * @param {string} baseURI - * If null, spec must specify an absolute URI. Otherwise, spec may be - * resolved relative to baseURI, depending on the protocol. - * @return A URI object - * @type nsIURI - */ -function createURI(spec, originCharset, baseURI) -{ - let iosvc = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - - return iosvc.newURI(spec, originCharset, baseURI); -} - -/** - * Empty the clipboard by assigning an empty string - */ -function emptyClipboard() { - var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"]. - getService(Ci.nsIClipboardHelper); - clipboard.copyString(""); -} - -/** - * Format a URL by replacing all placeholders - * - * @param {string} prefName - * The preference name which contains the URL - * @return The formatted URL - * @type string - */ -function formatUrlPref(prefName) { - var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"] - .getService(Ci.nsIURLFormatter); - - return formatter.formatURLPref(prefName); -} - -/** - * Returns the default home page - * - * @return The URL of the default homepage - * @type string - */ -function getDefaultHomepage() { - var preferences = prefs.preferences; - - var prefValue = preferences.getPref("browser.startup.homepage", "", - true, Ci.nsIPrefLocalizedString); - return prefValue.data; -} - -/** - * Returns the value of an individual entity in a DTD file. - * - * @param [string] urls - * Array of DTD urls. - * @param {string} entityId - * The ID of the entity to get the value of. - * - * @return The value of the requested entity - * @type string - */ -function getEntity(urls, entityId) { - // Add xhtml11.dtd to prevent missing entity errors with XHTML files - urls.push("resource:///res/dtd/xhtml11.dtd"); - - // Build a string of external entities - var extEntities = ""; - for (i = 0; i < urls.length; i++) { - extEntities += '<!ENTITY % dtd' + i + ' SYSTEM "' + - urls[i] + '">%dtd' + i + ';'; - } - - var parser = Cc["@mozilla.org/xmlextras/domparser;1"] - .createInstance(Ci.nsIDOMParser); - var header = '<?xml version="1.0"?><!DOCTYPE elem [' + extEntities + ']>'; - var elem = '<elem id="elementID">&' + entityId + ';</elem>'; - var doc = parser.parseFromString(header + elem, 'text/xml'); - var elemNode = doc.querySelector('elem[id="elementID"]'); - - if (elemNode == null) - throw new Error(arguments.callee.name + ": Unknown entity - " + entityId); - - return elemNode.textContent; -} - -/** - * Returns the value of an individual property. - * - * @param {string} url - * URL of the string bundle. - * @param {string} prefName - * The property to get the value of. - * - * @return The value of the requested property - * @type string - */ -function getProperty(url, prefName) { - var sbs = Cc["@mozilla.org/intl/stringbundle;1"] - .getService(Ci.nsIStringBundleService); - var bundle = sbs.createBundle(url); - - try { - return bundle.GetStringFromName(prefName); - } catch (ex) { - throw new Error(arguments.callee.name + ": Unknown property - " + prefName); - } -} - -/** - * Function to handle non-modal windows - * - * @param {string} type - * Specifies how to check for the new window (possible values: type or title) - * @param {string} text - * The window type of title string to search for - * @param {function} callback (optional) - * Callback function to call for window specific tests - * @param {boolean} close (optional - default: true) - * Make sure the window is closed after the return from the callback handler - * @returns The MozMillController of the window (if the window hasn't been closed) - */ -function handleWindow(type, text, callback, close) { - // Set the window opener function to use depending on the type - var func_ptr = null; - switch (type) { - case "type": - func_ptr = mozmill.utils.getWindowByType; - break; - case "title": - func_ptr = mozmill.utils.getWindowByTitle; - break; - default: - throw new Error(arguments.callee.name + ": Unknown opener type - " + type); - } - - var window = null; - var controller = null; - - try { - // Wait until the window has been opened - mozmill.utils.waitFor(function () { - window = func_ptr(text); - return window != null; - }, "Window has been found."); - - // XXX: We still have to find a reliable way to wait until the new window - // content has been finished loading. Let's wait for now. - controller = new mozmill.controller.MozMillController(window); - controller.sleep(200); - - if (callback) { - callback(controller); - } - - // Check if we have to close the window - if (close === undefined) - close = true; - - if (close && window) { - controller.window.close(); - mozmill.utils.waitFor(function () { - return func_ptr(text) != window; - }, "Window has been closed."); - - window = null; - controller = null; - } - - return controller; - } catch (ex) { - if (window) - window.close(); - - throw ex; - } -} - -// Export of variables -exports.appInfo = appInfo; - -// Export of functions -exports.assertElementVisible = assertElementVisible; -exports.assertLoadedUrlEqual = assertLoadedUrlEqual; -exports.closeContentAreaContextMenu = closeContentAreaContextMenu; -exports.checkSearchField = checkSearchField; -exports.createURI = createURI; -exports.formatUrlPref = formatUrlPref; -exports.emptyClipboard = emptyClipboard; -exports.getDefaultHomepage = getDefaultHomepage; -exports.getEntity = getEntity; -exports.getProperty = getProperty; -exports.handleWindow = handleWindow; diff --git a/common/tests/functional/shared-modules/widgets.js b/common/tests/functional/shared-modules/widgets.js deleted file mode 100644 index 6b796ee6..00000000 --- a/common/tests/functional/shared-modules/widgets.js +++ /dev/null @@ -1,82 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is MozMill Test code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Henrik Skupin <hskupin@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * @fileoverview - * The WidgetsAPI adds support for handling objects like trees. - */ - -var EventUtils = {}; -Components.utils.import('resource://mozmill/stdlib/EventUtils.js', EventUtils); - -const gTimeout = 5000; - -/** - * Click the specified tree cell - * - * @param {MozMillController} controller - * MozMillController of the browser window to operate on - * @param {tree} tree - * Tree to operate on - * @param {number } rowIndex - * Index of the row - * @param {number} columnIndex - * Index of the column - * @param {object} eventDetails - * Details about the mouse event - */ -function clickTreeCell(controller, tree, rowIndex, columnIndex, eventDetails) -{ - tree = tree.getNode(); - - var selection = tree.view.selection; - selection.select(rowIndex); - tree.treeBoxObject.ensureRowIsVisible(rowIndex); - - // get cell coordinates - var x = {}, y = {}, width = {}, height = {}; - var column = tree.columns[columnIndex]; - tree.treeBoxObject.getCoordsForCellItem(rowIndex, column, "text", - x, y, width, height); - - controller.sleep(0); - EventUtils.synthesizeMouse(tree.body, x.value + 4, y.value + 4, - eventDetails, tree.ownerDocument.defaultView); - controller.sleep(0); -} - -// Export of functions -exports.clickTreeCell = clickTreeCell; diff --git a/common/tests/functional/testAboutPage.js b/common/tests/functional/testAboutPage.js deleted file mode 100644 index 2dd5cfc0..00000000 --- a/common/tests/functional/testAboutPage.js +++ /dev/null @@ -1,18 +0,0 @@ -var setupModule = function (module) { - controller = mozmill.getBrowserController(); -}; - -var testAboutPage_WhenOpened_PageIsLoadedWithExpectedTitle = function () { - const ABOUT_PAGE_URL = "about:pentadactyl"; - const EXPECTED_TITLE = "About Pentadactyl"; - const BLANK_PAGE_URL = "about:blank"; - - controller.open(BLANK_PAGE_URL); - controller.waitForPageLoad(controller.tabs.activeTab); - controller.open(ABOUT_PAGE_URL); - controller.waitForPageLoad(controller.tabs.activeTab); - - controller.assert(function () controller.tabs.activeTab.title === EXPECTED_TITLE); -}; - -// vim: sw=4 ts=8 et: diff --git a/common/tests/functional/testEchoCommands.js b/common/tests/functional/testEchoCommands.js deleted file mode 100644 index cd1d65d2..00000000 --- a/common/tests/functional/testEchoCommands.js +++ /dev/null @@ -1,69 +0,0 @@ -var dactyllib = require("dactyl"); - -var setupModule = function (module) { - controller = mozmill.getBrowserController(); - dactyl = new dactyllib.Controller(controller); -}; - -var teardownTest = function (test) { - dactyl.closeMessageWindow(); -}; - -var testEchoCommand_SingleLineMessageAndClosedMOW_MessageDisplayedInMessageLine = function () { - const output = "foobar"; - - assertEchoGeneratesLineOutput({ - ECHO_COMMAND: "echo " + output.quote(), - EXPECTED_OUTPUT: output - }); -}; - -var testEchoCommand_SingleLineMessageAndOpenMOW_MessageAppendedToMOW = function () { - const output = "foobar"; - - dactyl.openMessageWindow(); - - assertEchoGeneratesWindowOutput({ - ECHO_COMMAND: "echo " + output.quote(), - EXPECTED_OUTPUT: RegExp(output) - }); -}; - -var testEchoCommand_MultilineMessageAndClosedMOW_MessageDisplayedInMOW = function () { - const output = "foo\nbar"; - - assertEchoGeneratesWindowOutput({ - ECHO_COMMAND: "echo " + output.quote(), - EXPECTED_OUTPUT: output - }); -}; - -var testEchoCommand_MultilineMessageAndOpenMOW_MessageAppendedToMOW = function () { - const output = "foo\nbar"; - - dactyl.openMessageWindow(); - - assertEchoGeneratesWindowOutput({ - ECHO_COMMAND: "echo " + output.quote(), - EXPECTED_OUTPUT: RegExp(output) - }); -}; - -var testEchoCommand_ObjectArgumentAndClosedMOW_MessageDisplayedInMOW = function () { - assertEchoGeneratesWindowOutput({ - ECHO_COMMAND: "echo var obj = { x: 1, y: 2 }; obj;", - EXPECTED_OUTPUT: "[object\u00A0Object]::\nx: 1\ny: 2\n" - }); -}; - -function assertEchoGeneratesWindowOutput({ ECHO_COMMAND, EXPECTED_OUTPUT }) { - dactyl.runExCommand(ECHO_COMMAND); - dactyl.assertMessageWindow(EXPECTED_OUTPUT); -} - -function assertEchoGeneratesLineOutput({ ECHO_COMMAND, EXPECTED_OUTPUT }) { - dactyl.runExCommand(ECHO_COMMAND); - dactyl.assertMessageLine(EXPECTED_OUTPUT); -} - -// vim: sw=4 ts=8 et: diff --git a/common/tests/functional/testFindCommands.js b/common/tests/functional/testFindCommands.js deleted file mode 100644 index 02aaeb3c..00000000 --- a/common/tests/functional/testFindCommands.js +++ /dev/null @@ -1,42 +0,0 @@ -var dactyllib = require("dactyl"); - -const FIND_TEST_PAGE = collector.addHttpResource("./data/") + "find.html"; - -var setupModule = function (module) { - controller = mozmill.getBrowserController(); - dactyl = new dactyllib.Controller(controller); -}; - -var setupTest = function (test) { - controller.open(FIND_TEST_PAGE); - controller.waitForPageLoad(controller.tabs.activeTab); -}; - -var testFindCommand_PresentAlphabeticText_TextSelected = function () { - assertTextFoundInPage("letter") -}; - -var testFindCommand_PresentNumericText_TextSelected = function () { - assertTextFoundInPage("3.141") -}; - -var testFindCommand_MissingText_ErrorMessageDisplayed = function () { - const MISSING_TEXT = "8c307545a017f60add90ef08955e148e"; - const PATTERN_NOT_FOUND_ERROR = "E486: Pattern not found: " + MISSING_TEXT; - - runTextSearchCommand(MISSING_TEXT); - - dactyl.assertErrorMessage(PATTERN_NOT_FOUND_ERROR); -}; - -function runTextSearchCommand(str) { - dactyl.runViCommand("/" + str); - dactyl.runViCommand([["VK_RETURN"]]); -} - -function assertTextFoundInPage(text) { - runTextSearchCommand(text); - dactyl.assertSelection(text); -} - -// vim: sw=4 ts=8 et: diff --git a/common/tests/functional/testHelpCommands.js b/common/tests/functional/testHelpCommands.js deleted file mode 100644 index a56ced0c..00000000 --- a/common/tests/functional/testHelpCommands.js +++ /dev/null @@ -1,62 +0,0 @@ -var jumlib = {}; Components.utils.import("resource://mozmill/modules/jum.js", jumlib); -var dactyllib = require("dactyl"); - -var setupModule = function (module) { - controller = mozmill.getBrowserController(); - dactyl = new dactyllib.Controller(controller); -}; - -var setupTest = function (test) { - dactyl.runViCommand([["VK_ESCAPE"]]); -}; - -const HELP_FILES = ["all", "tutorial", "intro", "starting", "browsing", - "buffer", "cmdline", "insert", "options", "pattern", "tabs", "hints", - "map", "eval", "marks", "repeat", "autocommands", "print", "gui", - "styling", "message", "developer", "various", "faq", "index", "plugins"]; - -var testViHelpCommand_OpensIntroHelpPage = function () { - assertHelpOpensPageWithTag({ - HELP_COMMAND: function () { dactyl.runViCommand([["VK_F1"]]); }, - EXPECTED_HELP_TAG: "intro.xml" - }); -}; - -var testViHelpAllCommand_OpensAllHelpPage = function () { - assertHelpOpensPageWithTag({ - HELP_COMMAND: function () { dactyl.runViCommand([["VK_F1", { altKey: true }]]); }, - EXPECTED_HELP_TAG: "all.xml" - }); -}; - -var testExHelpCommand_NoArgs_OpensIntroHelpPage = function () { - assertHelpOpensPageWithTag({ - HELP_COMMAND: function () { dactyl.runExCommand("help"); }, - EXPECTED_HELP_TAG: "intro.xml" - }); -}; - -var testExHelpAllCommand_NoArgs_OpensAllHelpPage = function () { - assertHelpOpensPageWithTag({ - HELP_COMMAND: function () { dactyl.runExCommand("helpall"); }, - EXPECTED_HELP_TAG: "all.xml" - }); -}; - -var testExHelpCommand_PageTagArg_OpensHelpPageContainingTag = function () { - for (let [, file] in Iterator(HELP_FILES)) { - let tag = file + ".xml"; - assertHelpOpensPageWithTag({ - HELP_COMMAND: function () { dactyl.runExCommand("help " + tag); }, - EXPECTED_HELP_TAG: tag - }); - } -}; - -function assertHelpOpensPageWithTag({ HELP_COMMAND, EXPECTED_HELP_TAG }) { - HELP_COMMAND(); - controller.waitForPageLoad(controller.tabs.activeTab); - controller.assertNode(new elementslib.ID(controller.tabs.activeTab, EXPECTED_HELP_TAG)); -} - -// vim: sw=4 ts=8 et: diff --git a/common/tests/functional/testShellCommands.js b/common/tests/functional/testShellCommands.js deleted file mode 100644 index 0a4ae7c1..00000000 --- a/common/tests/functional/testShellCommands.js +++ /dev/null @@ -1,33 +0,0 @@ -var dactyllib = require("dactyl"); - -var setupModule = function (module) { - controller = mozmill.getBrowserController(); - dactyl = new dactyllib.Controller(controller); -}; - -var teardownTest = function (test) { - dactyl.closeMessageWindow(); -}; - -var testRunCommand_ExecutingOutputCommand_OutputDisplayed = function () { - const EXPECTED_OUTPUT = "foobar"; - const COMMAND = "run echo " + EXPECTED_OUTPUT; - - dactyl.runExCommand(COMMAND); - - dactyl.assertMessageWindow(RegExp(EXPECTED_OUTPUT)); -}; - -var testRunCommand_RepeatArg_LastCommandRepeated = function () { - const EXPECTED_OUTPUT = /foobar$/; // XXX - const COMMAND = "run echo 'foobar'"; - const REPEAT_COMMAND = "run!"; - - dactyl.runExCommand(COMMAND); - dactyl.closeMessageWindow(); - dactyl.runExCommand(REPEAT_COMMAND); - - dactyl.assertMessageWindow(EXPECTED_OUTPUT); -}; - -// vim: sw=4 ts=8 et: diff --git a/common/tests/functional/testVersionCommand.js b/common/tests/functional/testVersionCommand.js deleted file mode 100644 index 6627dd12..00000000 --- a/common/tests/functional/testVersionCommand.js +++ /dev/null @@ -1,34 +0,0 @@ -var dactyllib = require("dactyl"); - -var setupModule = function (module) { - controller = mozmill.getBrowserController(); - dactyl = new dactyllib.Controller(controller); -}; - -var setupTest = function (test) { - dactyl.closeMessageWindow(); -}; - -var testVersionCommand_NoArg_VersionStringDisplayed = function () { - const EXPECTED_OUTPUT = RegExp(dactyl.applicationName + ".+ (.+) running on:.+"); // XXX - - dactyl.runExCommand("version"); - - dactyl.assertMessageWindow(EXPECTED_OUTPUT); -}; - -var testVersionCommand_BangArg_HostAppVersionPageDisplayed = function () { - const EXPECTED_URL = "about:"; - const EXPECTED_TITLE = "About:"; - const BLANK_PAGE_URL = "about:blank"; - - controller.open(BLANK_PAGE_URL); - controller.waitForPageLoad(controller.tabs.activeTab); - dactyl.runExCommand("version!"); - controller.waitForPageLoad(controller.tabs.activeTab); - - controller.assert(function () controller.tabs.activeTab.location.href === EXPECTED_URL); - controller.assert(function () controller.tabs.activeTab.title === EXPECTED_TITLE); -}; - -// vim: sw=4 ts=8 et: |