PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 6.1.3
Jetpack – WP Security, Backup, Speed, & Growth v6.1.3
16.2-beta 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 All 501 releases
jetpack / modules / likes / queuehandler.js

queuehandler.js in Jetpack – WP Security, Backup, Speed, & Growth 6.1.3, at modules/likes/queuehandler.js

385 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global pm, wpcom_reblog, JSON */
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 function JetpackLikesPostMessage(message, target ) {
16 if ( 'string' === typeof message ){
17 try {
18 message = JSON.parse( message );
19 } catch(e) {
20 return;
21 }
22 }
23
24 pm( {
25 target: target,
26 type: 'likesMessage',
27 data: message,
28 origin: '*'
29 } );
30 }
31
32 function JetpackLikesBatchHandler() {
33 var requests = [];
34 jQuery( 'div.jetpack-likes-widget-unloaded' ).each( function() {
35 if ( jetpackLikesWidgetBatch.indexOf( this.id ) > -1 ) {
36 return;
37 }
38
39 if ( ! jetpackIsScrolledIntoView( this ) ) {
40 return;
41 }
42
43 jetpackLikesWidgetBatch.push( this.id );
44
45 var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/,
46 match = regex.exec( this.id ),
47 info;
48
49 if ( ! match || match.length !== 5 ) {
50 return;
51 }
52
53 info = {
54 blog_id: match[2],
55 width: this.width
56 };
57
58 if ( 'post' === match[1] ) {
59 info.post_id = match[3];
60 } else if ( 'comment' === match[1] ) {
61 info.comment_id = match[3];
62 }
63
64 info.obj_id = match[4];
65
66 requests.push( info );
67 });
68
69 if ( requests.length > 0 ) {
70 JetpackLikesPostMessage( { event: 'initialBatch', requests: requests }, window.frames['likes-master'] );
71 }
72 }
73
74 function JetpackLikesMessageListener( event, message ) {
75 var allowedOrigin, $container, $list, offset, rowLength, height, scrollbarWidth;
76
77 if ( 'undefined' === typeof event.event ) {
78 return;
79 }
80
81 // We only allow messages from one origin
82 allowedOrigin = 'https://widgets.wp.com';
83 if ( allowedOrigin !== message.origin ) {
84 return;
85 }
86
87 switch ( event.event ) {
88 case 'masterReady':
89 jQuery( document ).ready( function() {
90 jetpackLikesMasterReady = true;
91
92 var stylesData = {
93 event: 'injectStyles'
94 },
95 $sdTextColor = jQuery( '.sd-text-color' ),
96 $sdLinkColor = jQuery( '.sd-link-color' );
97
98 if ( jQuery( 'iframe.admin-bar-likes-widget' ).length > 0 ) {
99 JetpackLikesPostMessage( { event: 'adminBarEnabled' }, window.frames[ 'likes-master' ] );
100
101 stylesData.adminBarStyles = {
102 background: jQuery( '#wpadminbar .quicklinks li#wp-admin-bar-wpl-like > a' ).css( 'background' ),
103 isRtl: ( 'rtl' === jQuery( '#wpadminbar' ).css( 'direction' ) )
104 };
105 }
106
107 if ( ! window.addEventListener ) {
108 jQuery( '#wp-admin-bar-admin-bar-likes-widget' ).hide();
109 }
110
111 stylesData.textStyles = {
112 color: $sdTextColor.css( 'color' ),
113 fontFamily: $sdTextColor.css( 'font-family' ),
114 fontSize: $sdTextColor.css( 'font-size' ),
115 direction: $sdTextColor.css( 'direction' ),
116 fontWeight: $sdTextColor.css( 'font-weight' ),
117 fontStyle: $sdTextColor.css( 'font-style' ),
118 textDecoration: $sdTextColor.css( 'text-decoration' )
119 };
120
121 stylesData.linkStyles = {
122 color: $sdLinkColor.css( 'color' ),
123 fontFamily: $sdLinkColor.css( 'font-family' ),
124 fontSize: $sdLinkColor.css( 'font-size' ),
125 textDecoration: $sdLinkColor.css( 'text-decoration' ),
126 fontWeight: $sdLinkColor.css( 'font-weight' ),
127 fontStyle: $sdLinkColor.css( 'font-style' )
128 };
129
130 JetpackLikesPostMessage( stylesData, window.frames[ 'likes-master' ] );
131
132 JetpackLikesBatchHandler();
133 } );
134
135 break;
136
137 case 'showLikeWidget':
138 jQuery( '#' + event.id + ' .likes-widget-placeholder' ).fadeOut( 'fast' );
139 break;
140
141 case 'showCommentLikeWidget':
142 jQuery( '#' + event.id + ' .likes-widget-placeholder' ).fadeOut( 'fast' );
143 break;
144
145 case 'killCommentLikes':
146 // If kill switch for comment likes is enabled remove all widgets wrappers and `Loading...` placeholders.
147 jQuery( '.jetpack-comment-likes-widget-wrapper' ).remove();
148 break;
149
150 case 'clickReblogFlair':
151 wpcom_reblog.toggle_reblog_box_flair( event.obj_id );
152 break;
153
154 case 'showOtherGravatars':
155 $container = jQuery( '#likes-other-gravatars' );
156 $list = $container.find( 'ul' );
157
158 $container.hide();
159 $list.html( '' );
160
161 $container.find( '.likes-text span' ).text( event.total );
162
163 jQuery.each( event.likers, function( i, liker ) {
164 var element;
165
166 if ( 'http' !== liker.profile_URL.substr( 0, 4 ) ) {
167 // We only display gravatars with http or https schema
168 return;
169 }
170
171 element = jQuery( '<li><a><img /></a></li>' );
172 element.addClass( liker.css_class );
173
174 element.find( 'a' ).
175 attr( {
176 href: liker.profile_URL,
177 rel: 'nofollow',
178 target: '_parent'
179 } ).
180 addClass( 'wpl-liker' );
181
182 element.find( 'img' ).
183 attr( {
184 src: liker.avatar_URL,
185 alt: liker.name
186 } ).
187 css( {
188 width: '30px',
189 height: '30px',
190 paddingRight: '3px'
191 } );
192
193 $list.append( element );
194 } );
195
196 offset = jQuery( '[name=\'' + event.parent + '\']' ).offset();
197
198 $container.css( 'left', offset.left + event.position.left - 10 + 'px' );
199 $container.css( 'top', offset.top + event.position.top - 33 + 'px' );
200
201 rowLength = Math.floor( event.width / 37 );
202 height = ( Math.ceil( event.likers.length / rowLength ) * 37 ) + 13;
203 if ( height > 204 ) {
204 height = 204;
205 }
206
207 $container.css( 'height', height + 'px' );
208 $container.css( 'width', rowLength * 37 - 7 + 'px' );
209
210 $list.css( 'width', rowLength * 37 + 'px' );
211
212 $container.fadeIn( 'slow' );
213
214 scrollbarWidth = $list[0].offsetWidth - $list[0].clientWidth;
215 if ( scrollbarWidth > 0 ) {
216 $container.width( $container.width() + scrollbarWidth );
217 $list.width( $list.width() + scrollbarWidth );
218 }
219 }
220 }
221
222 pm.bind( 'likesMessage', JetpackLikesMessageListener );
223
224 jQuery( document ).click( function( e ) {
225 var $container = jQuery( '#likes-other-gravatars' );
226
227 if ( $container.has( e.target ).length === 0 ) {
228 $container.fadeOut( 'slow' );
229 }
230 });
231
232 function JetpackLikesWidgetQueueHandler() {
233 var wrapperID;
234
235 if ( ! jetpackLikesMasterReady ) {
236 setTimeout( JetpackLikesWidgetQueueHandler, 500 );
237 return;
238 }
239
240 // Restore widgets to initial unloaded state when they are scrolled out of view.
241 jetpackUnloadScrolledOutWidgets();
242
243 var unloadedWidgetsInView = jetpackGetUnloadedWidgetsInView();
244
245 if ( unloadedWidgetsInView.length > 0 ) {
246 // Grab any unloaded widgets for a batch request
247 JetpackLikesBatchHandler();
248 }
249
250 for ( var i=0, length = unloadedWidgetsInView.length; i <= length - 1; i++ ) {
251 wrapperID = unloadedWidgetsInView[i].id;
252
253 if ( ! wrapperID ){
254 continue;
255 }
256
257 jetpackLoadLikeWidgetIframe( wrapperID );
258 }
259 }
260
261 function jetpackLoadLikeWidgetIframe( wrapperID ) {
262 var $wrapper;
263
264 if ( 'undefined' === typeof wrapperID ) {
265 return;
266 }
267
268 $wrapper = jQuery( '#' + wrapperID );
269 $wrapper.find( 'iframe' ).remove();
270
271 var placeholder = $wrapper.find( '.likes-widget-placeholder' );
272
273 // Post like iframe
274 if ( placeholder.hasClass( 'post-likes-widget-placeholder' ) ) {
275 var postLikesFrame = document.createElement( 'iframe' );
276
277 postLikesFrame['class'] = 'post-likes-widget jetpack-likes-widget';
278 postLikesFrame.name = $wrapper.data( 'name' );
279 postLikesFrame.src = $wrapper.data( 'src' );
280 postLikesFrame.height = '18px';
281 postLikesFrame.width = '200px';
282 postLikesFrame.frameBorder = '0';
283 postLikesFrame.scrolling = 'no';
284
285 if ( $wrapper.hasClass( 'slim-likes-widget' ) ) {
286 postLikesFrame.height = '22px';
287 postLikesFrame.width = '68px';
288 postLikesFrame.scrolling = 'no';
289 } else {
290 postLikesFrame.height = '55px';
291 postLikesFrame.width = '100%';
292 }
293
294 placeholder.after( postLikesFrame );
295 }
296
297 // Comment like iframe
298 if ( placeholder.hasClass( 'comment-likes-widget-placeholder' ) ) {
299 var commentLikesFrame = document.createElement( 'iframe' );
300
301 commentLikesFrame['class'] = 'comment-likes-widget-frame jetpack-likes-widget-frame';
302 commentLikesFrame.name = $wrapper.data( 'name' );
303 commentLikesFrame.src = $wrapper.data( 'src' );
304 commentLikesFrame.height = '18px';
305 commentLikesFrame.width = '100%';
306 commentLikesFrame.frameBorder = '0';
307 commentLikesFrame.scrolling = 'no';
308
309 $wrapper.find( '.comment-like-feedback' ).after( commentLikesFrame );
310
311 jetpackCommentLikesLoadedWidgets.push( commentLikesFrame );
312 }
313
314 $wrapper.removeClass( 'jetpack-likes-widget-unloaded' ).addClass( 'jetpack-likes-widget-loading' );
315
316 $wrapper.find( 'iframe' ).load( function( e ) {
317 var $iframe = jQuery( e.target );
318
319 JetpackLikesPostMessage( { event: 'loadLikeWidget', name: $iframe.attr( 'name' ), width: $iframe.width() }, window.frames[ 'likes-master' ] );
320
321 $wrapper.removeClass( 'jetpack-likes-widget-loading' ).addClass( 'jetpack-likes-widget-loaded' );
322
323 if ( $wrapper.hasClass( 'slim-likes-widget' ) ) {
324 $wrapper.find( 'iframe' ).Jetpack( 'resizeable' );
325 }
326 });
327 }
328
329 function jetpackGetUnloadedWidgetsInView() {
330 var $unloadedWidgets = jQuery( 'div.jetpack-likes-widget-unloaded' );
331
332 return $unloadedWidgets.filter( function() {
333 return jetpackIsScrolledIntoView( this );
334 } );
335 }
336
337 function jetpackIsScrolledIntoView( element ) {
338 var top = element.getBoundingClientRect().top;
339 var bottom = element.getBoundingClientRect().bottom;
340
341 // Allow some slack above and bellow the fold with jetpackLikesLookAhead,
342 // with the aim of hiding the transition from unloaded to loaded widget from users.
343 return ( top + jetpackLikesLookAhead >= 0 ) && ( bottom <= window.innerHeight + jetpackLikesLookAhead );
344 }
345
346 function jetpackUnloadScrolledOutWidgets() {
347 for ( var i = jetpackCommentLikesLoadedWidgets.length - 1; i >= 0; i-- ) {
348 var currentWidgetIframe = jetpackCommentLikesLoadedWidgets[ i ];
349
350 if ( ! jetpackIsScrolledIntoView( currentWidgetIframe ) ) {
351 var $widgetWrapper = jQuery( currentWidgetIframe ).parent().parent();
352
353 // Restore parent class to 'unloaded' so this widget can be picked up by queue manager again if needed.
354 $widgetWrapper
355 .removeClass( 'jetpack-likes-widget-loaded jetpack-likes-widget-loading' )
356 .addClass( 'jetpack-likes-widget-unloaded' );
357
358 // Bring back the loading placeholder into view.
359 $widgetWrapper.children( '.comment-likes-widget-placeholder' ).fadeIn();
360
361 // Remove it from the list of loaded widgets.
362 jetpackCommentLikesLoadedWidgets.splice( i, 1 );
363
364 // Remove comment like widget iFrame.
365 jQuery( currentWidgetIframe ).remove();
366 }
367 }
368 }
369
370 var jetpackWidgetsDelayedExec = function( after, fn ) {
371 var timer;
372 return function() {
373 timer && clearTimeout( timer );
374 timer = setTimeout( fn, after );
375 };
376 };
377
378 var jetpackOnScrollStopped = jetpackWidgetsDelayedExec( 250, JetpackLikesWidgetQueueHandler );
379
380 // Load initial batch of widgets, prior to any scrolling events.
381 JetpackLikesWidgetQueueHandler();
382
383 // Add event listener to execute queue handler after scroll.
384 window.addEventListener( 'scroll', jetpackOnScrollStopped, true );
385