PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.0.3
Jetpack – WP Security, Backup, Speed, & Growth v12.0.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / likes / queuehandler.js
jetpack / modules / likes Last commit date
jetpack-likes-master-iframe.php 3 years ago jetpack-likes-settings.php 3 years ago post-count-jetpack.js 4 years ago post-count.js 4 years ago queuehandler.js 4 years ago style.css 4 years ago
queuehandler.js
430 lines
1 /* global wpcom_reblog */
2
3 var jetpackLikesWidgetBatch = [];
4 var jetpackLikesMasterReady = false;
5
6 // Due to performance problems on pages with a large number of widget iframes that need to be loaded,
7 // we are limiting the processing at any instant to unloaded widgets that are currently in viewport,
8 // plus this constant that will allow processing of widgets above and bellow the current fold.
9 // This aim of it is to improve the UX and hide the transition from unloaded to loaded state from users.
10 var jetpackLikesLookAhead = 2000; // pixels
11
12 // Keeps track of loaded comment likes widget so we can unload them when they are scrolled out of view.
13 var jetpackCommentLikesLoadedWidgets = [];
14
15 var jetpackLikesDocReadyPromise = new Promise( resolve => {
16 if ( document.readyState !== 'loading' ) {
17 resolve();
18 } else {
19 window.addEventListener( 'DOMContentLoaded', () => resolve() );
20 }
21 } );
22
23 function JetpackLikesPostMessage( message, target ) {
24 if ( typeof message === 'string' ) {
25 try {
26 message = JSON.parse( message );
27 } catch ( e ) {
28 return;
29 }
30 }
31
32 if ( target && typeof target.postMessage === 'function' ) {
33 try {
34 target.postMessage(
35 JSON.stringify( {
36 type: 'likesMessage',
37 data: message,
38 } ),
39 '*'
40 );
41 } catch ( e ) {
42 return;
43 }
44 }
45 }
46
47 function JetpackLikesBatchHandler() {
48 const requests = [];
49 document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' ).forEach( widget => {
50 if ( jetpackLikesWidgetBatch.indexOf( widget.id ) > -1 ) {
51 return;
52 }
53
54 if ( ! jetpackIsScrolledIntoView( widget ) ) {
55 return;
56 }
57
58 jetpackLikesWidgetBatch.push( widget.id );
59
60 var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/,
61 match = regex.exec( widget.id ),
62 info;
63
64 if ( ! match || match.length !== 5 ) {
65 return;
66 }
67
68 info = {
69 blog_id: match[ 2 ],
70 width: widget.width,
71 };
72
73 if ( 'post' === match[ 1 ] ) {
74 info.post_id = match[ 3 ];
75 } else if ( 'comment' === match[ 1 ] ) {
76 info.comment_id = match[ 3 ];
77 }
78
79 info.obj_id = match[ 4 ];
80
81 requests.push( info );
82 } );
83
84 if ( requests.length > 0 ) {
85 JetpackLikesPostMessage(
86 { event: 'initialBatch', requests: requests },
87 window.frames[ 'likes-master' ]
88 );
89 }
90 }
91
92 function JetpackLikesMessageListener( event ) {
93 let message = event && event.data;
94 if ( typeof message === 'string' ) {
95 try {
96 message = JSON.parse( message );
97 } catch ( err ) {
98 return;
99 }
100 }
101
102 const type = message && message.type;
103 const data = message && message.data;
104
105 if ( type !== 'likesMessage' || typeof data.event === 'undefined' ) {
106 return;
107 }
108
109 // We only allow messages from one origin
110 const allowedOrigin = 'https://widgets.wp.com';
111 if ( allowedOrigin !== event.origin ) {
112 return;
113 }
114
115 switch ( data.event ) {
116 case 'masterReady':
117 jetpackLikesDocReadyPromise.then( () => {
118 jetpackLikesMasterReady = true;
119
120 const stylesData = {
121 event: 'injectStyles',
122 };
123 const sdTextColor = document.querySelector( '.sd-text-color' );
124 const sdLinkColor = document.querySelector( '.sd-link-color' );
125 const sdTextColorStyles = ( sdTextColor && getComputedStyle( sdTextColor ) ) || {};
126 const sdLinkColorStyles = ( sdLinkColor && getComputedStyle( sdLinkColor ) ) || {};
127
128 if ( document.querySelectorAll( 'iframe.admin-bar-likes-widget' ).length > 0 ) {
129 JetpackLikesPostMessage( { event: 'adminBarEnabled' }, window.frames[ 'likes-master' ] );
130
131 const bgSource = document.querySelector(
132 '#wpadminbar .quicklinks li#wp-admin-bar-wpl-like > a'
133 );
134
135 const wpAdminBar = document.querySelector( '#wpadminbar' );
136
137 stylesData.adminBarStyles = {
138 background: bgSource && getComputedStyle( bgSource ).background,
139 isRtl: wpAdminBar && getComputedStyle( wpAdminBar ).direction === 'rtl',
140 };
141 }
142
143 // enable reblogs if we're on a single post page
144 if ( document.body.classList.contains( 'single' ) ) {
145 JetpackLikesPostMessage( { event: 'reblogsEnabled' }, window.frames[ 'likes-master' ] );
146 }
147
148 stylesData.textStyles = {
149 color: sdTextColorStyles[ 'color' ],
150 fontFamily: sdTextColorStyles[ 'font-family' ],
151 fontSize: sdTextColorStyles[ 'font-size' ],
152 direction: sdTextColorStyles[ 'direction' ],
153 fontWeight: sdTextColorStyles[ 'font-weight' ],
154 fontStyle: sdTextColorStyles[ 'font-style' ],
155 textDecoration: sdTextColorStyles[ 'text-decoration' ],
156 };
157
158 stylesData.linkStyles = {
159 color: sdLinkColorStyles[ 'color' ],
160 fontFamily: sdLinkColorStyles[ 'font-family' ],
161 fontSize: sdLinkColorStyles[ 'font-size' ],
162 textDecoration: sdLinkColorStyles[ 'text-decoration' ],
163 fontWeight: sdLinkColorStyles[ 'font-weight' ],
164 fontStyle: sdLinkColorStyles[ 'font-style' ],
165 };
166
167 JetpackLikesPostMessage( stylesData, window.frames[ 'likes-master' ] );
168
169 JetpackLikesBatchHandler();
170 } );
171
172 break;
173
174 case 'showLikeWidget': {
175 const placeholder = document.querySelector( `#${ data.id } .likes-widget-placeholder` );
176 if ( placeholder ) {
177 placeholder.style.display = 'none';
178 }
179 break;
180 }
181
182 case 'showCommentLikeWidget': {
183 const placeholder = document.querySelector( `#${ data.id } .likes-widget-placeholder` );
184 if ( placeholder ) {
185 placeholder.style.display = 'none';
186 }
187 break;
188 }
189
190 case 'killCommentLikes':
191 // If kill switch for comment likes is enabled remove all widgets wrappers and `Loading...` placeholders.
192 document
193 .querySelectorAll( '.jetpack-comment-likes-widget-wrapper' )
194 .forEach( wrapper => wrapper.remove() );
195 break;
196
197 case 'clickReblogFlair':
198 if ( wpcom_reblog && typeof wpcom_reblog.toggle_reblog_box_flair === 'function' ) {
199 wpcom_reblog.toggle_reblog_box_flair( data.obj_id );
200 }
201 break;
202
203 case 'showOtherGravatars': {
204 const container = document.querySelector( '#likes-other-gravatars' );
205 if ( ! container ) {
206 break;
207 }
208
209 const list = container.querySelector( 'ul' );
210
211 container.style.display = 'none';
212 list.innerHTML = '';
213
214 container
215 .querySelectorAll( '.likes-text span' )
216 .forEach( item => ( item.textContent = data.total ) );
217
218 ( data.likers || [] ).forEach( liker => {
219 if ( liker.profile_URL.substr( 0, 4 ) !== 'http' ) {
220 // We only display gravatars with http or https schema
221 return;
222 }
223
224 const element = document.createElement( 'li' );
225 element.innerHTML = `
226 <a href="${ encodeURI( liker.profile_URL ) }" rel="nofollow" target="_parent" class="wpl-liker">
227 <img src="${ encodeURI( liker.avatar_URL ) }"
228 alt=""
229 style="width: 30px; height: 30px; padding-right: 3px;" />
230 </a>
231 `;
232
233 list.append( element );
234
235 // Add some extra attributes through native methods, to ensure strings are sanitized.
236 element.classList.add( liker.css_class );
237 element.querySelector( 'img' ).alt = liker.name;
238 } );
239
240 const el = document.querySelector( `*[name='${ data.parent }']` );
241 const rect = el.getBoundingClientRect();
242 const win = el.ownerDocument.defaultView;
243 const offset = {
244 top: rect.top + win.pageYOffset,
245 left: rect.left + win.pageXOffset,
246 };
247
248 container.style.left = offset.left + data.position.left - 10 + 'px';
249 container.style.top = offset.top + data.position.top - 33 + 'px';
250
251 const rowLength = Math.floor( data.width / 37 );
252 let height = Math.ceil( data.likers.length / rowLength ) * 37 + 13;
253 if ( height > 204 ) {
254 height = 204;
255 }
256
257 const containerWidth = rowLength * 37 - 7;
258 container.style.height = height + 'px';
259 container.style.width = containerWidth + 'px';
260
261 const listWidth = rowLength * 37;
262 list.style.width = listWidth + 'px';
263
264 container.style.display = 'block';
265
266 const scrollbarWidth = list.offsetWidth - list.clientWidth;
267 if ( scrollbarWidth > 0 ) {
268 container.style.width = containerWidth + scrollbarWidth + 'px';
269 list.style.width = listWidth + scrollbarWidth + 'px';
270 }
271 }
272 }
273 }
274
275 window.addEventListener( 'message', JetpackLikesMessageListener );
276
277 document.addEventListener( 'click', e => {
278 const container = document.querySelector( '#likes-other-gravatars' );
279
280 if ( container && ! container.contains( e.target ) ) {
281 container.style.display = 'none';
282 }
283 } );
284
285 function JetpackLikesWidgetQueueHandler() {
286 var wrapperID;
287
288 if ( ! jetpackLikesMasterReady ) {
289 setTimeout( JetpackLikesWidgetQueueHandler, 500 );
290 return;
291 }
292
293 // Restore widgets to initial unloaded state when they are scrolled out of view.
294 jetpackUnloadScrolledOutWidgets();
295
296 var unloadedWidgetsInView = jetpackGetUnloadedWidgetsInView();
297
298 if ( unloadedWidgetsInView.length > 0 ) {
299 // Grab any unloaded widgets for a batch request
300 JetpackLikesBatchHandler();
301 }
302
303 for ( var i = 0, length = unloadedWidgetsInView.length; i <= length - 1; i++ ) {
304 wrapperID = unloadedWidgetsInView[ i ].id;
305
306 if ( ! wrapperID ) {
307 continue;
308 }
309
310 jetpackLoadLikeWidgetIframe( wrapperID );
311 }
312 }
313
314 function jetpackLoadLikeWidgetIframe( wrapperID ) {
315 if ( typeof wrapperID === 'undefined' ) {
316 return;
317 }
318
319 const wrapper = document.querySelector( '#' + wrapperID );
320 wrapper.querySelectorAll( 'iframe' ).forEach( iFrame => iFrame.remove() );
321
322 const placeholder = wrapper.querySelector( '.likes-widget-placeholder' );
323
324 // Post like iframe
325 if ( placeholder && placeholder.classList.contains( 'post-likes-widget-placeholder' ) ) {
326 const postLikesFrame = document.createElement( 'iframe' );
327
328 postLikesFrame.classList.add( 'post-likes-widget', 'jetpack-likes-widget' );
329 postLikesFrame.name = wrapper.dataset.name;
330 postLikesFrame.src = wrapper.dataset.src;
331 postLikesFrame.height = '55px';
332 postLikesFrame.width = '100%';
333 postLikesFrame.frameBorder = '0';
334 postLikesFrame.scrolling = 'no';
335 postLikesFrame.title = wrapper.dataset.title;
336
337 placeholder.after( postLikesFrame );
338 }
339
340 // Comment like iframe
341 if ( placeholder.classList.contains( 'comment-likes-widget-placeholder' ) ) {
342 const commentLikesFrame = document.createElement( 'iframe' );
343
344 commentLikesFrame.class = 'comment-likes-widget-frame jetpack-likes-widget-frame';
345 commentLikesFrame.name = wrapper.dataset.name;
346 commentLikesFrame.src = wrapper.dataset.src;
347 commentLikesFrame.height = '18px';
348 commentLikesFrame.width = '100%';
349 commentLikesFrame.frameBorder = '0';
350 commentLikesFrame.scrolling = 'no';
351
352 wrapper.querySelector( '.comment-like-feedback' ).after( commentLikesFrame );
353
354 jetpackCommentLikesLoadedWidgets.push( commentLikesFrame );
355 }
356
357 wrapper.classList.remove( 'jetpack-likes-widget-unloaded' );
358 wrapper.classList.add( 'jetpack-likes-widget-loading' );
359
360 wrapper.querySelector( 'iframe' ).addEventListener( 'load', e => {
361 JetpackLikesPostMessage(
362 { event: 'loadLikeWidget', name: e.target.name, width: e.target.width },
363 window.frames[ 'likes-master' ]
364 );
365
366 wrapper.classList.remove( 'jetpack-likes-widget-loading' );
367 wrapper.classList.add( 'jetpack-likes-widget-loaded' );
368 } );
369 }
370
371 function jetpackGetUnloadedWidgetsInView() {
372 const unloadedWidgets = document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' );
373
374 return [ ...unloadedWidgets ].filter( item => jetpackIsScrolledIntoView( item ) );
375 }
376
377 function jetpackIsScrolledIntoView( element ) {
378 const top = element.getBoundingClientRect().top;
379 const bottom = element.getBoundingClientRect().bottom;
380
381 // Allow some slack above and bellow the fold with jetpackLikesLookAhead,
382 // with the aim of hiding the transition from unloaded to loaded widget from users.
383 return top + jetpackLikesLookAhead >= 0 && bottom <= window.innerHeight + jetpackLikesLookAhead;
384 }
385
386 function jetpackUnloadScrolledOutWidgets() {
387 for ( let i = jetpackCommentLikesLoadedWidgets.length - 1; i >= 0; i-- ) {
388 const currentWidgetIframe = jetpackCommentLikesLoadedWidgets[ i ];
389
390 if ( ! jetpackIsScrolledIntoView( currentWidgetIframe ) ) {
391 const widgetWrapper =
392 currentWidgetIframe &&
393 currentWidgetIframe.parentElement &&
394 currentWidgetIframe.parentElement.parentElement;
395
396 // Restore parent class to 'unloaded' so this widget can be picked up by queue manager again if needed.
397 widgetWrapper.classList.remove( 'jetpack-likes-widget-loaded' );
398 widgetWrapper.classList.remove( 'jetpack-likes-widget-loading' );
399 widgetWrapper.classList.add( 'jetpack-likes-widget-unloaded' );
400
401 // Bring back the loading placeholder into view.
402 widgetWrapper
403 .querySelectorAll( '.comment-likes-widget-placeholder' )
404 .forEach( item => ( item.style.display = 'block' ) );
405
406 // Remove it from the list of loaded widgets.
407 jetpackCommentLikesLoadedWidgets.splice( i, 1 );
408
409 // Remove comment like widget iFrame.
410 currentWidgetIframe.remove();
411 }
412 }
413 }
414
415 var jetpackWidgetsDelayedExec = function ( after, fn ) {
416 var timer;
417 return function () {
418 clearTimeout( timer );
419 timer = setTimeout( fn, after );
420 };
421 };
422
423 var jetpackOnScrollStopped = jetpackWidgetsDelayedExec( 250, JetpackLikesWidgetQueueHandler );
424
425 // Load initial batch of widgets, prior to any scrolling events.
426 JetpackLikesWidgetQueueHandler();
427
428 // Add event listener to execute queue handler after scroll.
429 window.addEventListener( 'scroll', jetpackOnScrollStopped, true );
430