1// listen for rlt authentication events and pass them to children of this document. 2( function() { 3 var currentToken; 4 var parentOrigin; 5 var iframeOrigins; 6 var registeredIframes = []; 7 var initializationListeners = []; 8 var hasBeenInitialized = false; 9 var RLT_KEY = 'jetpack:wpcomRLT'; 10 11 // should we inject RLT into this iframe? 12 function rltShouldAuthorizeIframe( frameOrigin ) { 13 if ( ! Array.isArray( iframeOrigins ) ) { 14 return false; 15 } 16 return iframeOrigins.includes( frameOrigin ); 17 } 18 19 function rltInvalidateWindowToken( token, target, origin ) { 20 if ( target && typeof target.postMessage === 'function' ) { 21 try { 22 target.postMessage( JSON.stringify( { 23 type: 'rltMessage', 24 data: { 25 event: 'invalidate', 26 token: token, 27 sourceOrigin: window.location.origin, 28 }, 29 } ), origin ); 30 } catch ( err ) { 31 return; 32 } 33 } 34 } 35 36 /** 37 * PUBLIC METHODS 38 */ 39 window.rltInvalidateToken = function( token, sourceOrigin ) { 40 // invalidate in current context 41 if ( token === currentToken ) { 42 currentToken = null; 43 } 44 45 // remove from localstorage, but only if in a top level window, not iframe 46 try { 47 if ( window.location === window.parent.location && window.localStorage ) { 48 if ( window.localStorage.getItem(RLT_KEY) === token ) { 49 window.localStorage.removeItem(RLT_KEY); 50 } 51 } 52 } catch( e ) { 53 console.info("localstorage access for invalidate denied - probably blocked third-party access", window.location.href); 54 } 55 56 // invalidate in registered iframes 57 for ( const [ frameOrigin, frameWindow ] of registeredIframes ) { 58 if ( frameOrigin !== sourceOrigin ) { 59 rltInvalidateWindowToken( token, frameWindow, frameOrigin ); 60 } 61 } 62 63 // invalidate in parent 64 if ( parentOrigin && parentOrigin !== sourceOrigin && window.parent ) { 65 rltInvalidateWindowToken( token, window.parent, parentOrigin ); 66 } 67 } 68 69 window.rltInjectToken = function( token, target, origin ) { 70 if ( target && typeof target.postMessage === 'function' ) { 71 try { 72 target.postMessage( JSON.stringify( { 73 type: 'loginMessage', 74 data: { 75 event: 'login', 76 success: true, 77 type: 'rlt', 78 token: token, 79 sourceOrigin: window.location.origin, 80 }, 81 } ), origin ); 82 } catch ( err ) { 83 return; 84 } 85 } 86 }; 87 88 window.rltIsAuthenticated = function() { 89 return !! currentToken; 90 }; 91 92 window.rltGetToken = function() { 93 return currentToken; 94 }; 95 96 window.rltAddInitializationListener = function( listener ) { 97 // if RLT is already initialized, call the listener immediately 98 if ( hasBeenInitialized ) { 99 listener( currentToken ); 100 } else { 101 initializationListeners.push( listener ); 102 } 103 }; 104 105 // store the token in localStorage 106 window.rltStoreToken = function( token ) { 107 currentToken = token; 108 try { 109 if ( window.location === window.parent.location && window.localStorage ) { 110 window.localStorage.setItem( RLT_KEY, token ); 111 } 112 } catch( e ) { 113 console.info("localstorage access denied - probably blocked third-party access", window.location.href); 114 } 115 } 116 117 window.rltInitialize = function( config ) { 118 if ( ! config || typeof window.postMessage !== 'function' ) { 119 return; 120 } 121 122 currentToken = config.token; 123 iframeOrigins = config.iframeOrigins; 124 parentOrigin = config.parentOrigin; // needed? 125 126 // load token from localStorage if possible, but only in top level window 127 try { 128 if ( ! currentToken && window.location === window.parent.location && window.localStorage ) { 129 currentToken = window.localStorage.getItem(RLT_KEY); 130 } 131 } catch( e ) { 132 console.info("localstorage access denied - probably blocked third-party access", window.location.href); 133 } 134 135 // listen for RLT events from approved origins 136 window.addEventListener( 'message', function( e ) { 137 var message = e && e.data; 138 if ( typeof message === 'string' ) { 139 try { 140 message = JSON.parse( message ); 141 } catch ( err ) { 142 return; 143 } 144 } 145 146 var type = message && message.type; 147 var data = message && message.data; 148 149 if ( type === 'loginMessage' ) { 150 if ( data && data.type === 'rlt' && data.token !== currentToken ) { 151 // put into localStorage if running in top-level window (not iframe) 152 rltStoreToken( data.token ); 153 154 // send to registered iframes 155 for ( const [ frameOrigin, frameWindow ] of registeredIframes ) { 156 rltInjectToken( currentToken, frameWindow, frameOrigin ); 157 } 158 159 // send to the parent, unless the event was sent _by_ the parent 160 if ( parentOrigin && parentOrigin !== data.sourceOrigin && window.parent ) { 161 rltInjectToken( currentToken, window.parent, parentOrigin ); 162 } 163 } 164 } 165 166 if ( type === 'rltMessage' ) {
167 if ( data && data.event === 'invalidate' && data.token === currentToken ) { 168 rltInvalidateToken( data.token ); 169 } 170 171 if ( data && data.event === 'register' ) { 172 if ( rltShouldAuthorizeIframe( e.origin ) ) { 173 registeredIframes.push( [ e.origin, e.source ] ); 174 if ( currentToken ) { 175 rltInjectToken( currentToken, e.source, e.origin ); 176 } 177 } 178 } 179 } 180 } ); 181 182 initializationListeners.forEach( function( listener ) { 183 listener( currentToken ); 184 } ); 185 186 initializationListeners = []; 187 188 // inform the parent that we are ready to receive the RLT token 189 window.parent.postMessage( { 190 type: 'rltMessage', 191 data: { 192 event: 'register' 193 }, 194 }, '*' ); 195 196 hasBeenInitialized = true; 197 }; 198} )(); 199; 200/** 201* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 202*/ 203;(function(window, document) { 204/*jshint evil:true */ 205 /** version */ 206 var version = '3.7.3'; 207 208 /** Preset options */ 209 var options = window.html5 || {}; 210 211 /** Used to skip problem elements */ 212 var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i; 213 214 /** Not all elements can be cloned in IE **/ 215 var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i; 216 217 /** Detect whether the browser supports default html5 styles */ 218 var supportsHtml5Styles; 219 220 /** Name of the expando, to work with multiple documents or to re-shiv one document */ 221 var expando = '_html5shiv'; 222 223 /** The id for the the documents expando */ 224 var expanID = 0; 225 226 /** Cached data for each document */ 227 var expandoData = {}; 228 229 /** Detect whether the browser supports unknown elements */ 230 var supportsUnknownElements; 231 232 (function() { 233 try { 234 var a = document.createElement('a'); 235 a.innerHTML = '<xyz></xyz>'; 236 //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles 237 supportsHtml5Styles = ('hidden' in a); 238 239 supportsUnknownElements = a.childNodes.length == 1 || (function() { 240 // assign a false positive if unable to shiv 241 (document.createElement)('a'); 242 var frag = document.createDocumentFragment(); 243 return ( 244 typeof frag.cloneNode == 'undefined' || 245 typeof frag.createDocumentFragment == 'undefined' || 246 typeof frag.createElement == 'undefined' 247 ); 248 }()); 249 } catch(e) { 250 // assign a false positive if detection fails => unable to shiv 251 supportsHtml5Styles = true; 252 supportsUnknownElements = true; 253 } 254 255 }()); 256 257 /*--------------------------------------------------------------------------*/ 258 259 /** 260 * Creates a style sheet with the given CSS text and adds it to the document. 261 * @private 262 * @param {Document} ownerDocument The document. 263 * @param {String} cssText The CSS text. 264 * @returns {StyleSheet} The style element. 265 */ 266 function addStyleSheet(ownerDocument, cssText) { 267 var p = ownerDocument.createElement('p'), 268 parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; 269 270 p.innerHTML = 'x<style>' + cssText + '</style>'; 271 return parent.insertBefore(p.lastChild, parent.firstChild); 272 } 273 274 /** 275 * Returns the value of `html5.elements` as an array. 276 * @private 277 * @returns {Array} An array of shived element node names. 278 */ 279 function getElements() { 280 var elements = html5.elements; 281 return typeof elements == 'string' ? elements.split(' ') : elements; 282 } 283 284 /** 285 * Extends the built-in list of html5 elements 286 * @memberOf html5 287 * @param {String|Array} newElements whitespace separated list or array of new element names to shiv 288 * @param {Document} ownerDocument The context document. 289 */ 290 function addElements(newElements, ownerDocument) { 291 var elements = html5.elements; 292 if(typeof elements != 'string'){ 293 elements = elements.join(' '); 294 } 295 if(typeof newElements != 'string'){ 296 newElements = newElements.join(' '); 297 } 298 html5.elements = elements +' '+ newElements; 299 shivDocument(ownerDocument); 300 } 301 302 /** 303 * Returns the data associated to the given document 304 * @private 305 * @param {Document} ownerDocument The document. 306 * @returns {Object} An object of data. 307 */ 308 function getExpandoData(ownerDocument) { 309 var data = expandoData[ownerDocument[expando]]; 310 if (!data) { 311 data = {}; 312 expanID++; 313 ownerDocument[expando] = expanID; 314 expandoData[expanID] = data; 315 } 316 return data; 317 } 318 319 /** 320 * returns a shived element for the given nodeName and document 321 * @memberOf html5 322 * @param {String}
vendor: 4,255 bytes, lines 322-449
322 nodeName name of the element 323 * @param {Document|DocumentFragment} ownerDocument The context document. 324 * @returns {Object} The shived element. 325 */ 326 function createElement(nodeName, ownerDocument, data){ 327 if (!ownerDocument) { 328 ownerDocument = document; 329 } 330 if(supportsUnknownElements){ 331 return ownerDocument.createElement(nodeName); 332 } 333 if (!data) { 334 data = getExpandoData(ownerDocument); 335 } 336 var node; 337 338 if (data.cache[nodeName]) { 339 node = data.cache[nodeName].cloneNode(); 340 } else if (saveClones.test(nodeName)) { 341 node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); 342 } else { 343 node = data.createElem(nodeName); 344 } 345 346 // Avoid adding some elements to fragments in IE < 9 because 347 // * Attributes like `name` or `type` cannot be set/changed once an element 348 // is inserted into a document/fragment 349 // * Link elements with `src` attributes that are inaccessible, as with 350 // a 403 response, will cause the tab/window to crash 351 // * Script elements appended to fragments will execute when their `src` 352 // or `text` property is set 353 return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node; 354 } 355 356 /** 357 * returns a shived DocumentFragment for the given document 358 * @memberOf html5 359 * @param {Document} ownerDocument The context document. 360 * @returns {Object} The shived DocumentFragment. 361 */ 362 function createDocumentFragment(ownerDocument, data){ 363 if (!ownerDocument) { 364 ownerDocument = document; 365 } 366 if(supportsUnknownElements){ 367 return ownerDocument.createDocumentFragment(); 368 } 369 data = data || getExpandoData(ownerDocument); 370 var clone = data.frag.cloneNode(), 371 i = 0, 372 elems = getElements(), 373 l = elems.length; 374 for(;i<l;i++){ 375 clone.createElement(elems[i]); 376 } 377 return clone; 378 } 379 380 /** 381 * Shivs the `createElement` and `createDocumentFragment` methods of the document. 382 * @private 383 * @param {Document|DocumentFragment} ownerDocument The document. 384 * @param {Object} data of the document. 385 */ 386 function shivMethods(ownerDocument, data) { 387 if (!data.cache) { 388 data.cache = {}; 389 data.createElem = ownerDocument.createElement; 390 data.createFrag = ownerDocument.createDocumentFragment; 391 data.frag = data.createFrag(); 392 } 393 394 395 ownerDocument.createElement = function(nodeName) { 396 //abort shiv 397 if (!html5.shivMethods) { 398 return data.createElem(nodeName); 399 } 400 return createElement(nodeName, ownerDocument, data); 401 }; 402 403 ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' + 404 'var n=f.cloneNode(),c=n.createElement;' + 405 'h.shivMethods&&(' + 406 // unroll the `createElement` calls 407 getElements().join().replace(/[\w\-:]+/g, function(nodeName) { 408 data.createElem(nodeName); 409 data.frag.createElement(nodeName); 410 return 'c("' + nodeName + '")'; 411 }) + 412 ');return n}' 413 )(html5, data.frag); 414 } 415 416 /*--------------------------------------------------------------------------*/ 417 418 /** 419 * Shivs the given document. 420 * @memberOf html5 421 * @param {Document} ownerDocument The document to shiv. 422 * @returns {Document} The shived document. 423 */ 424 function shivDocument(ownerDocument) { 425 if (!ownerDocument) { 426 ownerDocument = document; 427 } 428 var data = getExpandoData(ownerDocument); 429 430 if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) { 431 data.hasCSS = !!addStyleSheet(ownerDocument, 432 // corrects block display not defined in IE6/7/8/9 433 'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' + 434 // adds styling not present in IE6/7/8/9 435 'mark{background:#FF0;color:#000}' + 436 // hides non-rendered elements 437 'template{display:none}' 438 ); 439 } 440 if (!supportsUnknownElements) { 441 shivMethods(ownerDocument, data); 442 } 443 return ownerDocument; 444 } 445 446 /*--------------------------------------------------------------------------*/ 447 448 /** 449 * The `html5` object is exposed so that more elements can be shived and
450 * existing shiving can be detected on iframes. 451 * @type Object 452 * @example 453 * 454 * // options can be changed before the script is included 455 * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false }; 456 */ 457 var html5 = { 458 459 /** 460 * An array or space separated string of node names of the elements to shiv. 461 * @memberOf html5 462 * @type Array|String 463 */ 464 'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video', 465 466 /** 467 * current version of html5shiv 468 */ 469 'version': version, 470 471 /** 472 * A flag to indicate that the HTML5 style sheet should be inserted. 473 * @memberOf html5 474 * @type Boolean 475 */ 476 'shivCSS': (options.shivCSS !== false), 477 478 /** 479 * Is equal to true if a browser supports creating unknown/HTML5 elements 480 * @memberOf html5 481 * @type boolean 482 */ 483 'supportsUnknownElements': supportsUnknownElements, 484 485 /** 486 * A flag to indicate that the document's `createElement` and `createDocumentFragment` 487 * methods should be overwritten. 488 * @memberOf html5 489 * @type Boolean 490 */ 491 'shivMethods': (options.shivMethods !== false), 492 493 /** 494 * A string to describe the type of `html5` object ("default" or "default print"). 495 * @memberOf html5
496 * @type String 497 */ 498 'type': 'default', 499 500 // shivs the document according to the specified `html5` object options 501 'shivDocument': shivDocument, 502 503 //creates a shived element 504 createElement: createElement, 505 506 //creates a shived documentFragment 507 createDocumentFragment: createDocumentFragment, 508 509 //extends list of elements 510 addElements: addElements 511 }; 512 513 /*--------------------------------------------------------------------------*/ 514 515 // expose html5 516 window.html5 = html5; 517 518 // shiv the document 519 shivDocument(document); 520 521 if(typeof module == 'object' && module.exports){ 522 module.exports = html5; 523 } 524 525}(typeof window !== "undefined" ? window : this, document));; 526( function () { 527 let cookies = document.cookie.split( /;\s*/ ); 528 let cookie = false; 529 530 for ( let i = 0; i < cookies.length; i++ ) { 531 if ( cookies[ i ].match( /^wp_api=/ ) ) { 532 cookies = cookies[ i ].split( '=' ); 533 cookie = cookies[ 1 ]; 534 break; 535 } 536 } 537 538 function setAllLinks( followId, wasFollowing ) { 539 const allLinks = document.querySelectorAll( `a.f-${ followId }` ); 540 541 if ( wasFollowing ) { 542 allLinks.forEach( ( el ) => { 543 el.classList.remove( 'wpcom-following' ); 544 el.classList.add( 'wpcom-follow' ); 545 el.textContent = 'Follow'; 546 } ); 547 } else { 548 allLinks.forEach( ( el ) => { 549 el.classList.add( 'wpcom-following' ); 550 el.classList.remove( 'wpcom-follow' ); 551 el.textContent = 'Following'; 552 } ); 553 } 554 } 555 556 function setAllRestLinks( followId, wasFollowing, followText, followingText ) { 557 const sel = `data-blog-id="${ followId }"`; 558 const allLinks = document.querySelectorAll( 559 `a.wpcom-follow-rest[${ sel }], a.wpcom-following-rest[${ sel }]` 560 ); 561 562 if ( wasFollowing ) { 563 allLinks.forEach( ( el ) => { 564 el.classList.remove( 'wpcom-following-rest' ); 565 el.classList.add( 'wpcom-follow-rest' ); 566 el.textContent = followText; 567 } ); 568 } else { 569 allLinks.forEach( ( el ) => { 570 el.classList.add( 'wpcom-following-rest' ); 571 el.classList.remove( 'wpcom-follow-rest' ); 572 el.textContent = followingText; 573 } ); 574 } 575 } 576 577 let bubbleInitDone = false; 578 let isBubbleVisible = false; 579 let bubbleTimeout; 580 581 window.wpFollowButton = { 582 enable: function () { 583 document.querySelectorAll( 'a.wpcom-follow, a.wpcom-following' ).forEach( ( link ) => 584 link.addEventListener( 'click', ( e ) => { 585 e.preventDefault(); 586 587 const blogId = link.getAttribute( 'data-id' ); 588 const blogUrl = link.getAttribute( 'data-url' ); 589 const isFollowing = link.classList.contains( 'wpcom-following' ); 590 591 let followId; 592 593 if ( blogId ) { 594 followId = blogId; 595 } else { 596 const fClass = Array.from( link.classList ).find( ( c ) => c.startsWith( 'f-' ) ); 597 if ( fClass ) { 598 followId = fClass.slice( 2 ); 599 } 600 } 601 602 if ( ! followId ) { 603 return; 604 } 605 606 // Ensure followId represents a number. 607 followId = String( parseInt( followId, 10 ) || 0 ); 608 609 // Preemptively update all links (assume success). 610 setAllLinks( followId, isFollowing ); 611 612 const href = link.getAttribute( 'href' ); 613 if ( ! href ) { 614 return; 615 } 616 617 const url = new URL( href, window.location ); 618 619 fetch( url.origin + '/wp-admin/admin-ajax.php', { 620 method: 'POST', 621 headers: { 622 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 623 Accept: 'application/json', 624 }, 625 body: new URLSearchParams( { 626 action: isFollowing ? 'ab_unsubscribe_from_blog' : 'ab_subscribe_to_blog', 627 _wpnonce: url.searchParams.get( '_wpnonce' ) || undefined, 628 blog_id: blogId, 629 blog_url: blogUrl, 630 source: url.searchParams.get( 'src' ) || undefined, 631 } ).toString(), 632 } ) 633 .then( ( response ) => { 634 if ( ! response.ok ) { 635 throw new Error(); 636 } 637 return response.json(); 638 } ) 639 .then( ( json ) => { 640 if ( typeof json.errors === 'object' ) { 641 throw new Error(); 642 } 643 } ) 644 .catch( () => { 645 // Error; toggle back. 646 setAllLinks( followId, ! isFollowing ); 647 } ); 648 } ) 649 ); 650 }, 651 652 enable_rest: function ( link ) { 653 link.addEventListener( 'click', ( e ) => { 654 e.preventDefault(); 655 let blogId = link.getAttribute( 'data-blog-id' ); 656 const followText = link.getAttribute( 'data-follow-text' ); 657 const followingText = link.getAttribute( 'data-following-text' ); 658 const wasFollowing = link.classList.contains( 'wpcom-following-rest' ); 659 let restPath = `/sites/${ blogId }/follows/new`; 660 661 if ( wasFollowing ) { 662 restPath = `/sites/${ blogId }/follows/mine/delete`; 663 } 664 // Ensure followId represents a number. 665 blogId = String( parseInt( blogId, 10 ) || 0 ); 666 667 // Select and update ALL follow buttons on the page (could be more than one). 668 setAllRestLinks( blogId, wasFollowing, followText, followingText ); 669 670 this.ajax( { 671 type: 'POST', 672 path: restPath, 673 success: function ( res ) { 674 if ( ! res.success ) { 675 // Error; toggle back. 676 setAllRestLinks( blogId, ! wasFollowing, followText, followingText ); 677 this.hideBubble(); 678 } 679 }, 680 error: function () { 681 // Error; toggle back. 682 setAllRestLinks( blogId, ! wasFollowing, followText, followingText ); 683 this.hideBubble(); 684 }, 685 } ); 686 687 // Show post-follow bubble.
688 if ( ! wasFollowing ) { 689 e.stopPropagation(); 690 this.showBubble( link ); 691 this.bumpStat( link.getAttribute( 'data-stat-src' ) ); 692 } 693 } ); 694 695 // Show unfollow text on hover. 696 link.addEventListener( 'mouseenter', () => { 697 const isFollowing = link.classList.contains( 'wpcom-following-rest' ); 698 if ( isFollowing ) { 699 link.textContent = link.getAttribute( 'data-following-hover-text' ); 700 } 701 } ); 702 link.addEventListener( 'mouseleave', () => { 703 const isFollowing = link.classList.contains( 'wpcom-following-rest' ); 704 if ( isFollowing ) { 705 link.textContent = link.getAttribute( 'data-following-text' ); 706 } 707 } ); 708 }, 709 710 showBubble: function ( link ) { 711 const pos = { 712 left: link.offsetLeft, 713 top: link.offsetTop, 714 }; 715 716 let bubble = document.querySelector( 'div.follow-bubble' ); 717 if ( ! bubble ) { 718 bubble = document.createElement( 'div' ); 719 bubble.classList.add( 'wpcom-bubble', 'action-bubble', 'follow-bubble' ); 720 } 721 bubble.innerHTML = ` 722 <div class="bubble-txt"> 723 New posts from this blog will now appear in 724 <a style='float:none;' href='http://wordpress.com/reader/'>your reader</a>. 725 </div> 726 `; 727 link.parentElement.appendChild( bubble ); 728 729 bubble.style.display = 'block'; 730 const left = pos.left + link.offsetWidth / 2 - bubble.offsetWidth / 2; 731 const top = pos.top + link.offsetHeight + 8; 732 733 bubble.style.left = left + 'px'; 734 bubble.style.top = top + 'px'; 735 bubble.classList.add( 'fadein' ); 736 isBubbleVisible = true; 737 738 bubbleTimeout = setTimeout( this.hideBubble, 10000 ); 739 740 if ( bubbleInitDone ) { 741 return; 742 } 743 744 const clickHandler = ( e ) => { 745 if ( 746 ! e.target.classList.contains( 'follow-bubble' ) && 747 ! e.target.closest( 'div.follow-bubble' ) 748 ) { 749 this.hideBubble(); 750 } 751 }; 752 753 document.body.addEventListener( 'click', clickHandler ); 754 document.body.addEventListener( 'touchstart', clickHandler ); 755 756 document.addEventListener( 'scroll', () => { 757 if ( ! isBubbleVisible ) { 758 return; 759 } 760 this.hideBubble(); 761 } ); 762 763 bubbleInitDone = true; 764 }, 765 766 hideBubble: function () { 767 const bubble = document.querySelector( 'div.follow-bubble' ); 768 bubble.style.display = 'none'; 769 isBubbleVisible = false; 770 clearTimeout( bubbleTimeout ); 771 }, 772 773 // Common method for rendering a follow button from the object data 774 create: function ( { params }, source ) { 775 const isFollowing = params.is_following; 776 777 const followLink = document.createElement( 'a' ); 778 followLink.classList.add( isFollowing ? 'wpcom-following-rest' : 'wpcom-follow-rest' ); 779 780 Object.entries( { 781 href: `http://public-api.wordpress.com/sites/${ encodeURIComponent( 782 params.site_id 783 ) }/follows`, 784 title: `${ params.blog_title } (${ params.blog_domain })`, 785 'data-blog-id': params.site_id, 786 'data-stat-src': params[ 'stat-source' ], 787 'data-follow-text': params[ 'follow-text' ], 788 'data-following-text': params[ 'following-text' ], 789 'data-following-hover-text': params[ 'following-hover-text' ], 790 } ).forEach( ( [ key, val ] ) => followLink.setAttribute( key, val ) ); 791 792 followLink.textContent = isFollowing ? params[ 'following-text' ] : params[ 'follow-text' ]; 793 794 const followButton = document.createElement( 'div' ); 795 followButton.classList.add( 'wpcom-follow-container' ); 796 followButton.classList.add( 'wpcom-follow-attached' ); 797 followButton.style.display = 'inline-block'; 798 followButton.appendChild( followLink ); 799 800 this.enable_rest( followLink, source ); 801 return followButton; 802 }, 803 804 createAll: function () { 805 document 806 .querySelectorAll( '.wpcom-follow-container:not(.wpcom-follow-attached)' ) 807 .forEach( ( el ) => { 808 const json = JSON.parse( el.getAttribute( 'data-json' ) || '{}' ); 809 el.replaceWith( 810 this.create( json, el.getAttribute( 'data-follow-source' ) ) 811 ); 812 } ); 813 }, 814 815 ajax: function ( options ) { 816 if ( document.location.host === 'public-api.wordpress.com' ) { 817 // Regular AJAX call. 818 fetch( 'https://public-api.wordpress.com/rest/v1' + options.path, { 819 method: options.type, 820 headers: { 821 Authorization: `X-WPCOOKIE ${ cookie }:1:${ document.location.host }`, 822 Accept: 'application/json', 823 } 824 } ) 825 .then( ( response ) => { 826 if ( ! response.ok ) { 827 throw new Error(); 828 } 829 return response.json(); 830 } ) 831 .then( ( json ) => { 832 if ( typeof json.errors === 'object' ) { 833 throw new Error(); 834 } 835 options.success( json ); 836 } ) 837 .catch( () => { 838 options.error(); 839 } ); 840 } else { 841 // Proxied AJAX call. 842 const request = { 843 path: options.path, 844 method: options.type, 845 }; 846 847 const proxyRequestHandler = 848 window.WPCOM_Proxy_Request || ( window.jQuery && window.jQuery.wpcom_proxy_request ); 849 850 if ( ! proxyRequestHandler ) { 851 console.error( 'Cannot make AJAX call: missing proxy request handler.' ); 852 setTimeout( () => options.error() ); 853 return; 854 } 855 856 proxyRequestHandler( request ).done( ( response, statusCode ) => { 857 if ( statusCode === 200 ) { 858 options.success( response ); 859 } else { 860 options.error( statusCode ); 861 } 862 } ); 863 } 864 }, 865 866 bumpStat: function ( source ) { 867 new Image().src = `${ 868 document.location.protocol 869 }//pixel.wp.com/g.gif?v=wpcom-no-pv&x_follow_source=${ encodeURIComponent( 870 source 871 ) }&baba=${ Math.random() }`; 872 }, 873 }; 874
875 function init() { 876 window.wpFollowButton.enable(); 877 window.wpFollowButton.createAll(); 878 } 879 880 if ( document.readyState !== 'loading' ) { 881 init(); 882 } else { 883 document.addEventListener( 'DOMContentLoaded', init ); 884 } 885} )(); 886; 887( function () { 888 'use strict'; 889 890 function init() { 891 document.querySelectorAll( '.bump-view' ).forEach( function ( el ) { 892 el.addEventListener( 'click', function ( e ) { 893 var statarg = 'wref='; 894 var statval = el.getAttribute( 'data-bump-view' ); 895 var href = el.getAttribute( 'href' ); 896 el.setAttribute( 897 'href', 898 href + ( href.indexOf( '?' ) !== -1 ? '&' : '?' ) + statarg + statval 899 ); 900 } ); 901 } ); 902 } 903 904 if ( document.readyState !== 'loading' ) { 905 init(); 906 } else { 907 document.addEventListener( 'DOMContentLoaded', init ); 908 } 909} )(); 910;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.