Changeset 24360
- Timestamp:
- 05/25/2013 09:03:04 PM (13 years ago)
- Location:
- trunk/wp-includes/js
- Files:
-
- 2 edited
-
media-views.js (modified) (1 diff)
-
wp-backbone.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/wp-includes/js/media-views.js
r23956 r24360 844 844 */ 845 845 846 // wp.media.Views847 // -------------848 //849 // A subview manager.850 851 media.Views = function( view, views ) {852 this.view = view;853 this._views = _.isArray( views ) ? { '': views } : views || {};854 };855 856 media.Views.extend = Backbone.Model.extend;857 858 _.extend( media.Views.prototype, {859 // ### Fetch all of the subviews860 //861 // Returns an array of all subviews.862 all: function() {863 return _.flatten( this._views );864 },865 866 // ### Get a selector's subviews867 //868 // Fetches all subviews that match a given `selector`.869 //870 // If no `selector` is provided, it will grab all subviews attached871 // to the view's root.872 get: function( selector ) {873 selector = selector || '';874 return this._views[ selector ];875 },876 877 // ### Get a selector's first subview878 //879 // Fetches the first subview that matches a given `selector`.880 //881 // If no `selector` is provided, it will grab the first subview882 // attached to the view's root.883 //884 // Useful when a selector only has one subview at a time.885 first: function( selector ) {886 var views = this.get( selector );887 return views && views.length ? views[0] : null;888 },889 890 // ### Register subview(s)891 //892 // Registers any number of `views` to a `selector`.893 //894 // When no `selector` is provided, the root selector (the empty string)895 // is used. `views` accepts a `Backbone.View` instance or an array of896 // `Backbone.View` instances.897 //898 // ---899 //900 // Accepts an `options` object, which has a significant effect on the901 // resulting behavior.902 //903 // `options.silent` – *boolean, `false`*904 // > If `options.silent` is true, no DOM modifications will be made.905 //906 // `options.add` – *boolean, `false`*907 // > Use `Views.add()` as a shortcut for setting `options.add` to true.908 //909 // > By default, the provided `views` will replace910 // any existing views associated with the selector. If `options.add`911 // is true, the provided `views` will be added to the existing views.912 //913 // `options.at` – *integer, `undefined`*914 // > When adding, to insert `views` at a specific index, use915 // `options.at`. By default, `views` are added to the end of the array.916 set: function( selector, views, options ) {917 var existing, next;918 919 if ( ! _.isString( selector ) ) {920 options = views;921 views = selector;922 selector = '';923 }924 925 options = options || {};926 views = _.isArray( views ) ? views : [ views ];927 existing = this.get( selector );928 next = views;929 930 if ( existing ) {931 if ( options.add ) {932 if ( _.isUndefined( options.at ) ) {933 next = existing.concat( views );934 } else {935 next = existing;936 next.splice.apply( next, [ options.at, 0 ].concat( views ) );937 }938 } else {939 _.each( next, function( view ) {940 view.__detach = true;941 });942 943 _.each( existing, function( view ) {944 if ( view.__detach )945 view.$el.detach();946 else947 view.dispose();948 });949 950 _.each( next, function( view ) {951 delete view.__detach;952 });953 }954 }955 956 this._views[ selector ] = next;957 958 _.each( views, function( subview ) {959 var constructor = subview.Views || media.Views,960 subviews = subview.views = subview.views || new constructor( subview );961 subviews.parent = this.view;962 subviews.selector = selector;963 }, this );964 965 if ( ! options.silent )966 this._attach( selector, views, _.extend({ ready: this._isReady() }, options ) );967 968 return this;969 },970 971 // ### Add subview(s) to existing subviews972 //973 // An alias to `Views.set()`, which defaults `options.add` to true.974 //975 // Adds any number of `views` to a `selector`.976 //977 // When no `selector` is provided, the root selector (the empty string)978 // is used. `views` accepts a `Backbone.View` instance or an array of979 // `Backbone.View` instances.980 //981 // Use `Views.set()` when setting `options.add` to `false`.982 //983 // Accepts an `options` object. By default, provided `views` will be984 // inserted at the end of the array of existing views. To insert985 // `views` at a specific index, use `options.at`. If `options.silent`986 // is true, no DOM modifications will be made.987 //988 // For more information on the `options` object, see `Views.set()`.989 add: function( selector, views, options ) {990 if ( ! _.isString( selector ) ) {991 options = views;992 views = selector;993 selector = '';994 }995 996 return this.set( selector, views, _.extend({ add: true }, options ) );997 },998 999 // ### Stop tracking subviews1000 //1001 // Stops tracking `views` registered to a `selector`. If no `views` are1002 // set, then all of the `selector`'s subviews will be unregistered and1003 // disposed.1004 //1005 // Accepts an `options` object. If `options.silent` is set, `dispose`1006 // will *not* be triggered on the unregistered views.1007 unset: function( selector, views, options ) {1008 var existing;1009 1010 if ( ! _.isString( selector ) ) {1011 options = views;1012 views = selector;1013 selector = '';1014 }1015 1016 views = views || [];1017 1018 if ( existing = this.get( selector ) ) {1019 views = _.isArray( views ) ? views : [ views ];1020 this._views[ selector ] = views.length ? _.difference( existing, views ) : [];1021 }1022 1023 if ( ! options || ! options.silent )1024 _.invoke( views, 'dispose' );1025 1026 return this;1027 },1028 1029 // ### Detach all subviews1030 //1031 // Detaches all subviews from the DOM.1032 //1033 // Helps to preserve all subview events when re-rendering the master1034 // view. Used in conjunction with `Views.render()`.1035 detach: function() {1036 $( _.pluck( this.all(), 'el' ) ).detach();1037 return this;1038 },1039 1040 // ### Render all subviews1041 //1042 // Renders all subviews. Used in conjunction with `Views.detach()`.1043 render: function() {1044 var options = {1045 ready: this._isReady()1046 };1047 1048 _.each( this._views, function( views, selector ) {1049 this._attach( selector, views, options );1050 }, this );1051 1052 this.rendered = true;1053 return this;1054 },1055 1056 // ### Dispose all subviews1057 //1058 // Triggers the `dispose()` method on all subviews. Detaches the master1059 // view from its parent. Resets the internals of the views manager.1060 //1061 // Accepts an `options` object. If `options.silent` is set, `unset`1062 // will *not* be triggered on the master view's parent.1063 dispose: function( options ) {1064 if ( ! options || ! options.silent ) {1065 if ( this.parent && this.parent.views )1066 this.parent.views.unset( this.selector, this.view, { silent: true });1067 delete this.parent;1068 delete this.selector;1069 }1070 1071 _.invoke( this.all(), 'dispose' );1072 this._views = [];1073 return this;1074 },1075 1076 // ### Replace a selector's subviews1077 //1078 // By default, sets the `$target` selector's html to the subview `els`.1079 //1080 // Can be overridden in subclasses.1081 replace: function( $target, els ) {1082 $target.html( els );1083 return this;1084 },1085 1086 // ### Insert subviews into a selector1087 //1088 // By default, appends the subview `els` to the end of the `$target`1089 // selector. If `options.at` is set, inserts the subview `els` at the1090 // provided index.1091 //1092 // Can be overridden in subclasses.1093 insert: function( $target, els, options ) {1094 var at = options && options.at,1095 $children;1096 1097 if ( _.isNumber( at ) && ($children = $target.children()).length > at )1098 $children.eq( at ).before( els );1099 else1100 $target.append( els );1101 1102 return this;1103 },1104 1105 // ### Trigger the ready event1106 //1107 // **Only use this method if you know what you're doing.**1108 // For performance reasons, this method does not check if the view is1109 // actually attached to the DOM. It's taking your word for it.1110 //1111 // Fires the ready event on the current view and all attached subviews.1112 ready: function() {1113 this.view.trigger('ready');1114 1115 // Find all attached subviews, and call ready on them.1116 _.chain( this.all() ).map( function( view ) {1117 return view.views;1118 }).flatten().where({ attached: true }).invoke('ready');1119 },1120 1121 // #### Internal. Attaches a series of views to a selector.1122 //1123 // Checks to see if a matching selector exists, renders the views,1124 // performs the proper DOM operation, and then checks if the view is1125 // attached to the document.1126 _attach: function( selector, views, options ) {1127 var $selector = selector ? this.view.$( selector ) : this.view.$el,1128 managers;1129 1130 // Check if we found a location to attach the views.1131 if ( ! $selector.length )1132 return this;1133 1134 managers = _.chain( views ).pluck('views').flatten().value();1135 1136 // Render the views if necessary.1137 _.each( managers, function( manager ) {1138 if ( manager.rendered )1139 return;1140 1141 manager.view.render();1142 manager.rendered = true;1143 }, this );1144 1145 // Insert or replace the views.1146 this[ options.add ? 'insert' : 'replace' ]( $selector, _.pluck( views, 'el' ), options );1147 1148 // Set attached and trigger ready if the current view is already1149 // attached to the DOM.1150 _.each( managers, function( manager ) {1151 manager.attached = true;1152 1153 if ( options.ready )1154 manager.ready();1155 }, this );1156 1157 return this;1158 },1159 1160 // #### Internal. Checks if the current view is in the DOM.1161 _isReady: function() {1162 var node = this.view.el;1163 while ( node ) {1164 if ( node === document.body )1165 return true;1166 node = node.parentNode;1167 }1168 1169 return false;1170 }1171 });1172 1173 846 // wp.media.View 1174 847 // ------------- 1175 848 // 1176 849 // The base view class. 1177 media.View = Backbone.View.extend({ 1178 // The constructor for the `Views` manager. 1179 Views: media.Views, 1180 1181 constructor: function( options ) { 1182 this.views = new this.Views( this, this.views ); 1183 this.on( 'ready', this.ready, this ); 1184 1185 if ( options && options.controller ) 1186 this.controller = options.controller; 1187 1188 Backbone.View.apply( this, arguments ); 1189 }, 1190 1191 dispose: function() { 1192 // Undelegating events, removing events from the model, and 1193 // removing events from the controller mirror the code for 1194 // `Backbone.View.dispose` in Backbone master. 1195 this.undelegateEvents(); 1196 1197 if ( this.model && this.model.off ) 1198 this.model.off( null, null, this ); 1199 1200 if ( this.collection && this.collection.off ) 1201 this.collection.off( null, null, this ); 1202 1203 // Unbind controller events. 1204 if ( this.controller && this.controller.off ) 1205 this.controller.off( null, null, this ); 1206 1207 // Recursively dispose child views. 1208 if ( this.views ) 1209 this.views.dispose(); 1210 1211 return this; 1212 }, 1213 1214 remove: function() { 1215 this.dispose(); 1216 return Backbone.View.prototype.remove.apply( this, arguments ); 1217 }, 1218 1219 render: function() { 1220 var options; 1221 1222 if ( this.prepare ) 1223 options = this.prepare(); 1224 1225 this.views.detach(); 1226 1227 if ( this.template ) { 1228 options = options || {}; 1229 this.trigger( 'prepare', options ); 1230 this.$el.html( this.template( options ) ); 1231 } 1232 1233 this.views.render(); 1234 return this; 1235 }, 1236 1237 prepare: function() { 1238 return this.options; 1239 }, 1240 1241 ready: function() {} 1242 }); 850 media.View = wp.View; 1243 851 1244 852 /** -
trunk/wp-includes/js/wp-backbone.js
r24359 r24360 26 26 }); 27 27 28 29 // wp.Subviews 30 // ----------- 31 // 32 // A subview manager. 33 wp.Subviews = function( view, views ) { 34 this.view = view; 35 this._views = _.isArray( views ) ? { '': views } : views || {}; 36 }; 37 38 wp.Subviews.extend = Backbone.Model.extend; 39 40 _.extend( wp.Subviews.prototype, { 41 // ### Fetch all of the subviews 42 // 43 // Returns an array of all subviews. 44 all: function() { 45 return _.flatten( this._views ); 46 }, 47 48 // ### Get a selector's subviews 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 get: function( selector ) { 55 selector = selector || ''; 56 return this._views[ selector ]; 57 }, 58 59 // ### Get a selector's first subview 60 // 61 // Fetches the first subview that matches a given `selector`. 62 // 63 // If no `selector` is provided, it will grab the first subview 64 // attached to the view's root. 65 // 66 // Useful when a selector only has one subview at a time. 67 first: function( selector ) { 68 var views = this.get( selector ); 69 return views && views.length ? views[0] : null; 70 }, 71 72 // ### Register subview(s) 73 // 74 // Registers any number of `views` to a `selector`. 75 // 76 // When no `selector` is provided, the root selector (the empty string) 77 // is used. `views` accepts a `Backbone.View` instance or an array of 78 // `Backbone.View` instances. 79 // 80 // --- 81 // 82 // Accepts an `options` object, which has a significant effect on the 83 // resulting behavior. 84 // 85 // `options.silent` – *boolean, `false`* 86 // > If `options.silent` is true, no DOM modifications will be made. 87 // 88 // `options.add` – *boolean, `false`* 89 // > Use `Views.add()` as a shortcut for setting `options.add` to true. 90 // 91 // > By default, the provided `views` will replace 92 // any existing views associated with the selector. If `options.add` 93 // is true, the provided `views` will be added to the existing views. 94 // 95 // `options.at` – *integer, `undefined`* 96 // > When adding, to insert `views` at a specific index, use 97 // `options.at`. By default, `views` are added to the end of the array. 98 set: function( selector, views, options ) { 99 var existing, next; 100 101 if ( ! _.isString( selector ) ) { 102 options = views; 103 views = selector; 104 selector = ''; 105 } 106 107 options = options || {}; 108 views = _.isArray( views ) ? views : [ views ]; 109 existing = this.get( selector ); 110 next = views; 111 112 if ( existing ) { 113 if ( options.add ) { 114 if ( _.isUndefined( options.at ) ) { 115 next = existing.concat( views ); 116 } else { 117 next = existing; 118 next.splice.apply( next, [ options.at, 0 ].concat( views ) ); 119 } 120 } else { 121 _.each( next, function( view ) { 122 view.__detach = true; 123 }); 124 125 _.each( existing, function( view ) { 126 if ( view.__detach ) 127 view.$el.detach(); 128 else 129 view.dispose(); 130 }); 131 132 _.each( next, function( view ) { 133 delete view.__detach; 134 }); 135 } 136 } 137 138 this._views[ selector ] = next; 139 140 _.each( views, function( subview ) { 141 var constructor = subview.Views || wp.Subviews, 142 subviews = subview.views = subview.views || new constructor( subview ); 143 subviews.parent = this.view; 144 subviews.selector = selector; 145 }, this ); 146 147 if ( ! options.silent ) 148 this._attach( selector, views, _.extend({ ready: this._isReady() }, options ) ); 149 150 return this; 151 }, 152 153 // ### Add subview(s) to existing subviews 154 // 155 // An alias to `Views.set()`, which defaults `options.add` to true. 156 // 157 // Adds any number of `views` to a `selector`. 158 // 159 // When no `selector` is provided, the root selector (the empty string) 160 // is used. `views` accepts a `Backbone.View` instance or an array of 161 // `Backbone.View` instances. 162 // 163 // Use `Views.set()` when setting `options.add` to `false`. 164 // 165 // Accepts an `options` object. By default, provided `views` will be 166 // inserted at the end of the array of existing views. To insert 167 // `views` at a specific index, use `options.at`. If `options.silent` 168 // is true, no DOM modifications will be made. 169 // 170 // For more information on the `options` object, see `Views.set()`. 171 add: function( selector, views, options ) { 172 if ( ! _.isString( selector ) ) { 173 options = views; 174 views = selector; 175 selector = ''; 176 } 177 178 return this.set( selector, views, _.extend({ add: true }, options ) ); 179 }, 180 181 // ### Stop tracking subviews 182 // 183 // Stops tracking `views` registered to a `selector`. If no `views` are 184 // set, then all of the `selector`'s subviews will be unregistered and 185 // disposed. 186 // 187 // Accepts an `options` object. If `options.silent` is set, `dispose` 188 // will *not* be triggered on the unregistered views. 189 unset: function( selector, views, options ) { 190 var existing; 191 192 if ( ! _.isString( selector ) ) { 193 options = views; 194 views = selector; 195 selector = ''; 196 } 197 198 views = views || []; 199 200 if ( existing = this.get( selector ) ) { 201 views = _.isArray( views ) ? views : [ views ]; 202 this._views[ selector ] = views.length ? _.difference( existing, views ) : []; 203 } 204 205 if ( ! options || ! options.silent ) 206 _.invoke( views, 'dispose' ); 207 208 return this; 209 }, 210 211 // ### Detach all subviews 212 // 213 // Detaches all subviews from the DOM. 214 // 215 // Helps to preserve all subview events when re-rendering the master 216 // view. Used in conjunction with `Views.render()`. 217 detach: function() { 218 $( _.pluck( this.all(), 'el' ) ).detach(); 219 return this; 220 }, 221 222 // ### Render all subviews 223 // 224 // Renders all subviews. Used in conjunction with `Views.detach()`. 225 render: function() { 226 var options = { 227 ready: this._isReady() 228 }; 229 230 _.each( this._views, function( views, selector ) { 231 this._attach( selector, views, options ); 232 }, this ); 233 234 this.rendered = true; 235 return this; 236 }, 237 238 // ### Dispose all subviews 239 // 240 // Triggers the `dispose()` method on all subviews. Detaches the master 241 // view from its parent. Resets the internals of the views manager. 242 // 243 // Accepts an `options` object. If `options.silent` is set, `unset` 244 // will *not* be triggered on the master view's parent. 245 dispose: function( options ) { 246 if ( ! options || ! options.silent ) { 247 if ( this.parent && this.parent.views ) 248 this.parent.views.unset( this.selector, this.view, { silent: true }); 249 delete this.parent; 250 delete this.selector; 251 } 252 253 _.invoke( this.all(), 'dispose' ); 254 this._views = []; 255 return this; 256 }, 257 258 // ### Replace a selector's subviews 259 // 260 // By default, sets the `$target` selector's html to the subview `els`. 261 // 262 // Can be overridden in subclasses. 263 replace: function( $target, els ) { 264 $target.html( els ); 265 return this; 266 }, 267 268 // ### Insert subviews into a selector 269 // 270 // By default, appends the subview `els` to the end of the `$target` 271 // selector. If `options.at` is set, inserts the subview `els` at the 272 // provided index. 273 // 274 // Can be overridden in subclasses. 275 insert: function( $target, els, options ) { 276 var at = options && options.at, 277 $children; 278 279 if ( _.isNumber( at ) && ($children = $target.children()).length > at ) 280 $children.eq( at ).before( els ); 281 else 282 $target.append( els ); 283 284 return this; 285 }, 286 287 // ### Trigger the ready event 288 // 289 // **Only use this method if you know what you're doing.** 290 // For performance reasons, this method does not check if the view is 291 // actually attached to the DOM. It's taking your word for it. 292 // 293 // Fires the ready event on the current view and all attached subviews. 294 ready: function() { 295 this.view.trigger('ready'); 296 297 // Find all attached subviews, and call ready on them. 298 _.chain( this.all() ).map( function( view ) { 299 return view.views; 300 }).flatten().where({ attached: true }).invoke('ready'); 301 }, 302 303 // #### Internal. Attaches a series of views to a selector. 304 // 305 // Checks to see if a matching selector exists, renders the views, 306 // performs the proper DOM operation, and then checks if the view is 307 // attached to the document. 308 _attach: function( selector, views, options ) { 309 var $selector = selector ? this.view.$( selector ) : this.view.$el, 310 managers; 311 312 // Check if we found a location to attach the views. 313 if ( ! $selector.length ) 314 return this; 315 316 managers = _.chain( views ).pluck('views').flatten().value(); 317 318 // Render the views if necessary. 319 _.each( managers, function( manager ) { 320 if ( manager.rendered ) 321 return; 322 323 manager.view.render(); 324 manager.rendered = true; 325 }, this ); 326 327 // Insert or replace the views. 328 this[ options.add ? 'insert' : 'replace' ]( $selector, _.pluck( views, 'el' ), options ); 329 330 // Set attached and trigger ready if the current view is already 331 // attached to the DOM. 332 _.each( managers, function( manager ) { 333 manager.attached = true; 334 335 if ( options.ready ) 336 manager.ready(); 337 }, this ); 338 339 return this; 340 }, 341 342 // #### Internal. Checks if the current view is in the DOM. 343 _isReady: function() { 344 var node = this.view.el; 345 while ( node ) { 346 if ( node === document.body ) 347 return true; 348 node = node.parentNode; 349 } 350 351 return false; 352 } 353 }); 354 355 356 // wp.View 357 // ------- 358 // 359 // The base view class. 360 wp.View = Backbone.View.extend({ 361 // The constructor for the `Views` manager. 362 Subviews: wp.Subviews, 363 364 constructor: function( options ) { 365 this.views = new this.Subviews( this, this.views ); 366 this.on( 'ready', this.ready, this ); 367 368 if ( options && options.controller ) 369 this.controller = options.controller; 370 371 Backbone.View.apply( this, arguments ); 372 }, 373 374 dispose: function() { 375 // Undelegating events, removing events from the model, and 376 // removing events from the controller mirror the code for 377 // `Backbone.View.dispose` in Backbone master. 378 this.undelegateEvents(); 379 380 if ( this.model && this.model.off ) 381 this.model.off( null, null, this ); 382 383 if ( this.collection && this.collection.off ) 384 this.collection.off( null, null, this ); 385 386 // Unbind controller events. 387 if ( this.controller && this.controller.off ) 388 this.controller.off( null, null, this ); 389 390 // Recursively dispose child views. 391 if ( this.views ) 392 this.views.dispose(); 393 394 return this; 395 }, 396 397 remove: function() { 398 this.dispose(); 399 return Backbone.View.prototype.remove.apply( this, arguments ); 400 }, 401 402 render: function() { 403 var options; 404 405 if ( this.prepare ) 406 options = this.prepare(); 407 408 this.views.detach(); 409 410 if ( this.template ) { 411 options = options || {}; 412 this.trigger( 'prepare', options ); 413 this.$el.html( this.template( options ) ); 414 } 415 416 this.views.render(); 417 return this; 418 }, 419 420 prepare: function() { 421 return this.options; 422 }, 423 424 ready: function() {} 425 }); 28 426 }(jQuery));
Note: See TracChangeset
for help on using the changeset viewer.