You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

230 lines
6.6 KiB

  1. ( function( window, settings ) {
  2. function wpEmoji() {
  3. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
  4. // Compression and maintain local scope
  5. document = window.document,
  6. // Private
  7. twemoji, timer,
  8. loaded = false,
  9. count = 0,
  10. ie11 = window.navigator.userAgent.indexOf( 'Trident/7.0' ) > 0;
  11. /**
  12. * Detect if the browser supports SVG.
  13. *
  14. * @since 4.6.0
  15. *
  16. * @return {Boolean} True if the browser supports svg, false if not.
  17. */
  18. function browserSupportsSvgAsImage() {
  19. if ( !! document.implementation.hasFeature ) {
  20. // Source: Modernizr
  21. // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg/asimg.js
  22. return document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' );
  23. }
  24. // document.implementation.hasFeature is deprecated. It can be presumed
  25. // if future browsers remove it, the browser will support SVGs as images.
  26. return true;
  27. }
  28. /**
  29. * Runs when the document load event is fired, so we can do our first parse of the page.
  30. *
  31. * @since 4.2.0
  32. */
  33. function load() {
  34. if ( loaded ) {
  35. return;
  36. }
  37. if ( typeof window.twemoji === 'undefined' ) {
  38. // Break if waiting for longer than 30 sec.
  39. if ( count > 600 ) {
  40. return;
  41. }
  42. // Still waiting.
  43. window.clearTimeout( timer );
  44. timer = window.setTimeout( load, 50 );
  45. count++;
  46. return;
  47. }
  48. twemoji = window.twemoji;
  49. loaded = true;
  50. if ( MutationObserver ) {
  51. new MutationObserver( function( mutationRecords ) {
  52. var i = mutationRecords.length,
  53. addedNodes, removedNodes, ii, node;
  54. while ( i-- ) {
  55. addedNodes = mutationRecords[ i ].addedNodes;
  56. removedNodes = mutationRecords[ i ].removedNodes;
  57. ii = addedNodes.length;
  58. if (
  59. ii === 1 && removedNodes.length === 1 &&
  60. addedNodes[0].nodeType === 3 &&
  61. removedNodes[0].nodeName === 'IMG' &&
  62. addedNodes[0].data === removedNodes[0].alt &&
  63. 'load-failed' === removedNodes[0].getAttribute( 'data-error' )
  64. ) {
  65. return;
  66. }
  67. while ( ii-- ) {
  68. node = addedNodes[ ii ];
  69. if ( node.nodeType === 3 ) {
  70. if ( ! node.parentNode ) {
  71. continue;
  72. }
  73. if ( ie11 ) {
  74. /*
  75. * IE 11's implementation of MutationObserver is buggy.
  76. * It unnecessarily splits text nodes when it encounters a HTML
  77. * template interpolation symbol ( "{{", for example ). So, we
  78. * join the text nodes back together as a work-around.
  79. */
  80. while( node.nextSibling && 3 === node.nextSibling.nodeType ) {
  81. node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
  82. node.parentNode.removeChild( node.nextSibling );
  83. }
  84. }
  85. node = node.parentNode;
  86. }
  87. if ( ! node || node.nodeType !== 1 ||
  88. ( node.className && typeof node.className === 'string' && node.className.indexOf( 'wp-exclude-emoji' ) !== -1 ) ) {
  89. continue;
  90. }
  91. if ( test( node.textContent ) ) {
  92. parse( node );
  93. }
  94. }
  95. }
  96. } ).observe( document.body, {
  97. childList: true,
  98. subtree: true
  99. } );
  100. }
  101. parse( document.body );
  102. }
  103. /**
  104. * Test if a text string contains emoji characters.
  105. *
  106. * @since 4.3.0
  107. *
  108. * @param {String} text The string to test
  109. *
  110. * @return {Boolean} Whether the string contains emoji characters.
  111. */
  112. function test( text ) {
  113. // Single char. U+20E3 to detect keycaps. U+00A9 "copyright sign" and U+00AE "registered sign" not included.
  114. var single = /[\u203C\u2049\u20E3\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2300\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638\u2639\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692\u2693\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753\u2754\u2755\u2757\u2763\u2764\u2795\u2796\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05\u2B06\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]/,
  115. // Surrogate pair range. Only tests for the second half.
  116. pair = /[\uDC00-\uDFFF]/;
  117. if ( text ) {
  118. return pair.test( text ) || single.test( text );
  119. }
  120. return false;
  121. }
  122. /**
  123. * Given an element or string, parse any emoji characters into Twemoji images.
  124. *
  125. * @since 4.2.0
  126. *
  127. * @param {HTMLElement|String} object The element or string to parse.
  128. * @param {Object} args Additional options for Twemoji.
  129. */
  130. function parse( object, args ) {
  131. var params;
  132. if ( settings.supports.everything || ! twemoji || ! object ||
  133. ( 'string' !== typeof object && ( ! object.childNodes || ! object.childNodes.length ) ) ) {
  134. return object;
  135. }
  136. args = args || {};
  137. params = {
  138. base: browserSupportsSvgAsImage() ? settings.svgUrl : settings.baseUrl,
  139. ext: browserSupportsSvgAsImage() ? settings.svgExt : settings.ext,
  140. className: args.className || 'emoji',
  141. callback: function( icon, options ) {
  142. // Ignore some standard characters that TinyMCE recommends in its character map.
  143. switch ( icon ) {
  144. case 'a9':
  145. case 'ae':
  146. case '2122':
  147. case '2194':
  148. case '2660':
  149. case '2663':
  150. case '2665':
  151. case '2666':
  152. return false;
  153. }
  154. if ( settings.supports.everythingExceptFlag &&
  155. ! /^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test( icon ) && // Country flags
  156. ! /^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test( icon ) // Rainbow and pirate flags
  157. ) {
  158. return false;
  159. }
  160. return ''.concat( options.base, icon, options.ext );
  161. },
  162. onerror: function() {
  163. if ( twemoji.parentNode ) {
  164. this.setAttribute( 'data-error', 'load-failed' );
  165. twemoji.parentNode.replaceChild( document.createTextNode( twemoji.alt ), twemoji );
  166. }
  167. }
  168. };
  169. if ( typeof args.imgAttr === 'object' ) {
  170. params.attributes = function() {
  171. return args.imgAttr;
  172. };
  173. }
  174. return twemoji.parse( object, params );
  175. }
  176. /**
  177. * Initialize our emoji support, and set up listeners.
  178. */
  179. if ( settings ) {
  180. if ( settings.DOMReady ) {
  181. load();
  182. } else {
  183. settings.readyCallback = load;
  184. }
  185. }
  186. return {
  187. parse: parse,
  188. test: test
  189. };
  190. }
  191. window.wp = window.wp || {};
  192. window.wp.emoji = new wpEmoji();
  193. } )( window, window._wpemojiSettings );