Chris@0: {% autoescape 'js' %} Chris@0: (function (xpath, value) { Chris@0: function getElement(xpath, within) { Chris@0: var result; Chris@0: if (within === null || within === undefined) { Chris@0: within = document; Chris@0: } Chris@0: result = document.evaluate(xpath, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); Chris@0: if (result.snapshotLength !== 1) { Chris@0: return null; Chris@0: } Chris@0: return result.snapshotItem(0); Chris@0: } Chris@0: Chris@0: function isInput(element) { Chris@0: if (element === null || element === undefined) { Chris@0: return false; Chris@0: } Chris@0: return (element.tagName.toLowerCase() == "input"); Chris@0: } Chris@0: Chris@0: function isTextArea(element) { Chris@0: if (element === null || element === undefined) { Chris@0: return false; Chris@0: } Chris@0: return (element.tagName.toLowerCase() == "textarea"); Chris@0: } Chris@0: Chris@0: function isSelect(element) { Chris@0: if (element === null || element === undefined) { Chris@0: return false; Chris@0: } Chris@0: return (element.tagName.toLowerCase() == "select"); Chris@0: } Chris@0: Chris@0: function deselectAllOptions(element) { Chris@0: var i, l = element.options.length; Chris@0: for (i = 0; i < l; i++) { Chris@0: element.options[i].selected = false; Chris@0: } Chris@0: } Chris@0: Chris@0: function xpathStringLiteral(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: function clickOnElement(element) { Chris@0: // create a mouse click event Chris@0: var event = document.createEvent('MouseEvents'); Chris@0: event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); Chris@0: Chris@0: // send click to element Chris@0: element.dispatchEvent(event); Chris@0: Chris@0: //After dispatching the event let's wait for 2 seconds at least... Chris@0: return setTimeout(function () { Chris@0: }, 2); Chris@0: } Chris@0: Chris@0: function dispatchChange(element) { Chris@0: var tagName =element.tagName.toLowerCase(); Chris@0: var elementType = element.getAttribute("type"); Chris@0: if (tagName != "option" || (tagName == "input" && elementType == "radio")){ Chris@0: return true; Chris@0: } Chris@0: //Force the change when element is option Chris@0: var event; Chris@0: event = document.createEvent('HTMLEvents'); Chris@0: event.initEvent('change', true, false); Chris@0: element.dispatchEvent(event); Chris@0: return true; Chris@0: } Chris@0: Chris@0: function selectOptionOnElement(element, option, multiple) { Chris@0: var polterAgent = window.__poltergeist; Chris@0: var escapedOption = xpathStringLiteral(option); 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 = polterAgent.find("xpath", optionQuery, element); Chris@0: var polterNode = polterAgent.get(ids[0]); Chris@0: var optionElement = polterNode.element; Chris@0: Chris@0: if (multiple || !element.multiple) { Chris@0: if (!optionElement.selected) { Chris@0: clickOnElement(optionElement); Chris@0: optionElement.selected = true; Chris@0: } Chris@0: return dispatchChange(optionElement); Chris@0: } Chris@0: Chris@0: deselectAllOptions(element); Chris@0: clickOnElement(optionElement); Chris@0: optionElement.selected = true; Chris@0: return dispatchChange(optionElement); Chris@0: } Chris@0: Chris@0: function selectSetValue(element, value) { Chris@0: var option; Chris@0: if ((Array.isArray && Array.isArray(value)) || (value instanceof Array)) { Chris@0: deselectAllOptions(element); Chris@0: for (option in value) { Chris@0: if (value.hasOwnProperty(option)) { Chris@0: selectOptionOnElement(element, value[option], true); Chris@0: } Chris@0: } Chris@0: return true; Chris@0: } Chris@0: Chris@0: selectOptionOnElement(element, value, false); Chris@0: return true; Chris@0: } Chris@0: Chris@0: function selectRadioValue(element, value) { Chris@0: if (element.value === value) { Chris@0: clickOnElement(element); Chris@0: element.checked=true; Chris@0: dispatchChange(element); Chris@0: return true; Chris@0: } Chris@0: Chris@0: var formElements = element.form.elements; Chris@0: var name = element.getAttribute("name"); Chris@0: var radioElement, i; Chris@0: Chris@0: if (!name) { Chris@0: return null; Chris@0: } Chris@0: Chris@0: for (i = 0; i < formElements.length; i++) { Chris@0: radioElement = formElements[i]; Chris@0: if (radioElement.tagName.toLowerCase() == 'input' && radioElement.type.toLowerCase() == 'radio' && radioElement.name === name) { Chris@0: if (value === radioElement.value) { Chris@0: clickOnElement(radioElement); Chris@0: radioElement.checked=true; Chris@0: dispatchChange(radioElement); Chris@0: return true; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return null; Chris@0: } Chris@0: Chris@0: function inputSetValue(element, value, elementXpath) { Chris@0: var allowedTypes = ['submit', 'image', 'button', 'reset']; Chris@0: var elementType = element.type.toLowerCase(); Chris@0: var textLikeInputType = ['file', 'text', 'password', 'url', 'email', 'search', 'number', 'tel', 'range', 'date', 'month', 'week', 'time', 'datetime', 'color', 'datetime-local']; Chris@0: Chris@0: if (allowedTypes.indexOf(elementType) !== -1) { Chris@0: return null; Chris@0: } Chris@0: Chris@0: if (elementType == "checkbox") { Chris@0: var booleanValue = false; Chris@0: if (value == "1" || value == 1) { Chris@0: booleanValue = true; Chris@0: } else if (value == "0" || value == 0) { Chris@0: booleanValue = false; Chris@0: } Chris@0: if ((element.checked && !booleanValue) || (!element.checked && booleanValue)) { Chris@0: clickOnElement(element); Chris@0: dispatchChange(element); Chris@0: } Chris@0: return true; Chris@0: } Chris@0: Chris@0: if (elementType == "radio") { Chris@0: return selectRadioValue(element, value); Chris@0: } Chris@0: Chris@0: if (textLikeInputType.indexOf(elementType) !== -1) { Chris@0: return textAreaSetValue(elementXpath, value); Chris@0: } Chris@0: Chris@0: //No support for the moment for file stuff or other input types Chris@0: return null; Chris@0: Chris@0: } Chris@0: Chris@0: function textAreaSetValue(elementXpath, value) { Chris@0: var polterAgent = window.__poltergeist; Chris@0: var ids = polterAgent.find("xpath", elementXpath, document); Chris@0: var polterNode = polterAgent.get(ids[0]); Chris@0: polterNode.set(value); Chris@0: return true; Chris@0: } Chris@0: Chris@0: var node = getElement(xpath); Chris@0: if (node === null) { Chris@0: return null; Chris@0: } Chris@0: Chris@0: if (isSelect(node)) { Chris@0: return selectSetValue(node, value); Chris@0: } Chris@0: Chris@0: if (isInput(node)) { Chris@0: return inputSetValue(node, value, xpath); Chris@0: } Chris@0: Chris@0: if (isTextArea(node)) { Chris@0: return textAreaSetValue(xpath, value); Chris@0: } Chris@0: Chris@0: //for the moment everything else also to textArea stuff Chris@0: return textAreaSetValue(xpath, value); Chris@0: Chris@0: }('{{xpath}}', JSON.parse('{{ value }}'))); Chris@0: {% endautoescape %}