'+_href+''); }); }; // add page } // clear all pages { // ================= $R.clearAllPages = function () { // reset pages count $R.pagesCount = 0; // delete all pages $R.$iframePages.get(0).innerHTML = ''; // reset footnote count $R.footnotedLinksCount = 0; // delete all footnotes $R.$iframeFootnotedLinks.get(0).innerHTML = ''; }; // clear all pages } // return self // =========== return $R; }</script><script defer="" type="text/javascript" charset="ANSI">Evernote.ClearlyController = { _created : false, _visible : false, _logEnabled : false, _detectResult : null, logger : function(text) { if (!this._logEnabled) return; console.log('[Clearly] : ' + text); }, getSimplifiedArticle : function() { this.logger('getSimplifiedArticle()'); return Evernote.JQuery('#evernoteClearlyArticle #box #text').get(0); }, changeFrameClassTo : function(className) { this.clearlyFrame[0].className = ''; this.clearlyFrame.addClass(className); }, hide : function() { this.logger('hide()'); var self = this; if (this._created && this._visible) { this.clearlyBackground.stop(); this.changeFrameClassTo('processing'); this.clearlyBackground.animate({right:'100%'}, 500, null, function() { self.changeFrameClassTo('temphidden'); window.focus(); } ); this._visible = false; } }, show : function() { this.logger('show()'); var self = this; if (this._created && !this._visible) { this.clearlyBackground.stop(); this.changeFrameClassTo('processing'); this.clearlyBackground.animate({ right: "0px" }, 500, null, function() { self.changeFrameClassTo('visible'); window.focus(); } ); this._visible = true; } }, detectComponent : function(callback) { this.logger('detectComponent()'); window.ClearlyComponent__detect = { callbacks: { finished: function(data) { if (callback) callback(data); } }, window: window, document: document, jQuery: Evernote.JQuery }; window.ClearlyComponent__detect = initClearlyComponent__detect(window.ClearlyComponent__detect); window.ClearlyComponent__detect.start(); }, reformatComponent : function(callback){ this.logger('reformatComponent()'); window.ClearlyComponent__reformat = { callbacks: { frameCreated: function(data) { if (callback) callback(data); } }, settings: { cssPath: 'css/clearly', pageLabel: "page ", onCreateFrameUseThisId: "evernoteClearlyArticle", onCreateFrameDoNotInsertCSS: true }, window: window, document: document, jQuery: Evernote.JQuery }; window.ClearlyComponent__reformat = initClearlyComponent__reformat(window.ClearlyComponent__reformat); window.ClearlyComponent__reformat.createFrame(); }, getContentElementAndHTML : function (callback) { this.logger('getContentElementAndHTML()'); this.detectComponent(callback); }, getClearlyArticleText : function(callback) { this.logger('getClearlyArticleText()'); this.detectComponent(callback); }, assignClearlyArticleContent : function() { this.logger('showClearlyArticleContent()'); window.ClearlyComponent__reformat.$iframeBox.find('#text #pages')[0].innerHTML = this._detectResult; }, setContainersSize : function() { var maxHeight = Math.max(document.body.scrollHeight, this.clearlyFrame.scrollHeight); try { //old ie throws error this.clearlyFrame[0].style.height = maxHeight + "px"; } catch (e) { } }, startClearly : function() { this.logger('startClearly()'); var self = this; if (this._created) { self.show(); return; } function onDetectEnd(data) { self._detectResult = data._html.replace(/(id|class)="(.*?)"/ig,'cid="$2"'); self.assignClearlyArticleContent(); self.show(); } function onFrameCreated() { self.clearlyFrame = window.ClearlyComponent__reformat.$iframe; self.clearlyBackground = window.ClearlyComponent__reformat.$iframeBackground; self._created = true; self.setContainersSize(); self.detectComponent(onDetectEnd); } window.scrollTo(0,0); this.reformatComponent(onFrameCreated); }, isReady : function() { return this._created; }, isVisible : function() { return this._visible; }, highlight : function () { this.logger('highlight()'); var numTextHighlights; window.ClearlyComponent__highlight = { callbacks: { highlightAdded: function() { numTextHighlights++; }, highlightDeleted: function() { numTextHighlights--; } }, settings: { imgPath: "images/" }, window: window, document: document, jQuery: Evernote.JQuery }; window.ClearlyComponent__highlight = initClearlyComponent__highlight(window.ClearlyComponent__highlight); window.ClearlyComponent__highlight.insertCSS(); window.ClearlyComponent__highlight.addMouseHandlers(); window.ClearlyComponent__highlight.enable(); }, disableHighlight : function() { this.logger('disableHighlight()'); if (window.ClearlyComponent__highlight) { window.ClearlyComponent__highlight.disable(); } }, removeHighlighted : function() { this.logger('removeHighlighed()'); // Evernote.JQuery('.clearly_highlight_delete_element').click(); } };</script><script defer="" type="text/javascript" charset="ANSI">/** * SelectionFinder provides mechanism for finding selection on the page via * find(). It is able to traverse frames in order to find a selection. It will * report whether there's a selection via hasSelection(). After doing find(), * the selection is stored in the selection property, and the document property * will contain the document in which the selection was found. Find method will * only recurse documents if it was invoked as find(true), specifying to do * recursive search. You can use reset() to undo find(). */ Evernote.SelectionFinder = function SelectionFinder( doc ) { this._document = doc; }; Evernote.SelectionFinder.prototype._document = null; Evernote.SelectionFinder.prototype._selection = null; Evernote.SelectionFinder.prototype.hasSelection = function() { Evernote.Logger.debug( "SelectionFinder.hasSelection()" ); var range = Evernote.Utils.fixIERangeObject(this.getRange()); return range && (range.startContainer != range.endContainer || (range.startContainer == range.endContainer && range.startOffset != range.endOffset)); }; Evernote.SelectionFinder.prototype.find = function( deep ) { Evernote.Logger.debug( "SelectionFinder.find()" ); var result = this.findSelectionInDocument( this._document, deep ); this._document = result.document; this._selection = result.selection; }; Evernote.SelectionFinder.prototype.getRange = function() { Evernote.Logger.debug( "SelectionFinder.getRange()" ); if ( !this._selection || this._selection.rangeCount == 0 ) { return null; } if ( typeof this._selection.getRangeAt == 'function' ) { return this._selection.getRangeAt( 0 ); } if ( (window.Range && this._selection instanceof window.Range) || !this._selection.anchorNode ) { return this._selection; } var range = this._document.createRange(); range.setStart( this._selection.anchorNode, this._selection.anchorOffset ); range.setEnd( this._selection.focusNode, this._selection.focusOffset ); return range; }; Evernote.SelectionFinder.prototype.findSelectionInDocument = function( doc, deep ) { try { Evernote.Logger.debug( "SelectionFinder.findSelectionInDocument()" ); var sel = null; var hasSelection = false; var win = null; try { win = (doc.defaultView) ? doc.defaultView : window; } catch ( e ) { win = window; } if ( typeof win.getSelection == 'function' ) { sel = win.getSelection(); if ( sel && typeof sel.rangeCount != 'undefined' && sel.rangeCount > 0 ) { Evernote.Logger.debug("Found selection by win.getSelection()"); hasSelection = true; } } else if ( win.selection && typeof win.selection.createRange == 'function' ) { sel = win.selection.createRange(); if ( win.selection.type == 'Text' && typeof sel.htmlText == 'string' && sel.htmlText.length > 0 ) { Evernote.Logger.debug("Found selection by win.selection"); hasSelection = true; } } else if ( doc.selection && (typeof doc.selection.createRange == 'function' || typeof doc.selection.createRange == 'object') ) { sel = doc.selection.createRange(); if(doc.selection.type == "None") sel = undefined; if ( (doc.selection.type == 'Text') && (typeof sel.htmlText == 'string') && (sel.htmlText.length > 0) ) { Evernote.Logger.debug("Found selection by doc.selection"); hasSelection = true; } } if ( sel && !hasSelection && deep ) { var nestedDocs = Evernote.Utils.getNestedDocuments( doc ); for ( var i = 0; i < nestedDocs.length; ++i ) { if ( nestedDocs[ i ] ) { var framedSel = this.findSelectionInDocument( nestedDocs[ i ], deep ); if ( framedSel && framedSel.selection && framedSel.selection.rangeCount > 0 ) { return framedSel; } } } } //if do not find any selection in document, try to find selection in HTMLTextArea|Input. //Get Selection object for TextArea, and set selection as a Range object if(doc.activeElement) Evernote.Logger.debug( "Check selection in INPUT TEXT area (input, textarea), for active element :" + doc.activeElement.nodeName ); var activeEl = doc.activeElement && false; // disabled, because no need to search selections in this elements. if ( activeEl && ( (window.HTMLInputElement && (activeEl instanceof window.HTMLInputElement && activeEl.type == "text")) || ( window.HTMLTextAreaElement && (activeEl instanceof window.HTMLTextAreaElement)) ) ) { if ( activeEl.selectionStart != activeEl.selectionEnd ) { var range = doc.createRange(); var textNode = doc.createTextNode( activeEl.value ); range.setStart( textNode, activeEl.selectionStart ); range.setEnd( textNode, activeEl.selectionEnd ); sel = range; } } return { document : doc, selection : sel }; } catch(e) { Evernote.Logger.error("Failed to find selection on the page due to error " + e); //Do not throw exception here, it is better to not show error to user and allow to clip article or something else. } return { document: doc, selection: null } };</script><script defer="" type="text/javascript" charset="ANSI">Evernote.JSSerializer = { _selectionFinder : new Evernote.SelectionFinder(window.document), serializeAsync : function( element, fullPage, callback ) { try { var start = new Date().getTime(); var root = element || document.body.parentNode || document.body; var serializer = new Evernote.NodeSerializer( window, new Evernote.ClipFullStylingStrategy() ); var parser = new Evernote.DomParser( window, null ); var resultFunc = function() { var images = []; var imageUrls = serializer.getImagesUrls(); for(var i = 0; i < imageUrls.length; i++) { images.push(Evernote.Utils.makeAbsolutePath(serializer.getDocumentBase(), imageUrls[i]).replace(/\s/g, "%20")); } callback( { content : serializer.getSerializedDom(), imageUrls : images, docBase : serializer.getDocumentBase() }); }; parser.parseAsync( root, fullPage ? true: false, serializer, resultFunc); var end = new Date().getTime(); Evernote.Logger.debug( "Clip.clipFullPage(): clipped body in " + (end - start) + " milliseconds" ); } catch ( e ) { Evernote.Logger.error( "JSSerializer.serialize() failed: error = " + e ); throw e; } }, serialize : function( element, fullPage ) { try { var start = new Date().getTime(); var root = element || document.body.parentNode || document.body; var serializer = new Evernote.NodeSerializer( window, new Evernote.ClipFullStylingStrategy() ); var parser = new Evernote.DomParser( window, null ); parser.parse( root, fullPage ? true: false, serializer); var end = new Date().getTime(); Evernote.Logger.debug( "Clip.clipFullPage(): clipped body in " + (end - start) + " milliseconds" ); var images = []; var imageUrls = serializer.getImagesUrls(); for(var i = 0; i < imageUrls.length; i++) { images.push(Evernote.Utils.makeAbsolutePath(serializer.getDocumentBase(), imageUrls[i]).replace(/\s/g, "%20")); } return { content : serializer.getSerializedDom(), imageUrls : images, docBase : serializer.getDocumentBase() } } catch ( e ) { Evernote.Logger.error( "JSSerializer.serialize() failed: error = " + e ); throw e; } }, serializeSelectionAsync : function( range, callback ) { try { if( !range ) { if ( !this.hasSelection() ) { Evernote.Logger.warn( "JSSerializer.serializeSelection(): no selection to clip" ); callback(); return; } range = Evernote.Utils.fixIERangeObject(this._selectionFinder.getRange()); if ( !range ) { Evernote.Logger.warn( "JSSerializer.serializeSelection(): no range in selection" ); callback(); return; } } var start = new Date().getTime(); var ancestor = (this._styleStrategy && Evernote.Utils.Selection.getCommonAncestorContainer(range).nodeType == Evernote.Node.TEXT_NODE && Evernote.Utils.Selection.getCommonAncestorContainer(range).parentNode) ? Evernote.Utils.Selection.getCommonAncestorContainer(range).parentNode : Evernote.Utils.Selection.getCommonAncestorContainer(range); while ( typeof Evernote.ClipRules.NON_ANCESTOR_NODES[ ancestor.nodeName.toUpperCase() ] != 'undefined' && ancestor.parentNode ) { if ( ancestor.nodeName.toUpperCase() == "BODY" ) { break; } ancestor = ancestor.parentNode; } var serializer = new Evernote.NodeSerializer( window, new Evernote.ClipFullStylingStrategy(), null, true ); var parser = new Evernote.DomParser(window, Evernote.Utils.fixIERangeObject(range)); var resultFunc = function() { var images = []; var imageUrls = serializer.getImagesUrls(); for(var i = 0; i < imageUrls.length; i++) { images.push(Evernote.Utils.makeAbsolutePath(serializer.getDocumentBase(), imageUrls[i]).replace(/\s/g, "%20")); } callback( { content : serializer.getSerializedDom(), imageUrls : images, docBase : serializer.getDocumentBase() } ); }; parser.parseAsync( ancestor, false, serializer, resultFunc ); var end = new Date().getTime(); Evernote.Logger.debug( "JSSerializer.serializeSelection(): clipped selection in " + (end - start) + " milliseconds" ); } catch ( e ) { Evernote.Logger.error( "JSSerializer.serializeSelection() failed: error = " + e ); throw e; } }, serializeSelection : function( range ) { try { if( !range ) { if ( !this.hasSelection() ) { Evernote.Logger.warn( "JSSerializer.serializeSelection(): no selection to clip" ); return; } range = Evernote.Utils.fixIERangeObject(this._selectionFinder.getRange()); if ( !range ) { Evernote.Logger.warn( "JSSerializer.serializeSelection(): no range in selection" ); return; } } var start = new Date().getTime(); var ancestor = (this._styleStrategy && Evernote.Utils.Selection.getCommonAncestorContainer(range).nodeType == Evernote.Node.TEXT_NODE && Evernote.Utils.Selection.getCommonAncestorContainer(range).parentNode) ? Evernote.Utils.Selection.getCommonAncestorContainer(range).parentNode : Evernote.Utils.Selection.getCommonAncestorContainer(range); while ( typeof Evernote.ClipRules.NON_ANCESTOR_NODES[ ancestor.nodeName.toUpperCase() ] != 'undefined' && ancestor.parentNode ) { if ( ancestor.nodeName.toUpperCase() == "BODY" ) { break; } ancestor = ancestor.parentNode; } var serializer = new Evernote.NodeSerializer( window, new Evernote.ClipFullStylingStrategy() ); var parser = new Evernote.DomParser(window, Evernote.Utils.fixIERangeObject(range)); parser.parse( ancestor, false, serializer ); var end = new Date().getTime(); Evernote.Logger.debug( "JSSerializer.serializeSelection(): clipped selection in " + (end - start) + " milliseconds" ); var images = []; var imageUrls = serializer.getImagesUrls(); for(var i = 0; i < imageUrls.length; i++) { images.push(Evernote.Utils.makeAbsolutePath(serializer.getDocumentBase(), imageUrls[i]).replace(/\s/g, "%20")); } return { content : serializer.getSerializedDom(), imageUrls : images, docBase : serializer.getDocumentBase() } } catch ( e ) { Evernote.Logger.error( "JSSerializer.serializeSelection() failed: error = " + e ); throw e; } }, hasSelection : function() { Evernote.Logger.debug( "Clip.hasSelection()" ); if ( this._selectionFinder.hasSelection() ) { return true; } else { this._selectionFinder.find( true ); return this._selectionFinder.hasSelection(); } } };</script><script defer="" type="text/javascript" charset="ANSI">/** * Represents JQuery loader that allow to have two versions of JQuery loaded on the same page * @type {Object} */ Evernote.JQueryLoader = { /** * Initializes jquery instance on global Evernote context */ initJQuery : function() { if (!Evernote.JQuery) { Evernote.JQuery = $.noConflict(true); } } }; (function () { if (!Evernote.JQuery) { Evernote.JQuery = $.noConflict(true); } }());</script><script defer="" type="text/javascript" charset="ANSI">Evernote.ClipNotificator = function ClipNotificator() { }; // TODO: clip notificator is obsolete now. Remove it. Evernote.ClipNotificator.WAIT_CONTAINER_ID = "evernoteContentClipperWait"; Evernote.ClipNotificator.SHOW_WAIT_MIN_TIME = 2000; Evernote.ClipNotificator.prototype.showCopyNotification = function( doc, options, useAutoHide ) { Evernote.evernotePostClipPopup.fillOutPopup(options.title, options.notebookName); Evernote.evernotePostClipPopup.show(); try { var wait = this.getWaitContainer( doc, Evernote.Addin.getLocalizedMessage(Evernote.Messages.CLIPPING) ); wait.style.display = "none"; this.centerBox(wait); if ( doc.body ) { doc.body.appendChild( wait ); } if (useAutoHide) { var self = this; var timeout = this.constructor.SHOW_WAIT_MIN_TIME; setTimeout( function() { self.clearWait( doc ); }, timeout ); } } catch ( e ) { Evernote.Logger.error( "ClipNotificator.showCopyNotification() failed: error = " + e ); } }; Evernote.ClipNotificator.prototype.centerBox = function( container ) { // TODO: for what? It can be done with css. var topPosition = ((document.documentElement.scrollTop || document.body.scrollTop) + ((((document.documentElement.clientHeight || document.body.clientHeight) + (!container.offsetHeight && 0)) / 2) >> 0)); var leftPosition = (((document.documentElement.clientWidth || document.body.clientWidth) / 2) - (container.offsetWidth / 2)); container.style.position = "absolute"; container.style.top = (topPosition-20) + "px"; container.style.left = (leftPosition - 90) + "px"; }; Evernote.ClipNotificator.prototype.getWaitContainer = function( doc, msg ) { Evernote.Logger.debug( "ClipNotificator.getWaitContainer()" ); var container = doc.getElementById( this.constructor.WAIT_CONTAINER_ID ); if ( !container ) { container = doc.createElement( "evernotediv" ); if(Evernote.Utils.isQuirkMode()) { container.className = "quirk-mode-container"; } container.id = this.constructor.WAIT_CONTAINER_ID; var wait = doc.createElement( "div" ); wait.id = this.constructor.WAIT_CONTAINER_ID + "Content"; if(Evernote.BrowserDetection.isLessThanIE9()) { wait.className = "content-less-than-nine-container"; } container.appendChild( wait ); var center = doc.createElement( "center" ); wait.appendChild( center ); var spinner = doc.createElement( "div" ); spinner.id = "evernote-spinner-container"; center.appendChild( spinner ); var text = doc.createElement( "span" ); text.id = this.constructor.WAIT_CONTAINER_ID + "Text"; center.appendChild( text ); container._waitMsgBlock = text; container._waitMsgBlock.appendChild( doc.createTextNode( msg ) ); } return container; }; Evernote.ClipNotificator.prototype.clearWait = function( doc, immediately ) { Evernote.Logger.debug( "ClipNotificator.clearWait()" ); var wait = doc.getElementById( Evernote.ClipNotificator.WAIT_CONTAINER_ID ); if ( wait ) { wait.style.opacity = "0"; if (immediately) { wait.parentNode.removeChild( wait ); } else { setTimeout( function() { if ( wait.parentNode ) { wait.parentNode.removeChild( wait ); } }, 300 ); } } };</script><script defer="" type="text/javascript" charset="ANSI">/** * Represents clipper object that is capable of clipping elements from pages or clip elements based on preferences. */ Evernote.Clipper = { _serializer : Evernote.JSSerializer, _clipNotifier : new Evernote.ClipNotificator(), _defaultOptions : { title: PageContext.title, tags: [], comments: "", notebookUid: -1, notebookName : "" }, /** * Clips article element (one that user selected or default if no selection was made). */ clipArticle : function(options, clearly) { var currentOptions = this.initOptions(options); this._clipNotifier.showCopyNotification(document, currentOptions); var self = this; setTimeout(function() { var article if ( clearly ) { article = Evernote.ClearlyController.getSimplifiedArticle(); } else { article = Evernote.contentPreviewer.getArticleElement(); } if(!article) { article = Evernote.pageInfo.getDefaultArticle(function(article) {}); } var resultFunc = function(serializedDom) { self._clipNotifier.clearWait(document); Evernote.Addin.clipNote(currentOptions.comments + serializedDom.content, currentOptions, PageContext.url, serializedDom.imageUrls, true, document); Evernote.ClearlyController.hide(); }; self._serializer.serializeAsync(article, false, resultFunc); }, 100); }, initOptions: function(options) { if(!options) options = this._defaultOptions; options = Evernote.JQuery.extend({}, this._defaultOptions, options); if(!options.title || Evernote.JQuery.trim(options.title).length == 0) options.title = Evernote.Addin.getLocalizedMessage(Evernote.Messages.UNTITLED_NOTE); options.title = Evernote.JQuery.trim(Evernote.Utils.cutToLength(options.title, 255, " ")); /* get notebook name */ var notebookUid = options.notebookUid || 0; var notebook = Evernote.NotebooksLoader.getNotebookByUid(notebookUid); if(!notebook) { options.notebookName = Evernote.Addin.getLocalizedMessage(Evernote.Messages.DEFAULT_NOTEBOOK); } else { options.notebookName = notebook.name; } return options; }, /** * Clips full page. */ clipFullPage : function(options) { Evernote.Logger.debug("Clipper: clipFullPage"); var currentOptions = this.initOptions(options); this._clipNotifier.showCopyNotification(document , currentOptions); var self = this; setTimeout(function() { Evernote.Logger.debug("Start clipping of full page"); var resultFunc = function(serializedDom) { self._clipNotifier.clearWait(document); Evernote.Logger.debug("Image urls " + JSON.stringify(serializedDom.imageUrls)); Evernote.Logger.debug("Send clip to EN"); Evernote.Addin.clipNote(currentOptions.comments + serializedDom.content, currentOptions, PageContext.url, serializedDom.imageUrls, true, document); }; self._serializer.serializeAsync(null, true, resultFunc); }, 100); }, /** * Clips url with favicon (if favicon is recognized) */ clipUrl : function(options) { var currentOptions = this.initOptions(options); this._clipNotifier.showCopyNotification(document, currentOptions, true); var self = this; setTimeout(function() { var snippet = Evernote.contentPreviewer.getSnippetText(); if (snippet) { snippet = snippet.replace(/(<([^>]+)>)/ig,""); var content = Evernote.GlobalUtils.createUrlClipContent(PageContext.title, PageContext.url, PageContext.getFavIconUrl(), snippet); Evernote.Addin.clipNote(currentOptions.comments + content, currentOptions, PageContext.url, PageContext.getFavIconUrl(), true, document); }else { self._clipNotifier.clearWait(document, true); Evernote.ClearlyController.getClearlyArticleText( function (data) { snippet = data._html.replace(/(<([^>]+)>)/ig,""); var content = Evernote.GlobalUtils.createUrlClipContent(PageContext.title, PageContext.url, PageContext.getFavIconUrl(), snippet); Evernote.Addin.clipNote(currentOptions.comments + content, currentOptions, PageContext.url, PageContext.getFavIconUrl(), true, document); }); } }, 100); }, /** * Clips selection from the page. */ clipSelection : function( range, options ) { var currentOptions = this.initOptions(options); this._clipNotifier.showCopyNotification(document , currentOptions); var self = this; setTimeout(function() { var resultFunc = function(serializedDom) { self._clipNotifier.clearWait(document); if(serializedDom) { Evernote.Addin.clipNote(currentOptions.comments + serializedDom.content, currentOptions, PageContext.url, serializedDom.imageUrls, true, document); } }; self._serializer.serializeSelectionAsync( range, resultFunc ); }, 100); }, /** * Clips image from the page. */ clipImage : function(options ) { if (!options.imageElement) { Evernote.Logger.debug("clipImage Empty element"); return; } var currentOptions = this.initOptions(options); this._clipNotifier.showCopyNotification(document , currentOptions); var self = this; var clojureBug = Evernote.BrowserDetection.isIE7(); var CUSTOM_ID = 'evn-image-for-clip'; if (clojureBug) { // add attr to find this element later Evernote.JQuery(document).find(options.imageElement).attr( CUSTOM_ID ,'true'); } setTimeout(function() { var elementToSerialize = options.imageElement; if (clojureBug) { var elem = Evernote.JQuery('*['+ CUSTOM_ID +']'); elementToSerialize = Evernote.JQuery('*['+ CUSTOM_ID +']')[0]; elem.removeAttr(CUSTOM_ID); } Evernote.Logger.debug("Start clipping of image"); var resultFunc = function(serializedDom) { self._clipNotifier.clearWait(document); Evernote.Logger.debug("Image urls " + JSON.stringify(serializedDom.imageUrls)); Evernote.Logger.debug("Send clip to EN"); Evernote.Addin.clipNote(currentOptions.comments + serializedDom.content, currentOptions, PageContext.url, serializedDom.imageUrls, true, document); }; self._serializer.serializeAsync(elementToSerialize, false, resultFunc); }, 100); }, /** * Clips part of the page, defined in option (url, article or full page) or selection if presented. */ clipWithOptions : function(clipOptions) { function getNotebook() { return {uid : -1}; } var notebookToClipTo = getNotebook(); var alwaysTags = []; if (notebookToClipTo.type != Evernote.NotebookTypes.LINKED && Evernote.Options.tags.alwaysEnable == true) { alwaysTags = Evernote.Options.tags.alwaysData.split(','); } var options = { notebookUid: notebookToClipTo.uid, imageElement: EvernoteExternal.imageElement, tags: alwaysTags }; if(clipOptions.getClipAction() == Evernote.ClipperActions.CLIP_SELECTION && Evernote.Utils.hasSelection(window)) { Evernote.Clipper.clipSelection(null, options); } else if(clipOptions.getClipAction() == Evernote.ClipperActions.CLIP_URL) { Evernote.Clipper.clipUrl(options); } else if(clipOptions.getClipAction() == Evernote.ClipperActions.CLIP_FULL_PAGE) { Evernote.Clipper.clipFullPage(options); } else if(clipOptions.getClipAction() == Evernote.ClipperActions.CLIP_IMAGE) { Evernote.Clipper.clipImage(options); } else { Evernote.Logger.warn("Unknown option is specified : " + clipOptions.getClipAction()); } }, clipBase64Image : function(options, base64Image) { var self = this; var currentOptions = this.initOptions(options); this._clipNotifier.showCopyNotification(document , currentOptions); Evernote.Addin.clipImageAsync(options, function(result) { EvernoteGlobalReceiver(result); }, PageContext.url, base64Image); } };</script><script defer="" type="text/javascript" charset="ANSI">Evernote.ClipOptions = function ClipOptions(data) { this.clipAction = data.clipAction; }; Evernote.ClipOptions.prototype.getClipAction = function() { return this.clipAction; };</script><script defer="" type="text/javascript" charset="ANSI">function ContentVeil() { var veil = document.createElement("div"); veil.id = "evernoteContentVeil"; var inner = document.createElement("div"); inner.id = "evernoteInnerBox"; var pageCounter = document.createElement("div"); pageCounter.id = "evernotePageCounter"; veil.appendChild(pageCounter); veil.appendChild(inner); var pageHeight = document.body.scrollHeight; // used for infinite scroll handling /* IE10 doesn't support pointer-events:none; So we had to replace existing veil with new one, combined of 8 divs. Four of them has border to outline content, and four divs in corners has white filling only. There is no any element in center, over the content, so nothing will catch mouse events. It helps other functions, especially html highlighter, works as expected. veil structure: veilNW | veilTop | veilNE veilLeft | | veilRight veilSW | veilBottom | veilSE */ var veilTop = document.createElement("div"); veilTop.id = "evernoteContentVeilTop"; var veilLeft = document.createElement("div"); veilLeft.id = "evernoteContentVeilLeft"; var veilRight = document.createElement("div"); veilRight.id = "evernoteContentVeilRight"; var veilBottom = document.createElement("div"); veilBottom.id = "evernoteContentVeilBottom"; var veilNW = document.createElement("div"); veilNW.id = "evernoteContentVeilNW"; var veilNE = document.createElement("div"); veilNE.id = "evernoteContentVeilNE"; var veilSE = document.createElement("div"); veilSE.id = "evernoteContentVeilSE"; var veilSW = document.createElement("div"); veilSW.id = "evernoteContentVeilSW"; var veilAll = Evernote.JQuery([veilTop,veilBottom,veilLeft,veilRight]); var veilCorners = Evernote.JQuery([veilNW,veilNE,veilSE,veilSW]); veilAll.addClass('EvConVeil'); veilCorners.addClass('EvConVeilCorn'); function fireClickUnderVeil(evt) { var veil = Evernote.JQuery(this); veil.hide(); var bottomElement = document.elementFromPoint(evt.clientX, evt.clientY); veil.show(); bottomElement.click(); } // make veil imperceptible for mouse clicks. veilAll.click(fireClickUnderVeil); veilCorners.click(fireClickUnderVeil); var tooltipTimeout; var topExpandContract; var bottomExpandContract; for (var i = 0; i < 2; i++) { var expand = document.createElement("div"); var contract = document.createElement("div"); expand.className = "evernoteArticleExpand"; contract.className = "evernoteArticleContract"; expand.setAttribute('tooltip', Evernote.Addin.getLocalizedMessage(Evernote.Messages.EXPAND)); expand.setAttribute('unselectable', 'on'); contract.setAttribute('tooltip',Evernote.Addin.getLocalizedMessage(Evernote.Messages.CONTRACT)); contract.setAttribute('unselectable','on'); expand.addEventListener("mousemove", nudgeMousemoveHandler); expand.addEventListener("mouseout", nudgeMouseoutHandler); contract.addEventListener("mousemove", nudgeMousemoveHandler); contract.addEventListener("mouseout", nudgeMouseoutHandler); expand.addEventListener("click", function() { Evernote.contentPreviewer.previewNudge('up'); }); contract.addEventListener("click", function() { Evernote.contentPreviewer.previewNudge('down'); }); if (i == 0) { topExpandContract = document.createElement("div"); topExpandContract.className = "evernoteExpandContract evernoteUsingExpandContract"; topExpandContract.appendChild(expand); topExpandContract.appendChild(contract); veilTop.appendChild(topExpandContract); } else { bottomExpandContract = document.createElement("div"); bottomExpandContract.id = "bottomExpandContract"; bottomExpandContract.className = "evernoteExpandContract"; bottomExpandContract.appendChild(expand); bottomExpandContract.appendChild(contract); veilBottom.appendChild(bottomExpandContract); } } function nudgeMousemoveHandler(evt) { clearTimeout(tooltipTimeout); tooltipTimeout = setTimeout(function() { evt.srcElement.className += " tooltipon"; }, 250); } function nudgeMouseoutHandler() { clearTimeout(tooltipTimeout); this.className = this.className.replace(/\s*tooltipon/g, ""); } // We keep a record of what we're currently showing (at least in some cases) so that we can update it in case the // state of the page changes (like if the user scrolls). var currentlyShownRect = null; var currentlyShownElt = null; var currentRectOffsetTop = 0; var currentRectOffsetLeft = 0; var currentlyStatic = false; var currentlyShadowBox = false; function reset(doNotResetPageCount) { currentlyShownRect = null; currentlyShownElt = null; currentRectOffsetTop = 0; currentRectOffsetLeft = 0; currentlyShadowBox = false; inner.className = inner.className.replace(/\s*evernoteShadowBox/g, ""); veil.className = inner.className.replace(/\s*evernoteShadowBox/g, ""); veilAll.removeClass('evernoteShadowBoxActi'); if (!doNotResetPageCount) { setPageCount(); } topExpandContract.className = topExpandContract.className.replace(/\s*evernoteUsingExpandContract/g, ""); bottomExpandContract.className = bottomExpandContract.className.replace(/s*evernoteUsingExpandContract/g, ""); showElements("embed"); showElements("object"); showElements("iframe"); blank(); } function blank() { veil.style.height = document.body.scrollHeight - 6 + "px"; veil.style.width = document.body.scrollWidth - 6 + "px"; veil.style.borderWidth = "0"; } function gray() { show(); inner.style.display = "none"; veil.style.backgroundColor = "rgba(255, 255, 255, 0.75)"; veilAll.each(function(){this.style.borderWidth = "0";}); veilAll.addClass('evernoteGrayFillingActi'); revealRectNew({ top:0, bottom:getPageHeight(), left:0, right:0, width:document.body.scrollWidth, height:getPageHeight() }); } function show() { inner.style.display = ""; veil.style.backgroundColor = ""; veilAll.each(function(){this.style.borderWidth = ""}); veilAll.removeClass('evernoteGrayFillingActi'); if (!Evernote.ElementExtension.hasParentNode(veil)) { document.body.appendChild(veil); veilAll.each(function(){document.body.appendChild(this)}); veilCorners.each(function(){document.body.appendChild(this)}); } } function hide() { if (Evernote.ElementExtension.hasParentNode(veil)) { veilAll.each(function(){this.parentNode.removeChild(this)}); veilCorners.each(function(){this.parentNode.removeChild(this)}); veil.parentNode.removeChild(veil); } } function isHidden() { if (Evernote.ElementExtension.hasParentNode(veil)) { return false; } return true; } // Makes a rectangle bigger in all directions by the number of pixels specified (or smaller, if 'amount' is // negative). Returns the new rectangle. function expandRect(rect, amount) { return { top: (rect.top - amount), left: (rect.left - amount), bottom: (rect.bottom + amount), right: (rect.right + amount), width: (rect.width + (2 * amount)), height: (rect.height + (2 * amount)) }; } function getPageHeight() { var h = Math.abs(window.innerHeight - document.body.scrollHeight) < 15 ? document.body.scrollHeight : Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); var wh = window.innerHeight; if ((wh - h) > 15) return wh; return h; } function revealRect(rect, elt, staticView, shadowBox) { // Save this info. currentlyShownRect = rect; currentlyShownElt = elt; currentRectOffsetTop = Evernote.Utils.scrollTop(); currentRectOffsetLeft = Evernote.Utils.scrollLeft(); currentlyStatic = staticView; currentlyShadowBox = shadowBox; // We expand the rectangle for two reasons. // 1) we want to expand it by the width of the stroke, so that when we draw out outline, it doesn't overlap our // content. // 2) We want to leave a little extra room around the content for aesthetic reasons. rect = expandRect(rect, 8); var x = rect.left; var y = rect.top; var width = rect.width; var height = rect.height; var veilWidth = veil.style.width.replace("px", ""); var veilHeight = veil.style.height.replace("px", ""); inner.className = inner.className.replace(/\s*evernoteShadowBox/g, ""); veil.className = inner.className.replace(/\s*evernoteShadowBox/g, ""); veilAll.removeClass('evernoteShadowBoxActi'); if (shadowBox) { veilAll.addClass('evernoteShadowBoxActi'); inner.className += " evernoteShadowBox"; veil.className += " evernoteShadowBox"; } inner.style.display = "block"; veil.style.borderLeftWidth = Math.max(x, 0) + "px"; veil.style.borderTopWidth = Math.max(y, 0) + "px"; veil.style.borderRightWidth = Math.max((veilWidth - x - width), 0) + "px"; veil.style.borderBottomWidth = Math.max((veilHeight - y - height), 0) + "px"; /*oh my gosh*/ var rectNew = { top:Math.max(y, 0), left:Math.max(x, 0), bottom:Math.max((veilHeight - y - height),0), right:Math.max((veilWidth - x - width),0), width:document.body.scrollWidth, height:getPageHeight() }; if (!shadowBox) { rectNew.width = rectNew.width - 4; rectNew.height = rectNew.height - 4; } else { rectNew.width = rectNew.width - 6; rectNew.height = rectNew.height - 6; } /* // debug part. function toFix(rect) { for (var prop in rect) { rect[prop] = rect[prop].toFixed(0); } return rect; } console.log('old ' + JSON.stringify(toFix(rect))); console.log('new ' + JSON.stringify(toFix(rectNew))); */ revealRectNew(rectNew); } function revealRectNew(rect) { veilLeft.style.height = rect.height - rect.bottom - rect.top + 2 + 'px'; veilLeft.style.width = rect.left + 'px'; veilLeft.style.top = rect.top -1 + 'px'; veilRight.style.height = rect.height - rect.bottom - rect.top + 2 + 'px'; veilRight.style.width = rect.right + 'px'; veilRight.style.top = rect.top - 1 + 'px'; veilRight.style.left = rect.width - rect.right + 'px'; veilTop.style.height = rect.top + 'px'; veilTop.style.left = rect.left + 'px'; veilTop.style.right = rect.right + 'px'; veilTop.style.width = rect.width - rect.right - rect.left + 'px'; veilBottom.style.height = rect.bottom + 'px'; veilBottom.style.width = rect.width - rect.right - rect.left + 'px'; veilBottom.style.left = rect.left + 'px'; veilBottom.style.right = rect.right + 'px'; veilBottom.style.top = rect.height - rect.bottom + 'px'; veilNW.style.height = Math.max(rect.top - 1, 0) + 'px'; veilNW.style.width = rect.left + 'px'; veilNE.style.height = Math.max(rect.top - 1, 0) + 'px'; veilNE.style.width = rect.right + 'px'; veilNE.style.left = rect.width - rect.right + 'px'; veilSW.style.height = Math.max(rect.bottom - 1, 0) + 'px'; veilSW.style.top = rect.height - rect.bottom + 1 + 'px'; veilSW.style.width = rect.left + 'px'; veilSE.style.height = Math.max(rect.bottom - 1, 0) + 'px'; veilSE.style.top = rect.height - rect.bottom + 1 + 'px'; veilSE.style.left = rect.width - rect.right + 'px'; veilSE.style.width = rect.right + 'px'; } function revealStaticRect(rect, elt, shadowBox) { revealRect(rect, elt, true, shadowBox); } function outlineElement(element, scrollTo, shadowBox, articleAdjustment) { // See notes in Preview.js for why we use this method instead of just calling element.getBoundingClientRect(). var rect = Evernote.contentPreviewer.computeDescendantBoundingBox(element); if (rect) { reset(articleAdjustment); revealRect(rect, element, true, shadowBox); if (scrollTo) { element.scrollIntoView(); } hideElements("embed", element); hideElements("object", element); hideElements("iframe", element); topExpandContract.className += " evernoteUsingExpandContract"; if (rect.height - 30 > window.innerHeight) { bottomExpandContract.className += " evernoteUsingExpandContract"; } else { bottomExpandContract.className = bottomExpandContract.className.replace(/\s*evernoteUsingExpandContract/g, ""); } show(); } else { Evernote.Logger.warn("Couldn't create rectangle from element: " + element.toString()); } } function hideAllActiveObjects() { hideElements("embed"); hideElements("object"); hideElements("iframe"); } function hideElements (tagName, exceptInElement) { var els = document.getElementsByTagName(tagName); for (var i = 0; i < els.length; i++) { els[i].enSavedVisibility = els[i].style.visibility; els[i].style.visibility = "hidden"; } showElements(tagName, exceptInElement); } function showElements (tagName, inElement) { if (!inElement) { inElement = document; } var els = inElement.getElementsByTagName(tagName); for (var i = 0; i < els.length; i++) { if (typeof els[i].enSavedVisibility !== "undefined") { els[i].style.visibility = els[i].enSavedVisibility; try { delete els[i].enSavedVisibility; } catch(e) { els[i].enSavedVisibility = undefined; } } } } function getElement() { return veil; } function setPageCount(count) { if (!count) { pageCounter.innerText = ""; } else if (count == 1) { //TODO: test l10n pageCounter.innerText = "oneMorePageFound"; } else { //TODO:test l10n pageCounter.innerText = "morePagesFound" + count; } pageCounter.scrollIntoView(true); } var onScrollHandle = function(e) { if (currentlyShownRect && !currentlyStatic) { var rect = { top: currentlyShownRect.top, bottom: currentlyShownRect.bottom, left: currentlyShownRect.left, right: currentlyShownRect.right, width: currentlyShownRect.width, height: currentlyShownRect.height }; var vert = Evernote.Utils.scrollTop() - currentRectOffsetTop; var horiz = Evernote.Utils.scrollLeft() - currentRectOffsetLeft; if (!vert && !horiz) { return; } rect.top -= vert; rect.bottom -= vert; rect.left -= horiz; rect.right -= horiz; blank(); revealRect(rect, currentlyShownElt); } if (pageHeight < document.body.scrollHeight - 30) { pageHeight = document.body.scrollHeight; onResizeHandle(); } }; var onResizeHandle = function(e) { if (currentlyShownElt) { var rect = Evernote.contentPreviewer.computeDescendantBoundingBox(currentlyShownElt); if (rect) { blank(); if (currentlyShadowBox) { revealRect(rect, currentlyShownElt, true, true); } else { revealRect(rect, currentlyShownElt, true, false); } } } // todo: switch gray filling to position:fixed. if (veilAll.hasClass('evernoteGrayFillingActi')) { gray(); } }; window.addEventListener("resize", onResizeHandle); window.addEventListener("scroll", onScrollHandle, false); // Public API: this.reset = reset; this.show = show; this.gray = gray; this.hide = hide; this.revealRect = revealRect; this.revealStaticRect = revealStaticRect; this.outlineElement = outlineElement; this.expandRect = expandRect; this.hideAllActiveObjects = hideAllActiveObjects; }</script><script defer="" type="text/javascript" charset="ANSI">/** * Created by chizhikov on 11.04.14. */ function ScreenshotVeil() { var areaEl = document.createElement('div'); areaEl.id = 'evernoteScreenShotArea'; var startX, startY = 0; var global_tools = Evernote.JQuery('#' + Constants.CLIP_DIALOG_ID); var area = Evernote.JQuery(areaEl); var selecting = false; var startVertLine = document.createElement('div'); var startHorizLine = document.createElement('div'); startVertLine.className = 'screenAreaStartVertLine'; startHorizLine.className = 'screenAreaStartHorizLine'; var borderDiv = document.createElement('div'); borderDiv.id = 'screenAreaSelected'; areaEl.appendChild(startVertLine); areaEl.appendChild(startHorizLine); areaEl.appendChild(borderDiv); function sendMessageToPopup( msg ){ // send message to global tools var zoomModifier = screen.deviceXDPI / screen.logicalXDPI; with (borderDiv.style) { var topX = pixelLeft * zoomModifier; var topY = pixelTop * zoomModifier; var bottomX = (area.width() - pixelRight) * zoomModifier; var bottomY = (area.height() - pixelBottom) * zoomModifier; } // If any side of the rectangle that user is drawing is smaller than 16px then we interpret it as a // single click and should make a fullscreen capture. var rectWidth = Math.abs(topX - bottomX); var rectHeight = Math.abs(topY - bottomY); if (rectWidth < 16 || rectHeight < 16) { topX = 0; topY = 0; bottomX = area.width(); bottomY = area.height(); } global_tools.trigger(msg ,[topX,topY , bottomX, bottomY]); } function drawLines(e) { startVertLine.style.pixelLeft = e.clientX; startHorizLine.style.pixelTop = e.clientY; if (selecting) { drawRect(startX, startY, e.clientX, e.clientY); // TODO: prevent selection } } function drawRect( startX, startY, mouseX, mouseY) { var topX, topY, bottomX, bottomY; topX = Math.min(startX, mouseX); topY = Math.min(startY, mouseY); bottomX = Math.max(startX, mouseX); bottomY = Math.max(startY, mouseY); borderDiv.style.pixelTop = topY; borderDiv.style.pixelLeft = topX; borderDiv.style.pixelRight = area.width() - bottomX - 1; borderDiv.style.pixelBottom = area.height() - bottomY -1; } function clearSelectedAreaPosition() { borderDiv.style.pixelRight = ''; borderDiv.style.pixelBottom = ''; borderDiv.style.pixelTop = ''; borderDiv.style.pixelLeft = ''; selecting = false; } function startSelectArea(e) { if (e.button != 0) return; if (Evernote.JQuery(e.target).closest('#' + Constants.CLIP_DIALOG_NEW_ID).length == 0) { selecting = true; startX = e.clientX; startY = e.clientY; } e.preventDefault(); } function selectionEnd(e) { if (!selecting) return; if (Evernote.JQuery(e.target).closest('#cancelButton').length == 0 && Evernote.JQuery(e.target).closest('#closeSidebar').length == 0 ) { sendMessageToPopup('readyToScreenshot'); } else { sendMessageToPopup('cancelScreenshot'); } hide(); clearSelectedAreaPosition(); } function disableContextMenu(e) { e.preventDefault(); return false; } function show() { document.addEventListener('mousemove', drawLines); document.addEventListener('mousedown', startSelectArea); document.addEventListener('mouseup', selectionEnd); document.addEventListener('contextmenu', disableContextMenu); // TODO: remove scroll from page area.addClass('visible'); Evernote.JQuery('body').css('overflow','hidden'); } function hide() { area.removeClass('visible'); clearSelectedAreaPosition(); document.removeEventListener('mousemove', drawLines); document.removeEventListener('mousedown', startSelectArea); document.removeEventListener('mouseup', selectionEnd); document.removeEventListener('contextmenu', disableContextMenu); Evernote.JQuery('body').css('overflow','visible'); } document.body.appendChild(areaEl); this.show = show; this.hide = hide; }</script><script defer="" type="text/javascript" charset="ANSI">function PageInfo() { var newPageCallback; // This is a map of hostnames (for hostnames that begin with 'www.', the 'www.' will be stripped off first, so don't // include it in your lookup string) to CSS selectors. When we try and locate an article in a page, we'll see if we // can find the doamin for the page in this list, and if so, we'll try and find an element that matches the given // selector. If no element is returned, we'll fall back to the heuristic approach. var specialCases = { "penny-arcade.com": "div.contentArea > div.comic > img", "aspicyperspective.com": "div.entry-content", "thewirecutter.com": "div#content", "katespade.com": "div#pdpMain", "threadless.com": "section.product_section", "yelp.com": "div#bizBox", "flickr.com": "div#photo", "instagr.am": "div.stage > div.stage-inner", "stackoverflow.com": "div#mainbar", "makeprojects.com": "div#guideMain", "cookpad.com": "div#main", "imgur.com": "div.image", "smittenkitchen.com": "div.entry", "allrecipes.com": "div#content-wrapper", "qwantz.com": "img.comic", "questionablecontent.net": "img#strip", "cad-comic.com": "div#content" } var useFoundImage = [ "xkcd.com" ] // These are the items we're trying to collect. This first block is trivial. var containsImages = Boolean(document.getElementsByTagName("img").length > 0); var documentWidth = document.width; var documentHeight = document.height; var documentMode = document.documentMode; var url = document.location.href; // Very slow and useless assignment, takes more than a second. Temporary commented for speed up [actimind] // var documentLength = document.body.textContent ? document.body.textContent.length : 0; // These take slightly more work and are initialized only when requested. var article = null; var cleanArticles = []; var articleBoundingClientRect = null; var selection = false; // This is easy to get, but is always "false" at load time until the user selects something. var selectionIsInFrame = false; var documentIsFrameset = false; var selectionFrameElement = null; var recommendationText = null; // Internal state variables to keep us duplicating work. var hasCheckedArticle = false; // Experimental recognition of 'image' pages (like photo sites and comics). function findImage() { var imgs = document.getElementsByTagName("img"); var biggest = null; var biggestArea = 0; for (var i = 0; i < imgs.length; i++) { var style = Evernote.ElementExtension.getComputedStyle(imgs[i]); var width = style.width.replace(/[^0-9.-]/g, ""); var height = style.height.replace(/[^0-9.-]/g, ""); var area = width * height; if (!biggest || area > biggestArea) { biggest = imgs[i]; biggestArea = area; } } return biggest; } function getAncestors(node) { var an = []; while (node) { an.unshift(node); node = node.parentNode; } return an; } function getDeepestCommonNode(nodeList1, nodeList2) { var current = null; for (var i = 0; i < nodeList1.length; i++) { if (nodeList1[i] === nodeList2[i]) { current = nodeList1[i]; } else { break; } } return current; } function getCommonAncestor(nodeList) { if (!nodeList.length) return null; if (nodeList.length == 1) return nodeList[0]; var lastList = getAncestors(nodeList[0]); var node = null; for (var i = 1; i < nodeList.length; i++) { var list = getAncestors(nodeList[i]); node = getDeepestCommonNode(lastList, list); lastList = getAncestors(node); } return node; } function clearlyCallback(data, callback) { Evernote.Logger.debug("Clearly callback invoked"); findImage(); // See if we should special-case this. var host = getHostname(); if (specialCases[host]) { var candidate = Evernote.ElementExtension.querySelector(specialCases[host]); if (candidate) { Evernote.Logger.debug("Found article in specialCases"); article = candidate; articleBoundingClientRect = Evernote.ElementExtension.getBoundingClientRect(article); } } // Or see if it's a special case image page. else if (Evernote.ArrayExtension.indexOf(useFoundImage, host) != -1) { article = findImage(); if (article) { Evernote.Logger.debug("Found article in image"); articleBoundingClientRect = Evernote.ElementExtension.getBoundingClientRect(article); } } // If it's not a special case, see if it's a single image. if (!article) { var imageTypes = ['jpeg', 'jpg', 'gif', 'png']; var urlExtension = document.location.href.replace(/^.*\.(\w+)$/, "$1"); if (urlExtension && (Evernote.ArrayExtension.indexOf(imageTypes, urlExtension) != -1)) { var candidate = Evernote.JQuery("body > img"); if (candidate.length > 0) { Evernote.Logger.debug("Found article in a single image"); article = candidate.get(0); articleBoundingClientRect = Evernote.ElementExtension.getBoundingClientRect(article); } } } // If we still didn't find an article, let's see if maybe it's in a frame. Cleary fails on frames so we try this // check before we use our clearly info. if (!article) { if (document.body.nodeName.toLowerCase() == "frameset") { documentIsFrameset = true; var frame = findBiggestFrame(); if (frame && frame.contentDocument && frame.contentDocument.documentElement) { selectionFrameElement = frame; article = frame.contentDocument.documentElement; articleBoundingClientRect = Evernote.ElementExtension.getBoundingClientRect(article); } } } // If we didn't use any of our special case handling, we'll use whatever clearly found. if (!article) { Evernote.Logger.debug("Use clearly find article"); if (data && data._elements && data._elements.length) { article = data._elements[0]; if (data._elements.length > 1) { // This will include *all* clearly elements (and whatever else in in between them). article = getCommonAncestor(data._elements); // This includes *just the last (and therefore most important)* element from the clearly detection. // article = data._elements[data._elements.length - 1]; } if (article.nodeType === ( window.Node ? window.Node.TEXT_NODE : 1)) { article = article.parentNode; } } } if(article) { if(Evernote.JQuery(article).closest("#evernote-content").length != 0) article = undefined; } // If clearly found nothing (because it failed), then use the body of the document. if (!article) { article = document.body; } hasCheckedArticle = true; callback(); } // This will try and determine the 'default' page article. It will only run once per page, but it's specifically // called only on demand as it can be expensive. function findArticle(callback) { function afterInject() { // If we'd previously computed an article element, but it's lost its parent or become invisible, then we'll try // and re-compute the article. This can happen if, for example the page dynamically udaptes itself (like showing // the latest news article in a box that updates periodically). This doesn't guarantee that we clip something // sane if this happens, (if the page re-writes itself while a clip is taking place, the results are // indeterminate), but it will make such things less likely. if (article && (!article.parentNode || !article.getBoundingClientRect || Evernote.ElementExtension.getBoundingClientRect(article).width == 0)) { article = null; hasCheckedArticle = false; } Evernote.Logger.debug("afterInject"); if (!hasCheckedArticle) { Evernote.Logger.debug("no article"); if (!window) { Evernote.Logger.warn("Couldn't find clearly!"); clearlyCallback(null, callback); } else { Evernote.Logger.debug("Call clearly to select article"); try { Evernote.ClearlyController.getContentElementAndHTML(function(data){clearlyCallback(data, callback)}); } catch(e) { Evernote.Logger.error("Failed to find article by clearly due to error " + e.message); clearlyCallback(null, callback); } } } // If the page is big enough, clearly is excruciatingly slow. We'll just get the whole page. // TODO: Clearly was updated. Check, if big pages are still problem else if (document.body.innerHTML.length > (1024 * 1024)) { Evernote.Logger.warn("Page over 1mb, skipping article detection."); clearlyCallback(null, callback); } else { Evernote.Logger.debug("callback"); callback(); } } afterInject(); } function findBiggestFrame() { var frames = document.getElementsByTagName("frame"); var candidate = null; var candidateSize = 0; for (var i = 0; i < frames.length; i++) { if (frames[i].width && frames[i].height) { var area = frames[i].width * frames[i].height; if (area > candidateSize) { candidate = frames[i]; candidateSize = area; } } } return candidate; } function getHostname() { var match = document.location.href.match(/^.*?:\/\/(www\.)?(.*?)(\/|$)/); if (match) { return match[2]; } return null; } function getDefaultArticle(callback) { Evernote.Logger.debug("getDefaultArticle"); findArticle(function(){callback(article)}); // Article already exists, so we'll return it. if (article) return article; } function getBiggestImage(callback) { getDefaultArticle(function(art) { var imgs; if (art) { imgs = art.querySelectorAll("img"); } else { imgs = document.querySelectorAll("img"); } var maxHeight = 0; var maxWidth = 0; var maxImage; for (var i = 0; i < imgs.length; i++) { var w = imgs.item(i).width; var h = imgs.item(i).height; if (w * h > maxWidth * maxHeight) { maxHeight = h; maxWidth = w; maxImage = imgs.item(i).src; } } callback({ src: maxImage, width: maxWidth, height: maxHeight }); }); } // Looks for selections in the current document and descendent (i)frames. // Returns the *first* non-empty selection. function getSelection() { // First we check our main window and return a selection if that has one. var selection = window.getSelection(); if (selection && selection.rangeCount && !selection.isCollapsed) { return selection; } // Then we'll try our frames and iframes. var docs = []; var iframes = document.getElementsByTagName("iframe"); for (var i = 0; i < iframes.length; i++) { docs.push(iframes[i]); } var frames = document.getElementsByTagName("frame"); for (var i = 0; i < frames.length; i++) { docs.push(frames[i]); } var urlBase = document.location.href.replace(/^(https?:\/\/.*?)\/.*/i, "$1").toLowerCase(); for (var i = 0; i < docs.length; i++) { // If frames/iframes fail a same origin policy check, then they'll through annoying errors, and we wont be able // to access them anyway, so we attempt to skip anything that wont match. if (docs[i].src && docs[i].src.toLowerCase().substr(0, urlBase.length) !== urlBase) { continue; } var doc = docs[i].contentDocument; if (doc) { var frameSelection = doc.getSelection(); if (frameSelection && frameSelection.rangeCount && !frameSelection.isCollapsed) { selectionIsInFrame = true; selectionFrameElement = docs[i]; return frameSelection; } } else { Evernote.Logger.warn("iframe contained no Document object."); } } // Didn't find anything. return null; } function getUrl() { return url; } function getText(node, soFar, maxLen) { if (node.nodeType == Evernote.Node.TEXT_NODE) { var trimmed = (node.textContent) ? Evernote.JQuery.trim(node.textContent).replace(/\s+/g, " ") : ""; if (trimmed === " " || trimmed === "") return soFar; return soFar + " " + trimmed; } var banned = [ "style", "script", "noscript" ]; if (node.nodeType == Evernote.Node.ELEMENT_NODE) { if (Evernote.ArrayExtension.indexOf(banned, node.nodeName.toLowerCase()) == -1) { for (var i = 0; i < node.childNodes.length; i++) { soFar = getText(node.childNodes[i], soFar, maxLen); if (soFar.length > maxLen) { return soFar; } } } } return soFar; } function getRecommendationText() { var text = ""; var MAX_LEN = 5000; var selection = getSelection(); if (selection) { var df = selection.getRangeAt(0).cloneContents(); var div = document.createElement("div"); div.appendChild(df); text = getText(div, "", MAX_LEN); } else if (article) { text = getText(article, "", MAX_LEN); } else { text = getText(document.body, "", MAX_LEN); } text = document.title + " " + text; return text; } // Note: you must call getSelection() first to populate this field! function getSelectionFrame() { return selectionFrameElement; } function checkClearly() { var clearlyDoc = Evernote.ElementExtension.querySelector("iframe#readable_iframe"); if (clearlyDoc) clearlyDoc = clearlyDoc.contentDocument; if (clearlyDoc) clearlyDoc = Evernote.ElementExtension.querySelector("body#body div#box", clearlyDoc); if (clearlyDoc) { article = clearlyDoc; articleBoundingClientRect = Evernote.ElementExtension.getBoundingClientRect(article); } } // @TODO: This is fairly incomplete. function getFavIconUrl() { var links = document.getElementsByTagName("link"); var i; for (i = 0; i < links.length; i++) { if (links[i].rel) { var rels = links[i].rel.toLowerCase().split(/\s+/); if (Evernote.ArrayExtension.indexOf(rels, "icon") !== -1) { // Found it! return links[i].href; } } } return null; } function _getInfoRequestHandler(data, request, sender, sendResponse) { var isSelected = getSelection(); checkClearly(); var response = { containsImages: containsImages, documentWidth: documentWidth, documentHeight: documentHeight, url: url, selection: (isSelected !== null), selectionIsInFrame: selectionIsInFrame, documentLength: document.body.textContent.length, articleBoundingClientRect: articleBoundingClientRect, article: (article != null), recommendationText: getRecommendationText(), favIconUrl: getFavIconUrl(), documentIsFrameset: documentIsFrameset }; sendResponse(response); } function getInfoRequestHandler(request, sender, sendResponse) { findArticle(function(data){_getInfoRequestHandler(data, request, sender, respondWithInfo)}); } function getDocumentMode() { return documentMode; } function getCleanArticle(callback, _newPageCallback) { newPageCallback = _newPageCallback; findArticle(function() { callback(cleanArticles); }); } // Public API: this.getDefaultArticle = getDefaultArticle; this.getSelection = getSelection; this.getSelectionFrame = getSelectionFrame; this.getFavIconUrl = getFavIconUrl; //redesign this.getBiggestImage = getBiggestImage; this.getRecommendationText = getRecommendationText; this.getCleanArticle = getCleanArticle; this.getText = getText; this.getUrl = getUrl; this.getDocumentMode = getDocumentMode; }</script><script defer="" type="text/javascript" charset="ANSI">Evernote.Scroller = function Scroller( tab ) { this.initialize( tab ); }; Evernote.Scroller.prototype._tab = null; Evernote.Scroller.prototype.initialize = function ( tab ) { this._tab = tab; var scrollX = (this._tab.pageXOffset !== undefined) ? this._tab.pageXOffset : (this._tab.document.documentElement || this._tab.document.body.parentNode ||this._tab.document.body).scrollLeft; var scrollY = (this._tab.pageYOffset !== undefined) ? this._tab.pageYOffset : (this._tab.document.documentElement || this._tab.document.body.parentNode || this._tab.document.body).scrollTop; this.initialPoint = { x: scrollX, y: scrollY }; }; Evernote.Scroller.prototype.scrollTo = function ( endPoint, time, resolution ) { this.abort(); this.endPoint = endPoint; this.step = 0; this.calculatePath( time, resolution ); var self = this; this.proc = setInterval( function () { if ( !self.doScroll() ) { self.abort(); } }, resolution ); }; Evernote.Scroller.prototype.calculatePath = function ( time, resolution ) { this.path = []; var sx = this.initialPoint.x; var sy = this.initialPoint.y; var ex = this.endPoint.x; var ey = this.endPoint.y; var k = (Math.PI * resolution) / time; for ( var i = -(Math.PI / 2); i < (Math.PI / 2); i += k ) { var c = ((1 + Math.sin( i )) / 2); this.path.push( { x:(sx + c * (ex - sx)), y:(sy + c * (ey - sy)) } ); } }; Evernote.Scroller.prototype.doScroll = function () { var s = this.path[++this.step]; if ( !s ) { return false; } var view = this._tab.document.defaultView || this._tab; view.scrollTo( s.x, s.y ); return true; }; Evernote.Scroller.prototype.abort = function () { if ( this.proc ) { clearInterval( this.proc ); this.proc = null; } };</script><script defer="" type="text/javascript" charset="ANSI">function ContentPreview() { Evernote.Logger.debug("Start creating preview box"); var contentVeil = new ContentVeil(); var screenshotVeil = new ScreenshotVeil(); Evernote.Logger.debug("End creating preview box"); // Stores a reference to the last element that we used as a preview. var previewElement = null; var article = null; var snippet = null; function buildUrlElement() { var urlEl = document.createElement("div"); urlEl.id = "evernotePreviewContainer"; var className = "yui3-cssreset"; if(Evernote.Utils.isQuirkMode()) { className += " evernote-middle-fixed-position-quirks" } urlEl.className = className; return urlEl; } Evernote.Logger.debug("Build url element"); var urlElement = buildUrlElement(); function showUrlElement() { Evernote.Logger.debug("ContentPreview: showUrlElement start"); if (!Evernote.ElementExtension.hasParentNode(urlElement)) { document.documentElement.appendChild(urlElement); } // Make sure we're centered in the window. var elStyle = Evernote.ElementExtension.getComputedStyle(urlElement, ''); var w = parseInt(Evernote.StyleElementExtension.getPropertyValue(elStyle, "width")); var h = parseInt(Evernote.StyleElementExtension.getPropertyValue(elStyle, "height")); if (isNaN(w) || isNaN(h)) { // IE8 w = Evernote.JQuery(urlElement).width(); h = Evernote.JQuery(urlElement).height(); } if (w && h) { urlElement.style.marginLeft = (0 - w / 2) + "px"; urlElement.style.marginTop = (0 - h / 2) + "px"; } Evernote.Logger.debug("ContentPreview: showUrlElement end"); } function hideUrlElement() { if (Evernote.ElementExtension.hasParentNode(urlElement)) { urlElement.parentNode.removeChild(urlElement); } } function showScreenShotArea() { clear(); screenshotVeil.show(); } function showOverlay() { previewElement = null; clear(); contentVeil.reset(); contentVeil.hideAllActiveObjects(); contentVeil.gray(); } function previewUrl() { clear(); function buildContent ( data ) { var title = PageContext.title; var url = PageContext.url; var favIconUrl = PageContext.getFavIconUrl(); snippet = data.replace(/(<([^>]+)>)/ig,""); // remove html tags from text urlElement.innerHTML = Evernote.GlobalUtils.createUrlClipContent(title, url, favIconUrl, snippet); var element = Evernote.JQuery(urlElement); if(Evernote.Utils.isQuirkMode() && !element.hasClass("evernote-fixed-position-fix")) { element.addClass("evernote-fixed-position-fix"); } showUrlElement(); contentVeil.reset(); contentVeil.hideAllActiveObjects(); contentVeil.gray(); } Evernote.ClearlyController.getClearlyArticleText( function (data) { buildContent(data._html); }); } // This doesn't remove internal state of previewElement, because another script may not have finished clipping until // after the page looks 'clear'. function clear() { contentVeil.reset(); contentVeil.hide(); screenshotVeil.hide(); hideUrlElement(); } function _previewArticle () { Evernote.Logger.debug("Start previewing article element"); if (previewElement) { var selectionFrame; if (typeof Evernote.pageInfo !== undefined) { selectionFrame = Evernote.pageInfo.getSelectionFrame(); } Evernote.Logger.debug("Selection frame selected " + selectionFrame); if (selectionFrame) { var rect = { width: selectionFrame.width, height: selectionFrame.height, top: selectionFrame.offsetTop, bottom: (selectionFrame.height + selectionFrame.offsetTop), left: selectionFrame.offsetLeft, right: (selectionFrame.width + selectionFrame.offsetLeft) }; Evernote.Logger.debug("contentVeil.revealStaticRect " + rect); contentVeil.revealStaticRect(contentVeil.expandRect(rect, -9), selectionFrame, true); Evernote.Logger.debug("contentVeil.show "); contentVeil.show(); } else { // TODO: Scroll into article view. contentVeil.outlineElement(previewElement, false, true); window.scrollTo(0, previewElement.offsetTop - 30); } } else { Evernote.Logger.warn("Couldn't find a preview element. We should switch to 'full page' mode."); } } /** * Finds and preview article element. * If reloadArticle is specified and equals to true, then discard previously found article and re-start search of article again. * Otherwise use article found on previous call (if this is the first call then article will be searched anyway). * @param reloadArticle */ function previewArticle (reloadArticle) { clear(); previewElement = null; if(reloadArticle) { article = null; } Evernote.Logger.debug("Evernote.pageinfo " + Evernote.pageInfo); if (typeof Evernote.pageInfo !== undefined) { if(!article) { previewElement = Evernote.pageInfo.getDefaultArticle(function(el){ Evernote.Logger.debug("Article element " + el.nodeName); previewElement = el; article = el; Evernote.Logger.debug("Preview article "); _previewArticle(); }); article = previewElement; } else { previewElement = article; _previewArticle(); } } else { Evernote.Logger.warn("Couldn't find a 'pageInfo' object."); } } // When nudging the preview around the page, we want to skip nodes that aren't interesting. This includes empty // nodes, containers that have identical contents to the already selected node, invisible nodes, etc. // @TODO: There's a lot more we could probably add here. function looksInteresting(candidate, given) { if (!candidate) { Evernote.Logger.warn("Can't determine if 'null' is interesting (it's probably not)."); return false; } // This is the parent of our 'HTML' tag, but has no tag itself. There's no reason it's ever more interesting than // the HTML element. if (candidate === window.document) { return false; } //Disable clip of evernote main popup if(Evernote.JQuery(candidate).closest("#evernote-content").length != 0) { return false; } // Elements with neither text nor images are not interesting. if (!candidate.textContent && (candidate.getElementsByTagName("img").length === 0)) { return false; } // Elements with 0 area are not interesting. var rect = Evernote.ElementExtension.getBoundingClientRect(candidate); if (!rect.width || !rect.height) { return false; } // Invisible elements are not interesting. var style = Evernote.ElementExtension.getComputedStyle(candidate); if ((style.visibility === "hidden") || (style.display === "none")) { return false; } // If the nodes have a parent/child relationship, then they're only interesting if their visible contents differ. if (candidate.parentNode && given.parentNode) { if ((candidate.parentNode == given) || (given.parentNode == candidate)) { if ((candidate.textContent === given.textContent) && (candidate.getElementsByTagName("img").length === given.getElementsByTagName("img").length)) { return false; } } } return true; } // Returns the current article element, which may not be the same as the auto-detected one if the user has 'nudged' // the selection around the page. function getArticleElement() { return previewElement; } function nudgePreview(direction) { Evernote.Logger.debug("nudgePreview start"); if (!previewElement) { return; } var oldPreview = previewElement; Evernote.Logger.debug("nudgePreview: direction is " + direction); Evernote.Logger.debug("nudgePreview: previewElement is " + previewElement.nodeName); switch (direction) { case "up": var temp = previewElement.parentNode; while (temp) { if (looksInteresting(temp, previewElement)) { // If we move up and then down, we want to move back to where we started, not the first child. temp.enNudgeDescendToNode = previewElement; previewElement = temp; break; } temp = temp.parentNode; } break; case "down": Evernote.Logger.debug("nudgePreview: previewElement.enNudgeDescendToNode is " + previewElement.enNudgeDescendToNode); if (previewElement.enNudgeDescendToNode) { var temp = previewElement.enNudgeDescendToNode; // @TODO: make sure we clean these up somewhere else if we never reverse our nudging. try { delete previewElement.enNudgeDescendToNode; } catch(e) { previewElement.enNudgeDescendToNode = undefined; } previewElement = temp; } else { previewElement = descendTreeUntilUniqueElement(previewElement); } break; Evernote.Logger.debug("nudgePreview: previewElement.children.length = " + previewElement.children.length); for (var i = 0; i < previewElement.children.length; i++) { Evernote.Logger.debug("nudgePreview: checking child is " + previewElement.children[i].nodeName); if (looksInteresting(previewElement.children[i], previewElement)) { Evernote.Logger.debug("nudgePreview: found interesting child" + previewElement.children[i]); previewElement = previewElement.children[i]; break; } } break; case "left": var temp = previewElement.previousElementSibling; while (temp) { if (looksInteresting(temp, previewElement)) { previewElement = temp; break; } temp = temp.previousElementSibling; } break; case "right": var temp = previewElement.nextElementSibling; while (temp) { if (looksInteresting(temp, previewElement)) { previewElement = temp; break; } temp = temp.nextElementSibling; } break; default: Evernote.Logger.warn("Unhandled nudge direction: " + direction); } // Drawing is expensive so don't bother if nothing changed. if (oldPreview !== previewElement) { Evernote.Logger.debug("nudgePreview: draw new element."); function enoughSize(elem) { var el = Evernote.JQuery(elem); var w = el.width(); var h = el.height(); return (w > 30 && h > 15) } // if (enoughSize(previewElement) === false) return; contentVeil.outlineElement(previewElement, false, true, true); article = previewElement; // TODO: scroll into Element view here (probably, attach to Expand/Contract Container window.scrollTo(0, previewElement.offsetTop - 30); } } function sameElement(a, b) { var aRect = a.getBoundingClientRect(); var bRect = b.getBoundingClientRect(); if (aRect.bottom == bRect.bottom && aRect.height == bRect.height && aRect.left == bRect.left && aRect.right == bRect.right && aRect.top == bRect.top && aRect.width == bRect.width) { return false; } else if ((a.textContent === b.textContent) && (a.getElementsByTagName("img").length === b.getElementsByTagName("img").length)) { return false; } } function descendTreeUntilUniqueElement(parent) { for (var i = 0; i < parent.children.length; i++) { if (sameElement(parent.children[i], parent)) { return descendTreeUntilUniqueElement(parent.children[i]); } else if (looksInteresting(parent.children[i], parent)) { return parent.children[i]; } } return parent; } function previewFullPage() { var borderWidth = 4; var w = document.documentElement.scrollWidth; var h = document.documentElement.scrollHeight; var rect = { bottom: (h - borderWidth), top: (borderWidth), left: (borderWidth), right: (w - borderWidth), width: (w - (2 * borderWidth)), height: (h - (2 * borderWidth)) }; clear(); contentVeil.reset(); contentVeil.revealStaticRect(rect, document.body); contentVeil.show(); contentVeil.hideAllActiveObjects(); } // Creates the union of two rectangles, which is defined to be the smallest rectangle that contains both given // rectangles. function unionRectangles(rect1, rect2) { var rect = { top: (Math.min(rect1.top, rect2.top)), bottom: (Math.max(rect1.bottom, rect2.bottom)), left: (Math.min(rect1.left, rect2.left)), right: (Math.max(rect1.right, rect2.right)) } rect.width = rect.right - rect.left; rect.height = rect.bottom - rect.top; return rect; } // Returns true if the rectangles match, false otherwise. function rectanglesEqual(rect1, rect2) { if (!rect1 && !rect2) return true; if (!rect1) return false; if (!rect2) return false; if (rect1.top != rect2.top) return false; if (rect1.bottom != rect2.bottom) return false; if (rect1.left != rect2.left) return false; if (rect1.right != rect2.right) return false; if (rect1.width != rect2.width) return false; if (rect1.height != rect2.height) return false; return true; } // If the user triple-clicks a paragraph, we will often get a selection that includes the next paragraph after the // selected one, but only up to offset 0 in that paragraph. This causes the built in getBoundingClientRect to give a // box that includes the whole trailing paragraph, even though none of it is actually selected. Instead, we'll build // our own bounding rectangle that omits the trailing box. // @TODO: Currently this computes a box that is *too big* if you pass it a range that doesn't have start and/or end // offsets that are 0, because it will select the entire beginning and ending node, instead of jsut the selected // portion. function computeAlternateBoundingBox(range) { // If the end of selection isn't at offset 0 into an element node (rather than a text node), then we just return the // original matching rectangle. if ((range.endOffset !== 0) || (range.endContainer && range.endContainer.nodeType !== Evernote.Node.ELEMENT_NODE) || ( range.startContainer && range.startContainer && range.startContainer.getBoundingClientRect) || ( range.endContainer && range.endContainer.getBoundingClientRect) || ( range.commonAncestorContainer && range.commonAncestorContainer.getBoundingClientRect) ) { var rect = range.getBoundingClientRect(); if(rect.top == 0 && rect.bottom == 0 && rect.left == 0 && rect.right == 0) { if(range.commonAncestorContainer && range.commonAncestorContainer.getBoundingClientRect) { rect = range.commonAncestorContainer.getBoundingClientRect(); } else if(range.startContainer && range.startContainer.getBoundingClientRect) { rect = range.startContainer.getBoundingClientRect(); } else if(range.endContainer && range.endContainer.getBoundingClientRect) { rect = range.endContainer.getBoundingClientRect(); } } var mutableRect = { top: rect.top, bottom: rect.bottom, left: rect.left, right: rect.right, width: rect.width, height: rect.height }; return mutableRect; } // This is the one we don't want. var endElementRect = null; try { endElementRect = Evernote.ElementExtension.getBoundingClientRect(range.endContainer); } catch(ex) { Evernote.Logger.warn("Couldn't get a bounding client rect for our end element, maybe it's a text node."); } // We look for a rectangle matching our end element, and if we find it, we don't copy it to our list to keep. // You'd think we could just grab the last element in range.getClientRects() here and trim that one, which might be // true, but the spec makes no claim that these are returned in order, so I don't want to rely on that. // We keep track if we remove a rectangle, as we're only trying to remove one for the trailnig element. If there are // more than one matching rectangle, we want to keep all but one of them. var foundEnd = false; var keptRects = []; var initialRects = range.getClientRects(); for (var i = 0; i < initialRects.length; i++) { if (rectanglesEqual(endElementRect, initialRects[i]) && !foundEnd) { foundEnd = true; } else { keptRects.push(initialRects[i]); } } // Now compute our new bounding box and return that. if (keptRects.length == 0) return Evernote.ElementExtension.getBoundingClientRect(range); if (keptRects.length == 1) return keptRects[0]; var rect = keptRects[0]; for (var i = 1; i < keptRects.length; i++) { rect = unionRectangles(rect, keptRects[i]); } return rect; } // If every edge of the rectangle is in negative space, function rectIsOnScreen(rect) { // rtl pages have actual content in "negative" space. This case could be handled better. if (document.dir == "rtl") { return false; } // If both top and bottom are in negative space, we can't see this. if (rect.bottom < 0 && rect.top < 0) { return false; } // Or, if both left and right are in negative space, we can't see this. if (rect.left < 0 && rect.right < 0) { return false; } // Probably visible. return true; } function applyElementRect(element, rect) { var newRect = rect; var tempRect = Evernote.ElementExtension.getBoundingClientRect(element); tempRect = { bottom: tempRect.bottom + window.pageYOffset, height: tempRect.height, left: tempRect.left + window.pageXOffset, right: tempRect.right + window.pageXOffset, top: tempRect.top + window.pageYOffset, width: tempRect.width }; // Skip elements that are positioned off screen. if (!rectIsOnScreen(tempRect)) { return newRect; } var cs = getComputedStyle(element); // We won't descend into hidden elements. if (cs.display == "none") { return newRect; } // don't union a big rectangle that has hidden overflow if (cs.overflowX == "hidden" || cs.overflowY == "hidden") { return newRect; } // We skip anything with an area of one px or less. This is anything that has "display: none", or single pixel // images for loading ads and analytics and stuff. Most hidden items end up at 0:0 and will stretch our rectangle // to the top left corner of the screen if we include them. Sometimes single pixels are deliberately placed off // screen. if ((tempRect.width * tempRect.height) > 1) { newRect = unionRectangles(tempRect, rect); } if (element.children) { for (var i = 0; i < element.children.length; i++) { newRect = applyElementRect(element.children[i], newRect); } } return newRect; } // In the case of positioned elements, a bounding box around an element doesn't necessarily contain its child // elements, so we have this method to combine all of these into one bigger box. ContentVeil calls this function. function computeDescendantBoundingBox(element) { if (!element) return {top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0}; var rect = element.getBoundingClientRect(); var li = rect.top + window.pageYOffset return applyElementRect(element, { bottom: rect.bottom + window.pageYOffset, height: rect.height, left: rect.left + window.pageXOffset, right: rect.right + window.pageXOffset, top: rect.top + window.pageYOffset, width: rect.width }); } function previewSelection(sel) { var selection; var selectionFrame; if(sel) { selection = sel; } else if (typeof Evernote.pageInfo !== undefined) { selection = Evernote.pageInfo.getSelection(); // If our selection is in a frame or iframe, we'll compute an offset relative to that, so we need to adjust it by // the offset of the frame. selectionFrame = Evernote.pageInfo.getSelectionFrame(); } contentVeil.reset(); var frameRect = null; if (selectionFrame) { frameRect = Evernote.ElementExtension.getBoundingClientRect(selectionFrame); } var range, rect, i; // If !selection, then something has gone awry. if (selection) { clear(); contentVeil.reset(); // We attempt to highlight each selection, but this hasn't been tested for more than a single selection. for (i = 0; i < Evernote.Utils.Selection.getRangeCount(selection); i++) { range = Evernote.Utils.Selection.getRangeAt(selection, i); rect = computeAlternateBoundingBox(range); rect.top += document.documentElement.scrollTop; rect.bottom += document.documentElement.scrollTop; rect.left += document.documentElement.scrollLeft; rect.right += document.documentElement.scrollLeft; // Actual adjustment mentioned earlier regarding frames. if (frameRect) { rect.left += frameRect.left; rect.right += frameRect.left; rect.top += frameRect.top; rect.bottom += frameRect.top; } contentVeil.revealStaticRect(rect, selectionFrame, false); contentVeil.show(); } } contentVeil.show(); contentVeil.hideAllActiveObjects(); } function getSnippetText() { return snippet; } // Public API: this.getArticleElement = getArticleElement; this.looksInteresting = looksInteresting; this.computeDescendantBoundingBox = computeDescendantBoundingBox; this.previewArticle = previewArticle; this.previewFullPage = previewFullPage; this.previewSelection = previewSelection; this.previewUrl = previewUrl; this.clear = clear; this.previewNudge = nudgePreview; this.showOverlay = showOverlay; this.getSnippetText = getSnippetText; this.showScreenShotArea = showScreenShotArea; }</script><script defer="" type="text/javascript" charset="ANSI">Evernote.ElementExtension = { querySelector : function(selector, doc) { if(!doc) { doc = document; } if(doc.querySelector) { return doc.querySelector(selector); } else { var head = doc.documentElement.firstChild; var styleTag = doc.createElement("STYLE"); head.appendChild(styleTag); doc.__qsResult = []; styleTag.styleSheet.cssText = selector + "{x:expression_(document.__qsResult.push(this))}"; window.scrollBy(0, 0); head.removeChild(styleTag); var result = []; for (var i in doc.__qsResult) result.push(doc.__qsResult[i]); return result; } }, getComputedStyle : function(element, pseudoElement, win) { var pseudo = pseudoElement; var target = win; if(!target) target = window; if(!pseudo) { pseudo = null; } if(target.getComputedStyle) return target.getComputedStyle(element, pseudo); if(element.currentStyle) { try { var fixedElement = Evernote.Utils.cloneObject(element.currentStyle); fixedElement['fontSize'] = Evernote.Utils.getIEComputedStyle(element, 'fontSize'); return fixedElement; } catch (err) { return element.currentStyle; } } return null; }, hasParentNode : function(element) { return element.parentNode && element.parentNode.nodeType != 9 && element.parentNode.nodeType != 11; }, getBoundingClientRect : function(element) { if(element && element.getBoundingClientRect) { var rect = element.getBoundingClientRect(); var width = rect.width || element.offsetWidth || element.boundingWidth; var height = rect.height || element.offsetHeight || element.boundingHeight; return { left : rect.left, right : rect.right, top : rect.top, bottom : rect.bottom, width : width, height : height } } return null; }, hasAttribute : function(node, attrName) { if(node) { if(node.hasAttribute) { return node.hasAttribute(attrName); } if(node.attributes) { var attrValue = node.attributes[attrName]; return typeof attrValue != typeof undefined; } } } };</script><script defer="" type="text/javascript" charset="ANSI">Evernote.ArrayExtension = { indexOf : function(element, searchStr) { if(!element) { return -1; } if (element.indexOf) return element.indexOf(searchStr); for(var i = 0; i < element.length; i++) { if(element[i] == searchStr) return i; } return -1; }, containsCaseIgnore : function(element, searchStr) { if(!element) { return false; } for(var i = 0; i < element.length; i++) { if(element[i].toLowerCase() == searchStr.toLowerCase()) return true; } return false; }, remove : function(arr, element) { var elementPosition = Evernote.ArrayExtension.indexOf(arr, element); if(elementPosition != -1) { var rest = arr.slice(elementPosition + 1 || arr.length); arr.length = elementPosition; return arr.push.apply(arr, rest); } }, filter : function(arr, fun) { var len = arr.length >>> 0; if (typeof fun != "function") throw new TypeError(); var res = []; var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in arr) { var val = arr[i]; if (fun.call(thisp, val, i, arr)) { res.push(val); } } } return res; } }; </script><script defer="" type="text/javascript" charset="ANSI">Evernote.StyleElementExtension = { getPropertyValue : function(styleObj, propertyName) { var props = propertyName; if(!(props instanceof Array)) { props = [propertyName]; } Evernote.Logger.debug("Evernote.StyleElementExtension.getPropertyValue: number of properties to check " + props.length); for(var i = 0; i < props.length; i++) { var propName = props[i]; Evernote.Logger.debug("Evernote.StyleElementExtension.getPropertyValue: property name is " + propName); var val; if(styleObj.getPropertyValue) { val = styleObj.getPropertyValue(propName); Evernote.Logger.debug("Evernote.StyleElementExtension.getPropertyValue: value from getPropertyValue is " + val); if(val) return val; } val = styleObj[propName]; Evernote.Logger.debug("Evernote.StyleElementExtension.getPropertyValue: value from styleObj " + val); if(val) return val; } } }; </script><script defer="" type="text/javascript" charset="ANSI">Evernote.GlobalUtils = {}; (function(){ var urlMatcher = /^(.*?):\/\/((www\.)?(.*?))(:\d+)?(\/.*?)(\?.*)?$/; var BAD_FAV_ICON_URLS = {"http://localhost/favicon.ico": true}; Evernote.GlobalUtils.componentizeUrl = function(url) { var data = { protocol: null, domain: null, domainNoWww: null, port: null, path: null, queryString: null }; var matches = urlMatcher.exec(url); data.protocol = matches[1]; data.domain = matches[2]; data.domainNoWww = matches[4]; data.port = matches[5]; data.path = matches[6]; data.queryString = matches[7]; return data; }; Evernote.GlobalUtils.getMessageCode = function(messageConst) { Evernote.Logger.debug("getMessageCode: " + messageConst); return Evernote.Messages[messageConst]; }; Evernote.GlobalUtils.absolutizeImages = function(element, path) { if(path) { Evernote.Utils.changeBackgroundImage(element, Evernote.Addin.getPath("resources") + path); } else if(element.attributes && element.attributes["background-image"]) { // TODO: replace "oldlipper" with universal path Evernote.Utils.changeBackgroundImage(element, Evernote.Addin.getPath("resources") + 'oldclipper/' + element.attributes["background-image"].value); } Evernote.Logger.debug("absolutizeImages: walk through children"); for (var i = 0; i < element.children.length; i++) { Evernote.GlobalUtils.absolutizeImages(element.children[i]); } Evernote.Logger.debug("absolutizeImages: end"); }; Evernote.GlobalUtils.localize = function(element) { var node = element.nodeName.toLowerCase(); if (node == "input" || node == "textarea") { var type = element.type; if (node == "textarea") type = "textarea"; switch (element.type) { case "text": case "textarea": case "button": case "submit": case "search": if (element.attributes && element.attributes["placeholder"]) { var localizedMessage = Evernote.Addin.getLocalizedMessage(Evernote.GlobalUtils.getMessageCode(element.attributes["placeholder"].value)); Evernote.Logger.debug("localizedMessage is " + localizedMessage); if (localizedMessage) { try { element.attributes["placeholder"].value = localizedMessage; } catch(e) { var placeHolderAttr = document.createAttribute("placeholder"); placeHolderAttr.nodeValue = localizedMessage; element.setAttribute("placeholder", localizedMessage); } } } if (element.attributes && element.attributes["message"]) { var localizedMessage = Evernote.Addin.getLocalizedMessage(Evernote.GlobalUtils.getMessageCode(element.attributes["message"].value)); Evernote.Logger.debug("localizedMessage is " + localizedMessage); if (localizedMessage) { element.value = localizedMessage; } } break; // unlocalizable. case "checkbox": case "password": case "hidden": case "radio": break; default: throw new Error("We need to localize the value of input elements."); } } else if (element.attributes && element.attributes["message"]) { var localizedMessage = Evernote.Addin.getLocalizedMessage(Evernote.GlobalUtils.getMessageCode(element.attributes["message"].value)); if (localizedMessage) { element.innerHTML = localizedMessage; } else { element.innerHTML = 'l10n error'; // to spot if something goes wrong } } if (element.title){ var localizedTitle = Evernote.Addin.getLocalizedMessage(Evernote.GlobalUtils.getMessageCode(element.title)); if (localizedTitle) { element.title = localizedTitle; } } for (var i = 0; i < element.children.length; i++) { Evernote.GlobalUtils.localize(element.children[i]); } }; Evernote.GlobalUtils.getQueryParams = function(url) { var data = Evernote.GlobalUtils.componentizeUrl(url); var queryString = data.queryString; var params = {}; if (!queryString) { return params; }; queryString = queryString.substr(1); // Don't want the question mark. queryString = queryString.split("#")[0]; // Get rid of any fragment identifier. var pairs = queryString.split("&"); var i; for (i = 0; i < pairs.length; i++) { var item = pairs[i].split("="); if (item[1]) { item[1] = item[1].replace(/\+/g, " "); } params[item[0].toLowerCase()] = item[1]; } return params; }; Evernote.GlobalUtils.escapeXML = function(str) { var map = { "&" : "&", "<" : "<", ">" : ">", "\"" : """, "'" : "'" }; var a = str.split(""); for (var i = 0; i < a.length; i++) { if (map[a[i]]) { a[i] = map[a[i]]; } } return a.join(""); }; Evernote.GlobalUtils.decodeXML = function(str) { str = str.replace(/'/g, "'"); str = str.replace(/"/g, """); str = str.replace(/</g, "<"); str = str.replace(/>/g, ">"); return str; }; Evernote.GlobalUtils.cropImage = function( data ) { var img = new Image; img.onload = function(){ var canvas=document.createElement("canvas"); canvas.width=Math.min(150,data.width); canvas.height=Math.min(150,data.height); canvas.getContext("2d").drawImage(img ,Math.max(0,(data.width-150)/2),Math.max(0,(data.height-150)/2),canvas.width,canvas.height,0,0,canvas.width,canvas.height); return canvas.toDataURL(); // Not working. Cross origin policy forbids toDataUrl() method. }; img.src = data.src; }; Evernote.GlobalUtils.createUrlClipContent = function(title, url, favIcoUrl, snippet) { var titleAttr = (title) ? Evernote.GlobalUtils.escapeXML(title) : ""; var urlStr = Evernote.GlobalUtils.escapeXML(url); var snip = snippet; if (snip.length > 275) { snip = snip.substr(0, 275-3) + '...'; } snip = Evernote.GlobalUtils.escapeXML(snip); var contentStyle = 'text-align:left;padding:15px;font-size:12px;font-family:Verdana;max-width:370px;color:black;background-color:white;box-sizing:content-box;display:block;background-repeat:no-repeat;'; var titleStyle = 'white-space:nowrap;font-size:14px;font-weight:bold;overflow-x:hidden;text-overflow:ellipsis;height:24px;'; var hrStyle = 'border-top-width:1px;border-top-style:solid;border-top-color:#d8d8d8;height:0;width:100%;'; var imgStyle = 'position:relative;display:inline-block;float:left;width:150px;height:150px;margin:15px 30px 0 0;overflow:hidden;'; var contStyle = 'display:inline-block;vertical-align:top;margin:15px 0 0;width:364px;'; var linkDivStyle = 'padding:0px 0px 11px 0px;'; var faviconStyle = 'float:left;width:16px; height:16px; margin-right:9px; background-size:16px 16px;background-repeat: no-repeat; background-position:left center;'; var linkStyle = 'display:inline-block;text-decoration:none;line-height:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:rgb(12, 12, 12);width:325px;'; var snipStyle ='word-wrap:break-word;line-height:normal;text-align:left;font-size:12px'; var imgDiv = ''; var titleDiv = '
' + titleAttr + '
'; var hrDiv = '
'; Evernote.pageInfo.getBiggestImage(function(data) { if (data && data.src) { var im = ''; imgDiv = '
' + im + '
'; contentStyle = contentStyle.replace('max-width:370px','max-width:562px'); } }); var link = '' + urlStr + ''; var favicon = '