1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
14 * The Original Code is MozMill Test code.
16 * The Initial Developer of the Original Code is Mozilla Foundation.
17 * Portions created by the Initial Developer are Copyright (C) 2010
18 * the Initial Developer. All Rights Reserved.
21 * Henrik Skupin <hskupin@mozilla.com>
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.
35 * ***** END LICENSE BLOCK ***** */
37 // Include required modules
38 var domUtils = require("dom-utils");
39 var tabs = require("tabs");
40 var utils = require("utils");
47 function tabView(aController) {
48 this._controller = aController;
50 this._tabViewDoc = this._controller.window.document;
51 this._tabViewObject = this._controller.window.TabView;
59 ///////////////////////////////
61 ///////////////////////////////
64 * Returns the MozMill controller
66 * @returns Mozmill controller
67 * @type {MozMillController}
70 return this._controller;
74 * Check if the Tab View is open
76 * @returns True if the Tab View is open
80 var deck = this.getElement({type: "deck"});
81 return deck.getNode().getAttribute("selectedIndex") == "1";
87 open : function tabView_open() {
88 var menuitem = new elementslib.Elem(this._controller.menus['view-menu'].menu_tabview);
89 this._controller.click(menuitem);
92 this._tabView = this.getElement({type: "tabView"});
93 this._tabViewDoc = this._tabView.getNode().webNavigation.document;
97 * Reset the Tab View settings for the current window
99 reset : function tabView_reset() {
100 // Make sure to close TabView before resetting its ui
106 this._tabViewObject._initFrame(function () {
107 var contentWindow = self._tabViewObject._window;
108 contentWindow.UI.reset();
111 // Make sure all tabs will be shown
112 Array.forEach(this._controller.window.gBrowser.tabs, function (tab) {
113 this._controller.window.gBrowser.showTab(tab);
118 * Wait until the Tab View has been opened
120 waitForOpened : function tabView_waitForOpened() {
121 // Add event listener to wait until the tabview has been opened
122 var self = { opened: false };
123 function checkOpened() { self.opened = true; }
124 this._controller.window.addEventListener("tabviewshown", checkOpened, false);
127 mozmill.utils.waitFor(function () {
128 return self.opened == true;
129 }, "TabView is not open.");
131 this._groupItemsObject = this._tabViewObject._window.GroupItems;
132 this._tabItemsObject = this._tabViewObject._window.TabItems;
135 this._controller.window.removeEventListener("tabviewshown", checkOpened, false);
142 close : function tabView_close() {
143 var menuitem = new elementslib.Elem(this._controller.menus['view-menu'].menu_tabview);
144 this._controller.click(menuitem);
145 this.waitForClosed();
147 this._tabView = null;
148 this._tabViewDoc = this._controller.window.document;
152 * Wait until the Tab View has been closed
154 waitForClosed : function tabView_waitForClosed() {
155 // Add event listener to wait until the tabview has been closed
156 var self = { closed: false };
157 function checkClosed() { self.closed = true; }
158 this._controller.window.addEventListener("tabviewhidden", checkClosed, false);
161 mozmill.utils.waitFor(function () {
162 return self.closed == true;
163 }, "TabView is still open.");
165 this._controller.window.removeEventListener("tabviewhidden", checkClosed, false);
168 this._groupItemsObject = null;
169 this._tabItemsObject = null;
173 ///////////////////////////////
175 ///////////////////////////////
178 * Returns the tab groups which match the filter criteria
180 * @param {object} aSpec
181 * Information about the filter to apply
182 * Elements: filter - Type of filter to apply
184 * [optional - default: ""]
185 * value - Value of the element
186 * [optional - default: ""]
188 * @returns List of groups
189 * @type {array of ElemBase}
191 getGroups : function tabView_getGroups(aSpec) {
192 var spec = aSpec || {};
194 return this.getElements({
196 subtype: spec.filter,
202 * Retrieve the group's title box
204 * @param {object} aSpec
205 * Information on which group to operate on
206 * Elements: group - Group element
208 * @returns Group title box
211 getGroupTitleBox : function tabView_getGroupTitleBox(aSpec) {
212 var spec = aSpec || {};
213 var group = spec.group;
216 throw new Error(arguments.callee.name + ": Group not specified.");
219 return this.getElement({
220 type: "group_titleBox",
226 * Close the specified tab group
228 * @param {object} aSpec
229 * Information on which group to operate on
230 * Elements: group - Group
232 closeGroup : function tabView_closeGroup(aSpec) {
233 var spec = aSpec || {};
234 var group = spec.group;
237 throw new Error(arguments.callee.name + ": Group not specified.");
240 var button = this.getElement({
241 type: "group_closeButton",
244 this._controller.click(button);
246 this.waitForGroupClosed({group: group});
250 * Wait until the specified tab group has been closed
252 * @param {object} aSpec
253 * Information on which group to operate on
254 * Elements: group - Group
256 waitForGroupClosed : function tabView_waitForGroupClosed(aSpec) {
257 var spec = aSpec || {};
258 var group = spec.group;
261 var self = { closed: false };
262 function checkClosed() { self.closed = true; }
265 throw new Error(arguments.callee.name + ": Group not specified.");
268 this._groupItemsObject.groupItems.forEach(function (node) {
269 if (node.container == group.getNode()) {
275 throw new Error(arguments.callee.name + ": Group not found.");
279 groupObj.addSubscriber(groupObj, "groupHidden", checkClosed);
280 mozmill.utils.waitFor(function () {
282 }, "Tab Group has not been closed.");
285 groupObj.removeSubscriber(groupObj, "groupHidden");
290 * Undo the closing of the specified tab group
292 * @param {object} aSpec
293 * Information on which group to operate on
294 * Elements: group - Group
296 undoCloseGroup : function tabView_undoCloseGroup(aSpec) {
297 var spec = aSpec || {};
298 var group = spec.group;
301 throw new Error(arguments.callee.name + ": Group not specified.");
304 var undo = this.getElement({
305 type: "group_undoButton",
308 this._controller.waitThenClick(undo);
310 this.waitForGroupUndo({group: group});
314 * Wait until the specified tab group has been reopened
316 * @param {object} aSpec
317 * Information on which group to operate on
318 * Elements: group - Group
320 waitForGroupUndo : function tabView_waitForGroupUndo(aSpec) {
321 var spec = aSpec || {};
322 var group = spec.group;
325 var self = { reopened: false };
326 function checkClosed() { self.reopened = true; }
329 throw new Error(arguments.callee.name + ": Group not specified.");
333 this._groupItemsObject.groupItems.forEach(function(node) {
334 if (node.container == group.getNode()) {
340 throw new Error(arguments.callee.name + ": Group not found.");
344 groupObj.addSubscriber(groupObj, "groupShown", checkClosed);
345 mozmill.utils.waitFor(function () {
346 return self.reopened;
347 }, "Tab Group has not been reopened.");
350 groupObj.removeSubscriber(groupObj, "groupShown");
355 ///////////////////////////////
357 ///////////////////////////////
360 * Returns the tabs which match the filter criteria
362 * @param {object} aSpec
363 * Information about the filter to apply
364 * Elements: filter - Type of filter to apply
366 * [optional - default: ""]
367 * value - Value of the element
368 * [optional - default: ""]
370 * @returns List of tabs
371 * @type {array of ElemBase}
373 getTabs : function tabView_getTabs(aSpec) {
374 var spec = aSpec || {};
376 return this.getElements({
378 subtype: spec.filter,
386 * @param {object} aSpec
387 * Information about the element to operate on
388 * Elements: tab - Tab to close
390 closeTab : function tabView_closeTab(aSpec) {
391 var spec = aSpec || {};
395 throw new Error(arguments.callee.name + ": Tab not specified.");
398 var button = this.getElement({
399 type: "tab_closeButton",
402 this._controller.click(button);
406 * Retrieve the tab's title box
408 * @param {object} aSpec
409 * Information on which tab to operate on
410 * Elements: tab - Tab
412 * @returns Tab title box
415 getTabTitleBox : function tabView_getTabTitleBox(aSpec) {
416 var spec = aSpec || {};
420 throw new Error(arguments.callee.name + ": Tab not specified.");
423 return this.getElement({
424 type: "tab_titleBox",
430 * Open a new tab in the specified group
432 * @param {object} aSpec
433 * Information about the element to operate on
434 * Elements: group - Group to create a new tab in
436 openTab : function tabView_openTab(aSpec) {
437 var spec = aSpec || {};
438 var group = spec.group;
441 throw new Error(arguments.callee.name + ": Group not specified.");
444 var button = this.getElement({
445 type: "group_newTabButton",
449 this._controller.click(button);
450 this.waitForClosed();
454 ///////////////////////////////
455 // UI Elements section
456 ///////////////////////////////
459 * Retrieve an UI element based on the given specification
461 * @param {object} aSpec
462 * Information of the UI elements which should be retrieved
463 * Elements: type - Identifier of the element
464 * subtype - Attribute of the element to filter
465 * [optional - default: ""]
466 * value - Value of the attribute to filter
467 * [optional - default: ""]
468 * parent - Parent of the to find element
469 * [optional - default: document]
471 * @returns Element which has been found
474 getElement : function tabView_getElement(aSpec) {
475 var elements = this.getElements(aSpec);
477 return (elements.length > 0) ? elements[0] : undefined;
481 * Retrieve list of UI elements based on the given specification
483 * @param {object} aSpec
484 * Information of the UI elements which should be retrieved
485 * Elements: type - Identifier of the element
486 * subtype - Attribute of the element to filter
487 * [optional - default: ""]
488 * value - Value of the attribute to filter
489 * [optional - default: ""]
490 * parent - Parent of the to find element
491 * [optional - default: document]
493 * @returns Elements which have been found
494 * @type {array of ElemBase}
496 getElements : function tabView_getElement(aSpec) {
497 var spec = aSpec || { };
498 var type = spec.type;
499 var subtype = spec.subtype;
500 var value = spec.value;
501 var parent = spec.parent;
503 var root = parent ? parent.getNode() : this._tabViewDoc;
504 var nodeCollector = new domUtils.nodeCollector(root);
507 // Top level elements
509 nodeCollector.root = this._controller.window.document;
510 nodeCollector.queryNodes("#tab-view");
513 nodeCollector.queryNodes("#content");
516 nodeCollector.root = this._controller.window.document;
517 nodeCollector.queryNodes("#tab-view-deck");
520 nodeCollector.queryNodes("#exit-button");
524 case "group_appTabs":
525 nodeCollector.queryNodes(".appTabIcon");
527 case "group_closeButton":
528 nodeCollector.queryNodes(".close");
530 case "group_newTabButton":
531 nodeCollector.queryNodes(".newTabButton");
533 case "group_resizer":
534 nodeCollector.queryNodes(".iq-resizable-handle");
536 case "group_stackExpander":
537 nodeCollector.queryNodes(".stackExpander");
539 case "group_titleBox":
540 nodeCollector.queryNodes(".name");
542 case "group_undoButton":
543 // Bug 596504 - No reference to the undo button
544 nodeCollector.root = this._tabViewDoc;
545 nodeCollector.queryNodes(".undo").filter(function (node) {
546 var groups = this._groupItemsObject.groupItems;
547 for (var i = 0; i < groups.length; i++) {
548 var group = groups[i];
549 if (group.container == parent.getNode() &&
550 group.$undoContainer.length == 1) {
558 nodeCollector.queryNodes(".groupItem").filter(function (node) {
561 return node.className.indexOf("activeGroup") != -1;
563 // If no title is given the default name is used
565 value = utils.getProperty("chrome://browser/locale/tabview.properties",
566 "tabview.groupItem.defaultName");
568 var title = node.querySelector(".name");
569 return (value == title.value);
578 nodeCollector.queryNodes("#searchbox");
580 case "search_button":
581 nodeCollector.queryNodes("#searchbutton");
585 case "tab_closeButton":
586 nodeCollector.queryNodes(".tab .close");
589 nodeCollector.queryNodes(".tab .favicon");
592 nodeCollector.queryNodes(".tab .tab-title");
595 nodeCollector.queryNodes(".tab").filter(function (node) {
598 return (node.className.indexOf("focus") != -1);
600 var group = value ? value.getNode() : null;
602 var tabs = this._tabItemsObject.getItems();
603 for (var i = 0; i < tabs.length; i++) {
605 if (tab.parent && tab.parent.container == group) {
612 return (node.className.indexOf("tabInGroupItem") == -1);
620 throw new Error(arguments.callee.name + ": Unknown element type - " +
624 return nodeCollector.elements;
629 exports.tabView = tabView;