sharing.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /* global WPCOM_sharing_counts, grecaptcha */
  2. /* jshint unused:false */
  3. var sharing_js_options;
  4. if ( sharing_js_options && sharing_js_options.counts ) {
  5. var WPCOMSharing = {
  6. done_urls : [],
  7. get_counts : function() {
  8. var url, requests, id, service, service_request;
  9. if ( 'undefined' === typeof WPCOM_sharing_counts ) {
  10. return;
  11. }
  12. for ( url in WPCOM_sharing_counts ) {
  13. id = WPCOM_sharing_counts[ url ];
  14. if ( 'undefined' !== typeof WPCOMSharing.done_urls[ id ] ) {
  15. continue;
  16. }
  17. requests = {
  18. // Pinterest handles share counts for both http and https
  19. pinterest: [
  20. window.location.protocol +
  21. '//api.pinterest.com/v1/urls/count.json?callback=WPCOMSharing.update_pinterest_count&url=' +
  22. encodeURIComponent( url )
  23. ],
  24. // Facebook protocol summing has been shown to falsely double counts, so we only request the current URL
  25. facebook: [
  26. window.location.protocol +
  27. '//graph.facebook.com/?callback=WPCOMSharing.update_facebook_count&ids=' +
  28. encodeURIComponent( url )
  29. ]
  30. };
  31. for ( service in requests ) {
  32. if ( ! jQuery( 'a[data-shared=sharing-' + service + '-' + id + ']' ).length ) {
  33. continue;
  34. }
  35. while ( ( service_request = requests[ service ].pop() ) ) {
  36. jQuery.getScript( service_request );
  37. }
  38. WPCOMSharing.bump_sharing_count_stat( service );
  39. }
  40. WPCOMSharing.done_urls[ id ] = true;
  41. }
  42. },
  43. // get the version of the url that was stored in the dom (sharing-$service-URL)
  44. get_permalink: function( url ) {
  45. if ( 'https:' === window.location.protocol ) {
  46. url = url.replace( /^http:\/\//i, 'https://' );
  47. } else {
  48. url = url.replace( /^https:\/\//i, 'http://' );
  49. }
  50. return url;
  51. },
  52. update_facebook_count: function( data ) {
  53. var url, permalink;
  54. if ( ! data ) {
  55. return;
  56. }
  57. for ( url in data ) {
  58. if ( ! data.hasOwnProperty( url ) || ! data[ url ].share || ! data[ url ].share.share_count ) {
  59. continue;
  60. }
  61. permalink = WPCOMSharing.get_permalink( url );
  62. if ( ! ( permalink in WPCOM_sharing_counts ) ) {
  63. continue;
  64. }
  65. WPCOMSharing.inject_share_count( 'sharing-facebook-' + WPCOM_sharing_counts[ permalink ], data[ url ].share.share_count );
  66. }
  67. },
  68. update_pinterest_count : function( data ) {
  69. if ( 'undefined' !== typeof data.count && ( data.count * 1 ) > 0 ) {
  70. WPCOMSharing.inject_share_count( 'sharing-pinterest-' + WPCOM_sharing_counts[ data.url ], data.count );
  71. }
  72. },
  73. inject_share_count : function( id, count ) {
  74. var $share = jQuery( 'a[data-shared=' + id + '] > span');
  75. $share.find( '.share-count' ).remove();
  76. $share.append( '<span class="share-count">' + WPCOMSharing.format_count( count ) + '</span>' );
  77. },
  78. format_count : function( count ) {
  79. if ( count < 1000 ) {
  80. return count;
  81. }
  82. if ( count >= 1000 && count < 10000 ) {
  83. return String( count ).substring( 0, 1 ) + 'K+';
  84. }
  85. return '10K+';
  86. },
  87. bump_sharing_count_stat: function( service ) {
  88. new Image().src = document.location.protocol + '//pixel.wp.com/g.gif?v=wpcom-no-pv&x_sharing-count-request=' + service + '&r=' + Math.random();
  89. }
  90. };
  91. }
  92. (function($){
  93. var $body, $sharing_email;
  94. $.fn.extend( {
  95. share_is_email: function() {
  96. return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test( this.val() );
  97. }
  98. } );
  99. $body = $( document.body ).on( 'post-load', WPCOMSharing_do );
  100. $( document ).ready( function() {
  101. $sharing_email = $( '#sharing_email' );
  102. $body.append( $sharing_email );
  103. WPCOMSharing_do();
  104. } );
  105. function WPCOMSharing_do() {
  106. var $more_sharing_buttons;
  107. if ( 'undefined' !== typeof WPCOMSharing ) {
  108. WPCOMSharing.get_counts();
  109. }
  110. $more_sharing_buttons = $( '.sharedaddy a.sharing-anchor' );
  111. $more_sharing_buttons.click( function() {
  112. return false;
  113. } );
  114. $( '.sharedaddy a' ).each( function() {
  115. if ( $( this ).attr( 'href' ) && $( this ).attr( 'href' ).indexOf( 'share=' ) !== -1 ) {
  116. $( this ).attr( 'href', $( this ).attr( 'href' ) + '&nb=1' );
  117. }
  118. } );
  119. // Show hidden buttons
  120. // Touchscreen device: use click.
  121. // Non-touchscreen device: use click if not already appearing due to a hover event
  122. $more_sharing_buttons.on( 'click', function() {
  123. var $more_sharing_button = $( this ),
  124. $more_sharing_pane = $more_sharing_button.parents( 'div:first' ).find( '.inner' );
  125. if ( $more_sharing_pane.is( ':animated' ) ) {
  126. // We're in the middle of some other event's animation
  127. return;
  128. }
  129. if ( true === $more_sharing_pane.data( 'justSlid' ) ) {
  130. // We just finished some other event's animation - don't process click event so that slow-to-react-clickers don't get confused
  131. return;
  132. }
  133. $sharing_email.slideUp( 200 );
  134. $more_sharing_pane.css( {
  135. left: $more_sharing_button.position().left + 'px',
  136. top: $more_sharing_button.position().top + $more_sharing_button.height() + 3 + 'px'
  137. } ).slideToggle( 200 );
  138. } );
  139. if ( document.ontouchstart === undefined ) {
  140. // Non-touchscreen device: use hover/mouseout with delay
  141. $more_sharing_buttons.hover( function() {
  142. var $more_sharing_button = $( this ),
  143. $more_sharing_pane = $more_sharing_button.parents( 'div:first' ).find( '.inner' ),
  144. timer;
  145. if ( ! $more_sharing_pane.is( ':animated' ) ) {
  146. // Create a timer to make the area appear if the mouse hovers for a period
  147. timer = setTimeout( function() {
  148. var handler_item_leave, handler_item_enter, handler_original_leave, handler_original_enter, close_it;
  149. $sharing_email.slideUp( 200 );
  150. $more_sharing_pane.data( 'justSlid', true );
  151. $more_sharing_pane.css( {
  152. left: $more_sharing_button.position().left + 'px',
  153. top: $more_sharing_button.position().top + $more_sharing_button.height() + 3 + 'px'
  154. } ).slideDown( 200, function() {
  155. // Mark the item as have being appeared by the hover
  156. $more_sharing_button.data( 'hasoriginal', true ).data( 'hasitem', false );
  157. setTimeout( function() {
  158. $more_sharing_pane.data( 'justSlid', false );
  159. }, 300 );
  160. if ( $more_sharing_pane.find( '.share-google-plus-1' ).length ) {
  161. // The pane needs to stay open for the Google+ Button
  162. return;
  163. }
  164. $more_sharing_pane.mouseleave( handler_item_leave ).mouseenter( handler_item_enter );
  165. $more_sharing_button.mouseleave( handler_original_leave ).mouseenter( handler_original_enter );
  166. } );
  167. // The following handlers take care of the mouseenter/mouseleave for the share button and the share area - if both are left then we close the share area
  168. handler_item_leave = function() {
  169. $more_sharing_button.data( 'hasitem', false );
  170. if ( $more_sharing_button.data( 'hasoriginal' ) === false ) {
  171. var timer = setTimeout( close_it, 800 );
  172. $more_sharing_button.data( 'timer2', timer );
  173. }
  174. };
  175. handler_item_enter = function() {
  176. $more_sharing_button.data( 'hasitem', true );
  177. clearTimeout( $more_sharing_button.data( 'timer2' ) );
  178. };
  179. handler_original_leave = function() {
  180. $more_sharing_button.data( 'hasoriginal', false );
  181. if ( $more_sharing_button.data( 'hasitem' ) === false ) {
  182. var timer = setTimeout( close_it, 800 );
  183. $more_sharing_button.data( 'timer2', timer );
  184. }
  185. };
  186. handler_original_enter = function() {
  187. $more_sharing_button.data( 'hasoriginal', true );
  188. clearTimeout( $more_sharing_button.data( 'timer2' ) );
  189. };
  190. close_it = function() {
  191. $more_sharing_pane.data( 'justSlid', true );
  192. $more_sharing_pane.slideUp( 200, function() {
  193. setTimeout( function() {
  194. $more_sharing_pane.data( 'justSlid', false );
  195. }, 300 );
  196. } );
  197. // Clear all hooks
  198. $more_sharing_button.unbind( 'mouseleave', handler_original_leave ).unbind( 'mouseenter', handler_original_enter );
  199. $more_sharing_pane.unbind( 'mouseleave', handler_item_leave ).unbind( 'mouseenter', handler_item_leave );
  200. return false;
  201. };
  202. }, 200 );
  203. // Remember the timer so we can detect it on the mouseout
  204. $more_sharing_button.data( 'timer', timer );
  205. }
  206. }, function() {
  207. // Mouse out - remove any timer
  208. $more_sharing_buttons.each( function() {
  209. clearTimeout( $( this ).data( 'timer' ) );
  210. } );
  211. $more_sharing_buttons.data( 'timer', false );
  212. } );
  213. } else {
  214. $( document.body ).addClass( 'jp-sharing-input-touch' );
  215. }
  216. $( document ).click(function() {
  217. // Click outside
  218. // remove any timer
  219. $more_sharing_buttons.each( function() {
  220. clearTimeout( $( this ).data( 'timer' ) );
  221. } );
  222. $more_sharing_buttons.data( 'timer', false );
  223. // slide down forcibly
  224. $( '.sharedaddy .inner' ).slideUp();
  225. });
  226. // Add click functionality
  227. $( '.sharedaddy ul' ).each( function() {
  228. if ( 'yep' === $( this ).data( 'has-click-events' ) ) {
  229. return;
  230. }
  231. $( this ).data( 'has-click-events', 'yep' );
  232. var printUrl = function ( uniqueId, urlToPrint ) {
  233. $( 'body:first' ).append( '<iframe style="position:fixed;top:100;left:100;height:1px;width:1px;border:none;" id="printFrame-' + uniqueId + '" name="printFrame-' + uniqueId + '" src="' + urlToPrint + '" onload="frames[\'printFrame-' + uniqueId + '\'].focus();frames[\'printFrame-' + uniqueId + '\'].print();"></iframe>' );
  234. };
  235. // Print button
  236. $( this ).find( 'a.share-print' ).click( function() {
  237. var ref = $( this ).attr( 'href' ),
  238. do_print = function() {
  239. if ( ref.indexOf( '#print' ) === -1 ) {
  240. var uid = new Date().getTime();
  241. printUrl( uid , ref );
  242. } else {
  243. print();
  244. }
  245. };
  246. // Is the button in a dropdown?
  247. if ( $( this ).parents( '.sharing-hidden' ).length > 0 ) {
  248. $( this ).parents( '.inner' ).slideUp( 0, function() {
  249. do_print();
  250. } );
  251. } else {
  252. do_print();
  253. }
  254. return false;
  255. } );
  256. // Press This button
  257. $( this ).find( 'a.share-press-this' ).click( function() {
  258. var s = '';
  259. if ( window.getSelection ) {
  260. s = window.getSelection();
  261. } else if( document.getSelection ) {
  262. s = document.getSelection();
  263. } else if( document.selection ) {
  264. s = document.selection.createRange().text;
  265. }
  266. if ( s ) {
  267. $( this ).attr( 'href', $( this ).attr( 'href' ) + '&sel=' + encodeURI( s ) );
  268. }
  269. if ( !window.open( $( this ).attr( 'href' ), 't', 'toolbar=0,resizable=1,scrollbars=1,status=1,width=720,height=570' ) ) {
  270. document.location.href = $( this ).attr( 'href' );
  271. }
  272. return false;
  273. } );
  274. // Email button
  275. $( 'a.share-email', this ).on( 'click', function() {
  276. var url = $( this ).attr( 'href' );
  277. var currentDomain = window.location.protocol + '//' + window.location.hostname + '/';
  278. if ( url.indexOf( currentDomain ) !== 0 ) {
  279. return true;
  280. }
  281. if ( $sharing_email.is( ':visible' ) ) {
  282. $sharing_email.slideUp( 200 );
  283. } else {
  284. $( '.sharedaddy .inner' ).slideUp();
  285. $( '#sharing_email .response' ).remove();
  286. $( '#sharing_email form' ).show();
  287. $( '#sharing_email form input[type=submit]' ).removeAttr( 'disabled' );
  288. $( '#sharing_email form a.sharing_cancel' ).show();
  289. // Reset reCATPCHA if exists.
  290. if ( 'object' === typeof grecaptcha && 'function' === typeof grecaptcha.reset && window.___grecaptcha_cfg.count ) {
  291. grecaptcha.reset();
  292. }
  293. // Show dialog
  294. $sharing_email.css( {
  295. left: $( this ).offset().left + 'px',
  296. top: $( this ).offset().top + $( this ).height() + 'px'
  297. } ).slideDown( 200 );
  298. // Hook up other buttons
  299. $( '#sharing_email a.sharing_cancel' ).unbind( 'click' ).click( function() {
  300. $( '#sharing_email .errors' ).hide();
  301. $sharing_email.slideUp( 200 );
  302. $( '#sharing_background' ).fadeOut();
  303. return false;
  304. } );
  305. // Submit validation
  306. $( '#sharing_email input[type=submit]' ).unbind( 'click' ).click( function() {
  307. var form = $( this ).parents( 'form' );
  308. var source_email_input = form.find( 'input[name=source_email]' );
  309. var target_email_input = form.find( 'input[name=target_email]' );
  310. // Disable buttons + enable loading icon
  311. $( this ).prop( 'disabled', true );
  312. form.find( 'a.sharing_cancel' ).hide();
  313. form.find( 'img.loading' ).show();
  314. $( '#sharing_email .errors' ).hide();
  315. $( '#sharing_email .error' ).removeClass( 'error' );
  316. if ( ! source_email_input.share_is_email() ) {
  317. source_email_input.addClass( 'error' );
  318. }
  319. if ( ! target_email_input.share_is_email() ) {
  320. target_email_input.addClass( 'error' );
  321. }
  322. if ( $( '#sharing_email .error' ).length === 0 ) {
  323. // AJAX send the form
  324. $.ajax( {
  325. url: url,
  326. type: 'POST',
  327. data: form.serialize(),
  328. success: function( response ) {
  329. form.find( 'img.loading' ).hide();
  330. if ( response === '1' || response === '2' || response === '3' ) {
  331. $( '#sharing_email .errors-' + response ).show();
  332. form.find( 'input[type=submit]' ).removeAttr( 'disabled' );
  333. form.find( 'a.sharing_cancel' ).show();
  334. if ( 'object' === typeof grecaptcha && 'function' === typeof grecaptcha.reset ) {
  335. grecaptcha.reset();
  336. }
  337. }
  338. else {
  339. $( '#sharing_email form' ).hide();
  340. $sharing_email.append( response );
  341. $( '#sharing_email a.sharing_cancel' ).click( function() {
  342. $sharing_email.slideUp( 200 );
  343. $( '#sharing_background' ).fadeOut();
  344. return false;
  345. } );
  346. }
  347. }
  348. } );
  349. return false;
  350. }
  351. form.find( 'img.loading' ).hide();
  352. form.find( 'input[type=submit]' ).removeAttr( 'disabled' );
  353. form.find( 'a.sharing_cancel' ).show();
  354. $( '#sharing_email .errors-1' ).show();
  355. return false;
  356. } );
  357. }
  358. return false;
  359. } );
  360. } );
  361. $( 'li.share-email, li.share-custom a.sharing-anchor' ).addClass( 'share-service-visible' );
  362. }
  363. })( jQuery );