Changeset 30716
- Timestamp:
- 12/02/2014 10:55:48 PM (10 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/js/customize-controls.js
r30712 r30716 1 1 /* globals _wpCustomizeHeader, _wpMediaViewsL10n */ 2 2 (function( exports, $ ){ 3 var bubbleChildValueChanges, Container, focus, isKeydownButNotEnterEvent, areElementListsEqual, prioritySort, api = wp.customize; 4 5 // @todo Move private helper functions to wp.customize.utils so they can be unit tested 3 var Container, focus, api = wp.customize; 6 4 7 5 /** … … 34 32 35 33 /** 34 * Utility function namespace 35 */ 36 api.utils = {}; 37 38 /** 36 39 * Watch all changes to Value properties, and bubble changes to parent Values instance 37 40 * … … 39 42 * @param {Array} properties The names of the Value instances to watch. 40 43 */ 41 bubbleChildValueChanges = function ( instance, properties ) {44 api.utils.bubbleChildValueChanges = function ( instance, properties ) { 42 45 $.each( properties, function ( i, key ) { 43 46 instance[ key ].bind( function ( to, from ) { … … 87 90 * @returns {Number} 88 91 */ 89 prioritySort = function ( a, b ) {92 api.utils.prioritySort = function ( a, b ) { 90 93 if ( a.priority() === b.priority() && typeof a.params.instanceNumber === 'number' && typeof b.params.instanceNumber === 'number' ) { 91 94 return a.params.instanceNumber - b.params.instanceNumber; … … 101 104 * @returns {boolean} 102 105 */ 103 isKeydownButNotEnterEvent = function ( event ) {106 api.utils.isKeydownButNotEnterEvent = function ( event ) { 104 107 return ( 'keydown' === event.type && 13 !== event.which ); 105 108 }; … … 112 115 * @returns {boolean} 113 116 */ 114 a reElementListsEqual = function ( listA, listB ) {117 api.utils.areElementListsEqual = function ( listA, listB ) { 115 118 var equal = ( 116 119 listA.length === listB.length && // if lists are different lengths, then naturally they are not equal … … 143 146 144 147 container.deferred = { 145 ready: new $.Deferred()148 embedded: new $.Deferred() 146 149 }; 147 150 container.priority = new api.Value(); … … 156 159 active = ( active && container.isContextuallyActive() ); 157 160 container.onChangeActive( active, args ); 158 // @todo trigger 'activated' and 'deactivated' events based on the expanded param?159 161 }); 160 162 container.expanded.bind( function ( expanded ) { … … 162 164 args = $.extend( {}, container.defaultExpandedArguments, args ); 163 165 container.onChangeExpanded( expanded, args ); 164 // @todo trigger 'expanded' and 'collapsed' events based on the expanded param?165 166 }); 166 167 167 168 container.attachEvents(); 168 169 169 bubbleChildValueChanges( container, [ 'priority', 'active' ] );170 api.utils.bubbleChildValueChanges( container, [ 'priority', 'active' ] ); 170 171 171 172 container.priority.set( isNaN( container.params.priority ) ? 100 : container.params.priority ); 172 173 container.active.set( container.params.active ); 173 container.expanded.set( false ); // @todo True if deeplinking?174 container.expanded.set( false ); 174 175 }, 175 176 … … 194 195 } 195 196 } ); 196 children.sort( prioritySort );197 children.sort( api.utils.prioritySort ); 197 198 return children; 198 199 }, … … 203 204 */ 204 205 isContextuallyActive: function () { 205 throw new Error( ' Must override withsubclass.' );206 throw new Error( 'Container.isContextuallyActive() must be overridden in a subclass.' ); 206 207 }, 207 208 … … 336 337 }); 337 338 section.panel.set( section.params.panel || '' ); 338 bubbleChildValueChanges( section, [ 'panel' ] );339 api.utils.bubbleChildValueChanges( section, [ 'panel' ] ); 339 340 340 341 section.embed(); 341 section.deferred. ready.done( function () {342 section.deferred.embedded.done( function () { 342 343 section.ready(); 343 344 }); … … 357 358 api.panel( panelId, function ( panel ) { 358 359 // The panel has been registered, wait for it to become ready/initialized 359 panel.deferred. ready.done( function () {360 panel.deferred.embedded.done( function () { 360 361 parentContainer = panel.container.find( 'ul:first' ); 361 362 if ( ! section.container.parent().is( parentContainer ) ) { 362 363 parentContainer.append( section.container ); 363 364 } 364 section.deferred. ready.resolve(); // @todo Better to use `embedded` instead of `ready`365 section.deferred.embedded.resolve(); 365 366 }); 366 367 } ); … … 371 372 parentContainer.append( section.container ); 372 373 } 373 section.deferred. ready.resolve();374 section.deferred.embedded.resolve(); 374 375 } 375 376 }; … … 386 387 // Expand/Collapse accordion sections on click. 387 388 section.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) { 388 if ( isKeydownButNotEnterEvent( event ) ) {389 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 389 390 return; 390 391 } … … 480 481 Container.prototype.initialize.call( panel, id, options ); 481 482 panel.embed(); 482 panel.deferred. ready.done( function () {483 panel.deferred.embedded.done( function () { 483 484 panel.ready(); 484 485 }); … … 495 496 parentContainer.append( panel.container ); 496 497 } 497 panel.deferred. ready.resolve();498 panel.deferred.embedded.resolve(); 498 499 }, 499 500 … … 506 507 // Expand/Collapse accordion sections on click. 507 508 panel.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) { 508 if ( isKeydownButNotEnterEvent( event ) ) {509 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 509 510 return; 510 511 } … … 519 520 520 521 meta.find( '> .accordion-section-title' ).on( 'click keydown', function( event ) { 521 if ( isKeydownButNotEnterEvent( event ) ) {522 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 522 523 return; 523 524 } … … 677 678 678 679 control.deferred = { 679 ready: new $.Deferred()680 embedded: new $.Deferred() 680 681 }; 681 682 control.section = new api.Value(); … … 721 722 control.active.set( control.params.active ); 722 723 723 bubbleChildValueChanges( control, [ 'section', 'priority', 'active' ] );724 api.utils.bubbleChildValueChanges( control, [ 'section', 'priority', 'active' ] ); 724 725 725 726 // Associate this control with its settings when they are created … … 740 741 }) ); 741 742 742 control.deferred. ready.done( function () {743 control.deferred.embedded.done( function () { 743 744 control.ready(); 744 745 }); … … 761 762 api.section( sectionId, function ( section ) { 762 763 // Wait for the section to be ready/initialized 763 section.deferred. ready.done( function () {764 section.deferred.embedded.done( function () { 764 765 parentContainer = section.container.find( 'ul:first' ); 765 766 if ( ! control.container.parent().is( parentContainer ) ) { … … 767 768 control.renderContent(); 768 769 } 769 control.deferred. ready.resolve(); // @todo Better to use `embedded` instead of `ready`770 control.deferred.embedded.resolve(); 770 771 }); 771 772 }); … … 853 854 // Support the .dropdown class to open/close complex elements 854 855 this.container.on( 'click keydown', '.dropdown', function( event ) { 855 if ( isKeydownButNotEnterEvent( event ) ) {856 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 856 857 return; 857 858 } … … 936 937 * set up internal event bindings. 937 938 */ 938 939 ready: function() { 939 940 var control = this; 940 941 // Shortcut so that we don't have to use _.bind every time we add a callback. … … 955 956 */ 956 957 openFrame: function( event ) { 957 if ( event.type === 'keydown' && 13 !== event.which ) { // enter958 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 958 959 return; 959 960 } 960 961 961 962 event.preventDefault(); … … 985 986 }, 986 987 multiple: false 987 988 }); 988 989 989 990 // When a file is selected, run a callback. 990 991 this.frame.on( 'select', this.select ); 991 992 }, 992 993 993 994 /** … … 1009 1010 */ 1010 1011 restoreDefault: function( event ) { 1011 if ( event.type === 'keydown' && 13 !== event.which ) { // enter1012 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 1012 1013 return; 1013 1014 } … … 1024 1025 */ 1025 1026 removeFile: function( event ) { 1026 if ( event.type === 'keydown' && 13 !== event.which ) { // enter1027 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 1027 1028 return; 1028 1029 } 1029 1030 event.preventDefault(); 1030 1031 … … 1032 1033 this.setting( '' ); 1033 1034 this.renderContent(); // Not bound to setting change when emptying. 1034 1035 }, 1035 1036 1036 1037 // @deprecated … … 1039 1040 // @deprecated 1040 1041 removerVisibility: function() {} 1041 1042 }); 1042 1043 1043 1044 /** … … 1743 1744 1744 1745 // Check if we can run the Customizer. 1745 if ( ! api.settings ) 1746 if ( ! api.settings ) { 1746 1747 return; 1748 } 1747 1749 1748 1750 // Redirect to the fallback preview if any incompatibilities are found. … … 1769 1771 // Expand/Collapse the main customizer customize info 1770 1772 $( '#customize-info' ).find( '> .accordion-section-title' ).on( 'click keydown', function( event ) { 1771 if ( isKeydownButNotEnterEvent( event ) ) {1773 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 1772 1774 return; 1773 1775 } … … 1931 1933 instance = api[ type ]( id ); 1932 1934 // Wait until the element is embedded in the DOM 1933 instance.deferred. ready.done( function () {1935 instance.deferred.embedded.done( function () { 1934 1936 // Wait until the preview has activated and so active panels, sections, controls have been set 1935 1937 api.previewer.deferred.active.done( function () { … … 1957 1959 rootNodes.push( panel ); 1958 1960 appendContainer = panel.container.find( 'ul:first' ); 1959 if ( ! a reElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {1961 if ( ! api.utils.areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) { 1960 1962 _( sections ).each( function ( section ) { 1961 1963 appendContainer.append( section.container ); … … 1973 1975 } 1974 1976 appendContainer = section.container.find( 'ul:first' ); 1975 if ( ! a reElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {1977 if ( ! api.utils.areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) { 1976 1978 _( controls ).each( function ( control ) { 1977 1979 appendContainer.append( control.container ); … … 1982 1984 1983 1985 // Sort the root panels and sections 1984 rootNodes.sort( prioritySort );1986 rootNodes.sort( api.utils.prioritySort ); 1985 1987 rootContainers = _.pluck( rootNodes, 'container' ); 1986 1988 appendContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable 1987 if ( ! a reElementListsEqual( rootContainers, appendContainer.children() ) ) {1989 if ( ! api.utils.areElementListsEqual( rootContainers, appendContainer.children() ) ) { 1988 1990 _( rootNodes ).each( function ( rootNode ) { 1989 1991 appendContainer.append( rootNode.container ); … … 2081 2083 // Go back to the top-level Customizer accordion. 2082 2084 $( '#customize-header-actions' ).on( 'click keydown', '.control-panel-back', function( event ) { 2083 if ( isKeydownButNotEnterEvent( event ) ) {2085 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 2084 2086 return; 2085 2087 } … … 2100 2102 2101 2103 $('.collapse-sidebar').on( 'click keydown', function( event ) { 2102 if ( isKeydownButNotEnterEvent( event ) ) {2104 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 2103 2105 return; 2104 2106 } -
trunk/tests/qunit/index.html
r30102 r30716 32 32 <script src="../../src/wp-includes/js/customize-models.js"></script> 33 33 <script src="../../src/wp-includes/js/shortcode.js"></script> 34 <script src="../../src/wp-admin/js/customize-controls.js"></script> 34 35 35 36 <!-- Unit tests --> … … 38 39 <script src="wp-admin/js/customize-header.js"></script> 39 40 <script src="wp-includes/js/shortcode.js"></script> 41 <script src="wp-admin/js/customize-controls.js"></script> 42 <script src="wp-admin/js/customize-controls-utils.js"></script> 40 43 </div> 41 44 </body> -
trunk/tests/qunit/wp-admin/js/customize-base.js
r30102 r30716 2 2 3 3 jQuery( function( $ ) { 4 var FooSuperClass, BarSubClass, foo, bar; 4 var FooSuperClass, BarSubClass, foo, bar, ConstructorTestClass, newConstructor, constructorTest, $mockElement, mockString, 5 firstInitialValue, firstValueInstance, wasCallbackFired, mockValueCallback; 5 6 6 7 module( 'Customize Base: Class' ); … … 47 48 }); 48 49 49 // @todo Test Class.constructor() manipulation50 50 // @todo Test Class.applicator? 51 51 // @todo do we test object.instance? 52 53 52 54 53 module( 'Customize Base: Subclass' ); … … 83 82 }); 84 83 84 85 // Implements todo : Test Class.constructor() manipulation 86 module( 'Customize Base: Constructor Manipulation' ); 87 88 newConstructor = function ( instanceProps ) { 89 $.extend( this , instanceProps || {} ); 90 }; 91 92 ConstructorTestClass = wp.customize.Class.extend( 93 { 94 constructor : newConstructor, 95 protoProp: 'protoPropValue' 96 }, 97 { 98 staticProp: 'staticPropValue' 99 } 100 ); 101 102 test( 'New constructor added to class' , function () { 103 equal( ConstructorTestClass.prototype.constructor , newConstructor ); 104 }); 105 test( 'Class with new constructor has protoPropValue' , function () { 106 equal( ConstructorTestClass.prototype.protoProp , 'protoPropValue' ); 107 }); 108 109 constructorTest = new ConstructorTestClass( { instanceProp: 'instancePropValue' } ); 110 test( 'ConstructorTestClass instance constructorTest has the new constructor', function () { 111 equal( constructorTest.constructor, newConstructor ); 112 }); 113 114 test( 'ConstructorTestClass instance constructorTest extended Class', function () { 115 equal( constructorTest.extended( wp.customize.Class ), true ); 116 }); 117 118 test( 'ConstructorTestClass instance constructorTest has the added instance property', function () { 119 equal( constructorTest.instanceProp , 'instancePropValue' ); 120 }); 121 122 123 module( 'Customize Base: wp.customizer.ensure' ); 124 125 $mockElement = $( '<div id="mockElement"></div>' ); 126 127 test( 'Handles jQuery argument' , function() { 128 equal( wp.customize.ensure( $mockElement ) , $mockElement ); 129 }); 130 131 mockString = '<div class="mockString"></div>'; 132 133 test( 'Handles string argument' , function() { 134 ok( wp.customize.ensure( mockString ) instanceof jQuery ); 135 }); 136 137 138 module( 'Customize Base: Value Class' ); 139 140 firstInitialValue = true; 141 firstValueInstance = new wp.customize.Value( firstInitialValue ); 142 143 test( 'Initialized with the right value' , function() { 144 equal( firstValueInstance.get() , firstInitialValue ); 145 }); 146 147 test( '.set() works' , function() { 148 firstValueInstance.set( false ); 149 equal( firstValueInstance.get() , false ); 150 }); 151 152 test( '.bind() adds new callback that fires on set()' , function() { 153 wasCallbackFired = false; 154 mockValueCallback = function() { 155 wasCallbackFired = true; 156 }; 157 firstValueInstance.bind( mockValueCallback ); 158 firstValueInstance.set( 'newValue' ); 159 ok( wasCallbackFired ); 160 }); 85 161 });
Note: See TracChangeset
for help on using the changeset viewer.