mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-01-09 02:04:11 +01:00
Fix tab number updates in FF36. Closes issue 300.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user