]> git.donarmstrong.com Git - dactyl.git/blob - common/tests/functional/shared-modules/localization.js
Initial import of 1.0~b6
[dactyl.git] / common / tests / functional / shared-modules / localization.js
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is MozMill Test code.
15  *
16  * The Initial Developer of the Original Code is the Mozilla Foundation.
17  * Portions created by the Initial Developer are Copyright (C) 2010
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  *   Adrian Kalla <akalla@aviary.pl>
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either the GNU General Public License Version 2 or later (the "GPL"), or
25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the MPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the MPL, the GPL or the LGPL.
34  *
35  * ***** END LICENSE BLOCK ***** */
36
37 // Include required modules
38 var domUtils = require("dom-utils");
39 var screenshot = require("screenshot");
40 var utils = require("utils");
41
42 const jumlib = {};
43 Components.utils.import("resource://mozmill/modules/jum.js", jumlib);
44
45 /**
46  * Callback function for parsing the results of testing for duplicated
47  * access keys.
48  *
49  * This function processes the access keys found in one access keys scope
50  * looking for access keys that are listed more than one time.
51  * At the end, it calls the screenshot.create to create a screenshot with the
52  * elements containing the broken access keys highlighted.
53  *
54  * @param {array of array of object} accessKeysSet
55  * @param {MozmillController} controller
56  */
57 function checkAccessKeysResults(controller, accessKeysSet) {
58   // Sort the access keys to have them in a A->Z order
59   var accessKeysList = accessKeysSet.sort();
60
61   // List of access keys
62   var aKeysList = [];
63
64   // List of values to identify the access keys
65   var valueList = [];
66
67   // List of rectangles of nodes containing access keys
68   var rects = [];
69
70   // List of rectangles of nodes with broken access keys
71   var badRects = [];
72
73   // Makes lists of all access keys and the values the access keys are in
74   for (var i = 0; i < accessKeysList.length; i++) {
75     var accessKey = accessKeysList[i][0];
76     var node = accessKeysList[i][1];
77
78     // Set the id and label to be shown in the console
79     var id = node.id || "(id is undefined)";
80     var label = node.label || "(label is undefined)";
81
82     var box = node.boxObject;
83
84     var innerIds = [];
85     var innerRects = [];
86
87     // if the access key is already in our list, take it out to replace it
88     // later
89     if (accessKey == aKeysList[aKeysList.length-1]) {
90       innerIds = valueList.pop();
91       innerRects = rects.pop();
92     } else {
93       aKeysList.push([accessKey]);
94     }
95     innerIds.push("[id: " + id + ", label: " + label + "]");
96     valueList.push(innerIds);
97     innerRects.push([box.x, box.y, box.width, box.height]);
98     rects.push(innerRects);
99   }
100
101   // Go through all access keys and find the duplicated ones
102   for (var i = 0; i < valueList.length; i++) {
103     // Only access keys contained in more than one node are the ones we are
104     // looking for
105     if (valueList[i].length > 1) {
106       for (var j = 0; j < rects[i].length; j++) {
107         badRects.push(rects[i][j]);
108       }
109       jumlib.assert(false, 'accessKey: ' + aKeysList[i] +
110                     ' found in string\'s: ' + valueList[i].join(", "));
111     }
112   }
113
114   // If we have found broken access keys, make a screenshot
115   if (badRects.length > 0) {
116     screenshot.create(controller, badRects);
117   }
118 }
119
120 /**
121  * Callback function for testing for cropped elements.
122  *
123  * Checks if the XUL boxObject has screen coordinates outside of
124  * the screen coordinates of its parent. If there's no parent, return.
125  *
126  * @param {node} child
127  * @returns List of boxes that can be highlighted on a screenshot
128  * @type {array of array of int}
129  */
130 function checkDimensions(child) {
131   if (!child.boxObject)
132     return [];
133   var childBox = child.boxObject;
134   var parent = childBox.parentBox;
135
136   // toplevel element or hidden elements, like script tags
137   if (!parent || parent == child.element || !parent.boxObject) {
138     return [];
139   }
140   var parentBox = parent.boxObject;
141
142   var badRects = [];
143
144   // check width
145   if (childBox.height && childBox.screenX < parentBox.screenX) {
146     badRects.push([childBox.x, childBox.y, parentBox.x - childBox.x,
147                    childBox.height]);
148     jumlib.assert(false, 'Node is cut off at the left: ' +
149                   _reportNode(child) + '. Parent node: ' + _reportNode(parent));
150   }
151   if (childBox.height && childBox.screenX + childBox.width >
152       parentBox.screenX + parentBox.width) {
153     badRects.push([parentBox.x + parentBox.width, childBox.y,
154                    childBox.x + childBox.width - parentBox.x - parentBox.width,
155                    childBox.height]);
156     jumlib.assert(false, 'Node is cut off at the right: ' +
157                   _reportNode(child) + '. Parent node: ' + _reportNode(parent));
158   }
159
160   // check height
161   // We don't want to test menupopup's, as they always report the full height
162   // of all items in the popup
163   if (child.nodeName != 'menupopup' && parent.nodeName != 'menupopup') {
164     if (childBox.width && childBox.screenY < parentBox.screenY) {
165       badRects.push([childBox.x, childBox.y, parentBox.y - childBox.y,
166                      childBox.width]);
167       jumlib.assert(false, 'Node is cut off at the top: ' +
168                     _reportNode(child) + '. Parent node: ' + _reportNode(parent));
169     }
170     if (childBox.width && childBox.screenY + childBox.height >
171         parentBox.screenY + parentBox.height) {
172       badRects.push([childBox.x, parentBox.y + parentBox.height,
173                      childBox.width,
174                      childBox.y + childBox.height - parentBox.y - parentBox.height]);
175       jumlib.assert(false, 'Node is cut off at the bottom: ' +
176                     _reportNode(child) + '. Parent node: ' + _reportNode(parent));
177     }
178   }
179
180   return badRects;
181 }
182
183 /**
184  * Filters out nodes which should not be tested because they are not in the
185  * current access key scope.
186  *
187  * @param {node} node
188  * @returns Filter status of the given node
189  * @type {array of array of int}
190  */
191 function filterAccessKeys(node) {
192   // Menus will need a separate filter set
193   var notAllowedLocalNames = ["menu", "menubar", "menupopup", "popupset"];
194
195   if (!node.disabled && !node.collapsed && !node.hidden &&
196       notAllowedLocalNames.indexOf(node.localName) == -1) {
197     // Code specific to the preferences panes to reject out not visible nodes
198     // in the panes.
199     if (node.parentNode && (node.parentNode.localName == "prefwindow" &&
200                             node.parentNode.currentPane.id != node.id) ||
201         ((node.parentNode.localName == "tabpanels" ||
202           node.parentNode.localName == "deck") &&
203           node.parentNode.selectedPanel.id != node.id)) {
204       return domUtils.DOMWalker.FILTER_REJECT;
205       // end of the specific code
206     } else if (node.accessKey) {
207       return domUtils.DOMWalker.FILTER_ACCEPT;
208     } else {
209       return domUtils.DOMWalker.FILTER_SKIP;
210     }
211   } else {
212     // we don't want to test not visible elements
213     return domUtils.DOMWalker.FILTER_REJECT;
214   }
215 }
216
217 /**
218  * Filters out nodes which should not be tested because they are not visible
219  *
220  * @param {node} node
221  * @returns Filter status of the given node
222  * @type {array of array of int}
223  */
224 function filterCroppedNodes(node) {
225   if (!node.boxObject) {
226     return domUtils.DOMWalker.FILTER_SKIP;
227   } else {
228     if (!node.disabled && !node.collapsed && !node.hidden) {
229       // Code specific to the preferences panes to reject out not visible nodes
230       // in the panes.
231       if (node.parentNode && (node.parentNode.localName == "prefwindow" &&
232                               node.parentNode.currentPane.id != node.id) ||
233           ((node.parentNode.localName == "tabpanels" ||
234             node.parentNode.localName == "deck") &&
235            node.parentNode.selectedPanel.id != node.id)) {
236         return domUtils.DOMWalker.FILTER_REJECT;
237         // end of the specific code
238       } else {
239         return domUtils.DOMWalker.FILTER_ACCEPT;
240       }
241     } else {
242       // we don't want to test not visible elements
243       return domUtils.DOMWalker.FILTER_REJECT;
244     }
245   }
246 }
247
248 /**
249  * Callback function for testing access keys. To be used with the DOMWalker.
250  *
251  * It packs a submitted node and its access key into a double array
252  *
253  * @param {node} node Node containing the access key
254  * @returns lower-cased access key and its node in a nested array
255  * @type {array of array}
256  */
257 function prepareAccessKey(node) {
258   return [[node.accessKey.toLowerCase(), node]];
259 }
260
261 /**
262  * Callback function for parsing the results of testing for cropped elements.
263  *
264  * This function calls the screenshot.create method if there is at least one
265  * box.
266  *
267  * @param {array of array of int} boxes
268  * @param {MozmillController} controller
269  */
270 function processDimensionsResults(controller, boxes) {
271   if (boxes && boxes.length > 0) {
272     screenshot.create(controller, boxes);
273   }
274 }
275
276 /**
277  * Tries to return a useful string identificator of the given node
278  *
279  * @param {node} node
280  * @returns Identificator of the node
281  * @type {String}
282  */
283 function _reportNode(node) {
284   if (node.id) {
285     return "id: " + node.id;
286   } else if (node.label) {
287     return "label: " + node.label;
288   } else if (node.value) {
289     return "value: " + node.value;
290   } else if (node.hasAttributes()) {
291     var attrs = "node attributes: ";
292     for (var i = node.attributes.length - 1; i >= 0; i--) {
293       attrs += node.attributes[i].name + "->" + node.attributes[i].value + ";";
294     }
295     return attrs;
296   } else {
297     return "anonymous node";
298   }
299 }
300
301 // Export of functions
302 exports.checkAccessKeysResults = checkAccessKeysResults;
303 exports.checkDimensions = checkDimensions;
304 exports.filterAccessKeys = filterAccessKeys;
305 exports.filterCroppedNodes = filterCroppedNodes;
306 exports.prepareAccessKey = prepareAccessKey;
307 exports.processDimensionsResults = processDimensionsResults;