| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 /** 2 * @output wp-includes/js/wp-emoji.js 3 */ 4 5 /** 6 * Additional options accepted by wp.emoji.parse(). 7 * 8 * @typedef WPEmojiParseArgs 9 * @type {Object} 10 * @property {string} [className] Class name to give each generated image. 11 * @property {Record<string, string>} [imgAttr] Attributes to set on each generated image, in 12 * place of the default ones. 13 */ 14 15 /** 16 * wp-emoji.js is used to replace emoji with images in browsers when the browser 17 * doesn't support emoji natively. 18 * 19 * @param {Window} window The global window object. 20 * @param {WPEmojiSettings} settings The settings object. 21 */ 22 ( function ( window, settings ) { 23 /** 24 * Replaces emoji with images when browsers don't support emoji. 25 * 26 * @since 4.2.0 27 * @access private 28 * 29 * @see Twemoji 30 * @link https://github.com/jdecked/twemoji 31 * 32 * @return {{ 33 * parse: ( object: HTMLElement|string, args?: WPEmojiParseArgs ) => HTMLElement|string, 34 * test: ( text: ?string ) => boolean 35 * }} The wpEmoji parse and test functions. 36 */ 37 function wpEmoji() { 38 // Compression and maintain local scope. 39 const document = window.document; 40 41 // Private. 42 /** @type {Twemoji|undefined} */ 43 let twemoji; 44 45 /** @type {number|undefined} */ 46 let timer; 47 48 let loaded = false; 49 let count = 0; 50 51 /** 52 * Runs when the document load event is fired, so we can do our first parse of 53 * the page. 54 * 55 * Listens to all the DOM mutations and checks for added nodes that contain 56 * emoji characters and replaces those with twitter emoji images. 57 * 58 * @since 4.2.0 59 * @private 60 */ 61 function load() { 62 if ( loaded ) { 63 return; 64 } 65 66 // Ensure twemoji is available on the global window before proceeding. 67 if ( typeof window.twemoji === 'undefined' ) { 68 // Break if waiting for longer than 30 seconds. 69 if ( count > 600 ) { 70 return; 71 } 72 73 // Still waiting. 74 window.clearTimeout( timer ); 75 timer = window.setTimeout( load, 50 ); 76 count++; 77 78 return; 79 } 80 81 twemoji = window.twemoji; 82 loaded = true; 83 84 // Initialize the mutation observer, which checks all added nodes for 85 // replaceable emoji characters. 86 new MutationObserver( ( mutationRecords ) => { 87 for ( const { addedNodes, removedNodes } of mutationRecords ) { 88 const addedNode = addedNodes[ 0 ]; 89 const removedNode = removedNodes[ 0 ]; 90 91 /* 92 * Checks if an image has been replaced by a text element 93 * with the same text as the alternate description of the replaced image. 94 * (presumably because the image could not be loaded). 95 * If it is, leave this record alone, so that the text is not turned 96 * straight back into the image which just failed to load. 97 */ 98 if ( 99 addedNodes.length === 1 && removedNodes.length === 1 && 100 addedNode instanceof Text && 101 removedNode instanceof HTMLImageElement && 102 addedNode.data === removedNode.alt && 103 'load-failed' === removedNode.dataset.error 104 ) { 105 continue; 106 } 107 108 // Loop through all the added nodes. 109 for ( const addedNode of addedNodes ) { 110 // Emoji in a text node are replaced by parsing the element which contains it. 111 const node = addedNode instanceof Text ? addedNode.parentElement : addedNode; 112 113 if ( node instanceof HTMLElement && test( node.textContent ) ) { 114 parse( node ); 115 } 116 } 117 } 118 } ).observe( document.body, { 119 childList: true, 120 subtree: true 121 } ); 122 123 parse( document.body ); 124 } 125 126 /** 127 * Tests if a text string contains emoji characters. 128 * 129 * @since 4.3.0 130 * 131 * @memberOf wp.emoji 132 * 133 * @param {?string} text The string to test. 134 * 135 * @return {boolean} Whether the string contains emoji characters. 136 */ 137 function test( text ) { 138 // Single char. U+20E3 to detect keycaps. U+00A9 "copyright sign" and U+00AE "registered sign" not included. 139 const 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]/; 140 141 // Surrogate pair range. Only tests for the second half. 142 const pair = /[\uDC00-\uDFFF]/; 143 144 if ( text ) { 145 return pair.test( text ) || single.test( text ); 146 } 147 148 return false; 149 } 150 151 /** 152 * Parses any emoji characters into Twemoji images. 153 * 154 * - When passed an element the emoji characters are replaced inline. 155 * - When passed a string the emoji characters are replaced and the result is 156 * returned. 157 * 158 * @since 4.2.0 159 * 160 * @memberOf wp.emoji 161 * 162 * @param {HTMLElement|string} object The element or string to parse. 163 * @param {WPEmojiParseArgs} [args] Additional options for Twemoji. 164 * 165 * @return {HTMLElement|string} A string where all emoji are now image tags of 166 * emoji. Or the element that was passed as the first argument. 167 */ 168 function parse( object, args ) { 169 /* 170 * If the browser has full support, twemoji is not loaded or our 171 * object is not what was expected, we do not parse anything. 172 */ 173 if ( settings.supports.everything || ! twemoji || ! object || 174 ( 'string' !== typeof object && ( ! object.childNodes || ! object.childNodes.length ) ) ) { 175 176 return object; 177 } 178 179 // Compose the params for the twitter emoji library. 180 args = args || {}; 181 182 // The caller may replace the attributes given to every generated image. 183 const attributes = typeof args.imgAttr === 'object' ? args.imgAttr : { role: 'img' }; 184 185 /** @type {TwemojiParseOptions} */ 186 const params = { 187 base: settings.svgUrl, 188 ext: settings.svgExt, 189 className: args.className || 'emoji', 190 callback: ( icon, options ) => { 191 // Ignore some standard characters that TinyMCE recommends in its character map. 192 switch ( icon ) { 193 case 'a9': 194 case 'ae': 195 case '2122': 196 case '2194': 197 case '2660': 198 case '2663': 199 case '2665': 200 case '2666': 201 return false; 202 } 203 204 if ( settings.supports.everythingExceptFlag && 205 ! /^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test( icon ) && // Country flags. 206 ! /^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test( icon ) // Rainbow and pirate flags. 207 ) { 208 return false; 209 } 210 211 return ''.concat( options.base, icon, options.ext ); 212 }, 213 attributes: () => attributes, 214 onerror: function () { 215 /* 216 * Put the emoji character back in place of the image which failed to load. The 217 * attribute is what tells the MutationObserver above that this replacement is 218 * the one it must not turn straight back into an image. 219 */ 220 if ( this.parentNode ) { 221 this.dataset.error = 'load-failed'; 222 this.parentNode.replaceChild( document.createTextNode( this.alt ), this ); 223 } 224 }, 225 doNotParse: ( element ) => { 226 // Emoji will not be replaced in this element, nor in any of its descendants. 227 return element.classList.contains( 'wp-exclude-emoji' ); 228 } 229 }; 230 231 return twemoji.parse( object, params ); 232 } 233 234 load(); 235 236 return { parse, test }; 237 } 238 239 window.wp = window.wp || {}; 240 241 /** 242 * @namespace wp.emoji 243 */ 244 window.wp.emoji = wpEmoji(); 245 246 } )( window, window._wpemojiSettings );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Oct 25 08:20:35 2026 | Cross-referenced by PHPXref |