author | ymh <ymh.work@gmail.com> |
Mon, 14 Oct 2019 17:39:30 +0200 | |
changeset 7 | cf61fcea0001 |
parent 5 | 5e2f62d02dcd |
child 9 | 177826044cd9 |
permissions | -rw-r--r-- |
5 | 1 |
/* global tinymce */ |
2 |
||
3 |
/* |
|
4 |
* The TinyMCE view API. |
|
5 |
* |
|
6 |
* Note: this API is "experimental" meaning that it will probably change |
|
7 |
* in the next few releases based on feedback from 3.9.0. |
|
8 |
* If you decide to use it, please follow the development closely. |
|
9 |
* |
|
10 |
* Diagram |
|
11 |
* |
|
12 |
* |- registered view constructor (type) |
|
13 |
* | |- view instance (unique text) |
|
14 |
* | | |- editor 1 |
|
15 |
* | | | |- view node |
|
16 |
* | | | |- view node |
|
17 |
* | | | |- ... |
|
18 |
* | | |- editor 2 |
|
19 |
* | | | |- ... |
|
20 |
* | |- view instance |
|
21 |
* | | |- ... |
|
22 |
* |- registered view |
|
23 |
* | |- ... |
|
24 |
*/ |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
25 |
( function( window, wp, shortcode, $ ) { |
5 | 26 |
'use strict'; |
27 |
||
0 | 28 |
var views = {}, |
29 |
instances = {}; |
|
30 |
||
31 |
wp.mce = wp.mce || {}; |
|
32 |
||
5 | 33 |
/** |
34 |
* wp.mce.views |
|
35 |
* |
|
36 |
* A set of utilities that simplifies adding custom UI within a TinyMCE editor. |
|
37 |
* At its core, it serves as a series of converters, transforming text to a |
|
38 |
* custom UI, and back again. |
|
39 |
*/ |
|
40 |
wp.mce.views = { |
|
0 | 41 |
|
5 | 42 |
/** |
43 |
* Registers a new view type. |
|
44 |
* |
|
45 |
* @param {String} type The view type. |
|
46 |
* @param {Object} extend An object to extend wp.mce.View.prototype with. |
|
47 |
*/ |
|
48 |
register: function( type, extend ) { |
|
49 |
views[ type ] = wp.mce.View.extend( _.extend( extend, { type: type } ) ); |
|
50 |
}, |
|
0 | 51 |
|
5 | 52 |
/** |
53 |
* Unregisters a view type. |
|
54 |
* |
|
55 |
* @param {String} type The view type. |
|
56 |
*/ |
|
57 |
unregister: function( type ) { |
|
58 |
delete views[ type ]; |
|
0 | 59 |
}, |
60 |
||
5 | 61 |
/** |
62 |
* Returns the settings of a view type. |
|
63 |
* |
|
64 |
* @param {String} type The view type. |
|
65 |
* |
|
66 |
* @return {Function} The view constructor. |
|
67 |
*/ |
|
68 |
get: function( type ) { |
|
69 |
return views[ type ]; |
|
0 | 70 |
}, |
71 |
||
5 | 72 |
/** |
73 |
* Unbinds all view nodes. |
|
74 |
* Runs before removing all view nodes from the DOM. |
|
75 |
*/ |
|
76 |
unbind: function() { |
|
77 |
_.each( instances, function( instance ) { |
|
78 |
instance.unbind(); |
|
79 |
} ); |
|
0 | 80 |
}, |
81 |
||
5 | 82 |
/** |
83 |
* Scans a given string for each view's pattern, |
|
84 |
* replacing any matches with markers, |
|
85 |
* and creates a new instance for every match. |
|
86 |
* |
|
87 |
* @param {String} content The string to scan. |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
88 |
* @param {tinymce.Editor} editor The editor. |
5 | 89 |
* |
90 |
* @return {String} The string with markers. |
|
91 |
*/ |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
92 |
setMarkers: function( content, editor ) { |
0 | 93 |
var pieces = [ { content: content } ], |
5 | 94 |
self = this, |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
95 |
instance, current; |
0 | 96 |
|
5 | 97 |
_.each( views, function( view, type ) { |
0 | 98 |
current = pieces.slice(); |
99 |
pieces = []; |
|
100 |
||
101 |
_.each( current, function( piece ) { |
|
102 |
var remaining = piece.content, |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
103 |
result, text; |
0 | 104 |
|
105 |
// Ignore processed pieces, but retain their location. |
|
106 |
if ( piece.processed ) { |
|
107 |
pieces.push( piece ); |
|
108 |
return; |
|
109 |
} |
|
110 |
||
111 |
// Iterate through the string progressively matching views |
|
112 |
// and slicing the string as we go. |
|
5 | 113 |
while ( remaining && ( result = view.prototype.match( remaining ) ) ) { |
0 | 114 |
// Any text before the match becomes an unprocessed piece. |
5 | 115 |
if ( result.index ) { |
116 |
pieces.push( { content: remaining.substring( 0, result.index ) } ); |
|
117 |
} |
|
118 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
119 |
result.options.editor = editor; |
5 | 120 |
instance = self.createInstance( type, result.content, result.options ); |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
121 |
text = instance.loader ? '.' : instance.text; |
0 | 122 |
|
123 |
// Add the processed piece for the match. |
|
5 | 124 |
pieces.push( { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
125 |
content: instance.ignore ? text : '<p data-wpview-marker="' + instance.encodedText + '">' + text + '</p>', |
0 | 126 |
processed: true |
5 | 127 |
} ); |
0 | 128 |
|
129 |
// Update the remaining content. |
|
130 |
remaining = remaining.slice( result.index + result.content.length ); |
|
131 |
} |
|
132 |
||
5 | 133 |
// There are no additional matches. |
134 |
// If any content remains, add it as an unprocessed piece. |
|
135 |
if ( remaining ) { |
|
136 |
pieces.push( { content: remaining } ); |
|
137 |
} |
|
138 |
} ); |
|
139 |
} ); |
|
0 | 140 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
141 |
content = _.pluck( pieces, 'content' ).join( '' ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
142 |
return content.replace( /<p>\s*<p data-wpview-marker=/g, '<p data-wpview-marker=' ).replace( /<\/p>\s*<\/p>/g, '</p>' ); |
0 | 143 |
}, |
144 |
||
5 | 145 |
/** |
146 |
* Create a view instance. |
|
147 |
* |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
148 |
* @param {String} type The view type. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
149 |
* @param {String} text The textual representation of the view. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
150 |
* @param {Object} options Options. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
151 |
* @param {Boolean} force Recreate the instance. Optional. |
5 | 152 |
* |
153 |
* @return {wp.mce.View} The view instance. |
|
154 |
*/ |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
155 |
createInstance: function( type, text, options, force ) { |
5 | 156 |
var View = this.get( type ), |
157 |
encodedText, |
|
158 |
instance; |
|
0 | 159 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
160 |
if ( text.indexOf( '[' ) !== -1 && text.indexOf( ']' ) !== -1 ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
161 |
// Looks like a shortcode? Remove any line breaks from inside of shortcodes |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
162 |
// or autop will replace them with <p> and <br> later and the string won't match. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
163 |
text = text.replace( /\[[^\]]+\]/g, function( match ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
164 |
return match.replace( /[\r\n]/g, '' ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
165 |
}); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
166 |
} |
0 | 167 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
168 |
if ( ! force ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
169 |
instance = this.getInstance( text ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
170 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
171 |
if ( instance ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
172 |
return instance; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
173 |
} |
5 | 174 |
} |
0 | 175 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
176 |
encodedText = encodeURIComponent( text ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
177 |
|
5 | 178 |
options = _.extend( options || {}, { |
179 |
text: text, |
|
180 |
encodedText: encodedText |
|
181 |
} ); |
|
0 | 182 |
|
5 | 183 |
return instances[ encodedText ] = new View( options ); |
184 |
}, |
|
0 | 185 |
|
5 | 186 |
/** |
187 |
* Get a view instance. |
|
188 |
* |
|
189 |
* @param {(String|HTMLElement)} object The textual representation of the view or the view node. |
|
190 |
* |
|
191 |
* @return {wp.mce.View} The view instance or undefined. |
|
192 |
*/ |
|
193 |
getInstance: function( object ) { |
|
194 |
if ( typeof object === 'string' ) { |
|
195 |
return instances[ encodeURIComponent( object ) ]; |
|
196 |
} |
|
0 | 197 |
|
5 | 198 |
return instances[ $( object ).attr( 'data-wpview-text' ) ]; |
0 | 199 |
}, |
200 |
||
5 | 201 |
/** |
202 |
* Given a view node, get the view's text. |
|
203 |
* |
|
204 |
* @param {HTMLElement} node The view node. |
|
205 |
* |
|
206 |
* @return {String} The textual representation of the view. |
|
207 |
*/ |
|
208 |
getText: function( node ) { |
|
209 |
return decodeURIComponent( $( node ).attr( 'data-wpview-text' ) || '' ); |
|
0 | 210 |
}, |
211 |
||
5 | 212 |
/** |
213 |
* Renders all view nodes that are not yet rendered. |
|
214 |
* |
|
215 |
* @param {Boolean} force Rerender all view nodes. |
|
216 |
*/ |
|
217 |
render: function( force ) { |
|
218 |
_.each( instances, function( instance ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
219 |
instance.render( null, force ); |
5 | 220 |
} ); |
0 | 221 |
}, |
222 |
||
5 | 223 |
/** |
224 |
* Update the text of a given view node. |
|
225 |
* |
|
226 |
* @param {String} text The new text. |
|
227 |
* @param {tinymce.Editor} editor The TinyMCE editor instance the view node is in. |
|
228 |
* @param {HTMLElement} node The view node to update. |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
229 |
* @param {Boolean} force Recreate the instance. Optional. |
5 | 230 |
*/ |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
231 |
update: function( text, editor, node, force ) { |
5 | 232 |
var instance = this.getInstance( node ); |
0 | 233 |
|
5 | 234 |
if ( instance ) { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
235 |
instance.update( text, editor, node, force ); |
5 | 236 |
} |
0 | 237 |
}, |
238 |
||
5 | 239 |
/** |
240 |
* Renders any editing interface based on the view type. |
|
241 |
* |
|
242 |
* @param {tinymce.Editor} editor The TinyMCE editor instance the view node is in. |
|
243 |
* @param {HTMLElement} node The view node to edit. |
|
244 |
*/ |
|
245 |
edit: function( editor, node ) { |
|
246 |
var instance = this.getInstance( node ); |
|
0 | 247 |
|
5 | 248 |
if ( instance && instance.edit ) { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
249 |
instance.edit( instance.text, function( text, force ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
250 |
instance.update( text, editor, node, force ); |
5 | 251 |
} ); |
252 |
} |
|
0 | 253 |
}, |
254 |
||
5 | 255 |
/** |
256 |
* Remove a given view node from the DOM. |
|
257 |
* |
|
258 |
* @param {tinymce.Editor} editor The TinyMCE editor instance the view node is in. |
|
259 |
* @param {HTMLElement} node The view node to remove. |
|
260 |
*/ |
|
261 |
remove: function( editor, node ) { |
|
262 |
var instance = this.getInstance( node ); |
|
0 | 263 |
|
5 | 264 |
if ( instance ) { |
265 |
instance.remove( editor, node ); |
|
266 |
} |
|
0 | 267 |
} |
268 |
}; |
|
269 |
||
5 | 270 |
/** |
271 |
* A Backbone-like View constructor intended for use when rendering a TinyMCE View. |
|
272 |
* The main difference is that the TinyMCE View is not tied to a particular DOM node. |
|
273 |
* |
|
274 |
* @param {Object} options Options. |
|
275 |
*/ |
|
276 |
wp.mce.View = function( options ) { |
|
277 |
_.extend( this, options ); |
|
278 |
this.initialize(); |
|
279 |
}; |
|
280 |
||
281 |
wp.mce.View.extend = Backbone.View.extend; |
|
282 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
283 |
_.extend( wp.mce.View.prototype, /** @lends wp.mce.View.prototype */{ |
5 | 284 |
|
285 |
/** |
|
286 |
* The content. |
|
287 |
* |
|
288 |
* @type {*} |
|
289 |
*/ |
|
290 |
content: null, |
|
291 |
||
292 |
/** |
|
293 |
* Whether or not to display a loader. |
|
294 |
* |
|
295 |
* @type {Boolean} |
|
296 |
*/ |
|
297 |
loader: true, |
|
298 |
||
299 |
/** |
|
300 |
* Runs after the view instance is created. |
|
301 |
*/ |
|
302 |
initialize: function() {}, |
|
303 |
||
304 |
/** |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
305 |
* Returns the content to render in the view node. |
5 | 306 |
* |
307 |
* @return {*} |
|
308 |
*/ |
|
309 |
getContent: function() { |
|
310 |
return this.content; |
|
311 |
}, |
|
312 |
||
313 |
/** |
|
314 |
* Renders all view nodes tied to this view instance that are not yet rendered. |
|
315 |
* |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
316 |
* @param {String} content The content to render. Optional. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
317 |
* @param {Boolean} force Rerender all view nodes tied to this view instance. Optional. |
5 | 318 |
*/ |
319 |
render: function( content, force ) { |
|
320 |
if ( content != null ) { |
|
321 |
this.content = content; |
|
322 |
} |
|
323 |
||
324 |
content = this.getContent(); |
|
325 |
||
326 |
// If there's nothing to render an no loader needs to be shown, stop. |
|
327 |
if ( ! this.loader && ! content ) { |
|
328 |
return; |
|
329 |
} |
|
330 |
||
331 |
// We're about to rerender all views of this instance, so unbind rendered views. |
|
332 |
force && this.unbind(); |
|
333 |
||
334 |
// Replace any left over markers. |
|
335 |
this.replaceMarkers(); |
|
336 |
||
337 |
if ( content ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
338 |
this.setContent( content, function( editor, node ) { |
5 | 339 |
$( node ).data( 'rendered', true ); |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
340 |
this.bindNode.call( this, editor, node ); |
5 | 341 |
}, force ? null : false ); |
342 |
} else { |
|
343 |
this.setLoader(); |
|
344 |
} |
|
345 |
}, |
|
346 |
||
347 |
/** |
|
348 |
* Binds a given node after its content is added to the DOM. |
|
349 |
*/ |
|
350 |
bindNode: function() {}, |
|
351 |
||
352 |
/** |
|
353 |
* Unbinds a given node before its content is removed from the DOM. |
|
354 |
*/ |
|
355 |
unbindNode: function() {}, |
|
356 |
||
357 |
/** |
|
358 |
* Unbinds all view nodes tied to this view instance. |
|
359 |
* Runs before their content is removed from the DOM. |
|
360 |
*/ |
|
361 |
unbind: function() { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
362 |
this.getNodes( function( editor, node ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
363 |
this.unbindNode.call( this, editor, node ); |
5 | 364 |
}, true ); |
365 |
}, |
|
366 |
||
367 |
/** |
|
368 |
* Gets all the TinyMCE editor instances that support views. |
|
369 |
* |
|
370 |
* @param {Function} callback A callback. |
|
371 |
*/ |
|
372 |
getEditors: function( callback ) { |
|
373 |
_.each( tinymce.editors, function( editor ) { |
|
374 |
if ( editor.plugins.wpview ) { |
|
375 |
callback.call( this, editor ); |
|
376 |
} |
|
377 |
}, this ); |
|
378 |
}, |
|
379 |
||
380 |
/** |
|
381 |
* Gets all view nodes tied to this view instance. |
|
382 |
* |
|
383 |
* @param {Function} callback A callback. |
|
384 |
* @param {Boolean} rendered Get (un)rendered view nodes. Optional. |
|
385 |
*/ |
|
386 |
getNodes: function( callback, rendered ) { |
|
387 |
this.getEditors( function( editor ) { |
|
388 |
var self = this; |
|
389 |
||
390 |
$( editor.getBody() ) |
|
391 |
.find( '[data-wpview-text="' + self.encodedText + '"]' ) |
|
392 |
.filter( function() { |
|
393 |
var data; |
|
394 |
||
395 |
if ( rendered == null ) { |
|
396 |
return true; |
|
397 |
} |
|
398 |
||
399 |
data = $( this ).data( 'rendered' ) === true; |
|
400 |
||
401 |
return rendered ? data : ! data; |
|
402 |
} ) |
|
403 |
.each( function() { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
404 |
callback.call( self, editor, this, this /* back compat */ ); |
5 | 405 |
} ); |
406 |
} ); |
|
407 |
}, |
|
408 |
||
409 |
/** |
|
410 |
* Gets all marker nodes tied to this view instance. |
|
411 |
* |
|
412 |
* @param {Function} callback A callback. |
|
413 |
*/ |
|
414 |
getMarkers: function( callback ) { |
|
415 |
this.getEditors( function( editor ) { |
|
416 |
var self = this; |
|
417 |
||
418 |
$( editor.getBody() ) |
|
419 |
.find( '[data-wpview-marker="' + this.encodedText + '"]' ) |
|
420 |
.each( function() { |
|
421 |
callback.call( self, editor, this ); |
|
422 |
} ); |
|
423 |
} ); |
|
424 |
}, |
|
425 |
||
426 |
/** |
|
427 |
* Replaces all marker nodes tied to this view instance. |
|
428 |
*/ |
|
429 |
replaceMarkers: function() { |
|
430 |
this.getMarkers( function( editor, node ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
431 |
var selected = node === editor.selection.getNode(); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
432 |
var $viewNode; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
433 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
434 |
if ( ! this.loader && $( node ).text() !== tinymce.DOM.decode( this.text ) ) { |
5 | 435 |
editor.dom.setAttrib( node, 'data-wpview-marker', null ); |
436 |
return; |
|
437 |
} |
|
438 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
439 |
$viewNode = editor.$( |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
440 |
'<div class="wpview wpview-wrap" data-wpview-text="' + this.encodedText + '" data-wpview-type="' + this.type + '" contenteditable="false"></div>' |
5 | 441 |
); |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
442 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
443 |
editor.$( node ).replaceWith( $viewNode ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
444 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
445 |
if ( selected ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
446 |
setTimeout( function() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
447 |
editor.selection.select( $viewNode[0] ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
448 |
editor.selection.collapse(); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
449 |
} ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
450 |
} |
5 | 451 |
} ); |
452 |
}, |
|
453 |
||
454 |
/** |
|
455 |
* Removes all marker nodes tied to this view instance. |
|
456 |
*/ |
|
457 |
removeMarkers: function() { |
|
458 |
this.getMarkers( function( editor, node ) { |
|
459 |
editor.dom.setAttrib( node, 'data-wpview-marker', null ); |
|
460 |
} ); |
|
461 |
}, |
|
462 |
||
463 |
/** |
|
464 |
* Sets the content for all view nodes tied to this view instance. |
|
465 |
* |
|
466 |
* @param {*} content The content to set. |
|
467 |
* @param {Function} callback A callback. Optional. |
|
468 |
* @param {Boolean} rendered Only set for (un)rendered nodes. Optional. |
|
469 |
*/ |
|
470 |
setContent: function( content, callback, rendered ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
471 |
if ( _.isObject( content ) && ( content.sandbox || content.head || content.body.indexOf( '<script' ) !== -1 ) ) { |
5 | 472 |
this.setIframes( content.head || '', content.body, callback, rendered ); |
473 |
} else if ( _.isString( content ) && content.indexOf( '<script' ) !== -1 ) { |
|
474 |
this.setIframes( '', content, callback, rendered ); |
|
475 |
} else { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
476 |
this.getNodes( function( editor, node ) { |
5 | 477 |
content = content.body || content; |
478 |
||
479 |
if ( content.indexOf( '<iframe' ) !== -1 ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
480 |
content += '<span class="mce-shim"></span>'; |
5 | 481 |
} |
482 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
483 |
editor.undoManager.transact( function() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
484 |
node.innerHTML = ''; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
485 |
node.appendChild( _.isString( content ) ? editor.dom.createFragment( content ) : content ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
486 |
editor.dom.add( node, 'span', { 'class': 'wpview-end' } ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
487 |
} ); |
5 | 488 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
489 |
callback && callback.call( this, editor, node ); |
5 | 490 |
}, rendered ); |
491 |
} |
|
492 |
}, |
|
493 |
||
494 |
/** |
|
495 |
* Sets the content in an iframe for all view nodes tied to this view instance. |
|
496 |
* |
|
497 |
* @param {String} head HTML string to be added to the head of the document. |
|
498 |
* @param {String} body HTML string to be added to the body of the document. |
|
499 |
* @param {Function} callback A callback. Optional. |
|
500 |
* @param {Boolean} rendered Only set for (un)rendered nodes. Optional. |
|
501 |
*/ |
|
502 |
setIframes: function( head, body, callback, rendered ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
503 |
var self = this; |
5 | 504 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
505 |
if ( body.indexOf( '[' ) !== -1 && body.indexOf( ']' ) !== -1 ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
506 |
var shortcodesRegExp = new RegExp( '\\[\\/?(?:' + window.mceViewL10n.shortcodes.join( '|' ) + ')[^\\]]*?\\]', 'g' ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
507 |
// Escape tags inside shortcode previews. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
508 |
body = body.replace( shortcodesRegExp, function( match ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
509 |
return match.replace( /</g, '<' ).replace( />/g, '>' ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
510 |
} ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
511 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
512 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
513 |
this.getNodes( function( editor, node ) { |
5 | 514 |
var dom = editor.dom, |
515 |
styles = '', |
|
516 |
bodyClasses = editor.getBody().className || '', |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
517 |
editorHead = editor.getDoc().getElementsByTagName( 'head' )[0], |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
518 |
iframe, iframeWin, iframeDoc, MutationObserver, observer, i, block; |
5 | 519 |
|
520 |
tinymce.each( dom.$( 'link[rel="stylesheet"]', editorHead ), function( link ) { |
|
521 |
if ( link.href && link.href.indexOf( 'skins/lightgray/content.min.css' ) === -1 && |
|
522 |
link.href.indexOf( 'skins/wordpress/wp-content.css' ) === -1 ) { |
|
523 |
||
524 |
styles += dom.getOuterHTML( link ); |
|
525 |
} |
|
526 |
} ); |
|
527 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
528 |
if ( self.iframeHeight ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
529 |
dom.add( node, 'span', { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
530 |
'data-mce-bogus': 1, |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
531 |
style: { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
532 |
display: 'block', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
533 |
width: '100%', |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
534 |
height: self.iframeHeight |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
535 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
536 |
}, '\u200B' ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
537 |
} |
5 | 538 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
539 |
editor.undoManager.transact( function() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
540 |
node.innerHTML = ''; |
5 | 541 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
542 |
iframe = dom.add( node, 'iframe', { |
5 | 543 |
/* jshint scripturl: true */ |
544 |
src: tinymce.Env.ie ? 'javascript:""' : '', |
|
545 |
frameBorder: '0', |
|
546 |
allowTransparency: 'true', |
|
547 |
scrolling: 'no', |
|
548 |
'class': 'wpview-sandbox', |
|
549 |
style: { |
|
550 |
width: '100%', |
|
551 |
display: 'block' |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
552 |
}, |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
553 |
height: self.iframeHeight |
5 | 554 |
} ); |
555 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
556 |
dom.add( node, 'span', { 'class': 'mce-shim' } ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
557 |
dom.add( node, 'span', { 'class': 'wpview-end' } ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
558 |
} ); |
5 | 559 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
560 |
// Bail if the iframe node is not attached to the DOM. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
561 |
// Happens when the view is dragged in the editor. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
562 |
// There is a browser restriction when iframes are moved in the DOM. They get emptied. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
563 |
// The iframe will be rerendered after dropping the view node at the new location. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
564 |
if ( ! iframe.contentWindow ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
565 |
return; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
566 |
} |
5 | 567 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
568 |
iframeWin = iframe.contentWindow; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
569 |
iframeDoc = iframeWin.document; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
570 |
iframeDoc.open(); |
5 | 571 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
572 |
iframeDoc.write( |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
573 |
'<!DOCTYPE html>' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
574 |
'<html>' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
575 |
'<head>' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
576 |
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
577 |
head + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
578 |
styles + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
579 |
'<style>' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
580 |
'html {' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
581 |
'background: transparent;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
582 |
'padding: 0;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
583 |
'margin: 0;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
584 |
'}' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
585 |
'body#wpview-iframe-sandbox {' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
586 |
'background: transparent;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
587 |
'padding: 1px 0 !important;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
588 |
'margin: -1px 0 0 !important;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
589 |
'}' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
590 |
'body#wpview-iframe-sandbox:before,' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
591 |
'body#wpview-iframe-sandbox:after {' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
592 |
'display: none;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
593 |
'content: "";' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
594 |
'}' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
595 |
'iframe {' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
596 |
'max-width: 100%;' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
597 |
'}' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
598 |
'</style>' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
599 |
'</head>' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
600 |
'<body id="wpview-iframe-sandbox" class="' + bodyClasses + '">' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
601 |
body + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
602 |
'</body>' + |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
603 |
'</html>' |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
604 |
); |
5 | 605 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
606 |
iframeDoc.close(); |
5 | 607 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
608 |
function resize() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
609 |
var $iframe; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
610 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
611 |
if ( block ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
612 |
return; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
613 |
} |
5 | 614 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
615 |
// Make sure the iframe still exists. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
616 |
if ( iframe.contentWindow ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
617 |
$iframe = $( iframe ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
618 |
self.iframeHeight = $( iframeDoc.body ).height(); |
5 | 619 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
620 |
if ( $iframe.height() !== self.iframeHeight ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
621 |
$iframe.height( self.iframeHeight ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
622 |
editor.nodeChanged(); |
5 | 623 |
} |
624 |
} |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
625 |
} |
5 | 626 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
627 |
if ( self.iframeHeight ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
628 |
block = true; |
5 | 629 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
630 |
setTimeout( function() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
631 |
block = false; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
632 |
resize(); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
633 |
}, 3000 ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
634 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
635 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
636 |
function reload() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
637 |
if ( ! editor.isHidden() ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
638 |
$( node ).data( 'rendered', null ); |
5 | 639 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
640 |
setTimeout( function() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
641 |
wp.mce.views.render(); |
5 | 642 |
} ); |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
643 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
644 |
} |
5 | 645 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
646 |
function addObserver() { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
647 |
observer = new MutationObserver( _.debounce( resize, 100 ) ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
648 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
649 |
observer.observe( iframeDoc.body, { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
650 |
attributes: true, |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
651 |
childList: true, |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
652 |
subtree: true |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
653 |
} ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
654 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
655 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
656 |
$( iframeWin ).on( 'load', resize ).on( 'unload', reload ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
657 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
658 |
MutationObserver = iframeWin.MutationObserver || iframeWin.WebKitMutationObserver || iframeWin.MozMutationObserver; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
659 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
660 |
if ( MutationObserver ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
661 |
if ( ! iframeDoc.body ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
662 |
iframeDoc.addEventListener( 'DOMContentLoaded', addObserver, false ); |
5 | 663 |
} else { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
664 |
addObserver(); |
5 | 665 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
666 |
} else { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
667 |
for ( i = 1; i < 6; i++ ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
668 |
setTimeout( resize, i * 700 ); |
5 | 669 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
670 |
} |
5 | 671 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
672 |
callback && callback.call( self, editor, node ); |
5 | 673 |
}, rendered ); |
674 |
}, |
|
675 |
||
676 |
/** |
|
677 |
* Sets a loader for all view nodes tied to this view instance. |
|
678 |
*/ |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
679 |
setLoader: function( dashicon ) { |
5 | 680 |
this.setContent( |
681 |
'<div class="loading-placeholder">' + |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
682 |
'<div class="dashicons dashicons-' + ( dashicon || 'admin-media' ) + '"></div>' + |
5 | 683 |
'<div class="wpview-loading"><ins></ins></div>' + |
684 |
'</div>' |
|
685 |
); |
|
686 |
}, |
|
687 |
||
688 |
/** |
|
689 |
* Sets an error for all view nodes tied to this view instance. |
|
690 |
* |
|
691 |
* @param {String} message The error message to set. |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
692 |
* @param {String} dashicon A dashicon ID. Optional. {@link https://developer.wordpress.org/resource/dashicons/} |
5 | 693 |
*/ |
694 |
setError: function( message, dashicon ) { |
|
695 |
this.setContent( |
|
696 |
'<div class="wpview-error">' + |
|
697 |
'<div class="dashicons dashicons-' + ( dashicon || 'no' ) + '"></div>' + |
|
698 |
'<p>' + message + '</p>' + |
|
699 |
'</div>' |
|
700 |
); |
|
701 |
}, |
|
702 |
||
703 |
/** |
|
704 |
* Tries to find a text match in a given string. |
|
705 |
* |
|
706 |
* @param {String} content The string to scan. |
|
707 |
* |
|
708 |
* @return {Object} |
|
709 |
*/ |
|
710 |
match: function( content ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
711 |
var match = shortcode.next( this.type, content ); |
5 | 712 |
|
713 |
if ( match ) { |
|
714 |
return { |
|
715 |
index: match.index, |
|
716 |
content: match.content, |
|
717 |
options: { |
|
718 |
shortcode: match.shortcode |
|
719 |
} |
|
720 |
}; |
|
721 |
} |
|
722 |
}, |
|
723 |
||
724 |
/** |
|
725 |
* Update the text of a given view node. |
|
726 |
* |
|
727 |
* @param {String} text The new text. |
|
728 |
* @param {tinymce.Editor} editor The TinyMCE editor instance the view node is in. |
|
729 |
* @param {HTMLElement} node The view node to update. |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
730 |
* @param {Boolean} force Recreate the instance. Optional. |
5 | 731 |
*/ |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
732 |
update: function( text, editor, node, force ) { |
5 | 733 |
_.find( views, function( view, type ) { |
734 |
var match = view.prototype.match( text ); |
|
735 |
||
736 |
if ( match ) { |
|
737 |
$( node ).data( 'rendered', false ); |
|
738 |
editor.dom.setAttrib( node, 'data-wpview-text', encodeURIComponent( text ) ); |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
739 |
wp.mce.views.createInstance( type, text, match.options, force ).render(); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
740 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
741 |
editor.selection.select( node ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
742 |
editor.nodeChanged(); |
5 | 743 |
editor.focus(); |
744 |
||
745 |
return true; |
|
746 |
} |
|
747 |
} ); |
|
748 |
}, |
|
749 |
||
750 |
/** |
|
751 |
* Remove a given view node from the DOM. |
|
752 |
* |
|
753 |
* @param {tinymce.Editor} editor The TinyMCE editor instance the view node is in. |
|
754 |
* @param {HTMLElement} node The view node to remove. |
|
755 |
*/ |
|
756 |
remove: function( editor, node ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
757 |
this.unbindNode.call( this, editor, node ); |
5 | 758 |
editor.dom.remove( node ); |
759 |
editor.focus(); |
|
760 |
} |
|
761 |
} ); |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
762 |
} )( window, window.wp, window.wp.shortcode, window.jQuery ); |
5 | 763 |
|
764 |
/* |
|
765 |
* The WordPress core TinyMCE views. |
|
766 |
* Views for the gallery, audio, video, playlist and embed shortcodes, |
|
767 |
* and a view for embeddable URLs. |
|
768 |
*/ |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
769 |
( function( window, views, media, $ ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
770 |
var base, gallery, av, embed, |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
771 |
schema, parser, serializer; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
772 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
773 |
function verifyHTML( string ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
774 |
var settings = {}; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
775 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
776 |
if ( ! window.tinymce ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
777 |
return string.replace( /<[^>]+>/g, '' ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
778 |
} |
5 | 779 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
780 |
if ( ! string || ( string.indexOf( '<' ) === -1 && string.indexOf( '>' ) === -1 ) ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
781 |
return string; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
782 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
783 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
784 |
schema = schema || new window.tinymce.html.Schema( settings ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
785 |
parser = parser || new window.tinymce.html.DomParser( settings, schema ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
786 |
serializer = serializer || new window.tinymce.html.Serializer( settings, schema ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
787 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
788 |
return serializer.serialize( parser.parse( string, { forced_root_block: false } ) ); |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
789 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
790 |
|
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
791 |
base = { |
5 | 792 |
state: [], |
793 |
||
794 |
edit: function( text, update ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
795 |
var type = this.type, |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
796 |
frame = media[ type ].edit( text ); |
5 | 797 |
|
798 |
this.pausePlayers && this.pausePlayers(); |
|
799 |
||
800 |
_.each( this.state, function( state ) { |
|
801 |
frame.state( state ).on( 'update', function( selection ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
802 |
update( media[ type ].shortcode( selection ).string(), type === 'gallery' ); |
5 | 803 |
} ); |
804 |
} ); |
|
805 |
||
806 |
frame.on( 'close', function() { |
|
807 |
frame.detach(); |
|
808 |
} ); |
|
809 |
||
810 |
frame.open(); |
|
811 |
} |
|
812 |
}; |
|
813 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
814 |
gallery = _.extend( {}, base, { |
5 | 815 |
state: [ 'gallery-edit' ], |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
816 |
template: media.template( 'editor-gallery' ), |
5 | 817 |
|
818 |
initialize: function() { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
819 |
var attachments = media.gallery.attachments( this.shortcode, media.view.settings.post.id ), |
5 | 820 |
attrs = this.shortcode.attrs.named, |
821 |
self = this; |
|
822 |
||
823 |
attachments.more() |
|
824 |
.done( function() { |
|
825 |
attachments = attachments.toJSON(); |
|
826 |
||
827 |
_.each( attachments, function( attachment ) { |
|
828 |
if ( attachment.sizes ) { |
|
829 |
if ( attrs.size && attachment.sizes[ attrs.size ] ) { |
|
830 |
attachment.thumbnail = attachment.sizes[ attrs.size ]; |
|
831 |
} else if ( attachment.sizes.thumbnail ) { |
|
832 |
attachment.thumbnail = attachment.sizes.thumbnail; |
|
833 |
} else if ( attachment.sizes.full ) { |
|
834 |
attachment.thumbnail = attachment.sizes.full; |
|
835 |
} |
|
836 |
} |
|
837 |
} ); |
|
838 |
||
839 |
self.render( self.template( { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
840 |
verifyHTML: verifyHTML, |
5 | 841 |
attachments: attachments, |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
842 |
columns: attrs.columns ? parseInt( attrs.columns, 10 ) : media.galleryDefaults.columns |
5 | 843 |
} ) ); |
844 |
} ) |
|
845 |
.fail( function( jqXHR, textStatus ) { |
|
846 |
self.setError( textStatus ); |
|
847 |
} ); |
|
848 |
} |
|
849 |
} ); |
|
850 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
851 |
av = _.extend( {}, base, { |
5 | 852 |
action: 'parse-media-shortcode', |
853 |
||
854 |
initialize: function() { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
855 |
var self = this, maxwidth = null; |
5 | 856 |
|
857 |
if ( this.url ) { |
|
858 |
this.loader = false; |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
859 |
this.shortcode = media.embed.shortcode( { |
5 | 860 |
url: this.text |
861 |
} ); |
|
862 |
} |
|
863 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
864 |
// Obtain the target width for the embed. |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
865 |
if ( self.editor ) { |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
866 |
maxwidth = self.editor.getBody().clientWidth; |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
867 |
} |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
868 |
|
5 | 869 |
wp.ajax.post( this.action, { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
870 |
post_ID: media.view.settings.post.id, |
5 | 871 |
type: this.shortcode.tag, |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
872 |
shortcode: this.shortcode.string(), |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
873 |
maxwidth: maxwidth |
5 | 874 |
} ) |
875 |
.done( function( response ) { |
|
876 |
self.render( response ); |
|
877 |
} ) |
|
878 |
.fail( function( response ) { |
|
879 |
if ( self.url ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
880 |
self.ignore = true; |
5 | 881 |
self.removeMarkers(); |
882 |
} else { |
|
883 |
self.setError( response.message || response.statusText, 'admin-media' ); |
|
884 |
} |
|
885 |
} ); |
|
886 |
||
887 |
this.getEditors( function( editor ) { |
|
888 |
editor.on( 'wpview-selected', function() { |
|
889 |
self.pausePlayers(); |
|
890 |
} ); |
|
891 |
} ); |
|
892 |
}, |
|
893 |
||
894 |
pausePlayers: function() { |
|
895 |
this.getNodes( function( editor, node, content ) { |
|
896 |
var win = $( 'iframe.wpview-sandbox', content ).get( 0 ); |
|
897 |
||
898 |
if ( win && ( win = win.contentWindow ) && win.mejs ) { |
|
899 |
_.each( win.mejs.players, function( player ) { |
|
900 |
try { |
|
901 |
player.pause(); |
|
902 |
} catch ( e ) {} |
|
903 |
} ); |
|
904 |
} |
|
905 |
} ); |
|
906 |
} |
|
907 |
} ); |
|
908 |
||
909 |
embed = _.extend( {}, av, { |
|
910 |
action: 'parse-embed', |
|
911 |
||
912 |
edit: function( text, update ) { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
913 |
var frame = media.embed.edit( text, this.url ), |
5 | 914 |
self = this; |
915 |
||
916 |
this.pausePlayers(); |
|
917 |
||
918 |
frame.state( 'embed' ).props.on( 'change:url', function( model, url ) { |
|
919 |
if ( url && model.get( 'url' ) ) { |
|
920 |
frame.state( 'embed' ).metadata = model.toJSON(); |
|
921 |
} |
|
922 |
} ); |
|
923 |
||
924 |
frame.state( 'embed' ).on( 'select', function() { |
|
925 |
var data = frame.state( 'embed' ).metadata; |
|
926 |
||
927 |
if ( self.url ) { |
|
928 |
update( data.url ); |
|
929 |
} else { |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
930 |
update( media.embed.shortcode( data ).string() ); |
5 | 931 |
} |
932 |
} ); |
|
933 |
||
934 |
frame.on( 'close', function() { |
|
935 |
frame.detach(); |
|
936 |
} ); |
|
937 |
||
938 |
frame.open(); |
|
939 |
} |
|
940 |
} ); |
|
941 |
||
942 |
views.register( 'gallery', _.extend( {}, gallery ) ); |
|
943 |
||
944 |
views.register( 'audio', _.extend( {}, av, { |
|
945 |
state: [ 'audio-details' ] |
|
946 |
} ) ); |
|
947 |
||
948 |
views.register( 'video', _.extend( {}, av, { |
|
949 |
state: [ 'video-details' ] |
|
950 |
} ) ); |
|
951 |
||
952 |
views.register( 'playlist', _.extend( {}, av, { |
|
953 |
state: [ 'playlist-edit', 'video-playlist-edit' ] |
|
954 |
} ) ); |
|
955 |
||
956 |
views.register( 'embed', _.extend( {}, embed ) ); |
|
957 |
||
958 |
views.register( 'embedURL', _.extend( {}, embed, { |
|
959 |
match: function( content ) { |
|
960 |
var re = /(^|<p>)(https?:\/\/[^\s"]+?)(<\/p>\s*|$)/gi, |
|
961 |
match = re.exec( content ); |
|
962 |
||
963 |
if ( match ) { |
|
964 |
return { |
|
965 |
index: match.index + match[1].length, |
|
966 |
content: match[2], |
|
967 |
options: { |
|
968 |
url: true |
|
969 |
} |
|
970 |
}; |
|
971 |
} |
|
972 |
} |
|
973 |
} ) ); |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
974 |
} )( window, window.wp.mce.views, window.wp.media, window.jQuery ); |