akismet.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. jQuery( function ( $ ) {
  2. var mshotRemovalTimer = null;
  3. var mshotSecondTryTimer = null
  4. var mshotThirdTryTimer = null
  5. var mshotEnabledLinkSelector = 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a';
  6. $('.akismet-status').each(function () {
  7. var thisId = $(this).attr('commentid');
  8. $(this).prependTo('#comment-' + thisId + ' .column-comment');
  9. });
  10. $('.akismet-user-comment-count').each(function () {
  11. var thisId = $(this).attr('commentid');
  12. $(this).insertAfter('#comment-' + thisId + ' .author strong:first').show();
  13. });
  14. akismet_enable_comment_author_url_removal();
  15. $( '#the-comment-list' ).on( 'click', '.akismet_remove_url', function () {
  16. var thisId = $(this).attr('commentid');
  17. var data = {
  18. action: 'comment_author_deurl',
  19. _wpnonce: WPAkismet.comment_author_url_nonce,
  20. id: thisId
  21. };
  22. $.ajax({
  23. url: ajaxurl,
  24. type: 'POST',
  25. data: data,
  26. beforeSend: function () {
  27. // Removes "x" link
  28. $("a[commentid='"+ thisId +"']").hide();
  29. // Show temp status
  30. $("#author_comment_url_"+ thisId).html( $( '<span/>' ).text( WPAkismet.strings['Removing...'] ) );
  31. },
  32. success: function (response) {
  33. if (response) {
  34. // Show status/undo link
  35. $("#author_comment_url_"+ thisId)
  36. .attr('cid', thisId)
  37. .addClass('akismet_undo_link_removal')
  38. .html(
  39. $( '<span/>' ).text( WPAkismet.strings['URL removed'] )
  40. )
  41. .append( ' ' )
  42. .append(
  43. $( '<span/>' )
  44. .text( WPAkismet.strings['(undo)'] )
  45. .addClass( 'akismet-span-link' )
  46. );
  47. }
  48. }
  49. });
  50. return false;
  51. }).on( 'click', '.akismet_undo_link_removal', function () {
  52. var thisId = $(this).attr('cid');
  53. var thisUrl = $(this).attr('href');
  54. var data = {
  55. action: 'comment_author_reurl',
  56. _wpnonce: WPAkismet.comment_author_url_nonce,
  57. id: thisId,
  58. url: thisUrl
  59. };
  60. $.ajax({
  61. url: ajaxurl,
  62. type: 'POST',
  63. data: data,
  64. beforeSend: function () {
  65. // Show temp status
  66. $("#author_comment_url_"+ thisId).html( $( '<span/>' ).text( WPAkismet.strings['Re-adding...'] ) );
  67. },
  68. success: function (response) {
  69. if (response) {
  70. // Add "x" link
  71. $("a[commentid='"+ thisId +"']").show();
  72. // Show link. Core strips leading http://, so let's do that too.
  73. $("#author_comment_url_"+ thisId).removeClass('akismet_undo_link_removal').text( thisUrl.replace( /^http:\/\/(www\.)?/ig, '' ) );
  74. }
  75. }
  76. });
  77. return false;
  78. });
  79. // Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
  80. $( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
  81. clearTimeout( mshotRemovalTimer );
  82. if ( $( '.akismet-mshot' ).length > 0 ) {
  83. if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
  84. // The preview is already showing for this link.
  85. return;
  86. }
  87. else {
  88. // A new link is being hovered, so remove the old preview.
  89. $( '.akismet-mshot' ).remove();
  90. }
  91. }
  92. clearTimeout( mshotSecondTryTimer );
  93. clearTimeout( mshotThirdTryTimer );
  94. var thisHref = $( this ).attr( 'href' );
  95. var mShot = $( '<div class="akismet-mshot mshot-container"><div class="mshot-arrow"></div><img src="' + akismet_mshot_url( thisHref ) + '" width="450" height="338" class="mshot-image" /></div>' );
  96. mShot.data( 'link', this );
  97. var offset = $( this ).offset();
  98. mShot.offset( {
  99. 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.
  100. top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
  101. } );
  102. // These retries appear to be superfluous if .mshot-image has already loaded, but it's because mShots
  103. // can return a "Generating thumbnail..." image if it doesn't have a thumbnail ready, so we need
  104. // to retry to see if we can get the newly generated thumbnail.
  105. mshotSecondTryTimer = setTimeout( function () {
  106. mShot.find( '.mshot-image' ).attr( 'src', akismet_mshot_url( thisHref, 2 ) );
  107. }, 6000 );
  108. mshotThirdTryTimer = setTimeout( function () {
  109. mShot.find( '.mshot-image' ).attr( 'src', akismet_mshot_url( thisHref, 3 ) );
  110. }, 12000 );
  111. $( 'body' ).append( mShot );
  112. } ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
  113. mshotRemovalTimer = setTimeout( function () {
  114. clearTimeout( mshotSecondTryTimer );
  115. clearTimeout( mshotThirdTryTimer );
  116. $( '.akismet-mshot' ).remove();
  117. }, 200 );
  118. } ).on( 'mouseover', 'tr', function () {
  119. // When the mouse hovers over a comment row, begin preloading mshots for any links in the comment or the comment author.
  120. var linksToPreloadMshotsFor = $( this ).find( mshotEnabledLinkSelector );
  121. linksToPreloadMshotsFor.each( function () {
  122. // Don't attempt to preload an mshot for a single link twice. Browser caching should cover this, but in case of
  123. // race conditions, save a flag locally when we've begun trying to preload one.
  124. if ( ! $( this ).data( 'akismet-mshot-preloaded' ) ) {
  125. akismet_preload_mshot( $( this ).attr( 'href' ) );
  126. $( this ).data( 'akismet-mshot-preloaded', true );
  127. }
  128. } );
  129. } );
  130. $('.checkforspam:not(.button-disabled)').click( function(e) {
  131. e.preventDefault();
  132. $('.checkforspam:not(.button-disabled)').addClass('button-disabled');
  133. $('.checkforspam-spinner').addClass( 'spinner' ).addClass( 'is-active' );
  134. // Update the label on the "Check for Spam" button to use the active "Checking for Spam" language.
  135. $( '.checkforspam .akismet-label' ).text( $( '.checkforspam' ).data( 'active-label' ) );
  136. akismet_check_for_spam(0, 100);
  137. });
  138. var spam_count = 0;
  139. var recheck_count = 0;
  140. function akismet_check_for_spam(offset, limit) {
  141. var check_for_spam_buttons = $( '.checkforspam' );
  142. // We show the percentage complete down to one decimal point so even queues with 100k
  143. // pending comments will show some progress pretty quickly.
  144. var percentage_complete = Math.round( ( recheck_count / check_for_spam_buttons.data( 'pending-comment-count' ) ) * 1000 ) / 10;
  145. // Update the progress counter on the "Check for Spam" button.
  146. $( '.checkforspam-progress' ).text( check_for_spam_buttons.data( 'progress-label-format' ).replace( '%1$s', percentage_complete ) );
  147. $.post(
  148. ajaxurl,
  149. {
  150. 'action': 'akismet_recheck_queue',
  151. 'offset': offset,
  152. 'limit': limit
  153. },
  154. function(result) {
  155. recheck_count += result.counts.processed;
  156. spam_count += result.counts.spam;
  157. if (result.counts.processed < limit) {
  158. window.location.href = check_for_spam_buttons.data( 'success-url' ).replace( '__recheck_count__', recheck_count ).replace( '__spam_count__', spam_count );
  159. }
  160. else {
  161. // Account for comments that were caught as spam and moved out of the queue.
  162. akismet_check_for_spam(offset + limit - result.counts.spam, limit);
  163. }
  164. }
  165. );
  166. }
  167. if ( "start_recheck" in WPAkismet && WPAkismet.start_recheck ) {
  168. $( '.checkforspam' ).click();
  169. }
  170. if ( typeof MutationObserver !== 'undefined' ) {
  171. // Dynamically add the "X" next the the author URL links when a comment is quick-edited.
  172. var comment_list_container = document.getElementById( 'the-comment-list' );
  173. if ( comment_list_container ) {
  174. var observer = new MutationObserver( function ( mutations ) {
  175. for ( var i = 0, _len = mutations.length; i < _len; i++ ) {
  176. if ( mutations[i].addedNodes.length > 0 ) {
  177. akismet_enable_comment_author_url_removal();
  178. // Once we know that we'll have to check for new author links, skip the rest of the mutations.
  179. break;
  180. }
  181. }
  182. } );
  183. observer.observe( comment_list_container, { attributes: true, childList: true, characterData: true } );
  184. }
  185. }
  186. function akismet_enable_comment_author_url_removal() {
  187. $( '#the-comment-list' )
  188. .find( 'tr.comment, tr[id ^= "comment-"]' )
  189. .find( '.column-author a[href^="http"]:first' ) // Ignore mailto: links, which would be the comment author's email.
  190. .each(function () {
  191. if ( $( this ).parent().find( '.akismet_remove_url' ).length > 0 ) {
  192. return;
  193. }
  194. var linkHref = $(this).attr( 'href' );
  195. // Ignore any links to the current domain, which are diagnostic tools, like the IP address link
  196. // or any other links another plugin might add.
  197. var currentHostParts = document.location.href.split( '/' );
  198. var currentHost = currentHostParts[0] + '//' + currentHostParts[2] + '/';
  199. if ( linkHref.indexOf( currentHost ) != 0 ) {
  200. var thisCommentId = $(this).parents('tr:first').attr('id').split("-");
  201. $(this)
  202. .attr("id", "author_comment_url_"+ thisCommentId[1])
  203. .after(
  204. $( '<a href="#" class="akismet_remove_url">x</a>' )
  205. .attr( 'commentid', thisCommentId[1] )
  206. .attr( 'title', WPAkismet.strings['Remove this URL'] )
  207. );
  208. }
  209. });
  210. }
  211. /**
  212. * Generate an mShot URL if given a link URL.
  213. *
  214. * @param string linkUrl
  215. * @param int retry If retrying a request, the number of the retry.
  216. * @return string The mShot URL;
  217. */
  218. function akismet_mshot_url( linkUrl, retry ) {
  219. var mshotUrl = '//s0.wordpress.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
  220. if ( retry ) {
  221. mshotUrl += '&r=' + encodeURIComponent( retry );
  222. }
  223. return mshotUrl;
  224. }
  225. /**
  226. * Begin loading an mShot preview of a link.
  227. *
  228. * @param string linkUrl
  229. */
  230. function akismet_preload_mshot( linkUrl ) {
  231. var img = new Image();
  232. img.src = akismet_mshot_url( linkUrl );
  233. }
  234. /**
  235. * Sets the comment form privacy notice display to hide when one clicks Core's dismiss button on the related admin notice.
  236. */
  237. $( '#akismet-privacy-notice-admin-notice' ).on( 'click', '.notice-dismiss', function(){
  238. $.ajax({
  239. url: './options-general.php?page=akismet-key-config&akismet_comment_form_privacy_notice=hide',
  240. });
  241. });
  242. });