Chris@0: var __slice = [].slice; Chris@0: Chris@0: Poltergeist.Node = (function () { Chris@0: var name, _fn, _i, _len, _ref; Chris@0: var xpathStringLiteral; Chris@0: Chris@0: Node.DELEGATES = ['allText', 'visibleText', 'getAttribute', 'value', 'set', 'checked', Chris@0: 'setAttribute', 'isObsolete', 'removeAttribute', 'isMultiple', Chris@0: 'select', 'tagName', 'find', 'getAttributes', 'isVisible', Chris@0: 'position', 'trigger', 'input', 'parentId', 'parentIds', 'mouseEventTest', Chris@0: 'scrollIntoView', 'isDOMEqual', 'isDisabled', 'deleteText', 'selectRadioValue', Chris@0: 'containsSelection', 'allHTML', 'changed', 'getXPathForElement', 'deselectAllOptions']; Chris@0: Chris@0: function Node(page, id) { Chris@0: this.page = page; Chris@0: this.id = id; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the parent Node of this Node Chris@0: * @return {Poltergeist.Node} Chris@0: */ Chris@0: Node.prototype.parent = function () { Chris@0: return new Poltergeist.Node(this.page, this.parentId()); Chris@0: }; Chris@0: Chris@0: _ref = Node.DELEGATES; Chris@0: Chris@0: _fn = function (name) { Chris@0: return Node.prototype[name] = function () { Chris@0: var args = []; Chris@0: if (arguments.length >= 1) { Chris@0: args = __slice.call(arguments, 0) Chris@0: } Chris@0: return this.page.nodeCall(this.id, name, args); Chris@0: }; Chris@0: }; Chris@0: Chris@0: //Adding all the delegates from the agent Node to this Node Chris@0: for (_i = 0, _len = _ref.length; _i < _len; _i++) { Chris@0: name = _ref[_i]; Chris@0: _fn(name); Chris@0: } Chris@0: Chris@0: xpathStringLiteral = function (s) { Chris@0: if (s.indexOf('"') === -1) Chris@0: return '"' + s + '"'; Chris@0: if (s.indexOf("'") === -1) Chris@0: return "'" + s + "'"; Chris@0: return 'concat("' + s.replace(/"/g, '",\'"\',"') + '")'; Chris@0: }; Chris@0: Chris@0: /** Chris@0: * Gets an x,y position tailored for mouse event actions Chris@0: * @return {{x, y}} Chris@0: */ Chris@0: Node.prototype.mouseEventPosition = function () { Chris@0: var middle, pos, viewport; Chris@0: Chris@0: viewport = this.page.viewportSize(); Chris@0: pos = this.position(); Chris@0: middle = function (start, end, size) { Chris@0: return start + ((Math.min(end, size) - start) / 2); Chris@0: }; Chris@0: Chris@0: return { Chris@0: x: middle(pos.left, pos.right, viewport.width), Chris@0: y: middle(pos.top, pos.bottom, viewport.height) Chris@0: }; Chris@0: }; Chris@0: Chris@0: /** Chris@0: * Executes a phantomjs native mouse event Chris@0: * @param name Chris@0: * @return {{x, y}} Chris@0: */ Chris@0: Node.prototype.mouseEvent = function (name) { Chris@0: var pos, test; Chris@0: Chris@0: this.scrollIntoView(); Chris@0: pos = this.mouseEventPosition(); Chris@0: test = this.mouseEventTest(pos.x, pos.y); Chris@0: Chris@0: if (test.status === 'success') { Chris@0: if (name === 'rightclick') { Chris@0: this.page.mouseEvent('click', pos.x, pos.y, 'right'); Chris@0: this.trigger('contextmenu'); Chris@0: } else { Chris@0: this.page.mouseEvent(name, pos.x, pos.y); Chris@0: } Chris@0: return pos; Chris@0: } else { Chris@0: throw new Poltergeist.MouseEventFailed(name, test.selector, pos); Chris@0: } Chris@0: }; Chris@0: Chris@0: /** Chris@0: * Executes a mouse based drag from one node to another Chris@0: * @param other Chris@0: * @return {{x, y}} Chris@0: */ Chris@0: Node.prototype.dragTo = function (other) { Chris@0: var otherPosition, position; Chris@0: Chris@0: this.scrollIntoView(); Chris@0: position = this.mouseEventPosition(); Chris@0: otherPosition = other.mouseEventPosition(); Chris@0: this.page.mouseEvent('mousedown', position.x, position.y); Chris@0: return this.page.mouseEvent('mouseup', otherPosition.x, otherPosition.y); Chris@0: }; Chris@0: Chris@0: /** Chris@0: * Checks if one node is equal to another Chris@0: * @param other Chris@0: * @return {boolean} Chris@0: */ Chris@0: Node.prototype.isEqual = function (other) { Chris@0: return this.page === other.page && this.isDOMEqual(other.id); Chris@0: }; Chris@0: Chris@0: Chris@0: /** Chris@0: * The value to select Chris@0: * @param value Chris@0: * @param multiple Chris@0: */ Chris@0: Node.prototype.select_option = function (value, multiple) { Chris@0: var tagName = this.tagName().toLowerCase(); Chris@0: Chris@0: if (tagName === "select") { Chris@0: var escapedOption = xpathStringLiteral(value); Chris@0: // The value of an option is the normalized version of its text when it has no value attribute Chris@0: var optionQuery = ".//option[@value = " + escapedOption + " or (not(@value) and normalize-space(.) = " + escapedOption + ")]"; Chris@0: var ids = this.find("xpath", optionQuery); Chris@0: var polterNode = this.page.get(ids[0]); Chris@0: Chris@0: if (multiple || !this.getAttribute('multiple')) { Chris@0: if (!polterNode.getAttribute('selected')) { Chris@0: polterNode.select(value); Chris@0: this.trigger('click'); Chris@0: this.input(); Chris@0: } Chris@0: return true; Chris@0: } Chris@0: Chris@0: this.deselectAllOptions(); Chris@0: polterNode.select(value); Chris@0: this.trigger('click'); Chris@0: this.input(); Chris@0: return true; Chris@0: } else if (tagName === "input" && this.getAttribute("type").toLowerCase() === "radio") { Chris@0: return this.selectRadioValue(value); Chris@0: } Chris@0: Chris@0: throw new Poltergeist.BrowserError("The element is not a select or radio input"); Chris@0: Chris@0: }; Chris@0: Chris@0: return Node; Chris@0: Chris@0: }).call(this);