Ticket #28709: 28709.wip.2.diff
File 28709.wip.2.diff, 21.3 KB (added by , 10 years ago) |
---|
-
src/wp-admin/customize.php
diff --git src/wp-admin/customize.php src/wp-admin/customize.php index 3cfa0c7..2ce23b4 100644
do_action( 'customize_controls_print_scripts' ); 160 160 <?php endif; ?> 161 161 </div> 162 162 163 <div id="customize-theme-controls"><ul> 164 <?php 165 foreach ( $wp_customize->containers() as $container ) { 166 $container->maybe_render(); 167 } 168 ?> 169 </ul></div> 163 <div id="customize-theme-controls"> 164 <ul><?php // Panels and sections are managed here via JavaScript ?></ul> 165 </div> 170 166 </div> 171 167 </div> 172 168 … … do_action( 'customize_controls_print_scripts' ); 249 245 ), 250 246 'settings' => array(), 251 247 'controls' => array(), 248 'panels' => array(), 249 'sections' => array(), 252 250 'nonce' => array( 253 251 'save' => wp_create_nonce( 'save-customize_' . $wp_customize->get_stylesheet() ), 254 252 'preview' => wp_create_nonce( 'preview-customize_' . $wp_customize->get_stylesheet() ) … … do_action( 'customize_controls_print_scripts' ); 263 261 ); 264 262 } 265 263 266 // Prepare Customize Control objects to pass to Java script.264 // Prepare Customize Control objects to pass to JavaScript. 267 265 foreach ( $wp_customize->controls() as $id => $control ) { 268 $control->to_json(); 269 $settings['controls'][ $id ] = $control->json; 266 $settings['controls'][ $id ] = $control->json(); 267 } 268 269 // Prepare Customize Section objects to pass to JavaScript. 270 foreach ( $wp_customize->sections() as $id => $section ) { 271 $settings['sections'][ $id ] = $section->json(); 272 } 273 274 // Prepare Customize Panel objects to pass to JavaScript. 275 foreach ( $wp_customize->panels() as $id => $panel ) { 276 $settings['panels'][ $id ] = $panel->json(); 277 foreach ( $panel->sections as $section_id => $section ) { 278 $settings['sections'][ $section_id ] = $section->json(); 279 } 270 280 } 271 281 272 282 ?> -
src/wp-admin/js/accordion.js
diff --git src/wp-admin/js/accordion.js src/wp-admin/js/accordion.js index 6cb1c1c..63e14e8 100644
58 58 }); 59 59 }); 60 60 61 var sectionContent = $( '.accordion-section-content' );62 63 61 /** 64 62 * Close the current accordion section and open a new one. 65 63 * … … 69 67 function accordionSwitch ( el ) { 70 68 var section = el.closest( '.accordion-section' ), 71 69 siblings = section.closest( '.accordion-container' ).find( '.open' ), 72 content = section.find( sectionContent);70 content = section.find( '.accordion-section-content' ); 73 71 74 72 // This section has no content and cannot be expanded. 75 73 if ( section.hasClass( 'cannot-expand' ) ) { … … 87 85 content.toggle( true ).slideToggle( 150 ); 88 86 } else { 89 87 siblings.removeClass( 'open' ); 90 siblings.find( sectionContent).show().slideUp( 150 );88 siblings.find( '.accordion-section-content' ).show().slideUp( 150 ); 91 89 content.toggle( false ).slideToggle( 150 ); 92 90 section.toggleClass( 'open' ); 93 91 } … … 125 123 } else { 126 124 // Close all open sections in any accordion level. 127 125 siblings.removeClass( 'open' ); 128 siblings.find( sectionContent).show().slideUp( 0 );126 siblings.find( '.accordion-section-content' ).show().slideUp( 0 ); 129 127 content.show( 0, function() { 130 128 position = content.offset().top; 131 129 scroll = container.scrollTop(); -
src/wp-admin/js/customize-controls.js
diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js index 85b171d..9edc973 100644
1 1 /* globals _wpCustomizeHeader, _wpMediaViewsL10n */ 2 2 (function( exports, $ ){ 3 var api = wp.customize;3 var bubbleChildValueChanges, api = wp.customize; 4 4 5 5 /** 6 6 * @constructor … … 31 31 }); 32 32 33 33 /** 34 * Watch all changes to Value properties, and bubble changes to parent Values instance 35 * 36 * @param instance 37 */ 38 bubbleChildValueChanges = function ( instance ) { 39 $.each( instance, function ( key, value ) { 40 if ( value && value.extended && value.extended( api.Value ) ) { 41 value.bind( function () { 42 if ( instance.parent ) { 43 instance.parent.trigger( 'change', instance ); 44 } 45 } ); 46 } 47 } ); 48 }; 49 50 /** 51 * @constructor 52 * @augments wp.customize.Class 53 */ 54 api.Section = api.Class.extend({ 55 56 /** 57 * @param {String} id 58 * @param {Array} options 59 */ 60 initialize: function ( id, options ) { 61 var section = this; 62 section.id = id; 63 section.params = {}; 64 $.extend( section, options || {} ); 65 section.panel = new api.Value(); 66 section.container = $( section.params.content ); 67 section.priority = new api.Value( section.params.priority || 100 ); 68 section.panel.bind( function ( id ) { 69 $( section.container ).toggleClass( 'control-subsection', !! id ); 70 }); 71 section.panel.set( section.params.panel || '' ); 72 section.active = new api.Value( true ); // @todo pass from params; value is whether sections is not empty 73 section.active.bind( function ( active ) { 74 section.toggle( active ); 75 } ); 76 section.toggle( section.active() ); 77 bubbleChildValueChanges( this ); 78 }, 79 80 /** 81 * 82 */ 83 embed: function ( readyCallback ) { 84 var panel_id, 85 section = this; 86 87 panel_id = this.panel.get(); 88 if ( ! panel_id ) { 89 $( '#customize-theme-controls > ul' ).append( section.container ); 90 readyCallback(); 91 } else { 92 api.panel( panel_id, function ( panel ) { 93 panel.embed(); 94 panel.container.find( 'ul:first' ).append( section.container ); 95 readyCallback(); 96 } ); 97 } 98 }, 99 100 /** 101 * Get the controls that are associated with this section. 102 * 103 * @returns {Array} 104 */ 105 controls: function () { 106 var section = this, 107 controls = []; 108 api.control.each( function ( control ) { 109 if ( control.section.get() === section.id ) { 110 controls.push( control ); 111 } 112 } ); 113 controls.sort( function ( a, b ) { 114 return a.priority() - b.priority(); 115 } ); 116 return controls; 117 }, 118 119 /** 120 * Callback for change to the section's active state. 121 * 122 * Override function for custom behavior for the section being active/inactive. 123 * 124 * @param {Boolean} active 125 */ 126 toggle: function ( active ) { 127 if ( active ) { 128 this.container.slideDown(); 129 } else { 130 this.container.slideUp(); 131 } 132 }, 133 134 /** 135 * Bring the containing panel into view and then expand this section and bring it into view 136 */ 137 focus: function () { 138 throw new Error( 'Not implemented yet' ); 139 } 140 }); 141 142 /** 143 * @constructor 144 * @augments wp.customize.Class 145 */ 146 api.Panel = api.Class.extend({ 147 initialize: function ( id, options ) { 148 var panel = this; 149 panel.id = id; 150 panel.params = {}; 151 $.extend( panel, options || {} ); 152 panel.priority = new api.Value( panel.params.priority || 160 ); // @todo What if the priority gets changed dynamically? 153 panel.container = $( panel.params.content ); 154 panel.active = new api.Value( true ); // @todo pass from params; value is whether sections is not empty 155 panel.active.bind( function ( active ) { 156 panel.toggle( active ); 157 } ); 158 panel.toggle( panel.active() ); 159 bubbleChildValueChanges( this ); 160 }, 161 162 /** 163 * 164 */ 165 embed: function ( readyCallback ) { 166 $( '#customize-theme-controls > ul' ).append( this.container ); 167 if ( readyCallback ) { 168 readyCallback(); 169 } 170 }, 171 172 /** 173 * Get the controls that are associated with this section. 174 * 175 * @returns {Array} 176 */ 177 sections: function () { 178 var panel = this, 179 sections = []; 180 api.section.each( function ( section ) { 181 if ( section.panel.get() === panel.id ) { 182 sections.push( section ); 183 } 184 } ); 185 sections.sort( function ( a, b ) { 186 return a.priority() - b.priority(); 187 } ); 188 return sections; 189 }, 190 191 /** 192 * Callback for change to the panel's active state. 193 * 194 * Override function for custom behavior for the control being active/inactive. 195 * 196 * @param {Boolean} active 197 */ 198 toggle: function ( active ) { 199 if ( active ) { 200 this.container.slideDown(); 201 } else { 202 // @todo Need to first exit out of the Panel 203 this.container.slideUp(); 204 } 205 } 206 }); 207 208 /** 34 209 * @constructor 35 210 * @augments wp.customize.Class 36 211 */ … … 44 219 45 220 this.id = id; 46 221 this.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' ); 47 this.container = $( this.selector ); 222 this.container = this.params.content ? $( this.params.content ) : $( this.selector ); 223 224 this.section = new api.Value( this.params.section ); 225 this.priority = new api.Value( this.params.priority || 10 ); 48 226 this.active = new api.Value( this.params.active ); 49 227 50 228 settings = $.map( this.params.settings, function( value ) { … … 60 238 } 61 239 62 240 control.setting = control.settings['default'] || null; 63 control.ready(); 241 control.embed( function () { 242 control.ready(); 243 } ); 64 244 }) ); 65 245 66 246 control.elements = []; … … 74 254 75 255 if ( node.is(':radio') ) { 76 256 name = node.prop('name'); 77 if ( radios[ name ] ) 257 if ( radios[ name ] ) { 78 258 return; 259 } 79 260 80 261 radios[ name ] = true; 81 262 node = nodes.filter( '[name="' + name + '"]' ); … … 93 274 control.toggle( active ); 94 275 } ); 95 276 control.toggle( control.active() ); 277 278 bubbleChildValueChanges( this ); 279 }, 280 281 /** 282 * @param {Function} [readyCallback] Callback to fire when the embedding is done. 283 */ 284 embed: function ( readyCallback ) { 285 var section_id, 286 control = this; 287 288 section_id = control.section.get(); 289 if ( ! section_id ) { 290 throw new Error( 'A control must have an associated section.' ); 291 } 292 293 // Defer until the associated section is available 294 api.section( section_id, function ( section ) { 295 section.embed( function () { 296 section.container.find( 'ul:first' ).append( control.container ); 297 readyCallback(); 298 } ); 299 } ); 96 300 }, 97 301 98 302 /** … … 101 305 ready: function() {}, 102 306 103 307 /** 308 * Bring the containing section and panel into view and then this control into view, focusing on the first input 309 */ 310 focus: function () { 311 throw new Error( 'Not implemented yet' ); 312 }, 313 314 /** 104 315 * Callback for change to the control's active state. 105 316 * 106 317 * Override function for custom behavior for the control being active/inactive. … … 575 786 576 787 // Create the collection of Control objects. 577 788 api.control = new api.Values({ defaultConstructor: api.Control }); 789 api.section = new api.Values({ defaultConstructor: api.Section }); 790 api.panel = new api.Values({ defaultConstructor: api.Panel }); 578 791 579 792 /** 580 793 * @constructor … … 979 1192 image: api.ImageControl, 980 1193 header: api.HeaderControl 981 1194 }; 1195 api.panelConstructor = {}; 1196 api.sectionConstructor = {}; 982 1197 983 1198 $( function() { 984 1199 api.settings = window._wpCustomizeSettings; … … 1091 1306 $.extend( this.nonce, nonce ); 1092 1307 }); 1093 1308 1309 // Create Settings 1094 1310 $.each( api.settings.settings, function( id, data ) { 1095 1311 api.create( id, id, data.value, { 1096 1312 transport: data.transport, … … 1098 1314 } ); 1099 1315 }); 1100 1316 1317 // Create Panels 1318 $.each( api.settings.panels, function ( id, data ) { 1319 var constructor = api.panelConstructor[ data.type ] || api.Panel, 1320 panel; 1321 1322 panel = new constructor( id, { 1323 params: data 1324 } ); 1325 api.panel.add( id, panel ); 1326 }); 1327 1328 // Create Sections 1329 $.each( api.settings.sections, function ( id, data ) { 1330 var constructor = api.sectionConstructor[ data.type ] || api.Section, 1331 section; 1332 1333 section = new constructor( id, { 1334 params: data 1335 } ); 1336 api.section.add( id, section ); 1337 }); 1338 1339 // Create Controls 1340 // @todo factor this out 1101 1341 $.each( api.settings.controls, function( id, data ) { 1102 1342 var constructor = api.controlConstructor[ data.type ] || api.Control, 1103 1343 control; 1104 1344 1105 control = api.control.add( id,new constructor( id, {1345 control = new constructor( id, { 1106 1346 params: data, 1107 1347 previewer: api.previewer 1108 } ) ); 1348 } ); 1349 api.control.add( id, control ); 1109 1350 }); 1110 1351 1352 /** 1353 * Sort panels, sections, controls by priorities. Hide empty sections and panels. 1354 */ 1355 api.reflowPaneContents = _.bind( function () { 1356 1357 var appendContainer, rootNodes = []; 1358 1359 api.panel.each( function ( panel ) { 1360 rootNodes.push( panel ); 1361 1362 // Toggle display 1363 var activeCount = 0, 1364 sections = panel.sections(); 1365 _( sections ).each( function ( section ) { 1366 if ( section.active && section.active() ) { 1367 activeCount += 1; 1368 } 1369 } ); 1370 panel.toggle( 0 !== activeCount ); // @todo This is not sticking 1371 1372 // Sort sections 1373 appendContainer = panel.container.find( 'ul:first' ); 1374 _.chain( sections ).reverse().each( function ( section ) { 1375 appendContainer.append( section.container ); 1376 } ); 1377 } ); 1378 1379 api.section.each( function ( section ) { 1380 var activeCount = 0, 1381 controls = section.controls(); 1382 _( controls ).each( function ( control ) { 1383 if ( control.active && control.active() ) { 1384 activeCount += 1; 1385 } 1386 } ); 1387 section.toggle( 0 !== activeCount ); 1388 1389 if ( ! section.panel() ) { 1390 rootNodes.push( section ); 1391 } 1392 1393 // Sort controls 1394 appendContainer = section.container.find( 'ul:first' ); 1395 _.chain( controls ).reverse().each( function ( control ) { 1396 appendContainer.append( control.container ); 1397 } ); 1398 } ); 1399 1400 // Sort the root elements 1401 rootNodes.sort( function ( a, b ) { 1402 return a.priority() - b.priority(); 1403 } ); 1404 appendContainer = $( '#customize-theme-controls > ul' ); 1405 _.chain( rootNodes ).each( function ( rootNode ) { 1406 appendContainer.append( rootNode.container ); 1407 } ); 1408 }, api ); 1409 api.reflowPaneContents = _.debounce( api.reflowPaneContents, 100 ); 1410 $( [ api.panel, api.section, api.control ] ).each( function ( i, values ) { 1411 values.bind( 'add', api.reflowPaneContents ); 1412 values.bind( 'change', api.reflowPaneContents ); 1413 values.bind( 'remove', api.reflowPaneContents ); 1414 } ); 1415 api.bind( 'ready', api.reflowPaneContents ); 1416 1111 1417 // Check if preview url is valid and load the preview frame. 1112 1418 if ( api.previewer.previewUrl() ) { 1113 1419 api.previewer.refresh(); -
src/wp-includes/class-wp-customize-control.php
diff --git src/wp-includes/class-wp-customize-control.php src/wp-includes/class-wp-customize-control.php index 7ae21c8..4a5985f 100644
class WP_Customize_Control { 74 74 public $input_attrs = array(); 75 75 76 76 /** 77 * @deprecated It is better to just call the json() method 77 78 * @access public 78 79 * @var array 79 80 */ … … class WP_Customize_Control { 219 220 220 221 $this->json['type'] = $this->type; 221 222 $this->json['active'] = $this->active(); 223 $this->json['section'] = $this->section; 224 $this->json['content'] = $this->get_content(); 225 } 226 227 /** 228 * Get the data to export to the client via JSON. 229 * 230 * @since 4.1.0 231 * 232 * @return array 233 */ 234 public function json() { 235 $this->to_json(); 236 return $this->json; 222 237 } 223 238 224 239 /** … … class WP_Customize_Control { 242 257 } 243 258 244 259 /** 260 * Get the control's content for insertion into the Customizer pane. 261 * 262 * @since 4.1.0 263 * 264 * @return string 265 */ 266 public final function get_content() { 267 ob_start(); 268 $this->maybe_render(); 269 $template = trim( ob_get_contents() ); 270 ob_end_clean(); 271 return $template; 272 } 273 274 /** 245 275 * Check capabilities and render the control. 246 276 * 247 277 * @since 3.4.0 -
src/wp-includes/class-wp-customize-manager.php
diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php index c658198..bf0963c 100644
final class WP_Customize_Manager { 878 878 879 879 if ( ! $section->panel ) { 880 880 // Top-level section. 881 $sections[ ] = $section;881 $sections[ $section->id ] = $section; 882 882 } else { 883 883 // This section belongs to a panel. 884 884 if ( isset( $this->panels [ $section->panel ] ) ) { 885 $this->panels[ $section->panel ]->sections[ ] = $section;885 $this->panels[ $section->panel ]->sections[ $section->id ] = $section; 886 886 } 887 887 } 888 888 } … … final class WP_Customize_Manager { 899 899 continue; 900 900 } 901 901 902 u sort( $panel->sections, array( $this, '_cmp_priority' ) );903 $panels[ ] = $panel;902 uasort( $panel->sections, array( $this, '_cmp_priority' ) ); 903 $panels[ $panel->id ] = $panel; 904 904 } 905 905 $this->panels = $panels; 906 906 -
src/wp-includes/class-wp-customize-panel.php
diff --git src/wp-includes/class-wp-customize-panel.php src/wp-includes/class-wp-customize-panel.php index 8f85049..fdbe5b4 100644
class WP_Customize_Panel { 83 83 public $sections; 84 84 85 85 /** 86 * @since 4.1.0 87 * @access public 88 * @var string 89 */ 90 public $type; 91 92 /** 86 93 * Constructor. 87 94 * 88 95 * Any supplied $args override class property defaults. … … class WP_Customize_Panel { 110 117 } 111 118 112 119 /** 120 * Gather the parameters passed to client JavaScript via JSON. 121 * 122 * @since 4.1.0 123 * 124 * @return array The array to be exported to the client as JSON 125 */ 126 public function json() { 127 $array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'type' ) ); 128 $array['content'] = $this->get_content(); 129 return $array; 130 } 131 132 /** 113 133 * Checks required user capabilities and whether the theme has the 114 134 * feature support required by the panel. 115 135 * … … class WP_Customize_Panel { 130 150 } 131 151 132 152 /** 153 * Get the panel's content template for insertion into the Customizer pane. 154 * 155 * @since 4.1.0 156 * 157 * @return string 158 */ 159 public final function get_content() { 160 ob_start(); 161 $this->maybe_render(); 162 $template = trim( ob_get_contents() ); 163 ob_end_clean(); 164 return $template; 165 } 166 167 /** 133 168 * Check capabilities and render the panel. 134 169 * 135 170 * @since 4.0.0 … … class WP_Customize_Panel { 175 210 <span class="screen-reader-text"><?php _e( 'Press return or enter to open this panel' ); ?></span> 176 211 </h3> 177 212 <ul class="accordion-sub-container control-panel-content"> 178 <li class=" accordion-section control-section<?php if ( empty( $this->description ) ) echo ' cannot-expand'; ?>">213 <li class="panel-meta accordion-section control-section<?php if ( empty( $this->description ) ) echo ' cannot-expand'; ?>"> 179 214 <div class="accordion-section-title" tabindex="0"> 180 215 <span class="preview-notice"><?php 181 216 /* translators: %s is the site/panel title in the Customizer */ … … class WP_Customize_Panel { 188 223 </div> 189 224 <?php endif; ?> 190 225 </li> 191 <?php 192 foreach ( $this->sections as $section ) { 193 $section->maybe_render(); 194 } 195 ?> 226 196 227 </ul> 197 228 </li> 198 229 <?php -
src/wp-includes/class-wp-customize-section.php
diff --git src/wp-includes/class-wp-customize-section.php src/wp-includes/class-wp-customize-section.php index d740ddb..a905f32 100644
class WP_Customize_Section { 92 92 public $controls; 93 93 94 94 /** 95 * @since 4.1.0 96 * @access public 97 * @var string 98 */ 99 public $type; 100 101 /** 95 102 * Constructor. 96 103 * 97 104 * Any supplied $args override class property defaults. … … class WP_Customize_Section { 118 125 } 119 126 120 127 /** 128 * Gather the parameters passed to client JavaScript via JSON. 129 * 130 * @since 4.1.0 131 * 132 * @return array The array to be exported to the client as JSON 133 */ 134 public function json() { 135 $array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'panel', 'type' ) ); 136 $array['content'] = $this->get_content(); 137 return $array; 138 } 139 140 /** 121 141 * Checks required user capabilities and whether the theme has the 122 142 * feature support required by the section. 123 143 * … … class WP_Customize_Section { 136 156 } 137 157 138 158 /** 159 * Get the section's content template for insertion into the Customizer pane. 160 * 161 * @since 4.1.0 162 * 163 * @return string 164 */ 165 public final function get_content() { 166 ob_start(); 167 $this->maybe_render(); 168 $template = trim( ob_get_contents() ); 169 ob_end_clean(); 170 return $template; 171 } 172 173 /** 139 174 * Check capabilities and render the section. 140 175 * 141 176 * @since 3.4.0 … … class WP_Customize_Section { 172 207 */ 173 208 protected function render() { 174 209 $classes = 'control-section accordion-section'; 175 if ( $this->panel ) {176 $classes .= ' control-subsection';177 }178 210 ?> 179 211 <li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>"> 180 212 <h3 class="accordion-section-title" tabindex="0"> … … class WP_Customize_Section { 183 215 </h3> 184 216 <ul class="accordion-section-content"> 185 217 <?php if ( ! empty( $this->description ) ) : ?> 186 <li><p class="description customize-section-description"><?php echo $this->description; ?></p></li> 218 <li class="customize-section-description-container"> 219 <p class="description customize-section-description"><?php echo $this->description; ?></p> 220 </li> 187 221 <?php endif; ?> 188 <?php189 foreach ( $this->controls as $control )190 $control->maybe_render();191 ?>192 222 </ul> 193 223 </li> 194 224 <?php -
src/wp-includes/js/customize-base.js
diff --git src/wp-includes/js/customize-base.js src/wp-includes/js/customize-base.js index 6c41b40..13d6189 100644
window.wp = window.wp || {}; 183 183 to = this.validate( to ); 184 184 185 185 // Bail if the sanitized value is null or unchanged. 186 if ( null === to || this._value === to ) 186 if ( null === to || this._value === to ) { // @todo why bail if null? 187 187 return this; 188 } 188 189 189 190 this._value = to; 190 191