/services/sync/tps/extensions/mozmill/resource/modules/mozelement.js

http://github.com/zpao/v8monkey · JavaScript · 702 lines · 393 code · 96 blank · 213 comment · 124 complexity · bad47cde540c028086579e8882e04e78 MD5 · raw file

  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 Elements.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Mozilla Corporation
  18. *
  19. * Portions created by the Initial Developer are Copyright (C) 2011
  20. * the Initial Developer. All Rights Reserved.
  21. *
  22. * Contributor(s):
  23. * Andrew Halberstadt <halbersa@gmail.com>
  24. *
  25. * Alternatively, the contents of this file may be used under the terms of
  26. * either the GNU General Public License Version 2 or later (the "GPL"), or
  27. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28. * in which case the provisions of the GPL or the LGPL are applicable instead
  29. * of those above. If you wish to allow use of your version of this file only
  30. * under the terms of either the GPL or the LGPL, and not to allow others to
  31. * use your version of this file under the terms of the MPL, indicate your
  32. * decision by deleting the provisions above and replace them with the notice
  33. * and other provisions required by the GPL or the LGPL. If you do not delete
  34. * the provisions above, a recipient may use your version of this file under
  35. * the terms of any one of the MPL, the GPL or the LGPL.
  36. *
  37. * ***** END LICENSE BLOCK ***** */
  38. var EXPORTED_SYMBOLS = ["Elem", "Selector", "ID", "Link", "XPath", "Name", "Lookup",
  39. "MozMillElement", "MozMillCheckBox", "MozMillRadio", "MozMillDropList",
  40. "MozMillTextBox", "subclasses",
  41. ];
  42. var EventUtils = {}; Components.utils.import('resource://mozmill/stdlib/EventUtils.js', EventUtils);
  43. var frame = {}; Components.utils.import('resource://mozmill/modules/frame.js', frame);
  44. var utils = {}; Components.utils.import('resource://mozmill/modules/utils.js', utils);
  45. var elementslib = {}; Components.utils.import('resource://mozmill/modules/elementslib.js', elementslib);
  46. // A list of all the subclasses available. Shared modules can push their own subclasses onto this list
  47. var subclasses = [MozMillCheckBox, MozMillRadio, MozMillDropList, MozMillTextBox];
  48. /**
  49. * createInstance()
  50. *
  51. * Returns an new instance of a MozMillElement
  52. * The type of the element is automatically determined
  53. */
  54. function createInstance(locatorType, locator, elem) {
  55. if (elem) {
  56. var args = {"element":elem};
  57. for (var i = 0; i < subclasses.length; ++i) {
  58. if (subclasses[i].isType(elem)) {
  59. return new subclasses[i](locatorType, locator, args);
  60. }
  61. }
  62. if (MozMillElement.isType(elem)) return new MozMillElement(locatorType, locator, args);
  63. }
  64. throw new Error("could not find element " + locatorType + ": " + locator);
  65. };
  66. var Elem = function(node) {
  67. return createInstance("Elem", node, node);
  68. };
  69. var Selector = function(_document, selector, index) {
  70. return createInstance("Selector", selector, elementslib.Selector(_document, selector, index));
  71. };
  72. var ID = function(_document, nodeID) {
  73. return createInstance("ID", nodeID, elementslib.ID(_document, nodeID));
  74. };
  75. var Link = function(_document, linkName) {
  76. return createInstance("Link", linkName, elementslib.Link(_document, linkName));
  77. };
  78. var XPath = function(_document, expr) {
  79. return createInstance("XPath", expr, elementslib.XPath(_document, expr));
  80. };
  81. var Name = function(_document, nName) {
  82. return createInstance("Name", nName, elementslib.Name(_document, nName));
  83. };
  84. var Lookup = function(_document, expression) {
  85. return createInstance("Lookup", expression, elementslib.Lookup(_document, expression));
  86. };
  87. /**
  88. * MozMillElement
  89. * The base class for all mozmill elements
  90. */
  91. function MozMillElement(locatorType, locator, args) {
  92. args = args || {};
  93. this._locatorType = locatorType;
  94. this._locator = locator;
  95. this._element = args["element"];
  96. this._document = args["document"];
  97. this._owner = args["owner"];
  98. // Used to maintain backwards compatibility with controller.js
  99. this.isElement = true;
  100. }
  101. // Static method that returns true if node is of this element type
  102. MozMillElement.isType = function(node) {
  103. return true;
  104. };
  105. // This getter is the magic behind lazy loading (note distinction between _element and element)
  106. MozMillElement.prototype.__defineGetter__("element", function() {
  107. if (this._element == undefined) {
  108. if (elementslib[this._locatorType]) {
  109. this._element = elementslib[this._locatorType](this._document, this._locator);
  110. } else if (this._locatorType == "Elem") {
  111. this._element = this._locator;
  112. } else {
  113. throw new Error("Unknown locator type: " + this._locatorType);
  114. }
  115. }
  116. return this._element;
  117. });
  118. // Returns the actual wrapped DOM node
  119. MozMillElement.prototype.getNode = function() {
  120. return this.element;
  121. };
  122. MozMillElement.prototype.getInfo = function() {
  123. return this._locatorType + ": " + this._locator;
  124. };
  125. /**
  126. * Sometimes an element which once existed will no longer exist in the DOM
  127. * This function re-searches for the element
  128. */
  129. MozMillElement.prototype.exists = function() {
  130. this._element = undefined;
  131. if (this.element) return true;
  132. return false;
  133. };
  134. /**
  135. * Synthesize a keypress event on the given element
  136. *
  137. * @param {string} aKey
  138. * Key to use for synthesizing the keypress event. It can be a simple
  139. * character like "k" or a string like "VK_ESCAPE" for command keys
  140. * @param {object} aModifiers
  141. * Information about the modifier keys to send
  142. * Elements: accelKey - Hold down the accelerator key (ctrl/meta)
  143. * [optional - default: false]
  144. * altKey - Hold down the alt key
  145. * [optional - default: false]
  146. * ctrlKey - Hold down the ctrl key
  147. * [optional - default: false]
  148. * metaKey - Hold down the meta key (command key on Mac)
  149. * [optional - default: false]
  150. * shiftKey - Hold down the shift key
  151. * [optional - default: false]
  152. * @param {object} aExpectedEvent
  153. * Information about the expected event to occur
  154. * Elements: target - Element which should receive the event
  155. * [optional - default: current element]
  156. * type - Type of the expected key event
  157. */
  158. MozMillElement.prototype.keypress = function(aKey, aModifiers, aExpectedEvent) {
  159. if (!this.element) {
  160. throw new Error("Could not find element " + this.getInfo());
  161. }
  162. var win = this.element.ownerDocument? this.element.ownerDocument.defaultView : this.element;
  163. this.element.focus();
  164. if (aExpectedEvent) {
  165. var target = aExpectedEvent.target? aExpectedEvent.target.getNode() : this.element;
  166. EventUtils.synthesizeKeyExpectEvent(aKey, aModifiers || {}, target, aExpectedEvent.type,
  167. "MozMillElement.keypress()", win);
  168. } else {
  169. EventUtils.synthesizeKey(aKey, aModifiers || {}, win);
  170. }
  171. frame.events.pass({'function':'MozMillElement.keypress()'});
  172. return true;
  173. };
  174. /**
  175. * Synthesize a general mouse event on the given element
  176. *
  177. * @param {ElemBase} aTarget
  178. * Element which will receive the mouse event
  179. * @param {number} aOffsetX
  180. * Relative x offset in the elements bounds to click on
  181. * @param {number} aOffsetY
  182. * Relative y offset in the elements bounds to click on
  183. * @param {object} aEvent
  184. * Information about the event to send
  185. * Elements: accelKey - Hold down the accelerator key (ctrl/meta)
  186. * [optional - default: false]
  187. * altKey - Hold down the alt key
  188. * [optional - default: false]
  189. * button - Mouse button to use
  190. * [optional - default: 0]
  191. * clickCount - Number of counts to click
  192. * [optional - default: 1]
  193. * ctrlKey - Hold down the ctrl key
  194. * [optional - default: false]
  195. * metaKey - Hold down the meta key (command key on Mac)
  196. * [optional - default: false]
  197. * shiftKey - Hold down the shift key
  198. * [optional - default: false]
  199. * type - Type of the mouse event ('click', 'mousedown',
  200. * 'mouseup', 'mouseover', 'mouseout')
  201. * [optional - default: 'mousedown' + 'mouseup']
  202. * @param {object} aExpectedEvent
  203. * Information about the expected event to occur
  204. * Elements: target - Element which should receive the event
  205. * [optional - default: current element]
  206. * type - Type of the expected mouse event
  207. */
  208. MozMillElement.prototype.mouseEvent = function(aOffsetX, aOffsetY, aEvent, aExpectedEvent) {
  209. if (!this.element) {
  210. throw new Error(arguments.callee.name + ": could not find element " + this.getInfo());
  211. }
  212. // If no offset is given we will use the center of the element to click on.
  213. var rect = this.element.getBoundingClientRect();
  214. if (isNaN(aOffsetX)) {
  215. aOffsetX = rect.width / 2;
  216. }
  217. if (isNaN(aOffsetY)) {
  218. aOffsetY = rect.height / 2;
  219. }
  220. // Scroll element into view otherwise the click will fail
  221. if (this.element.scrollIntoView) {
  222. this.element.scrollIntoView();
  223. }
  224. if (aExpectedEvent) {
  225. // The expected event type has to be set
  226. if (!aExpectedEvent.type)
  227. throw new Error(arguments.callee.name + ": Expected event type not specified");
  228. // If no target has been specified use the specified element
  229. var target = aExpectedEvent.target ? aExpectedEvent.target.getNode() : this.element;
  230. if (!target) {
  231. throw new Error(arguments.callee.name + ": could not find element " + aExpectedEvent.target.getInfo());
  232. }
  233. EventUtils.synthesizeMouseExpectEvent(this.element, aOffsetX, aOffsetY, aEvent,
  234. target, aExpectedEvent.event,
  235. "MozMillElement.mouseEvent()",
  236. this.element.ownerDocument.defaultView);
  237. } else {
  238. EventUtils.synthesizeMouse(this.element, aOffsetX, aOffsetY, aEvent,
  239. this.element.ownerDocument.defaultView);
  240. }
  241. };
  242. /**
  243. * Synthesize a mouse click event on the given element
  244. */
  245. MozMillElement.prototype.click = function(left, top, expectedEvent) {
  246. // Handle menu items differently
  247. if (this.element && this.element.tagName == "menuitem") {
  248. this.element.click();
  249. } else {
  250. this.mouseEvent(left, top, {}, expectedEvent);
  251. }
  252. frame.events.pass({'function':'MozMillElement.click()'});
  253. };
  254. /**
  255. * Synthesize a double click on the given element
  256. */
  257. MozMillElement.prototype.doubleClick = function(left, top, expectedEvent) {
  258. this.mouseEvent(left, top, {clickCount: 2}, expectedEvent);
  259. frame.events.pass({'function':'MozMillElement.doubleClick()'});
  260. return true;
  261. };
  262. /**
  263. * Synthesize a mouse down event on the given element
  264. */
  265. MozMillElement.prototype.mouseDown = function (button, left, top, expectedEvent) {
  266. this.mouseEvent(left, top, {button: button, type: "mousedown"}, expectedEvent);
  267. frame.events.pass({'function':'MozMillElement.mouseDown()'});
  268. return true;
  269. };
  270. /**
  271. * Synthesize a mouse out event on the given element
  272. */
  273. MozMillElement.prototype.mouseOut = function (button, left, top, expectedEvent) {
  274. this.mouseEvent(left, top, {button: button, type: "mouseout"}, expectedEvent);
  275. frame.events.pass({'function':'MozMillElement.mouseOut()'});
  276. return true;
  277. };
  278. /**
  279. * Synthesize a mouse over event on the given element
  280. */
  281. MozMillElement.prototype.mouseOver = function (button, left, top, expectedEvent) {
  282. this.mouseEvent(left, top, {button: button, type: "mouseover"}, expectedEvent);
  283. frame.events.pass({'function':'MozMillElement.mouseOver()'});
  284. return true;
  285. };
  286. /**
  287. * Synthesize a mouse up event on the given element
  288. */
  289. MozMillElement.prototype.mouseUp = function (button, left, top, expectedEvent) {
  290. this.mouseEvent(left, top, {button: button, type: "mouseup"}, expectedEvent);
  291. frame.events.pass({'function':'MozMillElement.mouseUp()'});
  292. return true;
  293. };
  294. /**
  295. * Synthesize a mouse middle click event on the given element
  296. */
  297. MozMillElement.prototype.middleClick = function(left, top, expectedEvent) {
  298. this.mouseEvent(left, top, {button: 1}, expectedEvent);
  299. frame.events.pass({'function':'MozMillElement.middleClick()'});
  300. return true;
  301. };
  302. /**
  303. * Synthesize a mouse right click event on the given element
  304. */
  305. MozMillElement.prototype.rightClick = function(left, top, expectedEvent) {
  306. this.mouseEvent(left, top, {type : "contextmenu", button: 2 }, expectedEvent);
  307. frame.events.pass({'function':'MozMillElement.rightClick()'});
  308. return true;
  309. };
  310. MozMillElement.prototype.waitForElement = function(timeout, interval) {
  311. var elem = this;
  312. utils.waitFor(function() {
  313. return elem.exists();
  314. }, "Timeout exceeded for waitForElement " + this.getInfo(), timeout, interval);
  315. frame.events.pass({'function':'MozMillElement.waitForElement()'});
  316. };
  317. MozMillElement.prototype.waitForElementNotPresent = function(timeout, interval) {
  318. var elem = this;
  319. utils.waitFor(function() {
  320. return !elem.exists();
  321. }, "Timeout exceeded for waitForElementNotPresent " + this.getInfo(), timeout, interval);
  322. frame.events.pass({'function':'MozMillElement.waitForElementNotPresent()'});
  323. };
  324. MozMillElement.prototype.waitThenClick = function (timeout, interval, left, top, expectedEvent) {
  325. this.waitForElement(timeout, interval);
  326. this.click(left, top, expectedEvent);
  327. };
  328. // Dispatches an HTMLEvent
  329. MozMillElement.prototype.dispatchEvent = function (eventType, canBubble, modifiers) {
  330. canBubble = canBubble || true;
  331. var evt = this.element.ownerDocument.createEvent('HTMLEvents');
  332. evt.shiftKey = modifiers["shift"];
  333. evt.metaKey = modifiers["meta"];
  334. evt.altKey = modifiers["alt"];
  335. evt.ctrlKey = modifiers["ctrl"];
  336. evt.initEvent(eventType, canBubble, true);
  337. this.element.dispatchEvent(evt);
  338. };
  339. //---------------------------------------------------------------------------------------------------------------------------------------
  340. /**
  341. * MozMillCheckBox
  342. * Checkbox element, inherits from MozMillElement
  343. */
  344. MozMillCheckBox.prototype = new MozMillElement();
  345. MozMillCheckBox.prototype.parent = MozMillElement.prototype;
  346. MozMillCheckBox.prototype.constructor = MozMillCheckBox;
  347. function MozMillCheckBox(locatorType, locator, args) {
  348. this.parent.constructor.call(this, locatorType, locator, args);
  349. }
  350. // Static method returns true if node is this type of element
  351. MozMillCheckBox.isType = function(node) {
  352. if ((node.localName.toLowerCase() == "input" && node.getAttribute("type") == "checkbox") ||
  353. (node.localName.toLowerCase() == 'toolbarbutton' && node.getAttribute('type') == 'checkbox') ||
  354. (node.localName.toLowerCase() == 'checkbox')) {
  355. return true;
  356. }
  357. return false;
  358. };
  359. /**
  360. * Enable/Disable a checkbox depending on the target state
  361. */
  362. MozMillCheckBox.prototype.check = function(state) {
  363. var result = false;
  364. if (!this.element) {
  365. throw new Error("could not find element " + this.getInfo());
  366. return false;
  367. }
  368. // If we have a XUL element, unwrap its XPCNativeWrapper
  369. if (this.element.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul") {
  370. this.element = utils.unwrapNode(this.element);
  371. }
  372. state = (typeof(state) == "boolean") ? state : false;
  373. if (state != this.element.checked) {
  374. this.click();
  375. var element = this.element;
  376. utils.waitFor(function() {
  377. return element.checked == state;
  378. }, "Checkbox " + this.getInfo() + " could not be checked/unchecked", 500);
  379. result = true;
  380. }
  381. frame.events.pass({'function':'MozMillCheckBox.check(' + this.getInfo() + ', state: ' + state + ')'});
  382. return result;
  383. };
  384. //----------------------------------------------------------------------------------------------------------------------------------------
  385. /**
  386. * MozMillRadio
  387. * Radio button inherits from MozMillElement
  388. */
  389. MozMillRadio.prototype = new MozMillElement();
  390. MozMillRadio.prototype.parent = MozMillElement.prototype;
  391. MozMillRadio.prototype.constructor = MozMillRadio;
  392. function MozMillRadio(locatorType, locator, args) {
  393. this.parent.constructor.call(this, locatorType, locator, args);
  394. }
  395. // Static method returns true if node is this type of element
  396. MozMillRadio.isType = function(node) {
  397. if ((node.localName.toLowerCase() == 'input' && node.getAttribute('type') == 'radio') ||
  398. (node.localName.toLowerCase() == 'toolbarbutton' && node.getAttribute('type') == 'radio') ||
  399. (node.localName.toLowerCase() == 'radio') ||
  400. (node.localName.toLowerCase() == 'radiogroup')) {
  401. return true;
  402. }
  403. return false;
  404. };
  405. /**
  406. * Select the given radio button
  407. *
  408. * index - Specifies which radio button in the group to select (only applicable to radiogroup elements)
  409. * Defaults to the first radio button in the group
  410. */
  411. MozMillRadio.prototype.select = function(index) {
  412. if (!this.element) {
  413. throw new Error("could not find element " + this.getInfo());
  414. }
  415. if (this.element.localName.toLowerCase() == "radiogroup") {
  416. var element = this.element.getElementsByTagName("radio")[index || 0];
  417. new MozMillRadio("Elem", element).click();
  418. } else {
  419. var element = this.element;
  420. this.click();
  421. }
  422. utils.waitFor(function() {
  423. // If we have a XUL element, unwrap its XPCNativeWrapper
  424. if (element.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul") {
  425. element = utils.unwrapNode(element);
  426. return element.selected == true;
  427. }
  428. return element.checked == true;
  429. }, "Radio button " + this.getInfo() + " could not be selected", 500);
  430. frame.events.pass({'function':'MozMillRadio.select(' + this.getInfo() + ')'});
  431. return true;
  432. };
  433. //----------------------------------------------------------------------------------------------------------------------------------------
  434. /**
  435. * MozMillDropList
  436. * DropList inherits from MozMillElement
  437. */
  438. MozMillDropList.prototype = new MozMillElement();
  439. MozMillDropList.prototype.parent = MozMillElement.prototype;
  440. MozMillDropList.prototype.constructor = MozMillDropList;
  441. function MozMillDropList(locatorType, locator, args) {
  442. this.parent.constructor.call(this, locatorType, locator, args);
  443. };
  444. // Static method returns true if node is this type of element
  445. MozMillDropList.isType = function(node) {
  446. if ((node.localName.toLowerCase() == 'toolbarbutton' && (node.getAttribute('type') == 'menu' || node.getAttribute('type') == 'menu-button')) ||
  447. (node.localName.toLowerCase() == 'menu') ||
  448. (node.localName.toLowerCase() == 'menulist') ||
  449. (node.localName.toLowerCase() == 'select' )) {
  450. return true;
  451. }
  452. return false;
  453. };
  454. /* Select the specified option and trigger the relevant events of the element */
  455. MozMillDropList.prototype.select = function (indx, option, value) {
  456. if (!this.element){
  457. throw new Error("Could not find element " + this.getInfo());
  458. }
  459. //if we have a select drop down
  460. if (this.element.localName.toLowerCase() == "select"){
  461. var item = null;
  462. // The selected item should be set via its index
  463. if (indx != undefined) {
  464. // Resetting a menulist has to be handled separately
  465. if (indx == -1) {
  466. this.dispatchEvent('focus', false);
  467. this.element.selectedIndex = indx;
  468. this.dispatchEvent('change', true);
  469. frame.events.pass({'function':'MozMillDropList.select()'});
  470. return true;
  471. } else {
  472. item = this.element.options.item(indx);
  473. }
  474. } else {
  475. for (var i = 0; i < this.element.options.length; i++) {
  476. var entry = this.element.options.item(i);
  477. if (option != undefined && entry.innerHTML == option ||
  478. value != undefined && entry.value == value) {
  479. item = entry;
  480. break;
  481. }
  482. }
  483. }
  484. // Click the item
  485. try {
  486. // EventUtils.synthesizeMouse doesn't work.
  487. this.dispatchEvent('focus', false);
  488. item.selected = true;
  489. this.dispatchEvent('change', true);
  490. frame.events.pass({'function':'MozMillDropList.select()'});
  491. return true;
  492. } catch (ex) {
  493. throw new Error("No item selected for element " + this.getInfo());
  494. return false;
  495. }
  496. }
  497. //if we have a xul menupopup select accordingly
  498. else if (this.element.namespaceURI.toLowerCase() == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul") {
  499. var ownerDoc = this.element.ownerDocument;
  500. // Unwrap the XUL element's XPCNativeWrapper
  501. this.element = utils.unwrapNode(this.element);
  502. // Get the list of menuitems
  503. menuitems = this.element.getElementsByTagName("menupopup")[0].getElementsByTagName("menuitem");
  504. var item = null;
  505. if (indx != undefined) {
  506. if (indx == -1) {
  507. this.dispatchEvent('focus', false);
  508. this.element.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject).activeChild = null;
  509. this.dispatchEvent('change', true);
  510. frame.events.pass({'function':'MozMillDropList.select()'});
  511. return true;
  512. } else {
  513. item = menuitems[indx];
  514. }
  515. } else {
  516. for (var i = 0; i < menuitems.length; i++) {
  517. var entry = menuitems[i];
  518. if (option != undefined && entry.label == option ||
  519. value != undefined && entry.value == value) {
  520. item = entry;
  521. break;
  522. }
  523. }
  524. }
  525. // Click the item
  526. try {
  527. EventUtils.synthesizeMouse(this.element, 1, 1, {}, ownerDoc.defaultView);
  528. // Scroll down until item is visible
  529. for (var i = 0; i <= menuitems.length; ++i) {
  530. var selected = this.element.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject).activeChild;
  531. if (item == selected) {
  532. break;
  533. }
  534. EventUtils.synthesizeKey("VK_DOWN", {}, ownerDoc.defaultView);
  535. }
  536. EventUtils.synthesizeMouse(item, 1, 1, {}, ownerDoc.defaultView);
  537. frame.events.pass({'function':'MozMillDropList.select()'});
  538. return true;
  539. } catch (ex) {
  540. throw new Error('No item selected for element ' + this.getInfo());
  541. return false;
  542. }
  543. }
  544. };
  545. //----------------------------------------------------------------------------------------------------------------------------------------
  546. /**
  547. * MozMillTextBox
  548. * TextBox inherits from MozMillElement
  549. */
  550. MozMillTextBox.prototype = new MozMillElement();
  551. MozMillTextBox.prototype.parent = MozMillElement.prototype;
  552. MozMillTextBox.prototype.constructor = MozMillTextBox;
  553. function MozMillTextBox(locatorType, locator, args) {
  554. this.parent.constructor.call(this, locatorType, locator, args);
  555. };
  556. // Static method returns true if node is this type of element
  557. MozMillTextBox.isType = function(node) {
  558. if ((node.localName.toLowerCase() == 'input' && (node.getAttribute('type') == 'text' || node.getAttribute('type') == 'search')) ||
  559. (node.localName.toLowerCase() == 'textarea') ||
  560. (node.localName.toLowerCase() == 'textbox')) {
  561. return true;
  562. }
  563. return false;
  564. };
  565. /**
  566. * Synthesize keypress events for each character on the given element
  567. *
  568. * @param {string} aText
  569. * The text to send as single keypress events
  570. * @param {object} aModifiers
  571. * Information about the modifier keys to send
  572. * Elements: accelKey - Hold down the accelerator key (ctrl/meta)
  573. * [optional - default: false]
  574. * altKey - Hold down the alt key
  575. * [optional - default: false]
  576. * ctrlKey - Hold down the ctrl key
  577. * [optional - default: false]
  578. * metaKey - Hold down the meta key (command key on Mac)
  579. * [optional - default: false]
  580. * shiftKey - Hold down the shift key
  581. * [optional - default: false]
  582. * @param {object} aExpectedEvent
  583. * Information about the expected event to occur
  584. * Elements: target - Element which should receive the event
  585. * [optional - default: current element]
  586. * type - Type of the expected key event
  587. */
  588. MozMillTextBox.prototype.sendKeys = function (aText, aModifiers, aExpectedEvent) {
  589. if (!this.element) {
  590. throw new Error("could not find element " + this.getInfo());
  591. }
  592. var element = this.element;
  593. Array.forEach(aText, function(letter) {
  594. var win = element.ownerDocument? element.ownerDocument.defaultView : element;
  595. element.focus();
  596. if (aExpectedEvent) {
  597. var target = aExpectedEvent.target ? aExpectedEvent.target.getNode() : element;
  598. EventUtils.synthesizeKeyExpectEvent(letter, aModifiers || {}, target, aExpectedEvent.type,
  599. "MozMillTextBox.sendKeys()", win);
  600. } else {
  601. EventUtils.synthesizeKey(letter, aModifiers || {}, win);
  602. }
  603. });
  604. frame.events.pass({'function':'MozMillTextBox.type()'});
  605. return true;
  606. };