1 |
1 |
2 ( function( window, settings ) { |
2 ( function( window, settings ) { |
3 function wpEmoji() { |
3 function wpEmoji() { |
4 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver, |
4 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver, |
5 |
5 |
6 /** |
6 // Compression and maintain local scope |
7 * Flag to determine if we should replace emoji characters with images. |
7 document = window.document, |
8 * |
|
9 * @since 4.2.0 |
|
10 * |
|
11 * @var Boolean |
|
12 */ |
|
13 replaceEmoji = false, |
|
14 |
8 |
15 // Private |
9 // Private |
16 twemoji, timer, |
10 twemoji, timer, |
17 loaded = false, |
11 loaded = false, |
18 count = 0; |
12 count = 0, |
|
13 ie11 = window.navigator.userAgent.indexOf( 'Trident/7.0' ) > 0; |
|
14 |
|
15 /** |
|
16 * Detect if the browser supports SVG. |
|
17 * |
|
18 * @since 4.6.0 |
|
19 * |
|
20 * @return {Boolean} True if the browser supports svg, false if not. |
|
21 */ |
|
22 function browserSupportsSvgAsImage() { |
|
23 if ( !! document.implementation.hasFeature ) { |
|
24 // Source: Modernizr |
|
25 // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg/asimg.js |
|
26 return document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' ); |
|
27 } |
|
28 |
|
29 // document.implementation.hasFeature is deprecated. It can be presumed |
|
30 // if future browsers remove it, the browser will support SVGs as images. |
|
31 return true; |
|
32 } |
19 |
33 |
20 /** |
34 /** |
21 * Runs when the document load event is fired, so we can do our first parse of the page. |
35 * Runs when the document load event is fired, so we can do our first parse of the page. |
22 * |
36 * |
23 * @since 4.2.0 |
37 * @since 4.2.0 |
56 |
70 |
57 if ( |
71 if ( |
58 ii === 1 && removedNodes.length === 1 && |
72 ii === 1 && removedNodes.length === 1 && |
59 addedNodes[0].nodeType === 3 && |
73 addedNodes[0].nodeType === 3 && |
60 removedNodes[0].nodeName === 'IMG' && |
74 removedNodes[0].nodeName === 'IMG' && |
61 addedNodes[0].data === removedNodes[0].alt |
75 addedNodes[0].data === removedNodes[0].alt && |
|
76 'load-failed' === removedNodes[0].getAttribute( 'data-error' ) |
62 ) { |
77 ) { |
63 return; |
78 return; |
64 } |
79 } |
65 |
80 |
66 while ( ii-- ) { |
81 while ( ii-- ) { |
67 node = addedNodes[ ii ]; |
82 node = addedNodes[ ii ]; |
68 |
83 |
69 if ( node.nodeType === 3 ) { |
84 if ( node.nodeType === 3 ) { |
|
85 if ( ! node.parentNode ) { |
|
86 continue; |
|
87 } |
|
88 |
|
89 if ( ie11 ) { |
|
90 /* |
|
91 * IE 11's implementation of MutationObserver is buggy. |
|
92 * It unnecessarily splits text nodes when it encounters a HTML |
|
93 * template interpolation symbol ( "{{", for example ). So, we |
|
94 * join the text nodes back together as a work-around. |
|
95 */ |
|
96 while( node.nextSibling && 3 === node.nextSibling.nodeType ) { |
|
97 node.nodeValue = node.nodeValue + node.nextSibling.nodeValue; |
|
98 node.parentNode.removeChild( node.nextSibling ); |
|
99 } |
|
100 } |
|
101 |
70 node = node.parentNode; |
102 node = node.parentNode; |
71 } |
103 } |
72 |
104 |
73 if ( ! node || ( node.className && node.className.indexOf( 'wp-exclude-emoji' ) !== -1 ) ) { |
105 if ( ! node || node.nodeType !== 1 || |
|
106 ( node.className && typeof node.className === 'string' && node.className.indexOf( 'wp-exclude-emoji' ) !== -1 ) ) { |
|
107 |
74 continue; |
108 continue; |
75 } |
109 } |
76 |
110 |
77 if ( node && node.nodeType === 1 ) { |
111 if ( test( node.textContent ) ) { |
78 parse( node ); |
112 parse( node ); |
79 } |
113 } |
80 } |
114 } |
81 } |
115 } |
82 } ).observe( document.body, { |
116 } ).observe( document.body, { |
87 |
121 |
88 parse( document.body ); |
122 parse( document.body ); |
89 } |
123 } |
90 |
124 |
91 /** |
125 /** |
|
126 * Test if a text string contains emoji characters. |
|
127 * |
|
128 * @since 4.3.0 |
|
129 * |
|
130 * @param {String} text The string to test |
|
131 * |
|
132 * @return {Boolean} Whether the string contains emoji characters. |
|
133 */ |
|
134 function test( text ) { |
|
135 // Single char. U+20E3 to detect keycaps. U+00A9 "copyright sign" and U+00AE "registered sign" not included. |
|
136 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]/, |
|
137 // Surrogate pair range. Only tests for the second half. |
|
138 pair = /[\uDC00-\uDFFF]/; |
|
139 |
|
140 if ( text ) { |
|
141 return pair.test( text ) || single.test( text ); |
|
142 } |
|
143 |
|
144 return false; |
|
145 } |
|
146 |
|
147 /** |
92 * Given an element or string, parse any emoji characters into Twemoji images. |
148 * Given an element or string, parse any emoji characters into Twemoji images. |
93 * |
149 * |
94 * @since 4.2.0 |
150 * @since 4.2.0 |
95 * |
151 * |
96 * @param {HTMLElement|String} object The element or string to parse. |
152 * @param {HTMLElement|String} object The element or string to parse. |
97 * @param {Object} args Additional options for Twemoji. |
153 * @param {Object} args Additional options for Twemoji. |
98 */ |
154 */ |
99 function parse( object, args ) { |
155 function parse( object, args ) { |
100 if ( ! replaceEmoji || ! twemoji ) { |
156 var params; |
|
157 |
|
158 if ( settings.supports.everything || ! twemoji || ! object || |
|
159 ( 'string' !== typeof object && ( ! object.childNodes || ! object.childNodes.length ) ) ) { |
|
160 |
101 return object; |
161 return object; |
102 } |
162 } |
103 |
163 |
104 args = args || {}; |
164 args = args || {}; |
105 |
165 params = { |
106 return twemoji.parse( object, { |
166 base: browserSupportsSvgAsImage() ? settings.svgUrl : settings.baseUrl, |
107 base: settings.baseUrl, |
167 ext: browserSupportsSvgAsImage() ? settings.svgExt : settings.ext, |
108 ext: settings.ext, |
|
109 className: args.className || 'emoji', |
168 className: args.className || 'emoji', |
110 imgAttr: args.imgAttr, |
|
111 callback: function( icon, options ) { |
169 callback: function( icon, options ) { |
112 // Ignore some standard characters that TinyMCE recommends in its character map. |
170 // Ignore some standard characters that TinyMCE recommends in its character map. |
113 switch ( icon ) { |
171 switch ( icon ) { |
114 case 'a9': |
172 case 'a9': |
115 case 'ae': |
173 case 'ae': |
120 case '2665': |
178 case '2665': |
121 case '2666': |
179 case '2666': |
122 return false; |
180 return false; |
123 } |
181 } |
124 |
182 |
125 if ( ! settings.supports.flag && settings.supports.simple && |
183 if ( settings.supports.everythingExceptFlag && |
126 ! /^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test( icon ) ) { |
184 ! /^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test( icon ) && // Country flags |
127 |
185 ! /^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test( icon ) // Rainbow and pirate flags |
|
186 ) { |
128 return false; |
187 return false; |
129 } |
188 } |
130 |
189 |
131 return ''.concat( options.base, icon, options.ext ); |
190 return ''.concat( options.base, icon, options.ext ); |
|
191 }, |
|
192 onerror: function() { |
|
193 if ( twemoji.parentNode ) { |
|
194 this.setAttribute( 'data-error', 'load-failed' ); |
|
195 twemoji.parentNode.replaceChild( document.createTextNode( twemoji.alt ), twemoji ); |
|
196 } |
132 } |
197 } |
133 } ); |
198 }; |
|
199 |
|
200 if ( typeof args.imgAttr === 'object' ) { |
|
201 params.attributes = function() { |
|
202 return args.imgAttr; |
|
203 }; |
|
204 } |
|
205 |
|
206 return twemoji.parse( object, params ); |
134 } |
207 } |
135 |
208 |
136 /** |
209 /** |
137 * Initialize our emoji support, and set up listeners. |
210 * Initialize our emoji support, and set up listeners. |
138 */ |
211 */ |
139 if ( settings ) { |
212 if ( settings ) { |
140 replaceEmoji = ! settings.supports.simple || ! settings.supports.flag; |
|
141 |
|
142 if ( settings.DOMReady ) { |
213 if ( settings.DOMReady ) { |
143 load(); |
214 load(); |
144 } else { |
215 } else { |
145 settings.readyCallback = load; |
216 settings.readyCallback = load; |
146 } |
217 } |
147 } |
218 } |
148 |
219 |
149 return { |
220 return { |
150 replaceEmoji: replaceEmoji, |
221 parse: parse, |
151 parse: parse |
222 test: test |
152 }; |
223 }; |
153 } |
224 } |
154 |
225 |
155 window.wp = window.wp || {}; |
226 window.wp = window.wp || {}; |
156 window.wp.emoji = new wpEmoji(); |
227 window.wp.emoji = new wpEmoji(); |