Best JavaScript code snippet using webdriverio-monorepo
noteit.js
Source:noteit.js
1/*2 * Noteit3 * Evernote4 * $Rev: 109850 $5 *6 * Created by Pavel Skaldin on 7/13/107 * Copyright 2010 Evernote Corp. All rights reserved.8 */9var Evernote = (typeof Evernote == 'object' && Evernote != null) ? Evernote10 : {};11Evernote.logger = {12 debug : function(msg) {13 if (typeof console == 'object' && console != null14 && typeof console["log"] == 'function') {15 console.log(msg);16 }17 },18 isDebugEnabled : function() {19 return false;20 }21};22Evernote.detectCharacterEncoding = function(doc) {23 var d = (doc) ? doc : document;24 var cs = null;25 if (typeof d.characterSet == 'string') {26 cs = d.characterSet;27 } else if (typeof d.charset == 'string') {28 cs = d.charset;29 } else if (typeof d.inputEncoding == 'string') {30 cs = d.inputEncoding;31 } else if (typeof d.defaultCharset == 'string') {32 cs = d.defaultCharset;33 }34 return cs;35};36/** ************** Duck punching *************** */37if (typeof Array.prototype.indexOf != 'function') {38 Array.prototype.indexOf = function(o) {39 for (var i=0; i<this.length; i++) {40 if (this[i] == o) {41 return i;42 }43 }44 return -1;45 };46}47/** ************** Config *************** */48Evernote.Config = {49 insecureProto : "http://",50 secureProto : "https://",51 serviceDomain : "www.evernote.com",52 clipPath : "/noteit.action",53 getClipUrl : function() {54 return this.secureProto + this.serviceDomain + this.clipPath;55 }56};57/** ************** Inheritance *************** */58Evernote.inherit = function(childConstructor, parentClassOrObject,59 includeConstructorDefs) {60 if (parentClassOrObject.constructor == Function) {61 // Normal Inheritance62 childConstructor.prototype = new parentClassOrObject;63 childConstructor.prototype.constructor = childConstructor;64 childConstructor.prototype.parent = parentClassOrObject.prototype;65 childConstructor.constructor.parent = parentClassOrObject;66 } else {67 // Pure Virtual Inheritance68 childConstructor.prototype = parentClassOrObject;69 childConstructor.prototype.constructor = childConstructor;70 childConstructor.prototype.parent = parentClassOrObject;71 childConstructor.constructor.parent = parentClassOrObject;72 }73 if (includeConstructorDefs) {74 for ( var i in parentClassOrObject.prototype.constructor) {75 if (i != "parent"76 && i != "prototype"77 && parentClassOrObject.constructor[i] != parentClassOrObject.prototype.constructor[i]78 && typeof childConstructor.prototype.constructor[i] == 'undefined') {79 childConstructor.prototype.constructor[i] = parentClassOrObject.prototype.constructor[i];80 }81 }82 }83 if (typeof childConstructor.handleInheritance == 'function') {84 childConstructor.handleInheritance.apply(childConstructor, arguments);85 }86 return childConstructor;87};88Evernote.inherits = function(childConstructor, parentClass) {89 return (typeof childConstructor.prototype.parent != 'undefined' && childConstructor.prototype.parent.constructor == parentClass);90};91/** ************** Utility Methods *************** */92Evernote.isHtmlElement = function(element) {93 if (typeof HTMLElement == 'function') {94 return (element instanceof HTMLElement);95 } else if (typeof Element == 'function') {96 return (element instanceof Element);97 } else if (element != null) {98 // really trying our luck99 return (typeof element["nodeType"] != "undefined" && element["nodeType"] == 1);100 }101 return false;102};103Evernote.trimString = function(str) {104 if (typeof str == 'string') {105 return str.replace(/^\s+/, "").replace(/\s+$/, "");106 }107 return str;108};109Evernote.collapseString = function(str) {110 if (typeof str == 'string') {111 return str.replace(/[\s\t\n]+/g, " ").replace(/^\s+/, "").replace(/\s+$/,112 "");113 }114 return str;115};116Evernote.cleanArray = function(array, fn) {117 if (array instanceof Array && typeof fn == 'function') {118 var i = 0;119 while (i < array.length) {120 if (fn(array[i])) {121 array.splice(i, 1);122 } else {123 i += 1;124 }125 }126 }127};128Evernote.findChildren = function(anchor, fn, recursive) {129 var children = new Array();130 if (typeof anchor == 'object' && anchor != null131 && typeof anchor["nodeType"] == 'number' && anchor.nodeType == 1) {132 var childNodes = anchor.childNodes;133 for ( var i = 0; i < childNodes.length; i++) {134 if (typeof fn == 'function' && fn(childNodes[i])) {135 children.push(childNodes[i]);136 } else if (typeof fn != 'function') {137 children.push(childNodes[i]);138 }139 if (recursive && childNodes[i].childElementCount > 0) {140 var otherChildren = arguments.callee(childNodes[i], fn);141 if (otherChildren && otherChildren.length > 0) {142 children = Evernote.concatArrays(children, otherChildren);143 }144 }145 }146 }147 return children;148};149Evernote.findParent = function(anchor, fn) {150 if (typeof anchor == 'object' && anchor != null151 && typeof anchor["nodeType"] == 'number') {152 if (anchor.nodeName == "BODY") {153 return anchor;154 } else if (anchor.parentNode == "BODY") {155 return anchor;156 } else {157 var p = anchor;158 while (p.parentNode.nodeName != "BODY") {159 if (typeof fn == 'function' && fn(p.parentNode)) {160 return p.parentNode;161 } else if (typeof fn != 'function') {162 return p.parentNode;163 }164 p = p.parentNode;165 }166 }167 }168 return null;169};170Evernote.hasElementClass = function(element, className, caseSensitive) {171 if (!this.isHtmlElement(element))172 return false;173 try {174 var classAttr = element.getAttribute("class");175 if (typeof classAttr != 'string')176 return false;177 if (!caseSensitive) {178 classAttr = classAttr.toLowerCase();179 className = className.toLowerCase();180 }181 var classNames = classAttr.replace(/\s+/, " ").split(" ");182 return classNames.indexOf(className) >= 0;183 } catch (e) {184 }185 return false;186};187Evernote.containsElementClass = function(element, className, caseSensitive) {188 if (!this.isHtmlElement(element))189 return false;190 try {191 var classAttr = element.getAttribute("class");192 if (typeof classAttr != 'string')193 return false;194 if (!caseSensitive) {195 classAttr = classAttr.toLowerCase();196 className = className.toLowerCase();197 }198 return classAttr.indexOf(className) >= 0;199 } catch (e) {200 }201 return false;202};203Evernote.hasElementId = function(element, id, caseSensitive) {204 if (!this.isHtmlElement(element))205 return false;206 try {207 var idAttr = element.getAttribute("id");208 if (typeof idAttr != 'string')209 return false;210 if (!caseSensitive) {211 idAttr = idAttr.toLowerCase();212 id = id.toLowerCase();213 }214 return idAttr == id;215 } catch (e) {216 }217 return false;218};219Evernote.containsElementId = function(element, id, caseSensitive) {220 if (!this.isHtmlElement(element))221 return false;222 try {223 var idAttr = element.getAttribute("id");224 if (typeof idAttr != 'string')225 return false;226 if (!caseSensitive) {227 idAttr = idAttr.toLowerCase();228 id = id.toLowerCase();229 }230 return idAttr.indexOf(id) >= 0;231 } catch (e) {232 }233 return false;234};235Evernote.isElementVisible = function(element) {236 if (!this.isHtmlElement(element))237 return false;238 try {239 var style = element.ownerDocument.defaultView.getComputedStyle(element);240 if (style) {241 if (style.getPropertyValue("display") != "none"242 && style.getPropertyValue("visibility") != "none") {243 return true;244 }245 }246 } catch (e) {247 }248 return false;249};250Evernote.getElementClassNames = function(element) {251 if (!this.isHtmlElement(element))252 return false;253 return element.getAttribute("class").replace(/\s+/, " ").split(" ");254};255Evernote.getElementSortedClassName = function(element) {256 if (!this.isHtmlElement(element))257 return null;258 return Evernote.getElementClassNames().sort().join(" ");259};260/** ************** Clip *************** */261Evernote.Clip = function(aWindow, stylingStrategy) {262 this.initialize(aWindow, stylingStrategy);263};264Evernote.Clip.constants = {265 isIE : (navigator.appVersion.indexOf("MSIE", 0) != -1),266 isSafari : (navigator.appVersion.indexOf("WebKit", 0) != -1),267 isFirefox : (navigator.userAgent.indexOf("Firefox", 0) != -1),268 isIpad : (navigator.userAgent.indexOf("WebKit") > 0 && navigator.userAgent269 .indexOf("iPad") > 0),270 isIphone : (navigator.userAgent.indexOf("WebKit") > 0 && navigator.userAgent271 .indexOf("iPhone") > 0)272};273Evernote.Clip.contentMarkers = [ "article", "post", "content", "story", "body" ];274Evernote.Clip.filterMarkers = [ "comment", "feedback", "breadcrumb", "share",275 "sharing", "social", "sociable", "tools", "links", "extra", "related",276 "sponsor", "ads", "adsense", "banner", "chat", "shout", "module" ];277Evernote.Clip.NOKEEP_NODE_ATTRIBUTES = {278 "style" : null,279 "class" : null,280 "id" : null,281 "onclick" : null,282 "onsubmit" : null,283 "onmouseover" : null,284 "onmouseout" : null285};286Evernote.Clip.NOKEEP_NODE_NAMES = {287 "style" : null,288 "script" : null,289 "input" : null,290 "select" : null,291 "option" : null,292 "textarea" : null293};294Evernote.Clip.SELF_CLOSING_NODE_NAMES = {295 "base" : null,296 "basefont" : null,297 "frame" : null,298 "link" : null,299 "meta" : null,300 "area" : null,301 "br" : null,302 "col" : null,303 "hr" : null,304 "img" : null,305 "input" : null,306 "param" : null307};308Evernote.Clip.NODE_NAME_TRANSLATIONS = {309 "body" : "div",310 "form" : "div"311};312Evernote.Clip.LIST_NODE_NAMES = {313 "ul" : null,314 "ol" : null315};316Evernote.Clip.HTMLEncode = function(str) {317 var result = "";318 for ( var i = 0; i < str.length; i++) {319 var charcode = str.charCodeAt(i);320 var aChar = str[i];321 if (charcode > 0x7f) {322 result += "&#" + charcode + ";";323 } else if (aChar == '>') {324 result += ">";325 } else if (aChar == '<') {326 result += "<";327 } else if (aChar == '&') {328 result += "&";329 } else {330 result += str.charAt(i);331 }332 }333 return result;334};335Evernote.Clip.unicodeEntities = function(str) {336 var result = "";337 if (typeof str == 'string') {338 for ( var i = 0; i < str.length; i++) {339 var c = str.charCodeAt(i);340 if (c > 127) {341 result += "&#" + c + ";";342 } else {343 result += str.charAt(i);344 }345 }346 }347 return result;348};349Evernote.Clip.isHtmlElement = function(element) {350 return Evernote.isHtmlElement(element);351};352Evernote.Clip.trimString = function(str) {353 return Evernote.trimString(str);354};355Evernote.Clip.collapseString = function(str) {356 return Evernote.collapseString(str);357};358/**359 * When serializing DOM elements, this attribute is checked to see if it's a360 * function. If it is, it's passed currently serialized element. If the function361 * returns a truthful result, the element will be serialized, otherwise - it362 * will be excluded/skipped. This is meant to globally define the behavior and363 * is called from Evernote.Clip.prototype.nodeFilter by default.364 *365 * For custom filtering logic on per-object basis - override366 * Evernote.Clip.prototype.nodeFilter; for all instanceof of Evernote.Clip - you367 * override Evernote.Clip.nodeFilter.368 */369Evernote.Clip.nodeFilter = null;370Evernote.Clip.prototype.title = null;371Evernote.Clip.prototype.location = null;372Evernote.Clip.prototype.window = null;373Evernote.Clip.prototype.selectionFinder = null;374Evernote.Clip.prototype.deep = true;375Evernote.Clip.prototype.content = null;376Evernote.Clip.prototype.range = null;377Evernote.Clip.prototype._stylingStrategy = null;378Evernote.Clip.prototype._verboseLog = false;379// Declares the content and source of a web clip380Evernote.Clip.prototype.initialize = function(aWindow, stylingStrategy) {381 this.title = (typeof aWindow.document.title == 'string') ? aWindow.document.title382 : "";383 this.title = Evernote.Clip.collapseString(this.title);384 this.location = aWindow.location;385 this.window = aWindow;386 this.selectionFinder = new Evernote.SelectionFinder(aWindow.document);387 this.range = null;388 if (stylingStrategy) {389 this.setStylingStrategy(stylingStrategy);390 }391};392Evernote.Clip.prototype.isFullPage = function() {393 return !this.hasSelection();394};395Evernote.Clip.prototype.hasSelection = function() {396 if (this.selectionFinder.hasSelection()) {397 return true;398 } else {399 this.findSelection();400 return this.selectionFinder.hasSelection();401 }402};403Evernote.Clip.prototype.findSelection = function() {404 this.selectionFinder.find(this.deep);405};406Evernote.Clip.prototype.getSelection = function() {407 if (this.hasSelection()) {408 return this.selectionFinder.selection;409 }410 return null;411};412Evernote.Clip.prototype.getRange = function() {413 if (this.hasSelection()) {414 return this.selectionFinder.getRange();415 }416 return null;417};418Evernote.Clip.prototype.getBody = function() {419 return this.window.document.getElementsByTagName('body')[0];420};421Evernote.Clip.prototype.hasBody = function() {422 try {423 var body = this.getBody();424 return body ? true : false;425 } catch (e) {426 return false;427 }428};429Evernote.Clip.prototype.hasContentToClip = function() {430 return (this.hasBody() || this.hasSelection());431};432/**433 * Captures all the content of the document434 */435Evernote.Clip.prototype.clipBody = function() {436 if (!this.hasBody()) {437 Evernote.logger.debug("Document has no body...");438 return false;439 }440 return this.clipElement(this.getBody());441};442/**443 * Captures content within an element444 *445 * @param element446 * @return447 */448Evernote.Clip.prototype.clipElement = function(element) {449 if (element && Evernote.Clip.isHtmlElement(element)) {450 var s = 0;451 var e = 0;452 if (this._verboseLog) {453 Evernote.logger.debug("Getting element contents: " + this);454 s = new Date().getTime();455 }456 this.content = this.serializeDOMNode(element, null, true);457 if (this._verboseLog) {458 e = new Date().getTime();459 Evernote.logger.debug("Clipped element contents in " + (e - s)460 + " seconds");461 }462 if (typeof this.content != 'string') {463 return false;464 }465 return true;466 } else {467 Evernote.logger.debug("Nothing to clip...");468 return false;469 }470};471/**472 * Captures selection in the document473 */474Evernote.Clip.prototype.clipSelection = function() {475 if (!this.hasSelection()) {476 Evernote.logger.debug("No selection to clip");477 return false;478 }479 // IE special case480 if (Evernote.Clip.constants.isIE) {481 this.content = this.selectionFinder.selection.htmlText;482 return true;483 }484 var s = 0;485 var e = 0;486 this.range = this.getRange();487 if (this.range) {488 if (this._verboseLog)489 var s = new Date().getTime();490 this.content = this.serializeDOMNode(this.range.commonAncestorContainer);491 if (this._verboseLog)492 var e = new Date().getTime();493 this.range = null;494 if (this._verboseLog) {495 Evernote.logger.debug("Success...");496 Evernote.logger.debug("Clipped selection in " + (e - s) + " seconds");497 }498 return true;499 }500 this.range = null;501 Evernote.logger.debug("Failed to clip selection");502 return false;503};504Evernote.Clip.prototype.clipLink = function(url, title) {505 if (typeof url != 'string') {506 url = this.window.document.location.href;507 }508 if (typeof title != 'string') {509 title = Evernote.Clip.collapseString(this.window.document.title);510 }511 this.content = "<a href='" + url + "'>" + title + "</a>";512 return true;513};514Evernote.Clip.prototype.rangeIntersectsNode = function(node) {515 if (this.range) {516 var nodeRange = node.ownerDocument.createRange();517 try {518 nodeRange.selectNode(node);519 } catch (e) {520 nodeRange.selectNodeContents(node);521 }522 return this.range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1523 && this.range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1;524 }525 return false;526};527Evernote.Clip.prototype.serializeDOMNode = function(node, parentNode, force) {528 if (this._verboseLog)529 Evernote.logger.debug("Clip.serializeDOMNode");530 var str = "";531 if (!force) {532 if (this.range && !this.rangeIntersectsNode(node)) {533 if (this._verboseLog)534 Evernote.logger.debug("Skipping serialization of node: "535 + node.nodeName + " cuz it's not in range...");536 return str;537 }538 if (!this.keepNode(node)) {539 if (this._verboseLog)540 Evernote.logger.debug("Skipping seralization of node: " + node.nodeName541 + " cuz it's a no-keeper");542 return str;543 }544 }545 if (this._verboseLog)546 Evernote.logger.debug("SerializeDOMNode: " + node.nodeName);547 if (node.nodeType == 3) { // Text block548 if (this._verboseLog)549 Evernote.logger.debug("Serializing text node...");550 if (this.range) {551 if (this.range.startContainer == node552 && this.range.startContainer == this.range.endContainer) {553 str += this.constructor.HTMLEncode(node.nodeValue.substring(554 this.range.startOffset, this.range.endOffset));555 } else if (this.range.startContainer == node) {556 str += this.constructor.HTMLEncode(node.nodeValue557 .substring(this.range.startOffset));558 } else if (this.range.endContainer == node) {559 str += this.constructor.HTMLEncode(node.nodeValue.substring(0,560 this.range.endOffset));561 } else if (this.range.commonAncestorContainer != node) {562 str += this.constructor.HTMLEncode(node.nodeValue);563 }564 } else {565 str += this.constructor.HTMLEncode(node.nodeValue);566 }567 } else if (node.nodeType == 1) {568 // ignore range ancestor as long as it's not a list container569 if (this.range && this.range.commonAncestorContainer == node570 && this.range.startContainer != this.range.commonAncestorContainer571 && !this.isListNode(node)) {572 if (this._verboseLog)573 Evernote.logger.debug("Ignoring range ancestor: " + node.nodeName);574 } else {575 // serialize node576 if (this._verboseLog)577 Evernote.logger.debug("Serializing node: " + node.nodeName);578 var translatedNodeName = this.translateNodeName(node);579 str += "<" + translatedNodeName;580 // include attrs581 var attrStr = this.nodeAttributesToString(node);582 if (attrStr.length > 0)583 str += " " + attrStr;584 // include style585 if (this.getStylingStrategy()) {586 if (this._verboseLog)587 Evernote.logger.debug("Styling node: " + node.nodeName);588 var nodeStyle = this.getStylingStrategy()589 .styleForNode(node, parentNode);590 if (this._verboseLog)591 Evernote.logger.debug(nodeStyle);592 if (nodeStyle instanceof Evernote.ClipStyle && nodeStyle.length > 0) {593 str += " style=\"" + nodeStyle.toString() + "\"";594 } else if (this._verboseLog) {595 Evernote.logger.debug("Empty style...");596 }597 }598 if (!node.hasChildNodes() && this.isSelfClosingNode(node)) {599 if (this._verboseLog)600 Evernote.logger.debug("Closing self-closing tag: " + node.nodeName);601 str += "/>";602 } else {603 str += ">";604 }605 }606 // recurse children607 if (node.nodeName.toLowerCase() != "iframe" && node.hasChildNodes()) {608 var children = node.childNodes;609 for ( var j = 0; j < children.length; j++) {610 var child = children[j];611 if (child != null && child.nodeType > 0 && child.nodeName != 'SCRIPT'612 && child.nodeName != 'IFRAME') {613 var childStr = this.serializeDOMNode(child, node);614 if (childStr && childStr.length > 0)615 str += childStr;616 }617 }618 }619 if (this.range && this.range.commonAncestorContainer == node620 && !this.isListNode(node)) {621 if (this._verboseLog)622 Evernote.logger.debug("Ignoring range ancestor: " + node.nodeName);623 } else if (node.hasChildNodes() || !this.isSelfClosingNode(node)) {624 str += "</" + translatedNodeName + ">";625 }626 }627 return str;628};629Evernote.Clip.prototype.keepNodeAttr = function(attrName) {630 return (typeof attrName == 'string' && typeof Evernote.Clip.NOKEEP_NODE_ATTRIBUTES[attrName631 .toLowerCase()] == 'undefined');632};633Evernote.Clip.prototype.keepNode = function(node) {634 if (node) {635 if (node.nodeType == 3) {636 return true;637 } else if (node.nodeType == 1) {638 if (node.nodeName.indexOf('#') == 0 || !this.isNodeVisible(node))639 return false;640 return (typeof Evernote.Clip.NOKEEP_NODE_NAMES[node.nodeName641 .toLowerCase()] == 'undefined' && this.nodeFilter(node));642 }643 }644 return false;645};646Evernote.Clip.prototype.nodeFilter = function(node) {647 // by default, check if there's a globaly defined nodeFilter, and use that648 if (typeof Evernote.Clip.nodeFilter == 'function') {649 return Evernote.Clip.nodeFilter(node);650 }651 return true;652};653Evernote.Clip.prototype.isNodeVisible = function(node) {654 var display = this.getNodeStylePropertyValue(node, "display");655 return (display && display != "none");656};657Evernote.Clip.prototype.isSelfClosingNode = function(node) {658 return (node && typeof Evernote.Clip.SELF_CLOSING_NODE_NAMES[node.nodeName659 .toLowerCase()] != 'undefined');660};661Evernote.Clip.prototype.isListNode = function(node) {662 return (node && node.nodeType == 1 && typeof Evernote.Clip.LIST_NODE_NAMES[node.nodeName663 .toLowerCase()] != 'undefined');664};665Evernote.Clip.prototype.nodeAttributesToString = function(node) {666 var str = "";667 var attrs = node.attributes;668 if (attrs != null) {669 for ( var i = 0; i < attrs.length; i++) {670 var a = attrs[i].nodeName.toLowerCase();671 var v = attrs[i].nodeValue;672 if (a == "href" && v.toLowerCase().indexOf("javascript:") == 0) {673 continue;674 }675 if (this.keepNodeAttr(a) && v != null && v.length > 0) {676 str += a + '=' + '"' + v + '" ';677 }678 }679 }680 return str.replace(/\s+$/, "");681};682Evernote.Clip.prototype.translateNodeName = function(node) {683 if (typeof Evernote.Clip.NODE_NAME_TRANSLATIONS[node.nodeName.toLowerCase()] != 'undefined') {684 return Evernote.Clip.NODE_NAME_TRANSLATIONS[node.nodeName.toLowerCase()];685 }686 return node.nodeName;687};688/**689 * Returns CSS style for the given node as a ClipStyle object. If computed is690 * true, the style will be computed, otherwise - it would only contain style691 * attributes matching the node.692 */693Evernote.Clip.prototype.getNodeStyle = function(node, computed, filter) {694 return Evernote.ClipStyle.getNodeStyle(node, computed, filter);695};696Evernote.Clip.prototype.getNodeStylePropertyValue = function(node, propName) {697 if (node && typeof node.nodeType == 'number' && node.nodeType == 1698 && typeof propName == 'string') {699 var doc = node.ownerDocument;700 var view = null;701 try {702 view = (doc.defaultView) ? doc.defaultView : this.window;703 } catch (e) {704 if (this._verboseLog)705 Evernote.logger.debug("Could not obtain parent window. Using default.");706 view = this.window;707 }708 if (typeof view.getComputedStyle == 'function') {709 var style = view.getComputedStyle(node, null);710 return style.getPropertyValue(propName);711 } else if (typeof node.currentStyle == 'object'712 && node.currentStyle != null) {713 return node.currentStyle[propName];714 }715 }716 return null;717};718Evernote.Clip.prototype.setStylingStrategy = function(strategy) {719 if (typeof strategy == 'function'720 && Evernote.inherits(strategy, Evernote.ClipStylingStrategy)) {721 this._stylingStrategy = new strategy(this.window);722 } else if (strategy instanceof Evernote.ClipStylingStrategy) {723 this._stylingStrategy = strategy;724 } else if (strategy == null) {725 this._stylingStrategy = null;726 }727};728Evernote.Clip.prototype.getStylingStrategy = function() {729 return this._stylingStrategy;730};731Evernote.Clip.prototype.toString = function() {732 return "Clip[" + this.location + "] " + this.title;733};734// return POSTable length of this Clip735Evernote.Clip.prototype.getLength = function() {736 var total = 0;737 var o = this.toDataObject();738 for ( var i in o) {739 total += ("" + o[i]).length + i.length + 2;740 }741 total -= 1;742 return total;743};744Evernote.Clip.prototype.toDataObject = function() {745 return {746 "content" : this.content,747 "title" : this.title,748 "url" : this.location.href,749 "fullPage" : this.isFullPage()750 };751};752/** ************** ClipStyle *************** */753/**754 * ClipStyle is a container for CSS styles. It is able to add and remove755 * CSSStyleRules (and parse CSSRuleList's for rules), as well as756 * CSSStyleDeclaration's and instances of itself.757 *758 * ClipStyle provides a mechanism to serialize itself via toString(), and759 * reports its length via length property. It also provides a method to clone760 * itself and expects to be manipulated via addStyle and removeStyle.761 */762Evernote.ClipStyle = function(css, filter) {763 this.initialize(css, filter);764};765Evernote.ClipStyle.stylePrefix = function(style) {766 if (typeof style == 'string') {767 var i = 0;768 if ((i = style.indexOf("-")) > 0) {769 return style.substring(0, i);770 }771 }772 return style;773};774Evernote.ClipStyle.prototype.length = 0;775Evernote.ClipStyle.prototype.filter = null;776Evernote.ClipStyle.prototype._verboseLog = false;777Evernote.ClipStyle.prototype.initialize = function(css, filter) {778 if (filter)779 this.setFilter(filter);780 try {781 if (CSSRuleList && css instanceof CSSRuleList) {782 if (css.length > 0) {783 for ( var i = 0; i < css.length; i++) {784 this.addStyle(css[i].style);785 }786 }787 } else if (typeof CSSStyleRule != 'undefined'788 && css instanceof CSSStyleRule) {789 this.addStyle(css.style);790 } else if (typeof CSSStyleDeclaration != 'undefined'791 && css instanceof CSSStyleDeclaration) {792 this.addStyle(css);793 } else if (typeof CSSCurrentStyleDeclaration != 'undefined'794 && css instanceof CSSCurrentStyleDeclaration) {795 this.addStyle(css);796 }797 } catch (e) {798 Evernote.logger.debug("Error initializing Evernote.ClipStyle: " + e);799 }800};801Evernote.ClipStyle.prototype.addStyle = function(style) {802 if (typeof CSSStyleDeclaration != 'undefined'803 && style instanceof CSSStyleDeclaration && style.length > 0) {804 for ( var i = 0; i < style.length; i++) {805 var prop = style[i];806 if (typeof this.filter == 'function' && !this.filter(prop)) {807 continue;808 }809 var val = style.getPropertyValue(prop);810 if (typeof this[prop] == 'undefined') {811 this.length++;812 }813 this[prop] = val;814 }815 } else if (typeof CSSCurrentStyleDeclaration != 'undefined'816 && style instanceof CSSCurrentStyleDeclaration) {817 for ( var prop in style) {818 if (typeof this.filter == 'function' && !this.filter(prop))819 continue;820 this[prop] = style[prop];821 }822 } else if (style instanceof Evernote.ClipStyle) {823 for ( var prop in style) {824 if (typeof this.constructor.prototype[prop] == 'undefined') {825 if (typeof this.filter == 'function' && !this.filter(prop)) {826 continue;827 }828 this[prop] = style[prop];829 }830 }831 } else if (typeof style == 'object' && style != null) {832 for ( var i in style) {833 if (typeof this.filter == 'function' && !this.filter(i)) {834 continue;835 }836 if (typeof style[i] != 'function'837 && typeof this.constructor.prototype[i] == 'undefined') {838 if (typeof this[i] == 'undefined') {839 this.length++;840 }841 this[i] = style[i];842 }843 }844 }845};846Evernote.ClipStyle.prototype.removeStyle = function(style, fn) {847 var self = this;848 function rem(prop, value) {849 if (typeof self[prop] != 'undefined'850 && typeof self.constructor.prototype[prop] == 'undefined'851 && (typeof fn == 'function' || self[prop] == value)) {852 if (typeof fn != 'function'853 || (typeof fn == 'function' && fn(prop, self[prop], value))) {854 if (delete (self[prop]))855 self.length--;856 }857 }858 }859 if (typeof CSSStyleDeclaration != 'undefined'860 && style instanceof CSSStyleDeclaration && style.length > 0) {861 for ( var i = 0; i < style.length; i++) {862 var prop = style[i];863 rem(prop, style.getPropertyValue(prop));864 }865 } else if (style instanceof Evernote.ClipStyle && style.length > 0) {866 for ( var prop in style) {867 rem(prop, style[prop]);868 }869 }870};871Evernote.ClipStyle.prototype.removeStyleIgnoreValue = function(style) {872 this.removeStyle(style, function(prop, propValue, value) {873 return true;874 });875};876Evernote.ClipStyle.styleInArray = function(style, styleArray) {877 if (typeof style != 'string' || !(styleArray instanceof Array))878 return false;879 var i = -1;880 var style = style.toLowerCase();881 var styleType = ((i = style.indexOf("-")) > 0) ? style.substring(0, i)882 .toLowerCase() : style.toLowerCase();883 for ( var i = 0; i < styleArray.length; i++) {884 if (styleArray[i] == style || styleArray[i] == styleType)885 return true;886 }887 return false;888};889/**890 * Derives to smaller set of style attributes by comparing differences with891 * given style and makes sure that style attributes in matchSyle are preserved.892 * This is useful for removing style attributes that are present in the parent893 * node. In that case, the instance will contain combined style attributes, and894 * the first argument to this function will be combined style attributes of the895 * parent node. The second argument will contain matched style attributes. The896 * result will contain only attributes that are free of duplicates while897 * preserving uniqueness of the style represented by this instance.898 */899Evernote.ClipStyle.prototype.deriveStyle = function(style, matchStyle,900 keepArray) {901 this.removeStyle(style, function(prop, propValue, value) {902 if (keepArray instanceof Array903 && Evernote.ClipStyle.styleInArray(prop, keepArray))904 return false;905 return (typeof matchStyle[prop] == 'undefined' && propValue == value);906 });907};908Evernote.ClipStyle.prototype.setFilter = function(filter) {909 if (typeof filter == 'function') {910 this.filter = filter;911 } else if (filter == null) {912 this.filter = null;913 }914};915Evernote.ClipStyle.prototype.getFilter = function() {916 return this.filter;917};918Evernote.ClipStyle.prototype.mergeStyle = function(style, override) {919 if (style instanceof Evernote.ClipStyle && style.length == 0) {920 for ( var i in style) {921 if (typeof this.constructor.prototype[i] != 'undefined') {922 continue;923 }924 if (typeof this[i] == 'undefined' || override) {925 this[i] = style[i];926 }927 }928 }929};930Evernote.ClipStyle.prototype.clone = function() {931 var clone = new Evernote.ClipStyle();932 for ( var prop in this) {933 if (typeof this.constructor.prototype[prop] == 'undefined') {934 clone[prop] = this[prop];935 }936 }937 clone.length = this.length;938 return clone;939};940Evernote.ClipStyle.prototype.toString = function() {941 var str = "";942 if (this.length > 0) {943 for ( var i in this) {944 if (typeof this[i] != 'string'945 || typeof this.constructor.prototype[i] != 'undefined'946 || this[i].length == 0)947 continue;948 str += i + ":" + this[i] + ";";949 }950 }951 return str;952};953Evernote.ClipStyle.getNodeStyle = function(node, computed, filter) {954 var style = new Evernote.ClipStyle();955 // Evernote.logger.debug(">>> NODE: " + node.nodeName + "/" + node.nodeType);956 if (node && typeof node.nodeType == 'number' && node.nodeType == 1) {957 var doc = node.ownerDocument;958 var view = null;959 try {960 view = (doc.defaultView) ? doc.defaultView : window;961 } catch (e) {962 Evernote.logger963 .debug("Could not obtain default view... using default window");964 view = window;965 }966 if (computed) {967 if (typeof view.getComputedStyle == 'function') {968 style = new Evernote.ClipStyle(view.getComputedStyle(node, null),969 filter);970 } else if (typeof node.currentStyle == 'object'971 && node.currentStyle != null) {972 style = new Evernote.ClipStyle(node.currentStyle, filter);973 }974 } else if (typeof view.getMatchedCSSRules == 'function') {975 // Evernote.logger.debug(">>> Getting matched rules");976 style = new Evernote.ClipStyle(view.getMatchedCSSRules(node), filter);977 } else {978 try {979 if (typeof CSSStyleDeclaration != 'undefined'980 && node.style instanceof CSSStyleDeclaration981 && node.style.length > 0) {982 style = new Evernote.ClipStyle(node.style, filter);983 }984 } catch (e) {985 // Evernote.logger.debug("Could not retrieve node style: " + e);986 }987 }988 }989 // Evernote.logger.debug(">>> " + node.nodeName + " style: " +990 // style.toString());991 return style;992};993/** ************** SelectionFinder *************** */994/**995 * SelectionFinder provides mechanism for finding selection on the page via996 * find(). It is able to traverse frames in order to find a selection. It will997 * report whether there's a selection via hasSelection(). After doing find(),998 * the selection is stored in the selection property, and the document property999 * will contain the document in which the selection was found. Find method will1000 * only recurse documents if it was invoked as find(true), specifying to do1001 * recursive search. You can use reset() to undo find().1002 */1003Evernote.SelectionFinder = function(document) {1004 this.initDocument = document;1005 this.document = document;1006};1007Evernote.SelectionFinder.prototype.initDocument = null;1008Evernote.SelectionFinder.prototype.document = null;1009Evernote.SelectionFinder.prototype.selection = null;1010Evernote.SelectionFinder.prototype.findNestedDocuments = function(doc) {1011 var documents = new Array();1012 var frames = null;1013 var iframes = null;1014 try {1015 frames = doc.getElementsByTagName("frame");1016 } catch (e) {1017 Evernote.logger.debug("Could not get all the frames in the document");1018 }1019 if (frames.length > 0) {1020 for ( var i = 0; i < frames.length; i++) {1021 documents.push(frames[i].contentDocument);1022 }1023 }1024 try {1025 iframes = doc.getElementsByTagName("iframe");1026 } catch (e) {1027 Evernote.logger.debug("Could not get all iframes in document");1028 }1029 try {1030 if (iframes.length > 0) {1031 for ( var i = 0; i < iframes.length; i++) {1032 var docz = iframes[i].contentDocument;1033 if (docz) {1034 documents.push(docz);1035 }1036 }1037 }1038 } catch (e) {1039 }1040 return documents;1041};1042Evernote.SelectionFinder.prototype.reset = function() {1043 this.document = this.initDocument;1044 this.selection = null;1045};1046Evernote.SelectionFinder.prototype.hasSelection = function() {1047 if (Evernote.Clip.constants.isIE) {1048 return (this.selection && this.selection.htmlText && this.selection.htmlText.length > 0);1049 }1050 var range = this.getRange();1051 if (range1052 && (range.startContainer != range.endContainer || (range.startContainer == range.endContainer && range.startOffset != range.endOffset))) {1053 return true;1054 }1055 return false;1056};1057Evernote.SelectionFinder.prototype.find = function(deep) {1058 var sel = this._findSelectionInDocument(this.document, deep);1059 this.document = sel.document;1060 this.selection = sel.selection;1061};1062Evernote.SelectionFinder.prototype.getRange = function() {1063 if (!this.selection || this.selection.rangeCount == 0) {1064 return null;1065 }1066 if (typeof this.selection.getRangeAt == 'function') {1067 return this.selection.getRangeAt(0);1068 } else {1069 var range = this.document.createRange();1070 range.setStart(this.selection.anchorNode, this.selection.anchorOffset);1071 range.setEnd(this.selection.focusNode, this.selection.focusOffset);1072 return range;1073 }1074 return null;1075};1076Evernote.SelectionFinder.prototype._findSelectionInDocument = function(doc,1077 deep) {1078 var sel = null;1079 var hasSelection = false;1080 var win = null;1081 try {1082 win = (doc.defaultView) ? doc.defaultView : window;1083 } catch (e) {1084 Evernote.logger1085 .debug("Could not retrieve default view... using default window");1086 win = window;1087 }1088 if (typeof win.getSelection == 'function') {1089 sel = win.getSelection();1090 if (sel && typeof sel.rangeCount != 'undefined' && sel.rangeCount > 0) {1091 hasSelection = true;1092 }1093 } else if (win.selection && typeof win.selection.createRange == 'function') {1094 sel = win.selection.createRange();1095 if (typeof win.selection.type == 'Text' && typeof sel.htmlText == 'string'1096 && sel.htmlText.length > 0) {1097 hasSelection = true;1098 }1099 } else if (doc.selection && doc.selection.createRange) {1100 sel = doc.selection.createRange();1101 if (typeof doc.selection.type == 'Text' && typeof sel.htmlText == 'string'1102 && sel.htmlText.length > 0) {1103 hasSelection = true;1104 }1105 }1106 if (sel && !hasSelection && deep) {1107 Evernote.logger.debug("Empty range, trying frames");1108 var nestedDocs = this.findNestedDocuments(doc);1109 Evernote.logger.debug("# of nested docs: " + nestedDocs.length);1110 if (nestedDocs.length > 0) {1111 for ( var i = 0; i < nestedDocs.length; i++) {1112 if (nestedDocs[i]) {1113 Evernote.logger.debug("Trying nested doc: " + nestedDocs[i]);1114 var framedSel = this._findSelectionInDocument(nestedDocs[i], deep);1115 if (framedSel && framedSel.selection1116 && framedSel.selection.rangeCount > 0) {1117 return framedSel;1118 }1119 }1120 }1121 }1122 }1123 return {1124 document : doc,1125 selection : sel1126 };1127};1128/** ************** ClipStylingStrategy *************** */1129Evernote.ClipStylingStrategy = function(window) {1130 this.initialize(window);1131};1132Evernote.ClipStylingStrategy.prototype._verboseLog = false;1133Evernote.ClipStylingStrategy.prototype.initialize = function(window) {1134 this.window = window;1135};1136Evernote.ClipStylingStrategy.prototype.styleForNode = function(node, parentNode) {1137 return null;1138};1139Evernote.ClipStylingStrategy.prototype.getNodeStyle = function(node, computed,1140 filter) {1141 return Evernote.ClipStyle.getNodeStyle(node, computed, filter);1142};1143Evernote.ClipTextStylingStrategy = function(window) {1144 this.initialize(window);1145};1146Evernote1147 .inherit(Evernote.ClipTextStylingStrategy, Evernote.ClipStylingStrategy);1148Evernote.ClipTextStylingStrategy.FORMAT_NODE_NAMES = {1149 "b" : null,1150 "big" : null,1151 "em" : null,1152 "i" : null,1153 "small" : null,1154 "strong" : null,1155 "sub" : null,1156 "sup" : null,1157 "ins" : null,1158 "del" : null,1159 "s" : null,1160 "strike" : null,1161 "u" : null,1162 "code" : null,1163 "kbd" : null,1164 "samp" : null,1165 "tt" : null,1166 "var" : null,1167 "pre" : null,1168 "listing" : null,1169 "plaintext" : null,1170 "xmp" : null,1171 "abbr" : null,1172 "acronym" : null,1173 "address" : null,1174 "bdo" : null,1175 "blockquote" : null,1176 "q" : null,1177 "cite" : null,1178 "dfn" : null1179};1180Evernote.ClipTextStylingStrategy.STYLE_ATTRS = {1181 "font" : null,1182 "text" : null,1183 "color" : null1184};1185Evernote.ClipTextStylingStrategy.prototype.isFormatNode = function(node) {1186 return (node && node.nodeType == 1 && typeof Evernote.ClipTextStylingStrategy.FORMAT_NODE_NAMES[node.nodeName1187 .toLowerCase()] != 'undefined');1188};1189Evernote.ClipTextStylingStrategy.prototype.hasTextNodes = function(node) {1190 if (node && node.nodeType == 1 && node.childNodes.length > 0) {1191 for ( var i = 0; i < node.childNodes.length; i++) {1192 if (node.childNodes[i].nodeType == 3) {1193 if (this._verboseLog) {1194 Evernote.logger.debug("Node " + node.nodeName + " has text nodes");1195 }1196 return true;1197 }1198 }1199 }1200 return false;1201};1202Evernote.ClipTextStylingStrategy.prototype.styleFilter = function(style) {1203 var s = Evernote.ClipStyle.stylePrefix(style.toLowerCase());1204 if (typeof Evernote.ClipTextStylingStrategy.STYLE_ATTRS[s] != 'undefined') {1205 return true;1206 } else if (this._verboseLog) {1207 Evernote.logger.debug("Filter excluding: " + style);1208 }1209};1210Evernote.ClipTextStylingStrategy.prototype.styleForNode = function(node,1211 parentNode) {1212 var nodeStyle = null;1213 if (this.isFormatNode(node) || this.hasTextNodes(node)) {1214 nodeStyle = this.getNodeStyle(node, true, this.styleFilter);1215 }1216 return nodeStyle;1217};1218Evernote.ClipFullStylingStrategy = function(window) {1219 this.initialize(window);1220};1221Evernote1222 .inherit(Evernote.ClipFullStylingStrategy, Evernote.ClipStylingStrategy);1223Evernote.ClipFullStylingStrategy.ALWAYS_KEEP = {1224 "*" : [ "font", "text", "color", "margin", "padding" ],1225 "img" : [ "width", "height", "border" ],1226 "li" : [ "list", "margin", "padding" ],1227 "ul" : [ "list", "margin", "padding" ],1228 "dl" : [ "margin", "padding" ],1229 "dt" : [ "margin", "padding" ],1230 "h1" : [ "margin", "padding" ],1231 "h2" : [ "margin", "padding" ],1232 "h3" : [ "margin", "padding" ],1233 "h4" : [ "margin", "padding" ],1234 "h5" : [ "margin", "padding" ],1235 "h6" : [ "margin", "padding" ],1236 "h7" : [ "margin", "padding" ],1237 "h8" : [ "margin", "padding" ],1238 "h9" : [ "margin", "padding" ],1239 "form" : [ "height", "width", "margin", "padding" ]1240};1241Evernote.ClipFullStylingStrategy.prototype.styleForNode = function(node,1242 parentNode) {1243 var nodeStyle = null;1244 if (node && node.nodeType == 1) {1245 nodeStyle = this.getNodeStyle(node, true);1246 if (parentNode) {1247 if (this._verboseLog)1248 Evernote.logger.debug("Deriving style...");1249 var nodeMatchedStyle = this.getNodeStyle(node, false);1250 var parentStyle = this.getNodeStyle(parentNode, true);1251 var keepers = (typeof Evernote.ClipFullStylingStrategy.ALWAYS_KEEP[node.nodeName1252 .toLowerCase()] != 'undefined') ? Evernote.ClipFullStylingStrategy.ALWAYS_KEEP[node.nodeName1253 .toLowerCase()]1254 : Evernote.ClipFullStylingStrategy.ALWAYS_KEEP["*"];1255 nodeStyle.deriveStyle(parentStyle, nodeMatchedStyle, keepers);1256 }1257 }1258 return nodeStyle;1259};1260/** ************** Evernote.CSSSelector *************** */1261Evernote.CSSSelector = function(selectorText) {1262 this.initialize(selectorText);1263};1264Evernote.CSSSelector.P_TAGNAME = 1;1265Evernote.CSSSelector.P_TAGTYPE = 2;1266Evernote.CSSSelector.P_ID = 3;1267Evernote.CSSSelector.P_CLASS = 4;1268Evernote.CSSSelector.P_START_ATTR = 5;1269Evernote.CSSSelector.P_ATTR_KVSEP = 6;1270Evernote.CSSSelector.P_END_ATTR = 7;1271Evernote.CSSSelector.P_MODIFIER = 8;1272Evernote.CSSSelector.fromString = function(str) {1273 return new Evernote.CSSSelector(str);1274};1275Evernote.CSSSelector.fromElement = function(element) {1276 var s = new Evernote.CSSSelector();1277 if (typeof element.nodeName == 'string')1278 s.tagName = element.nodeName.toLowerCase();1279 try {1280 var attrs = element.attributes;1281 for ( var i = 0; i < attrs.length; i++) {1282 var attr = attrs[i];1283 var attrName = attr.name.toLowerCase();1284 if (attrName == "id" && attr.value) {1285 s.id = attr.value;1286 } else if (attrName == "class" && attr.value) {1287 s.classes = attr.value.replace(/\s+/, " ").split(" ");1288 } else if (s.attributes instanceof Array) {1289 s.attributes.push( {1290 name : attrName,1291 value : attr.value1292 });1293 } else {1294 s.attributes = [ {1295 name : attrName,1296 value : attr.value1297 } ];1298 }1299 }1300 } catch (e) {1301 }1302 return s;1303};1304Evernote.CSSSelector.prototype.tagName = null;1305Evernote.CSSSelector.prototype.tagType = null;1306Evernote.CSSSelector.prototype.id = null;1307Evernote.CSSSelector.prototype.classes = null;1308Evernote.CSSSelector.prototype.attributes = null;1309Evernote.CSSSelector.prototype.modifier = null;1310Evernote.CSSSelector.prototype.initialize = function(selectorText) {1311 if (typeof selectorText == 'string')1312 this.parse(selectorText);1313};1314Evernote.CSSSelector.prototype.reset = function() {1315 this.tagName = null;1316 this.tagType = null;1317 this.id = null;1318 this.classes = null;1319 this.attributes = null;1320 this.modifier = null;1321};1322Evernote.CSSSelector.prototype.parse = function(str) {1323 var i = 0;1324 var cur = Evernote.CSSSelector.P_TAGNAME;1325 str = Evernote.trim(str);1326 this.reset();1327 while (i < str.length) {1328 var c = str.charAt(i);1329 if (c == ":") {1330 cur = (i == 0) ? Evernote.CSSSelector.P_TAGTYPE1331 : Evernote.CSSSelector.P_MODIFIER;1332 } else if (c == "#") {1333 cur = Evernote.CSSSelector.P_ID;1334 } else if (c == ".") {1335 cur = Evernote.CSSSelector.P_CLASS;1336 if (!this.classes) {1337 this.classes = new Array();1338 }1339 this.classes.push("");1340 } else if (c == "[") {1341 cur = Evernote.CSSSelector.P_START_ATTR;1342 if (!this.attributes)1343 this.attributes = new Array();1344 this.attributes.push( {1345 name : "",1346 value : null1347 });1348 } else if (c == "=" && cur == Evernote.CSSSelector.P_START_ATTR) {1349 cur = Evernote.CSSSelector.P_ATTR_KVSEP;1350 } else if (c == "]") {1351 cur = Evernote.CSSSelector.P_END_ATTR;1352 } else {1353 if (cur == Evernote.CSSSelector.P_TAGTYPE) {1354 this.tagType = (this.tagType) ? this.tagType + c : c;1355 } else if (cur == Evernote.CSSSelector.P_TAGNAME && c != "*") {1356 this.tagName = (this.tagName) ? this.tagName + c.toLowerCase() : c1357 .toLowerCase();1358 } else if (cur == Evernote.CSSSelector.P_ID) {1359 this.id = (this.id) ? this.id + c : c;1360 } else if (cur == Evernote.CSSSelector.P_CLASS) {1361 this.classes[this.classes.length - 1] += c;1362 } else if (cur == Evernote.CSSSelector.P_START_ATTR) {1363 var last = this.attributes[this.attributes.length - 1];1364 last["name"] += c.toLowerCase();1365 } else if (cur == Evernote.CSSSelector.P_ATTR_KVSEP) {1366 var last = this.attributes[this.attributes.length - 1];1367 last["value"] = (last["value"]) ? last["value"] + c : c;1368 } else if (cur == Evernote.CSSSelector.P_MODIFIER) {1369 this.modifier = (this.modifier) ? this.modifier + c : c;1370 }1371 }1372 i += 1;1373 }1374 this.update();1375};1376Evernote.CSSSelector.prototype.update = function() {1377 // clean up1378 if (this.classes) {1379 Evernote.cleanArray(this.classes, function(val) {1380 return (typeof val != 'string' || Evernote.trim(val).length == 0);1381 });1382 if (this.classes.length == 0) {1383 this.classes = null;1384 } else {1385 this.classes.sort();1386 }1387 }1388 if (this.attributes) {1389 Evernote1390 .cleanArray(this.attributes,1391 function(val) {1392 return (typeof val["name"] != 'string' || Evernote1393 .trim(val["name"]).length == 0);1394 });1395 if (this.attributes.length == 0) {1396 this.attributes = null;1397 } else {1398 this.attributes.sort(function(a, b) {1399 return a.name > b.name;1400 });1401 }1402 }1403};1404Evernote.CSSSelector.prototype.getAttributeMap = function() {1405 var attrs = {};1406 if (this.attributes) {1407 for ( var i = 0; i < this.attributes.length; i++) {1408 attrs[this.attributes[i].name] = this.attributes[i].value;1409 }1410 }1411 return attrs;1412};1413Evernote.CSSSelector.prototype.appliesTo = function(cssSelectorOrElement) {1414 var o = null;1415 if (cssSelectorOrElement instanceof Evernote.CSSSelector) {1416 o = cssSelectorOrElement;1417 } else if (typeof cssSelectorOrElement == 'string') {1418 o = Evernote.CSSSelector.fromString(cssSelectorOrElement);1419 } else if (typeof cssSelectorOrElement == 'object'1420 && cssSelectorOrElement != null1421 && typeof cssSelectorOrElement.nodeName == 'string') {1422 o = Evernote.CSSSelector.fromElement(cssSelectorOrElement);1423 } else {1424 o = new Evernote.CSSSelector();1425 }1426 if (this.tagName && this.tagName != o.tagName)1427 return false;1428 if (this.tagType != o.tagType)1429 return false;1430 if (this.id && (this.id != o.id)) {1431 return false;1432 }1433 if (this.classes && o.classes) {1434 for ( var i = 0; i < this.classes.length; i++) {1435 if (o.classes.indexOf(this.classes[i]) < 0)1436 return false;1437 }1438 } else if (this.classes && !o.classes) {1439 return false;1440 }1441 if (this.attributes && o.attributes) {1442 var oAttrs = o.getAttributeMap();1443 for ( var i = 0; i < this.attributes.length; i++) {1444 if (typeof oAttrs[this.attributes[i].name] == 'undefined') {1445 return false;1446 }1447 }1448 } else if (this.attributes && !o.attributes) {1449 return false;1450 }1451 if (this.modifier && this.modifier != o.modifier) {1452 return false;1453 }1454 return true;1455};1456Evernote.CSSSelector.prototype.toString = function() {1457 var str = "";1458 if (this.tagType) {1459 str += ":" + this.tagType;1460 } else if (this.tagName) {1461 str += this.tagName;1462 }1463 if (this.id) {1464 str += "#" + this.id;1465 }1466 if (this.classes && this.classes.length > 0) {1467 str += "." + this.classes.join(".");1468 }1469 if (this.attributes && this.attributes.length > 0) {1470 for ( var i = 0; i < this.attributes.length; i++) {1471 str += "[" + this.attributes[i].name + "=" + this.attributes[i].value1472 + "]";1473 }1474 }1475 if (this.modifier) {1476 str += ":" + this.modifier;1477 }1478 return str;1479};1480/** ************** AJAX Support *************** */1481Evernote.Ajax = {1482 options : {1483 async : true,1484 type : "GET",1485 data : null,1486 success : null,1487 error : null,1488 context : null,1489 complete : null,1490 timeout : 100001491 },1492 getXhr : function() {1493 if (window.XMLHttpRequest1494 && (window.location.protocol !== "file:" || !window.ActiveXObject)) {1495 return new window.XMLHttpRequest();1496 } else {1497 try {1498 return new window.ActiveXObject("Microsoft.XMLHTTP");1499 } catch (e) {1500 }1501 }1502 return null;1503 },1504 doRequest : function(options) {1505 var opts = Evernote.extend(true, {}, this.options,1506 ((typeof options == 'object' && options != null) ? options : {}));1507 var xhr = this.getXhr();1508 xhr.open(opts.type, opts.url, opts.async);1509 opts.context = (opts.context) ? opts.context : this;1510 var success = function(data, statusText, xhr) {1511 if (typeof opts.success == 'function') {1512 opts.success.apply(opts.context, [ data, statusText, xhr ]);1513 }1514 };1515 var error = function(xhr, statusText, error) {1516 if (typeof opts.error == 'function') {1517 opts.error.apply(opts.context, [ xhr, statusText, error ]);1518 }1519 };1520 var complete = (typeof opts.complete == 'function') ? opts.complete1521 : function(xhr, textStatus) {1522 if (xhr.status == 200)1523 success(xhr.responseText, textStatus, xhr);1524 else1525 error(xhr, textStatus, null);1526 };1527 if (opts.async) {1528 // bind listener1529 xhr.onreadystatechange = function() {1530 if (xhr.readyState == 4) {1531 complete(xhr, xhr.statusText);1532 }1533 };1534 }1535 if (opts.timeout) {1536 setTimeout(function() {1537 if (xhr && xhr.readyState < 4) {1538 xhr.abort();1539 error(xhr, xhr.statusText, 'timeout');1540 }1541 }, opts.timeout);1542 }1543 if (!opts.async) {1544 try {1545 xhr.send(opts.data);1546 complete(xhr, xhr.statusText);1547 } catch (e) {1548 error(xhr, xhr.statusText, e);1549 }1550 } else {1551 try {1552 xhr.send(opts.data);1553 } catch (e) {1554 error(xhr, xhr.statusText, e);1555 }1556 }1557 },1558 get : function(options) {1559 var opts = (typeof options == 'object' && options != null) ? options : {};1560 opts.type = "GET";1561 this.doRequest(options);1562 }1563};1564/** ************** Utility Methods *************** */1565Evernote.CLIP_OPTIONS = {1566 // URL that will be associated with the clip (will be assigned to the1567 // sourceURL attribute of the note)1568 url : null,1569 // Title for the clip1570 title : null,1571 // signature (HTML or DOM Element) that will be appended to the note,1572 // separated by horizontal rule1573 signature : null,1574 // header (HTML or DOM Element) that will be prepended to the content1575 header : null,1576 // footer (HTML or DOM Element) that will be appended to the content1577 footer : null,1578 // content (HTML or DOM Element) that will be the content of the clip1579 content : null,1580 // id of the DOM Element whose contents will become the content of the clip1581 contentId : null,1582 // URL from which to retrieve content to be clipped1583 contentUrl : null,1584 // optional function used to filter which DOM elements get included when1585 // serializing DOM. This function will be passed a single argument - the DOM1586 // element, and if the function return a truthful result - the passed DOM1587 // element will be serialized, otherwise it will be skipped.1588 filter : null,1589 // comma-separated list of tag names1590 suggestTags : null,1591 // notebook name1592 suggestNotebook : null,1593 // friendly name for the content provider (defaults to source URL)1594 providerName : null,1595 // partner code1596 code : null,1597 // latitude and longitude coordinates (optional, and if specified, should be1598 // floats)1599 latitude : null,1600 longitude : null,1601 // DOM styling strategy (accepts 'none', 'text', 'full' or actual implementing1602 // Function)1603 styling : Evernote.ClipTextStylingStrategy1604};1605Evernote.CLIP_WINDOW_ATTRIBUTES = {1606 windowUrl : "",1607 windowName : "evernoteClipWindow",1608 windowOptions : "width=500,height=480,scrollbars=yes,resizable=yes"1609};1610Evernote.CLIP_FORM_ATTRIBUTES = {1611 action : Evernote.Config.getClipUrl(),1612 method : "post",1613 enctype : "multipart/form-data",1614 encoding : "multipart/form-data", // cuz IE is special1615 "accept-charset" : "UTF-8",1616 id : "evernoteClipForm",1617 target : Evernote.CLIP_WINDOW_ATTRIBUTES.windowName1618};1619Evernote.extend = function() {1620 var args = arguments;1621 var recurse = false;1622 var initialIndex = 0;1623 if (typeof args[0] == 'boolean') {1624 recurse = args[0];1625 initialIndex = 1;1626 }1627 var rootObj = args[initialIndex];1628 for ( var i = (initialIndex + 1); i < args.length; i++) {1629 if (typeof args[i] == 'object' && args[i] != null) {1630 for ( var j in args[i]) {1631 if (typeof args[i][j] == 'object' && args[i][j] != null && recurse) {1632 Evernote.extend(true, (typeof rootObj[j] != 'undefined') ? rootObj[j]1633 : {}, args[i][j]);1634 } else {1635 rootObj[j] = args[i][j];1636 }1637 }1638 }1639 }1640 return rootObj;1641};1642Evernote.trim = function(str) {1643 if (typeof str == 'string') {1644 return str.replace(/^[\s\t]+/, "").replace(/[\s\t]+$/, "");1645 }1646 return str;1647};1648Evernote.cleanString = function(str) {1649 if (typeof str == 'string') {1650 return Evernote.trim(str);1651 }1652 return "";1653};1654Evernote.concatArrays = function() {1655 if (arguments.length <= 1) {1656 return arguments[0];1657 }1658 var args = new Array();1659 for ( var i = 0; i < arguments.length; i++) {1660 args.push(arguments[i]);1661 }1662 if (typeof Array.prototype.concat == 'function') {1663 return args[0].concat.apply(args[0], args.slice(1));1664 } else {1665 for ( var i = 1; i < args.length; i++) {1666 var a = args[i];1667 for ( var ii = 0; ii < a.length; ii++) {1668 args[0].push(a[ii]);1669 }1670 }1671 return args[0];1672 }1673};1674Evernote.createClipForm = function(clip, options) {1675 var opts = Evernote.extend( {}, Evernote.CLIP_OPTIONS,1676 (typeof options == 'object' && options != null) ? options : {});1677 var form = document.createElement("form");1678 for ( var a in Evernote.CLIP_FORM_ATTRIBUTES) {1679 if (typeof Evernote.CLIP_FORM_ATTRIBUTES[a] == 'function') {1680 form.setAttribute(a, Evernote.CLIP_FORM_ATTRIBUTES[a]());1681 } else if (Evernote.CLIP_FORM_ATTRIBUTES[a] != null) {1682 form.setAttribute(a, Evernote.CLIP_FORM_ATTRIBUTES[a]);1683 }1684 }1685 form.style.display = "none";1686 var url = (opts['url']) ? opts['url'] : clip.location.href;1687 if (!url)1688 url = document.location.href;1689 var title = (opts['title']) ? opts['title'] : clip.title;1690 if (!title)1691 title = document.title;1692 var formData = {1693 title : Evernote.cleanString(title),1694 htmlTitle: Evernote.Clip.unicodeEntities(Evernote.cleanString(title)),1695 url : Evernote.cleanString(url),1696 suggestTags : Evernote.cleanString(opts['suggestTags']),1697 suggestNotebook : Evernote.cleanString(opts['suggestNotebook']),1698 code : Evernote.cleanString(opts['code']),1699 providerName : Evernote.cleanString(opts['providerName'])1700 };1701 // since IE doesn't deal properly with accept-charset,1702 // we encode unicode chars in all of the relevant form data using html entities,1703 // and inform the server about changed charset1704 if (Evernote.Clip.constants.isIE) {1705 var encAttrs = ["title", "suggestTags", "suggestNotebook", "providerName"];1706 for (var i=0; i<encAttrs.length; i++) {1707 formData[encAttrs[i]] = Evernote.Clip.unicodeEntities(formData[encAttrs[i]]);1708 }1709 formData["charset"] = "htmlentities";1710 }1711 var lat = parseFloat(opts.latitude);1712 var lon = parseFloat(opts.longitude);1713 if (typeof lat == 'number' && !isNaN(lat) && lat >= -90 && lat <= 901714 && typeof lon == 'number' && !isNaN(lon) && lon >= -180 && lon <= 180) {1715 formData["latitude"] = lat;1716 formData["longitude"] = lon;1717 }1718 if (clip && clip instanceof Evernote.Clip) {1719 formData.content = clip.content;1720 }1721 for ( var i in formData) {1722 var e = document.createElement("input");1723 e.setAttribute("type", "hidden");1724 e.setAttribute("name", i);1725 e.value = formData[i];1726 Evernote.logger.debug(e);1727 form.appendChild(e);1728 }1729 return form;1730};1731Evernote.createClip = function(options) {1732 var opts = Evernote.extend( {}, Evernote.CLIP_OPTIONS,1733 (typeof options == 'object' && options != null) ? options : {});1734 if (typeof opts.styling == 'string') {1735 switch (opts.styling.toLowerCase()) {1736 case "none":1737 opts.styling = null;1738 break;1739 case "text":1740 opts.styling = Evernote.ClipTextStylingStrategy;1741 break;1742 case "full":1743 opts.styling = Evernote.ClipFullStylingStrategy;1744 break;1745 default:1746 opts.styling = Evernote.ClipTextStylingStrategy;1747 }1748 }1749 var clip = new Evernote.Clip(window, opts.styling);1750 if (typeof opts.filter == 'function') {1751 clip.nodeFilter = opts.filter;1752 } else if (typeof opts.filter == 'string') {1753 try {1754 var _noteit_temp_F = undefined;1755 eval("var _noteit_temp_F = " + opts.filter);1756 if (typeof _noteit_temp_F == 'function') {1757 clip.nodeFilter = _noteit_temp_F;1758 }1759 } catch (e) {1760 }1761 }1762 var contentElement = null;1763 if (typeof opts.content == 'string') {1764 clip.content = opts.content;1765 } else if (Evernote.Clip.isHtmlElement(opts.content)) {1766 clip.clipElement(opts.content);1767 } else if (typeof opts.contentId == 'string'1768 && (contentElement = window.document.getElementById(opts.contentId))) {1769 clip.clipElement(contentElement);1770 } else if (typeof opts.contentUrl == 'string') {1771 Evernote.Ajax.get( {1772 url : opts.contentUrl,1773 async : false,1774 success : function(data, status, xhr) {1775 clip.content = data;1776 },1777 error : function(xhr, status, error) {1778 alert("Error retrieving clip content!");1779 clip.content = "";1780 }1781 });1782 } else {1783 // no content was specified - use BODY tag and if that cannot be found for1784 // some reason, just make a link-only note1785 contentElement = document.getElementsByTagName("BODY")[0];1786 if (contentElement) {1787 clip.clipElement(contentElement);1788 } else {1789 // something went terribly wrong and we don't know what to clip1790 clip.clipLink(opts.url, opts.title);1791 }1792 }1793 // custom signature1794 if (opts.signature) {1795 if (typeof opts.signature == 'string') {1796 clip.content += "<hr/>" + opts.signature;1797 } else if (Evernote.Clip.isHtmlElement(opts.signature)) {1798 var signatureClip = new Evernote.Clip(window, opts.styling);1799 signatureClip.clipElement(opts.signature);1800 if (signatureClip.content) {1801 clip.content += "<hr/>" + signatureClip.content;1802 }1803 }1804 }1805 // custom header1806 if (opts.header) {1807 if (typeof opts.header == 'string') {1808 clip.content = opts.header + clip.content;1809 } else if (Evernote.Clip.isHtmlElement(opts.header)) {1810 var headerClip = new Evernote.Clip(window, opts.styling);1811 headerClip.clipElement(opts.header);1812 if (headerClip.content) {1813 clip.content = headerClip.content + clip.content;1814 }1815 }1816 }1817 // custom footer1818 if (opts.footer) {1819 if (typeof opts.header == 'string') {1820 clip.content += opts.footer;1821 } else if (Evernote.Clip.isHtmlElement(opts.footer)) {1822 var footerClip = new Evernote.Clip(window, opts.styling);1823 footerClip.clipElement(opts.footer);1824 if (footerClip.content) {1825 clip.content += footerClip.content;1826 }1827 }1828 }1829 return clip;1830};1831Evernote.doClip = function(options) {1832 var opts = (typeof options == 'object' && options != null) ? options : {};1833 if (typeof opts.content == 'undefined'1834 && typeof opts.contentId == 'undefined'1835 && typeof opts.contentUrl == 'undefined') {1836 if (typeof opts.filter != 'function') {1837 opts.filter = function(el) {1838 // try not to clip the element that got clicked to make a clip in the1839 // first place1840 if (typeof event == 'object' && event != null && event.target1841 && el == event.target) {1842 return false;1843 }1844 // skip any markers we know of1845 for ( var i = 0; i < Evernote.Clip.filterMarkers.length; i++) {1846 if (Evernote.containsElementId(el, Evernote.Clip.filterMarkers[i])1847 || Evernote.containsElementClass(el,1848 Evernote.Clip.filterMarkers[i])) {1849 return false;1850 }1851 }1852 return true;1853 };1854 }1855 var classMarkedElements = [];1856 opts.content = (typeof event == 'object' && event != null && event.target) ? Evernote1857 .findParent(event.target, function(el) {1858 if (!Evernote.isHtmlElement(el)) {1859 return false;1860 }1861 for ( var i = 0; i < Evernote.Clip.contentMarkers.length; i++) {1862 if (Evernote.isElementVisible(el) && opts.filter(el)) {1863 if (Evernote.containsElementClass(el,1864 Evernote.Clip.contentMarkers[i])) {1865 classMarkedElements.push(el);1866 }1867 if (Evernote.containsElementId(el,1868 Evernote.Clip.contentMarkers[i])1869 || Evernote.hasElementClass(el,1870 Evernote.Clip.contentMarkers[i])) {1871 opts.styling = 'full';1872 return true;1873 }1874 }1875 }1876 return false;1877 })1878 : document.getElementsByTagName("BODY")[0];1879 if (!opts.content && classMarkedElements.length > 0) {1880 opts.content = classMarkedElements[classMarkedElements.length - 1];1881 } else if (classMarkedElements.length > 0) {1882 var topClassMarkedElement = classMarkedElements[classMarkedElements.length - 1];1883 var topClassMarkedClassNames = Evernote1884 .getElementClassNames(topClassMarkedElement);1885 var classMarkedChildren = Evernote.findChildren(opts.content,1886 function(el) {1887 for ( var i = 0; i < topClassMarkedClassNames.length; i++) {1888 if (Evernote.hasElementClass(el, topClassMarkedClassNames[i]))1889 return true;1890 }1891 return false;1892 }, true);1893 if (classMarkedChildren.length > 1) {1894 opts.content = topClassMarkedElement;1895 }1896 }1897 }1898 var clip = Evernote.createClip(opts);1899 var oldForm = document.getElementById(Evernote.CLIP_FORM_ATTRIBUTES.id);1900 if (oldForm) {1901 oldForm.parentNode.removeChild(oldForm);1902 }1903 var form = Evernote.createClipForm(clip, opts);1904 var body = document.getElementsByTagName("body")[0];1905 var postWindow = window.open(Evernote.CLIP_WINDOW_ATTRIBUTES.windowUrl,1906 Evernote.CLIP_WINDOW_ATTRIBUTES.windowName,1907 Evernote.CLIP_WINDOW_ATTRIBUTES.windowOptions);1908 if (body) {1909 var oldForm = document.getElementById(Evernote.CLIP_FORM_ATTRIBUTES["id"]);1910 if (typeof oldForm == 'object' && oldForm != null1911 && typeof oldForm.parentNode == 'object'1912 && typeof oldForm.parentNode != null) {1913 oldForm.parentNode.removeChild(oldForm);1914 }1915 body.appendChild(form);1916 form.submit();1917 try {1918 postWindow.window.focus();1919 } catch (e) {1920 }1921 }...
web.js
Source:web.js
...18 this.curWebFrames = [];19 logger.debug('Leaving web frame and going back to default content');20 return;21 }22 if (helpers.hasElementId(frame)) {23 let atomsElement = this.useAtomsElement(helpers.getElementId(frame));24 let value = await this.executeAtom('get_frame_window', [atomsElement]);25 logger.debug(`Entering new web frame: '${value.WINDOW}'`);26 this.curWebFrames.unshift(value.WINDOW);27 } else {28 atom = _.isNumber(frame) ? 'frame_by_index' : 'frame_by_id_or_name';29 let value = await this.executeAtom(atom, [frame]);30 if (_.isNull(value) || _.isUndefined(value.WINDOW)) {31 throw new errors.NoSuchFrameError();32 }33 logger.debug(`Entering new web frame: '${value.WINDOW}'`);34 this.curWebFrames.unshift(value.WINDOW);35 }36};37commands.getCssProperty = async function getCssProperty (propertyName, el) {38 let atomsElement = this.useAtomsElement(el);39 return await this.executeAtom('get_value_of_css_property', [atomsElement, propertyName]);40};41commands.submit = async function submit (el) {42 if (this.isWebContext()) {43 let atomsElement = this.useAtomsElement(el);44 await this.executeAtom('submit', [atomsElement]);45 } else {46 throw new errors.NotImplementedError();47 }48};49commands.refresh = async function refresh () {50 if (this.isWebContext()) {51 await this.executeAtom('refresh', []);52 } else {53 throw new errors.NotImplementedError();54 }55};56commands.getUrl = async function getUrl () {57 if (!this.isWebContext()) {58 throw new errors.NotImplementedError();59 }60 let url = await this.remote.execute('window.location.href');61 return url;62};63commands.title = async function title () {64 if (!this.isWebContext()) {65 throw new errors.NotImplementedError();66 }67 return await this.executeAtom('title', [], true);68};69commands.getCookies = async function getCookies () {70 if (!this.isWebContext()) {71 throw new errors.NotImplementedError();72 }73 logger.debug('Retrieving all cookies');74 let script = 'return document.cookie';75 let jsCookies = await this.executeAtom('execute_script', [script, []]);76 let cookies = [];77 try {78 for (let [name, value] of _.toPairs(cookieUtils.createJWPCookie(undefined, jsCookies))) {79 cookies.push({name, value});80 }81 return cookies;82 } catch (err) {83 logger.error(err);84 throw new errors.UnknownError(`Error parsing cookies from result: '${jsCookies}'`);85 }86};87commands.setCookie = async function setCookie (cookie) {88 if (!this.isWebContext()) {89 throw new errors.NotImplementedError();90 }91 cookie = _.clone(cookie);92 // if `path` field is not specified, Safari will not update cookies as expected; eg issue #170893 if (!cookie.path) {94 cookie.path = '/';95 }96 const jsCookie = cookieUtils.createJSCookie(cookie.name, cookie.value, {97 expires: _.isNumber(cookie.expiry) ? (new Date(cookie.expiry * 1000)).toUTCString() :98 cookie.expiry,99 path: cookie.path,100 domain: cookie.domain,101 httpOnly: cookie.httpOnly,102 secure: cookie.secure103 });104 let script = `document.cookie = ${JSON.stringify(jsCookie)}`;105 await this.executeAtom('execute_script', [script, []]);106};107commands.deleteCookie = async function deleteCookie (cookieName) {108 if (!this.isWebContext()) {109 throw new errors.NotImplementedError();110 }111 // check cookie existence112 let cookies = await this.getCookies();113 if (_.indexOf(_.map(cookies, 'name'), cookieName) === -1) {114 logger.debug(`Cookie '${cookieName}' not found. Ignoring.`);115 return true;116 }117 return await this._deleteCookie(cookieName);118};119commands.deleteCookies = async function deleteCookies () {120 if (!this.isWebContext()) {121 throw new errors.NotImplementedError();122 }123 let cookies = await this.getCookies();124 if (cookies.length) {125 for (let cookie of cookies) {126 await this._deleteCookie(cookie.name);127 }128 }129 return true;130};131helpers._deleteCookie = async function _deleteCookie (cookieName) {132 logger.debug(`Deleting cookie '${cookieName}'`);133 let webCookie = cookieUtils.expireCookie(cookieName, {path: '/'});134 let script = `document.cookie = ${JSON.stringify(webCookie)}`;135 await this.executeAtom('execute_script', [script, []]);136};137extensions.findWebElementOrElements = async function findWebElementOrElements (strategy, selector, many, ctx) {138 let atomsElement = this.getAtomsElement(ctx);139 let element;140 let doFind = async () => {141 element = await this.executeAtom(`find_element${many ? 's' : ''}`, [strategy, selector, atomsElement]);142 return !_.isNull(element);143 };144 try {145 await this.implicitWaitForCondition(doFind);146 } catch (err) {147 if (err.message && _.isFunction(err.message.match) && err.message.match(/Condition unmet/)) {148 // condition was not met setting res to empty array149 element = [];150 } else {151 throw err;152 }153 }154 if (many) {155 return element;156 } else {157 if (!element || _.size(element) === 0) {158 throw new errors.NoSuchElementError();159 }160 return element;161 }162};163extensions.webFlickElement = async function webFlickElement (el, xoffset, yoffset) {164 let atomsElement = await this.useAtomsElement(el);165 let {x, y} = await this.executeAtom('get_top_left_coordinates', [atomsElement]);166 let {width, height} = await this.executeAtom('get_size', [atomsElement]);167 // translate to proper coordinates168 x = x + (width / 2);169 y = y + (height / 2);170 let from = await this.translateWebCoords({x, y});171 let to = await this.translateWebCoords({x: x + xoffset, y: y + yoffset});172 let args = {from, to};173 let command = `au.flick(${JSON.stringify(args)})`;174 await this.uiAutoClient.sendCommand(command);175};176extensions.mobileWebNav = async function mobileWebNav (navType) {177 this.remote.allowNavigationWithoutReload();178 await this.executeAtom('execute_script', [`history.${navType}();`, null]);179};180extensions.nativeWebTap = async function nativeWebTap (el) {181 let atomsElement = this.useAtomsElement(el);182 let {x, y} = await this.executeAtom('get_top_left_coordinates', [atomsElement]);183 let {width, height} = await this.executeAtom('get_size', [atomsElement]);184 x = x + (width / 2);185 y = y + (height / 2) + await this.getExtraNativeWebTapOffset();186 this.curWebCoords = {x, y};187 await this.clickWebCoords();188 // make sure real tap actually has time to register189 await B.delay(500);190};191extensions.getExtraNativeWebTapOffset = async function getExtraNativeWebTapOffset () { // eslint-disable-line require-await192 // this will be filled in by drivers using it193 return 0;194};195extensions.clickWebCoords = async function clickWebCoords () {196 let coords = await this.translateWebCoords(this.curWebCoords);197 await this.clickCoords(coords);198};199extensions.translateWebCoords = async function translateWebCoords (coords) {200 logger.debug(`Translating coordinates (${JSON.stringify(coords)}) to web coordinates`);201 let wvCmd = 'au.getElementsByType(\'webview\')';202 let webviewIndex = this.webContextIndex();203 // add static offset for safari in landscape mode204 let yOffset = this.opts.curOrientation === 'LANDSCAPE' ? this.landscapeWebCoordsOffset : 0;205 // absolutize web coords206 let webviews = await this.uiAutoClient.sendCommand(wvCmd);207 if (webviews.length < 1) {208 throw new errors.UnknownError.code('Could not find any webviews to click inside!');209 }210 if (_.isUndefined(webviews[webviewIndex])) {211 logger.warn(`Could not find webview at index ${webviewIndex}, taking ` +212 `last available one for clicking purposes`);213 webviewIndex = webviews.length - 1;214 }215 let wvId = helpers.getElementId(webviews[webviewIndex]);216 let locCmd = `au.getElement('${wvId}').rect()`;217 let rect = await this.uiAutoClient.sendCommand(locCmd);218 let wvPos = {x: rect.origin.x, y: rect.origin.y};219 let realDims = {w: rect.size.width, h: rect.size.height};220 let cmd = '(function () { return {w: document.width, h: document.height}; })()';221 let {w, h} = await this.remote.execute(cmd);222 let wvDims = {w, h};223 if (wvDims && realDims && wvPos) {224 let xRatio = realDims.w / wvDims.w;225 let yRatio = realDims.h / wvDims.h;226 let serviceBarHeight = 20;227 if (parseFloat(this.opts.platformVersion) >= 8) {228 // ios8 includes the service bar height in the app229 serviceBarHeight = 0;230 }231 let newCoords = {232 x: wvPos.x + Math.round(xRatio * coords.x),233 y: wvPos.y + yOffset + Math.round(yRatio * coords.y) - serviceBarHeight234 };235 logger.debug(`Converted web coords ${JSON.stringify(coords)} ` +236 `into real coords ${JSON.stringify(newCoords)}`);237 return newCoords;238 }239};240helpers.clickCoords = async function clickCoords (coords) {241 if (this.useRobot) {242 // var tapUrl = this.args.robotUrl + "/tap";243 // request.post({url:tapUrl, form: {x:coords.x, y:coords.y}}, cb);244 /*TODO*/throw new errors.NotYetImplementedError();245 } else {246 let opts = coords;247 opts.tapCount = 1;248 opts.duration = 0.3;249 opts.touchCount = 1;250 let command = `au.complexTap(${JSON.stringify(opts)})`;251 await this.uiAutoClient.sendCommand(command);252 }253};254helpers.executeAtom = async function executeAtom (atom, args, alwaysDefaultFrame = false) {255 let frames = alwaysDefaultFrame === true ? [] : this.curWebFrames;256 let promise = this.remote.executeAtom(atom, args, frames);257 return await this.waitForAtom(promise);258};259helpers.executeAtomAsync = async function executeAtomAsync (atom, args, responseUrl) {260 // save the resolve and reject methods of the promise to be waited for261 let promise = new B((resolve, reject) => {262 this.asyncPromise = {resolve, reject};263 });264 await this.remote.executeAtomAsync(atom, args, this.curWebFrames, responseUrl);265 return await this.waitForAtom(promise);266};267helpers.waitForAtom = async function waitForAtom (promise) {268 // need to check for alert while the atom is being executed.269 // so notify ourselves when it happens270 let done = false;271 let error = null;272 promise.then((res) => { // eslint-disable-line promise/prefer-await-to-then273 done = true;274 return res;275 })276 .catch((err) => { // eslint-disable-line promise/prefer-await-to-callbacks277 logger.debug(`Error received while executing atom: ${err.message}`);278 // error gets swallowed, so save and check later279 done = true;280 error = err;281 });282 // try ten times to check alert, if we are not done yet283 for (let i = 0; i < 10; i++) {284 // check if the promise has been resolved285 if (done) break; // eslint-disable-line curly286 await B.delay(500);287 if (done) break; // eslint-disable-line curly288 // check if there is an alert289 if (await this.checkForAlert()) {290 // we found an alert, and should just return control291 return '';292 }293 }294 let res = await promise;295 if (error) {296 throw error;297 }298 return this.parseExecuteResponse(res);299};300helpers.checkForAlert = async function checkForAlert () {301 if (!_.isNull(this.uiAutoClient)) {302 logger.debug('atom did not return yet, checking to see if ' +303 'we are blocked by an alert');304 let present = await this.uiAutoClient.sendCommand('au.alertIsPresent()');305 if (!present) {306 logger.debug('No alert found.');307 } else {308 logger.debug('Found an alert, returning control to client');309 }310 return present;311 }312};313helpers.getAtomsElement = function getAtomsElement (wdId) {314 let atomsId;315 try {316 atomsId = this.webElementIds[parseInt(wdId, 10) - ELEMENT_OFFSET];317 } catch (e) {318 return null;319 }320 if (_.isUndefined(atomsId)) {321 return null;322 }323 return {ELEMENT: atomsId};324};325helpers.useAtomsElement = function useAtomsElement (el) {326 if (parseInt(el, 10) < ELEMENT_OFFSET) {327 logger.debug(`Element with id '${el}' passed in for use with ` +328 `atoms, but it's out of our internal scope. Adding ${ELEMENT_OFFSET}.`);329 el = (parseInt(el, 10) + ELEMENT_OFFSET).toString();330 }331 let atomsElement = this.getAtomsElement(el);332 if (atomsElement === null) {333 throw new errors.UnknownError(`Error converting element ID for using in WD atoms: '${el}'`);334 }335 return atomsElement;336};337helpers.convertElementsForAtoms = function convertElementsForAtoms (args = []) {338 const resultArgs = [];339 for (const arg of args) {340 if (helpers.hasElementId(arg)) {341 // Get the element key from W3C or MJSONWP key342 const elementId = helpers.getElementId(arg);343 const atomsElement = this.getAtomsElement(elementId);344 if (atomsElement === null) {345 throw new errors.UnknownError(`Error converting element ID for using in WD atoms: '${elementId}'`);346 }347 resultArgs.push(atomsElement);348 } else if (_.isArray(arg)) {349 resultArgs.push(this.convertElementsForAtoms(arg));350 } else {351 resultArgs.push(arg);352 }353 }354 return resultArgs;355};356helpers.parseExecuteResponse = function parseExecuteResponse (res) {357 if (_.isNull(res) || _.isUndefined(res)) return null; // eslint-disable-line curly358 let wdElement = null;359 if (!_.isArray(res)) {360 if (helpers.hasElementId(res)) {361 wdElement = this.parseElementResponse(res);362 if (wdElement === null) {363 throw new errors.UnknownError(`Error converting element ID atom for using in WD: '${helpers.getElementId(res)}'`);364 }365 res = wdElement;366 }367 } else {368 // value is an array, so go through and convert each369 let args = [];370 for (let arg of res) {371 wdElement = arg;372 if (helpers.hasElementId(arg)) {373 wdElement = this.parseElementResponse(arg);374 if (wdElement === null) {375 throw new errors.UnknownError(`Error converting element ID atom for using in WD: '${helpers.getElementId(arg)}'`);376 }377 args.push(wdElement);378 } else {379 args.push(arg);380 }381 }382 res = args;383 }384 return res;385};386helpers.parseElementResponse = function parseElementResponse (element) {...
index.js
Source:index.js
...271}272function getScrollPosition(scope) {273 return getBrowserObject(scope).execute('return { scrollX: this.pageXOffset, scrollY: this.pageYOffset };');274}275async function hasElementId(element) {276 if (!element.elementId) {277 const method = element.isReactElement ? 'react$' : '$';278 element.elementId = (await element.parent[method](element.selector)).elementId;279 }280 if (!element.elementId) {281 return false;282 }283 return true;284}285function addLocatorStrategyHandler(scope) {286 return (name, script) => {287 if (scope.strategies.get(name)) {288 throw new Error(`Strategy ${name} already exists`);289 }...
ProgressionPlayerElementController.js
Source:ProgressionPlayerElementController.js
1/**2 Control an element displayed to the user, including rendering, updating, and destroying.3 This controller is an abstract class.4 @class ProgressionPlayerElementController5 @extends ElementController6 @constructor7*/8function ProgressionPlayerElementController() {9 require('ProgressionUtilities').create().inheritElementController().constructor.apply(this, arguments);10}11/**12 Build the ProgressionPlayerElementController prototype.13 @method buildProgressionPlayerElementControllerPrototype14 @return {void}15*/16function buildProgressionPlayerElementControllerPrototype() {17 ProgressionPlayerElementController.prototype = require('ProgressionUtilities').create().inheritElementController();18 ProgressionPlayerElementController.prototype.constructor = ProgressionPlayerElementController;19 /**20 Return whether the user's answer for this element is correct.21 Inheriting controllers with an interactive element should override this.22 @method isCorrect23 @return {Boolean} Whether the user's answer is correct for this element. Default is true.24 */25 ProgressionPlayerElementController.prototype.isCorrect = function() {26 return true;27 };28 /**29 Mark the element as a wrong answer.30 @method markAsWrongAnswer31 @return {void}32 */33 ProgressionPlayerElementController.prototype.markAsWrongAnswer = function() {34 this._$element.addClass('wrong-answer');35 };36 /**37 Return whether the elements have an invalid configuration.38 Inheriting controllers with an interactive element should override this.39 @method isInvalidAnswer40 @return {Boolean} True if any element has an invalid configuration. Default is false.41 */42 ProgressionPlayerElementController.prototype.isInvalidAnswer = function() {43 return false;44 };45 /**46 Mark the element as an invalid answer.47 @method markAsInvalidAnswer48 @return {void}49 */50 ProgressionPlayerElementController.prototype.markAsInvalidAnswer = function() {51 this._$element.addClass('invalid-answer');52 };53 /**54 Return the user's answer for the element.55 Inheriting controllers with an interactive element should override this.56 @method userAnswer57 @return {String} The user's answer for this element. Default is empty string.58 */59 ProgressionPlayerElementController.prototype.userAnswer = function() {60 return {61 id: this._elementRendered.id,62 userAnswer: this._elementSpecificUserAnswer(),63 };64 };65 /**66 Return the user's answer for this specific element.67 @method _elementSpecificUserAnswer68 @private69 @return {String} The user answer for this specific element.70 */71 ProgressionPlayerElementController.prototype._elementSpecificUserAnswer = function() { // eslint-disable-line no-underscore-dangle72 return '';73 };74 /**75 Return the expected answer for the element.76 Inheriting controllers with an interactive element should override this.77 @method expectedAnswer78 @return {String} The expected answer for this element. Default is empty string.79 */80 ProgressionPlayerElementController.prototype.expectedAnswer = function() {81 return {82 id: this._elementRendered.id,83 expectedAnswer: this._elementSpecificExpectedAnswer(),84 };85 };86 /**87 Return the expected answer for this specific element.88 @method _elementSpecificExpectedAnswer89 @private90 @return {String} The user answer for this specific element.91 */92 ProgressionPlayerElementController.prototype._elementSpecificExpectedAnswer = function() { // eslint-disable-line no-underscore-dangle93 return '';94 };95 /**96 Remove the invalid answer class from |_$element|.97 @method removeInvalidAnswerStatus98 @return {void}99 */100 ProgressionPlayerElementController.prototype.removeInvalidAnswerStatus = function() {101 this._$element.removeClass('invalid-answer');102 };103 /**104 Disable the controller's interactive elements.105 Inheriting objects that are interactive should override this.106 @method disable107 @return {void}108 */109 ProgressionPlayerElementController.prototype.disable = function() {};110 /**111 Enable the controller's interactive elements.112 Inheriting objects that are interactive should override this.113 @method enable114 @return {void}115 */116 ProgressionPlayerElementController.prototype.enable = function() {};117 /**118 Whether the element supports being focused upon.119 @property doesSupportFocus120 @type {Boolean}121 @default false122 */123 ProgressionPlayerElementController.prototype.doesSupportFocus = false;124 /**125 Move browser focus to the controller's interactive element.126 @method focus127 @return {void}128 */129 ProgressionPlayerElementController.prototype.focus = function() {}; // eslint-disable-line no-empty-function130 /**131 Whether the element is assessed for correctness.132 @property isAssessedForCorrectness133 @type {Boolean}134 @default false135 */136 ProgressionPlayerElementController.prototype.isAssessedForCorrectness = false;137 /**138 Return whether this controller's element has the given id.139 @method hasElementId140 @param {String} id The given id.141 @return {Boolean} Whether this controller's element has the given id.142 */143 ProgressionPlayerElementController.prototype.hasElementId = function(id) {144 return this._elementRendered.id === id;145 };146 /**147 Set the controller's answer with the given answer.148 @method setUserAnswer149 @param {Object} answer The answer to set.150 @return {Boolean} Whether this controller's element has the given id.151 */152 ProgressionPlayerElementController.prototype.setAnswer = function(answer) {}; // eslint-disable-line...
Controllers.js
Source:Controllers.js
...118Controllers.prototype.setAnswers = function(userAnswers) {119 userAnswers.forEach(userAnswer => {120 const answer = userAnswer.userAnswer;121 if (answer) {122 const answerController = this.find(controller => controller.hasElementId(userAnswer.id));123 if (answerController) {124 answerController.setAnswer(answer);125 }126 }127 });...
isDisplayed.js
Source:isDisplayed.js
1"use strict";2Object.defineProperty(exports, "__esModule", {3 value: true4});5exports.default = isDisplayed;6var _constants = require("../../constants");7var _utils = require("../../utils");8var _isElementDisplayed = _interopRequireDefault(require("../../scripts/isElementDisplayed"));9function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }10const noW3CEndpoint = ['microsoftedge', 'safari', 'chrome', 'safari technology preview'];11async function isDisplayed() {12 let browser = (0, _utils.getBrowserObject)(this);13 if (!(await (0, _utils.hasElementId)(this))) {14 return false;15 }16 return browser.isDevTools || browser.isW3C && !browser.isMobile && noW3CEndpoint.includes(browser.capabilities.browserName.toLowerCase()) ? await browser.execute(_isElementDisplayed.default, {17 [_constants.ELEMENT_KEY]: this.elementId,18 ELEMENT: this.elementId19 }) : await this.isElementDisplayed(this.elementId);...
attributes.js
Source:attributes.js
1// getAttribute, setAttribute, hasAttribute, removeAtrribute2const addresses = document.querySelectorAll("input[name='address']")3addresses.forEach((element) => {4 const inputElement = element;5 const id = inputElement.getAttribute("id");6 const type = inputElement.getAttribute("type");7 inputElement.setAttribute("data-read", "yes");8 inputElement.setAttribute("data-selected", "no");9 let hasElementId = inputElement.hasAttribute("id");10 console.log(id, type, hasElementId, inputElement.dataset)11 inputElement.getAttribute("data-read");...
Using AI Code Generation
1var webdriverio = require('webdriverio');2var options = {3 desiredCapabilities: {4 }5};6 .remote(options)7 .init()8 .hasElementId('#hplogo')9 .then(function(isExisting) {10 console.log(isExisting);11 })12 .end();13 .remote(options)14 .init()15 .hasElementIdNot('#hplog')16 .then(function(isExisting) {17 console.log(isExisting);18 })19 .end();20Related posts: WebdriverIO hasElementIdNot() Method Example WebdriverIO hasElementByCss() Method Example WebdriverIO hasElementByXpath() Method Example WebdriverIO hasElementByLinkText() Method Example WebdriverIO hasElementByPartialLinkText() Method Example WebdriverIO hasElementByName() Method Example WebdriverIO hasElementByTagName() Method Example WebdriverIO hasElementByClassName() Method Example WebdriverIO hasElementByCssSelector() Method Example WebdriverIO hasElementByXPath() Method Example WebdriverIO hasElementByLinkText() Method Example WebdriverIO hasElementByPartialLinkText() Method Example WebdriverIO hasElementByName() Method Example WebdriverIO hasElementByTagName() Method Example WebdriverIO hasElementByClassName() Method Example WebdriverIO hasElementByCssSelector() Method Example WebdriverIO hasElementByXPath() Method Example WebdriverIO hasElementByLinkText() Method Example WebdriverIO hasElementByPartialLinkText() Method Example WebdriverIO hasElementByName() Method Example WebdriverIO hasElementByTagName() Method Example WebdriverIO hasElementByClassName() Method Example WebdriverIO hasElementByCssSelector() Method Example WebdriverIO hasElementByXPath() Method Example WebdriverIO hasElementByLinkText() Method Example WebdriverIO hasElementByPartialLinkText() Method Example WebdriverIO hasElementByName() Method Example WebdriverIO hasElementByTagName() Method Example WebdriverIO hasElementByClassName() Method Example WebdriverIO hasElementByCssSelector()
Using AI Code Generation
1var webdriverio = require('webdriverio');2var options = {3 desiredCapabilities: {4 }5};6 .remote(options)7 .init()8 .hasElementId('gbqfbb')9 .then(function(hasElementId) {10 console.log(hasElementId);11 })12 .end();
Using AI Code Generation
1var webdriverio = require('webdriverio');2var options = {3 desiredCapabilities: {4 }5};6 .remote(options)7 .init()8 .hasElementId('someId')9 .then(function(hasElement) {10 })11 .end();
Using AI Code Generation
1var webdriverio = require('webdriverio');2var options = { desiredCapabilities: { browserName: 'chrome' } };3 .remote(options)4 .init()5 .hasElementId('hplogo')6 .then(function(hasElement) {7 })8 .end();
Using AI Code Generation
1var webdriverio = require('webdriverio');2var options = {3 desiredCapabilities: {4 }5};6 .remote(options)7 .init()8 .hasElementId('hplogo')9 .then(function(hasElement) {10 console.log(hasElement);11 })12 .end();
Wondering what could be a next-gen browser and mobile test automation framework that is also simple and concise? Yes, that’s right, it's WebdriverIO. Since the setup is very easy to follow compared to Selenium testing configuration, you can configure the features manually thereby being the center of attraction for automation testing. Therefore the testers adopt WedriverIO to fulfill their needs of browser testing.
Learn to run automation testing with WebdriverIO tutorial. Go from a beginner to a professional automation test expert with LambdaTest WebdriverIO tutorial.
Running Your First Automation Script - Learn the steps involved to execute your first Test Automation Script using WebdriverIO since the setup is very easy to follow and the features can be configured manually.
Selenium Automation With WebdriverIO - Read more about automation testing with WebdriverIO and how it supports both browsers and mobile devices.
Browser Commands For Selenium Testing - Understand more about the barriers faced while working on your Selenium Automation Scripts in WebdriverIO, the ‘browser’ object and how to use them?
Handling Alerts & Overlay In Selenium - Learn different types of alerts faced during automation, how to handle these alerts and pops and also overlay modal in WebdriverIO.
How To Use Selenium Locators? - Understand how Webdriver uses selenium locators in a most unique way since having to choose web elements very carefully for script execution is very important to get stable test results.
Deep Selectors In Selenium WebdriverIO - The most popular automation testing framework that is extensively adopted by all the testers at a global level is WebdriverIO. Learn how you can use Deep Selectors in Selenium WebdriverIO.
Handling Dropdown In Selenium - Learn more about handling dropdowns and how it's important while performing automated browser testing.
Automated Monkey Testing with Selenium & WebdriverIO - Understand how you can leverage the amazing quality of WebdriverIO along with selenium framework to automate monkey testing of your website or web applications.
JavaScript Testing with Selenium and WebdriverIO - Speed up your Javascript testing with Selenium and WebdriverIO.
Cross Browser Testing With WebdriverIO - Learn more with this step-by-step tutorial about WebdriverIO framework and how cross-browser testing is done with WebdriverIO.
Get 100 minutes of automation test minutes FREE!!