PluginProbe ʕ •ᴥ•ʔ
Akismet Anti-spam: Spam Protection / 5.7
Akismet Anti-spam: Spam Protection v5.7
5.7 3.0.4 3.0.5 3.1 3.1.1 3.1.10 3.1.11 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1 4.1.1 4.1.10 4.1.11 4.1.12 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 5.0 5.0.1 5.0.2 5.1 5.2 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4 5.5 5.6 trunk 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.4.0 2.4.1 2.5.0 2.5.1 2.5.10 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 3.0.0 3.0.0-RC1 3.0.1 3.0.2 3.0.3
akismet / _inc / akismet.js
akismet / _inc Last commit date
fonts 1 month ago img 1 month ago rtl 1 month ago akismet-admin.css 1 month ago akismet-admin.js 2 months ago akismet-frontend.js 2 months ago akismet.css 6 months ago akismet.js 1 month ago
akismet.js
398 lines
1 jQuery( function ( $ ) {
2 var mshotRemovalTimer = null;
3 var mshotRetryTimer = null;
4 var mshotTries = 0;
5 var mshotRetryInterval = 1000;
6 var mshotEnabledLinkSelector = 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a';
7
8 var preloadedMshotURLs = [];
9
10 $('.akismet-status').each(function () {
11 var thisId = $(this).attr('commentid');
12 $(this).prependTo('#comment-' + thisId + ' .column-comment');
13 });
14 $('.akismet-user-comment-count').each(function () {
15 var thisId = $(this).attr('commentid');
16 $(this).insertAfter('#comment-' + thisId + ' .author strong:first').show();
17 });
18
19 akismet_enable_comment_author_url_removal();
20
21 $( '#the-comment-list' ).on( 'click', '.akismet_remove_url', function () {
22 var thisId = $(this).attr('commentid');
23 var data = {
24 action: 'comment_author_deurl',
25 _wpnonce: WPAkismet.comment_author_url_nonce,
26 id: thisId
27 };
28 $.ajax({
29 url: ajaxurl,
30 type: 'POST',
31 data: data,
32 beforeSend: function () {
33 // Removes "x" link
34 $("a[commentid='"+ thisId +"']").hide();
35 // Show temp status
36 $("#author_comment_url_"+ thisId).html( $( '<span/>' ).text( WPAkismet.strings['Removing...'] ) );
37 },
38 success: function (response) {
39 if (response) {
40 // Show status/undo link
41 $("#author_comment_url_"+ thisId)
42 .attr('cid', thisId)
43 .addClass('akismet_undo_link_removal')
44 .html(
45 $( '<span/>' ).text( WPAkismet.strings['URL removed'] )
46 )
47 .append( ' ' )
48 .append(
49 $( '<span/>' )
50 .text( WPAkismet.strings['(undo)'] )
51 .addClass( 'akismet-span-link' )
52 );
53 }
54 }
55 });
56
57 return false;
58 }).on( 'click', '.akismet_undo_link_removal', function () {
59 var thisId = $(this).attr('cid');
60 var thisUrl = $(this).attr('href');
61 var data = {
62 action: 'comment_author_reurl',
63 _wpnonce: WPAkismet.comment_author_url_nonce,
64 id: thisId,
65 url: thisUrl
66 };
67 $.ajax({
68 url: ajaxurl,
69 type: 'POST',
70 data: data,
71 beforeSend: function () {
72 // Show temp status
73 $("#author_comment_url_"+ thisId).html( $( '<span/>' ).text( WPAkismet.strings['Re-adding...'] ) );
74 },
75 success: function (response) {
76 if (response) {
77 // Add "x" link
78 $("a[commentid='"+ thisId +"']").show();
79 // Show link. Core strips leading http://, so let's do that too.
80 $("#author_comment_url_"+ thisId).removeClass('akismet_undo_link_removal').text( thisUrl.replace( /^http:\/\/(www\.)?/ig, '' ) );
81 }
82 }
83 });
84
85 return false;
86 });
87
88 // Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
89 if ( "enable_mshots" in WPAkismet && WPAkismet.enable_mshots ) {
90 $( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
91 clearTimeout( mshotRemovalTimer );
92
93 if ( $( '.akismet-mshot' ).length > 0 ) {
94 if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
95 // The preview is already showing for this link.
96 return;
97 }
98 else {
99 // A new link is being hovered, so remove the old preview.
100 $( '.akismet-mshot' ).remove();
101 }
102 }
103
104 clearTimeout( mshotRetryTimer );
105
106 var linkUrl = $( this ).attr( 'href' );
107
108 if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
109 // This preview image was already preloaded, so begin with a retry URL so the user doesn't see the placeholder image for the first second.
110 mshotTries = 2;
111 }
112 else {
113 mshotTries = 1;
114 }
115
116 var mShot = $( '<div class="akismet-mshot mshot-container"><div class="mshot-arrow"></div><img src="' + akismet_mshot_url( linkUrl, mshotTries ) + '" width="450" height="338" class="mshot-image" /></div>' );
117 mShot.data( 'link', this );
118 mShot.data( 'url', linkUrl );
119
120 mShot.find( 'img' ).on( 'load', function () {
121 $( '.akismet-mshot' ).data( 'pending-request', false );
122 } );
123
124 var offset = $( this ).offset();
125
126 mShot.offset( {
127 left : Math.min( $( window ).width() - 475, offset.left + $( this ).width() + 10 ), // Keep it on the screen if the link is near the edge of the window.
128 top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
129 } );
130
131 $( 'body' ).append( mShot );
132
133 mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
134 } ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
135 mshotRemovalTimer = setTimeout( function () {
136 clearTimeout( mshotRetryTimer );
137
138 $( '.akismet-mshot' ).remove();
139 }, 200 );
140 } );
141
142 var preloadDelayTimer = null;
143
144 $( window ).on( 'scroll resize', function () {
145 clearTimeout( preloadDelayTimer );
146
147 preloadDelayTimer = setTimeout( preloadMshotsInViewport, 500 );
148 } );
149
150 preloadMshotsInViewport();
151 }
152
153 /**
154 * The way mShots works is if there was no screenshot already recently generated for the URL,
155 * it returns a "loading..." image for the first request. Then, some subsequent request will
156 * receive the actual screenshot, but it's unknown how long it will take. So, what we do here
157 * is continually re-request the mShot, waiting a second after every response until we get the
158 * actual screenshot.
159 */
160 function retryMshotUntilLoaded() {
161 clearTimeout( mshotRetryTimer );
162
163 var imageWidth = $( '.akismet-mshot img' ).get(0).naturalWidth;
164
165 if ( imageWidth == 0 ) {
166 // It hasn't finished loading yet the first time. Check again shortly.
167 setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
168 }
169 else if ( imageWidth == 400 ) {
170 // It loaded the preview image.
171
172 if ( mshotTries == 20 ) {
173 // Give up if we've requested the mShot 20 times already.
174 return;
175 }
176
177 if ( ! $( '.akismet-mshot' ).data( 'pending-request' ) ) {
178 $( '.akismet-mshot' ).data( 'pending-request', true );
179
180 mshotTries++;
181
182 $( '.akismet-mshot .mshot-image' ).attr( 'src', akismet_mshot_url( $( '.akismet-mshot' ).data( 'url' ), mshotTries ) );
183 }
184
185 mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
186 }
187 else {
188 // All done.
189 }
190 }
191
192 function preloadMshotsInViewport() {
193 var windowWidth = $( window ).width();
194 var windowHeight = $( window ).height();
195
196 $( '#the-comment-list' ).find( mshotEnabledLinkSelector ).each( function ( index, element ) {
197 var linkUrl = $( this ).attr( 'href' );
198
199 // Don't attempt to preload an mshot for a single link twice.
200 if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
201 // The URL is already preloaded.
202 return true;
203 }
204
205 if ( typeof element.getBoundingClientRect !== 'function' ) {
206 // The browser is too old. Return false to stop this preloading entirely.
207 return false;
208 }
209
210 var rect = element.getBoundingClientRect();
211
212 if ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= windowHeight && rect.right <= windowWidth ) {
213 akismet_preload_mshot( linkUrl );
214 $( this ).data( 'akismet-mshot-preloaded', true );
215 }
216 } );
217 }
218
219 $( '.checkforspam.enable-on-load' ).on( 'click', function( e ) {
220 if ( $( this ).hasClass( 'ajax-disabled' ) ) {
221 // Akismet hasn't been configured yet. Allow the user to proceed to the button's link.
222 return;
223 }
224
225 e.preventDefault();
226
227 if ( $( this ).hasClass( 'button-disabled' ) ) {
228 window.location.href = $( this ).data( 'success-url' ).replace( '__recheck_count__', 0 ).replace( '__spam_count__', 0 );
229 return;
230 }
231
232 $('.checkforspam').addClass('button-disabled').addClass( 'checking' );
233 $('.checkforspam-spinner').addClass( 'spinner' ).addClass( 'is-active' );
234
235 akismet_check_for_spam(0, 100);
236 }).removeClass( 'button-disabled' );
237
238 var spam_count = 0;
239 var recheck_count = 0;
240
241 function akismet_check_for_spam(offset, limit) {
242 var check_for_spam_buttons = $( '.checkforspam' );
243
244 var nonce = check_for_spam_buttons.data( 'nonce' );
245
246 // We show the percentage complete down to one decimal point so even queues with 100k
247 // pending comments will show some progress pretty quickly.
248 var percentage_complete = Math.round( ( recheck_count / check_for_spam_buttons.data( 'pending-comment-count' ) ) * 1000 ) / 10;
249
250 // Update the progress counter on the "Check for Spam" button.
251 $( '.checkforspam' ).text( check_for_spam_buttons.data( 'progress-label' ).replace( '%1$s', percentage_complete ) );
252
253 $.post(
254 ajaxurl,
255 {
256 'action': 'akismet_recheck_queue',
257 'offset': offset,
258 'limit': limit,
259 'nonce': nonce
260 },
261 function(result) {
262 if ( 'error' in result ) {
263 // An error is only returned in the case of a missing nonce, so we don't need the actual error message.
264 window.location.href = check_for_spam_buttons.data( 'failure-url' );
265 return;
266 }
267
268 recheck_count += result.counts.processed;
269 spam_count += result.counts.spam;
270
271 if (result.counts.processed < limit) {
272 window.location.href = check_for_spam_buttons.data( 'success-url' ).replace( '__recheck_count__', recheck_count ).replace( '__spam_count__', spam_count );
273 }
274 else {
275 // Account for comments that were caught as spam and moved out of the queue.
276 akismet_check_for_spam(offset + limit - result.counts.spam, limit);
277 }
278 }
279 );
280 }
281
282 if ( "start_recheck" in WPAkismet && WPAkismet.start_recheck ) {
283 $( '.checkforspam:first' ).click();
284 }
285
286 if ( typeof MutationObserver !== 'undefined' ) {
287 // Dynamically add the "X" next the the author URL links when a comment is quick-edited.
288 var comment_list_container = document.getElementById( 'the-comment-list' );
289
290 if ( comment_list_container ) {
291 var observer = new MutationObserver( function ( mutations ) {
292 for ( var i = 0, _len = mutations.length; i < _len; i++ ) {
293 if ( mutations[i].addedNodes.length > 0 ) {
294 akismet_enable_comment_author_url_removal();
295
296 // Once we know that we'll have to check for new author links, skip the rest of the mutations.
297 break;
298 }
299 }
300 } );
301
302 observer.observe( comment_list_container, { attributes: true, childList: true, characterData: true } );
303 }
304 }
305
306 function akismet_enable_comment_author_url_removal() {
307 $( '#the-comment-list' )
308 .find( 'tr.comment, tr[id ^= "comment-"]' )
309 .find( '.column-author a[href^="http"]:first' ) // Ignore mailto: links, which would be the comment author's email.
310 .each(function () {
311 if ( $( this ).parent().find( '.akismet_remove_url' ).length > 0 ) {
312 return;
313 }
314
315 var linkHref = $(this).attr( 'href' );
316
317 // Ignore any links to the current domain, which are diagnostic tools, like the IP address link
318 // or any other links another plugin might add.
319 var currentHostParts = document.location.href.split( '/' );
320 var currentHost = currentHostParts[0] + '//' + currentHostParts[2] + '/';
321
322 if ( linkHref.indexOf( currentHost ) != 0 ) {
323 var thisCommentId = $(this).parents('tr:first').attr('id').split("-");
324
325 $(this)
326 .attr("id", "author_comment_url_"+ thisCommentId[1])
327 .after(
328 $( '<a href="#" class="akismet_remove_url">x</a>' )
329 .attr( 'commentid', thisCommentId[1] )
330 .attr( 'title', WPAkismet.strings['Remove this URL'] )
331 );
332 }
333 });
334 }
335
336 /**
337 * Generate an mShot URL if given a link URL.
338 *
339 * @param string linkUrl
340 * @param int retry If retrying a request, the number of the retry.
341 * @return string The mShot URL;
342 */
343 function akismet_mshot_url( linkUrl, retry ) {
344 var mshotUrl = '//s0.wp.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
345
346 if ( retry > 1 ) {
347 mshotUrl += '&r=' + encodeURIComponent( retry );
348 }
349
350 mshotUrl += '&source=akismet';
351
352 return mshotUrl;
353 }
354
355 /**
356 * Begin loading an mShot preview of a link.
357 *
358 * @param string linkUrl
359 */
360 function akismet_preload_mshot( linkUrl ) {
361 var img = new Image();
362 img.src = akismet_mshot_url( linkUrl );
363
364 preloadedMshotURLs.push( linkUrl );
365 }
366
367 $( '.akismet-could-be-primary' ).each( function () {
368 var form = $( this ).closest( 'form' );
369
370 form.data( 'initial-state', form.serialize() );
371
372 form.on( 'change keyup', function () {
373 var self = $( this );
374 var submit_button = self.find( '.akismet-could-be-primary' );
375
376 if ( self.serialize() != self.data( 'initial-state' ) ) {
377 submit_button.addClass( 'akismet-is-primary' );
378 }
379 else {
380 submit_button.removeClass( 'akismet-is-primary' );
381 }
382 } );
383 } );
384
385 /**
386 * Shows the Enter API key form
387 */
388 $( '.akismet-enter-api-key-box__reveal' ).on( 'click', function ( e ) {
389 e.preventDefault();
390
391 var div = $( '.akismet-enter-api-key-box__form-wrapper' );
392 div.show();
393 div.find( 'input[name=key]' ).focus();
394
395 $( this ).hide();
396 } );
397 });
398