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