Make WordPress Core

Ticket #28709: 28709.14.diff

File 28709.14.diff, 29.8 KB (added by westonruter, 10 years ago)

https://github.com/xwp/wordpress-develop/pull/56

  • src/wp-admin/js/customize-controls.js

    diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js
    index 7b9f7b1..0a7e4f4 100644
     
    11/* globals _wpCustomizeHeader, _wpMediaViewsL10n */
    22(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, containerRootElement, api = wp.customize;
    64
    75        /**
    86         * @class
     
    3331        });
    3432
    3533        /**
     34         * Utility function namespace
     35         */
     36        api.utils = {};
     37
     38        /**
    3639         * Watch all changes to Value properties, and bubble changes to parent Values instance
    3740         *
    3841         * @param {wp.customize.Class} instance
    3942         * @param {Array} properties  The names of the Value instances to watch.
    4043         */
    41         bubbleChildValueChanges = function ( instance, properties ) {
     44        api.utils.bubbleChildValueChanges = function ( instance, properties ) {
    4245                $.each( properties, function ( i, key ) {
    4346                        instance[ key ].bind( function ( to, from ) {
    4447                                if ( instance.parent && to !== from ) {
     
    4952        };
    5053
    5154        /**
     55         * Set the element which serves as the root container for the Customizer UI.
     56         *
     57         * @param {Element|jQuery} rootElement
     58         */
     59        api.utils.setContainerRootElement = function( rootElement ) {
     60                containerRootElement = $( rootElement );
     61        };
     62
     63        /**
     64         * Get the element which serves as the root container for the Customizer UI.
     65         *
     66         * @returns {jQuery}
     67         */
     68        api.utils.getContainerRootElement = function() {
     69                return containerRootElement;
     70        };
     71
     72        /**
    5273         * Expand a panel, section, or control and focus on the first focusable element.
    5374         *
    5475         * @param {Object} [params]
     
    86107         * @param {(wp.customize.Panel|wp.customize.Section|wp.customize.Control)} b
    87108         * @returns {Number}
    88109         */
    89         prioritySort = function ( a, b ) {
     110        api.utils.prioritySort = function ( a, b ) {
    90111                if ( a.priority() === b.priority() && typeof a.params.instanceNumber === 'number' && typeof b.params.instanceNumber === 'number' ) {
    91112                        return a.params.instanceNumber - b.params.instanceNumber;
    92113                } else {
     
    100121         * @param {jQuery.Event} event
    101122         * @returns {boolean}
    102123         */
    103         isKeydownButNotEnterEvent = function ( event ) {
     124        api.utils.isKeydownButNotEnterEvent = function ( event ) {
    104125                return ( 'keydown' === event.type && 13 !== event.which );
    105126        };
    106127
     
    111132         * @param {Array|jQuery} listB
    112133         * @returns {boolean}
    113134         */
    114         areElementListsEqual = function ( listA, listB ) {
     135        api.utils.areElementListsEqual = function ( listA, listB ) {
    115136                var equal = (
    116137                        listA.length === listB.length && // if lists are different lengths, then naturally they are not equal
    117138                        -1 === _.map( // are there any false values in the list returned by map?
     
    142163                        container.container = $( container.params.content );
    143164
    144165                        container.deferred = {
    145                                 ready: new $.Deferred()
     166                                embedded: new $.Deferred()
    146167                        };
    147168                        container.priority = new api.Value();
    148169                        container.active = new api.Value();
     
    155176                                args = $.extend( {}, container.defaultActiveArguments, args );
    156177                                active = ( active && container.isContextuallyActive() );
    157178                                container.onChangeActive( active, args );
    158                                 // @todo trigger 'activated' and 'deactivated' events based on the expanded param?
    159179                        });
    160180                        container.expanded.bind( function ( expanded ) {
    161181                                var args = container.expandedArgumentsQueue.shift();
    162182                                args = $.extend( {}, container.defaultExpandedArguments, args );
    163183                                container.onChangeExpanded( expanded, args );
    164                                 // @todo trigger 'expanded' and 'collapsed' events based on the expanded param?
    165184                        });
    166185
    167186                        container.attachEvents();
    168187
    169                         bubbleChildValueChanges( container, [ 'priority', 'active' ] );
     188                        api.utils.bubbleChildValueChanges( container, [ 'priority', 'active' ] );
    170189
    171190                        container.priority.set( isNaN( container.params.priority ) ? 100 : container.params.priority );
    172191                        container.active.set( container.params.active );
    173                         container.expanded.set( false ); // @todo True if deeplinking?
     192                        container.expanded.set( false );
    174193                },
    175194
    176195                /**
     
    193212                                        children.push( child );
    194213                                }
    195214                        } );
    196                         children.sort( prioritySort );
     215                        children.sort( api.utils.prioritySort );
    197216                        return children;
    198217                },
    199218
     
    335354                                $( section.container ).toggleClass( 'control-subsection', !! id );
    336355                        });
    337356                        section.panel.set( section.params.panel || '' );
    338                         bubbleChildValueChanges( section, [ 'panel' ] );
     357                        api.utils.bubbleChildValueChanges( section, [ 'panel' ] );
    339358
    340359                        section.embed();
    341                         section.deferred.ready.done( function () {
     360                        section.deferred.embedded.done( function () {
    342361                                section.ready();
    343362                        });
    344363                },
     
    356375                                        // The panel has been supplied, so wait until the panel object is registered
    357376                                        api.panel( panelId, function ( panel ) {
    358377                                                // The panel has been registered, wait for it to become ready/initialized
    359                                                 panel.deferred.ready.done( function () {
     378                                                panel.deferred.embedded.done( function () {
    360379                                                        parentContainer = panel.container.find( 'ul:first' );
    361380                                                        if ( ! section.container.parent().is( parentContainer ) ) {
    362381                                                                parentContainer.append( section.container );
    363382                                                        }
    364                                                         section.deferred.ready.resolve(); // @todo Better to use `embedded` instead of `ready`
     383                                                        section.deferred.embedded.resolve();
    365384                                                });
    366385                                        } );
    367386                                } else {
    368387                                        // There is no panel, so embed the section in the root of the customizer
    369                                         parentContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
     388                                        parentContainer = api.utils.getContainerRootElement(); // implements todo: This should be defined elsewhere, and to be configurable
    370389                                        if ( ! section.container.parent().is( parentContainer ) ) {
    371390                                                parentContainer.append( section.container );
    372391                                        }
    373                                         section.deferred.ready.resolve();
     392                                        section.deferred.embedded.resolve();
    374393                                }
    375394                        };
    376395                        section.panel.bind( inject );
     
    385404
    386405                        // Expand/Collapse accordion sections on click.
    387406                        section.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
    388                                 if ( isKeydownButNotEnterEvent( event ) ) {
     407                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    389408                                        return;
    390409                                }
    391410                                event.preventDefault(); // Keep this AFTER the key filter above
     
    479498                        var panel = this;
    480499                        Container.prototype.initialize.call( panel, id, options );
    481500                        panel.embed();
    482                         panel.deferred.ready.done( function () {
     501                        panel.deferred.embedded.done( function () {
    483502                                panel.ready();
    484503                        });
    485504                },
     
    489508                 */
    490509                embed: function () {
    491510                        var panel = this,
    492                                 parentContainer = $( '#customize-theme-controls > ul' ); // @todo This should be defined elsewhere, and to be configurable
     511                                parentContainer = api.utils.getContainerRootElement(); // implements todo: This should be defined elsewhere, and to be configurable
    493512
    494513                        if ( ! panel.container.parent().is( parentContainer ) ) {
    495514                                parentContainer.append( panel.container );
    496515                        }
    497                         panel.deferred.ready.resolve();
     516                        panel.deferred.embedded.resolve();
    498517                },
    499518
    500519                /**
     
    505524
    506525                        // Expand/Collapse accordion sections on click.
    507526                        panel.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
    508                                 if ( isKeydownButNotEnterEvent( event ) ) {
     527                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    509528                                        return;
    510529                                }
    511530                                event.preventDefault(); // Keep this AFTER the key filter above
     
    518537                        meta = panel.container.find( '.panel-meta:first' );
    519538
    520539                        meta.find( '> .accordion-section-title' ).on( 'click keydown', function( event ) {
    521                                 if ( isKeydownButNotEnterEvent( event ) ) {
     540                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    522541                                        return;
    523542                                }
    524543                                event.preventDefault(); // Keep this AFTER the key filter above
     
    588607                                overlay = section.closest( '.wp-full-overlay' ),
    589608                                container = section.closest( '.accordion-container' ),
    590609                                siblings = container.find( '.open' ),
    591                                 topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ).add( '#customize-info > .accordion-section-title' ),
     610                                $ContainerRootElement = api.utils.getContainerRootElement(),
     611                                topPanel = overlay.find( $ContainerRootElement ).find( '> .accordion-section > .accordion-section-title' ).add( '#customize-info > .accordion-section-title' ),
    592612                                backBtn = overlay.find( '.control-panel-back' ),
    593613                                panelTitle = section.find( '.accordion-section-title' ).first(),
    594614                                content = section.find( '.control-panel-content' );
     
    676696                        control.container = control.params.content ? $( control.params.content ) : $( control.selector );
    677697
    678698                        control.deferred = {
    679                                 ready: new $.Deferred()
     699                                embedded: new $.Deferred()
    680700                        };
    681701                        control.section = new api.Value();
    682702                        control.priority = new api.Value();
     
    720740                        control.priority.set( isNaN( control.params.priority ) ? 10 : control.params.priority );
    721741                        control.active.set( control.params.active );
    722742
    723                         bubbleChildValueChanges( control, [ 'section', 'priority', 'active' ] );
     743                        api.utils.bubbleChildValueChanges( control, [ 'section', 'priority', 'active' ] );
    724744
    725745                        // Associate this control with its settings when they are created
    726746                        settings = $.map( control.params.settings, function( value ) {
     
    739759                                control.embed();
    740760                        }) );
    741761
    742                         control.deferred.ready.done( function () {
     762                        control.deferred.embedded.done( function () {
    743763                                control.ready();
    744764                        });
    745765                },
     
    760780                                // Wait for the section to be registered
    761781                                api.section( sectionId, function ( section ) {
    762782                                        // Wait for the section to be ready/initialized
    763                                         section.deferred.ready.done( function () {
     783                                        section.deferred.embedded.done( function () {
    764784                                                parentContainer = section.container.find( 'ul:first' );
    765785                                                if ( ! control.container.parent().is( parentContainer ) ) {
    766786                                                        parentContainer.append( control.container );
    767787                                                        control.renderContent();
    768788                                                }
    769                                                 control.deferred.ready.resolve(); // @todo Better to use `embedded` instead of `ready`
     789                                                control.deferred.embedded.resolve();
    770790                                        });
    771791                                });
    772792                        };
     
    852872
    853873                        // Support the .dropdown class to open/close complex elements
    854874                        this.container.on( 'click keydown', '.dropdown', function( event ) {
    855                                 if ( isKeydownButNotEnterEvent( event ) ) {
     875                                if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    856876                                        return;
    857877                                }
    858878
     
    935955                 * When the control's DOM structure is ready,
    936956                 * set up internal event bindings.
    937957                 */
    938                 ready: function() {
     958                ready: function() {
    939959                        var control = this;
    940960                        // Shortcut so that we don't have to use _.bind every time we add a callback.
    941961                        _.bindAll( control, 'restoreDefault', 'removeFile', 'openFrame', 'select' );
     
    956976                openFrame: function( event ) {
    957977                        if ( event.type === 'keydown' &&  13 !== event.which ) { // enter
    958978                                return;
    959                         }
     979                        }
    960980
    961981                        event.preventDefault();
    962982
     
    9841004                                        text: this.params.button_labels.frame_button
    9851005                                },
    9861006                                multiple: false
    987                         });
     1007                        });
    9881008
    9891009                        // When a file is selected, run a callback.
    9901010                        this.frame.on( 'select', this.select );
    991                 },
     1011                },
    9921012
    9931013                /**
    9941014                 * Callback handler for when an attachment is selected in the media modal.
     
    10081028                 * Reset the setting to the default value.
    10091029                 */
    10101030                restoreDefault: function( event ) {
    1011                         if ( event.type === 'keydown' &&  13 !== event.which ) { // enter
     1031                        if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    10121032                                return;
    10131033                        }
    10141034                        event.preventDefault();
    10151035
    10161036                        this.params.attachment = this.params.defaultAttachment;
    10171037                        this.setting( this.params.defaultAttachment.url );
    1018                 },
     1038                },
    10191039
    10201040                /**
    10211041                 * Called when the "Remove" link is clicked. Empties the setting.
     
    10251045                removeFile: function( event ) {
    10261046                        if ( event.type === 'keydown' &&  13 !== event.which ) { // enter
    10271047                                return;
    1028                         }
     1048                        }
    10291049                        event.preventDefault();
    10301050
    10311051                        this.params.attachment = {};
    10321052                        this.setting( '' );
    10331053                        this.renderContent(); // Not bound to setting change when emptying.
    1034                 },
     1054                },
    10351055
    10361056                // @deprecated
    10371057                success: function() {},
    10381058
    10391059                // @deprecated
    10401060                removerVisibility: function() {}
    1041         });
     1061        });
    10421062
    10431063        /**
    10441064         * A control for uploading images.
     
    17401760        $( function() {
    17411761                api.settings = window._wpCustomizeSettings;
    17421762                api.l10n = window._wpCustomizeControlsL10n;
     1763                api.utils.setContainerRootElement( $( '#customize-theme-controls' ).children( 'ul:first' ) );
    17431764
    17441765                // Check if we can run the Customizer.
    1745                 if ( ! api.settings )
     1766                if ( ! api.settings ) {
    17461767                        return;
     1768                }
    17471769
    17481770                // Redirect to the fallback preview if any incompatibilities are found.
    17491771                if ( ! $.support.postMessage || ( ! $.support.cors && api.settings.isCrossDomain ) )
     
    17681790
    17691791                // Expand/Collapse the main customizer customize info
    17701792                $( '#customize-info' ).find( '> .accordion-section-title' ).on( 'click keydown', function( event ) {
    1771                         if ( isKeydownButNotEnterEvent( event ) ) {
     1793                        if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    17721794                                return;
    17731795                        }
    17741796                        event.preventDefault(); // Keep this AFTER the key filter above
     
    19301952                        if ( id && api[ type ]( id ) ) {
    19311953                                instance = api[ type ]( id );
    19321954                                // Wait until the element is embedded in the DOM
    1933                                 instance.deferred.ready.done( function () {
     1955                                instance.deferred.embedded.done( function () {
    19341956                                        // Wait until the preview has activated and so active panels, sections, controls have been set
    19351957                                        api.previewer.deferred.active.done( function () {
    19361958                                                instance.focus();
     
    19561978                                        sectionContainers = _.pluck( sections, 'container' );
    19571979                                rootNodes.push( panel );
    19581980                                appendContainer = panel.container.find( 'ul:first' );
    1959                                 if ( ! areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {
     1981                                if ( ! api.utils.areElementListsEqual( sectionContainers, appendContainer.children( '[id]' ) ) ) {
    19601982                                        _( sections ).each( function ( section ) {
    19611983                                                appendContainer.append( section.container );
    19621984                                        } );
     
    19721994                                        rootNodes.push( section );
    19731995                                }
    19741996                                appendContainer = section.container.find( 'ul:first' );
    1975                                 if ( ! areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {
     1997                                if ( ! api.utils.areElementListsEqual( controlContainers, appendContainer.children( '[id]' ) ) ) {
    19761998                                        _( controls ).each( function ( control ) {
    19771999                                                appendContainer.append( control.container );
    19782000                                        } );
     
    19812003                        } );
    19822004
    19832005                        // Sort the root panels and sections
    1984                         rootNodes.sort( prioritySort );
     2006                        rootNodes.sort( api.utils.prioritySort );
    19852007                        rootContainers = _.pluck( rootNodes, 'container' );
    1986                         appendContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable
    1987                         if ( ! areElementListsEqual( rootContainers, appendContainer.children() ) ) {
     2008                        appendContainer = api.utils.getContainerRootElement(); // implements todo: This should be defined elsewhere, and to be configurable
     2009                        if ( ! api.utils.areElementListsEqual( rootContainers, appendContainer.children() ) ) {
    19882010                                _( rootNodes ).each( function ( rootNode ) {
    19892011                                        appendContainer.append( rootNode.container );
    19902012                                } );
     
    20802102
    20812103                // Go back to the top-level Customizer accordion.
    20822104                $( '#customize-header-actions' ).on( 'click keydown', '.control-panel-back', function( event ) {
    2083                         if ( isKeydownButNotEnterEvent( event ) ) {
     2105                        if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    20842106                                return;
    20852107                        }
    20862108
     
    21042126                });
    21052127
    21062128                $('.collapse-sidebar').on( 'click keydown', function( event ) {
    2107                         if ( isKeydownButNotEnterEvent( event ) ) {
     2129                        if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
    21082130                                return;
    21092131                        }
    21102132
  • tests/qunit/index.html

    diff --git tests/qunit/index.html tests/qunit/index.html
    index ce11144..df51b7a 100644
     
    3131    <script src="../../src/wp-includes/js/customize-base.js"></script>
    3232    <script src="../../src/wp-includes/js/customize-models.js"></script>
    3333    <script src="../../src/wp-includes/js/shortcode.js"></script>
     34    <script src="../../src/wp-admin/js/customize-controls.js"></script>
    3435
    3536    <!-- Unit tests -->
    3637    <script src="wp-admin/js/password-strength-meter.js"></script>
    3738    <script src="wp-admin/js/customize-base.js"></script>
    3839    <script src="wp-admin/js/customize-header.js"></script>
    3940    <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>
    4043  </div>
    4144</body>
    4245</html>
  • tests/qunit/wp-admin/js/customize-base.js

    diff --git tests/qunit/wp-admin/js/customize-base.js tests/qunit/wp-admin/js/customize-base.js
    index 422111f..56357c9 100644
     
    11/* global wp */
    22
    33jQuery( function( $ ) {
    4         var FooSuperClass, BarSubClass, foo, bar;
     4        var FooSuperClass, BarSubClass, foo, bar, ConstructorTestClass, newConstructor, constructorTest, $mockElement, mockString,
     5        firstInitialValue, firstValueInstance, wasCallbackFired, mockValueCallback;
    56
    67        module( 'Customize Base: Class' );
    78
    jQuery( function( $ ) { 
    4647                equal( foo.instanceProp, 'instancePropValue' );
    4748        });
    4849
    49         // @todo Test Class.constructor() manipulation
    5050        // @todo Test Class.applicator?
    5151        // @todo do we test object.instance?
    5252
    53 
    5453        module( 'Customize Base: Subclass' );
    5554
    5655        BarSubClass = FooSuperClass.extend(
    jQuery( function( $ ) { 
    8281                equal( bar.extended( FooSuperClass ), true );
    8382        });
    8483
     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        });
     161
    85162});
  • new file tests/qunit/wp-admin/js/customize-controls-utils.js

    diff --git tests/qunit/wp-admin/js/customize-controls-utils.js tests/qunit/wp-admin/js/customize-controls-utils.js
    new file mode 100644
    index 0000000..8c82a3c
    - +  
     1/* global wp */
     2
     3jQuery( function( $ ) {
     4        var trueMockEvent, falseMockEvent, mockElementLists, $firstMockElement, $secondMockElement, $thirdMockElement,
     5                BubbleTester, BubbleTesterTwoValues, bubbleTesterParent, firstBubbleTester, secondBubbleTester, $newRoot;
     6
     7        module( 'Customizer Model Utility functions' );
     8
     9        trueMockEvent = {
     10                type : 'keydown',
     11                which : 14
     12        };
     13
     14        falseMockEvent = {
     15                type : 'keydown',
     16                which : 13
     17        };
     18
     19        test( 'isKeydownButNotEnterEvent returns true' , function () {
     20                ok( wp.customize.utils.isKeydownButNotEnterEvent( trueMockEvent ) );
     21        });
     22
     23        test( 'isKeydownButNotEnterEvent returns false' , function () {
     24                equal( wp.customize.utils.isKeydownButNotEnterEvent( falseMockEvent ) , false );
     25        });
     26
     27        $firstMockElement = $( '<div id="foo"></div>' );
     28        $secondMockElement = $( '<li id="bar"></li>' );
     29        $thirdMockElement = $( '<div id="thirdElement"></div>' );
     30
     31        mockElementLists = {
     32                first : [ $firstMockElement , $secondMockElement ],
     33                second : [ $secondMockElement ],
     34                firstInReverseOrder : [ $secondMockElement , $firstMockElement ],
     35                third : [ $firstMockElement, $secondMockElement ],
     36                thirdButLonger : [ $firstMockElement, $secondMockElement, $thirdMockElement ]
     37        };
     38
     39        test( 'areElementListsEqual returns true' , function () {
     40                ok( wp.customize.utils.areElementListsEqual( mockElementLists.first , mockElementLists.first ) );
     41        });
     42
     43        test( 'areElementListsEqual returns false' , function () {
     44                equal( wp.customize.utils.areElementListsEqual( mockElementLists.first , mockElementLists.second ) , false );
     45        });
     46
     47        test( 'areElementListsEqual: lists have same values, but in reverse order' , function () {
     48                equal( wp.customize.utils.areElementListsEqual( mockElementLists.first , mockElementLists.firstInReverseOrder ) , false );
     49        });
     50
     51        test( 'areElementListsEqual: lists have same values, but one is longer' , function () {
     52                equal( wp.customize.utils.areElementListsEqual( mockElementLists.third , mockElementLists.thirdButLonger ) , false );
     53        });
     54
     55
     56        bubbleTesterParent = function() {
     57                this.trigger = function( event , instance ) {
     58                        this.wasChangeTriggered = true;
     59                        this.instancePassedInTrigger = instance;
     60                };
     61                this.wasChangeTriggered = false;
     62                this.instancePassedInTrigger = {};
     63        };
     64
     65        BubbleTester = wp.customize.Class.extend(
     66                {
     67                        parent : new bubbleTesterParent(),
     68                        fooValue : new wp.customize.Value()
     69                },
     70                {
     71                        staticProperty : 'propertyValue'
     72                }
     73        );
     74
     75        test( 'bubbleChildValueChanges notifies parent of change' , function() {
     76                firstBubbleTester = new BubbleTester();
     77                wp.customize.utils.bubbleChildValueChanges( firstBubbleTester , [ 'fooValue' ] );
     78                firstBubbleTester.fooValue.set( 'new value' );
     79                ok( firstBubbleTester.parent.wasChangeTriggered );
     80        });
     81
     82        test( 'bubbleChildValueChanges passes a reference to its instance' , function() {
     83                ok( firstBubbleTester.parent.instancePassedInTrigger instanceof BubbleTester );
     84        });
     85
     86        BubbleTesterTwoValues = wp.customize.Class.extend(
     87                {
     88                        parent : new bubbleTesterParent(),
     89                        exampleValue : new wp.customize.Value(),
     90                        barValue : new wp.customize.Value()
     91                },
     92                {
     93                        staticProperty : 'propertyValue'
     94                }
     95        );
     96
     97        secondBubbleTester = new BubbleTesterTwoValues();
     98        wp.customize.utils.bubbleChildValueChanges( secondBubbleTester , [ 'exampleValue' , 'barValue' ] );
     99        secondBubbleTester.barValue.set( 'new value' );
     100
     101        test( 'bubbleChildValueChanges notifies parent of change when two values are bound' , function() {
     102                ok( secondBubbleTester.parent.wasChangeTriggered );
     103        });
     104
     105        test( 'bubbleChildValueChanges passes a reference to its instance when two values are bound' , function() {
     106                ok( secondBubbleTester.parent.instancePassedInTrigger instanceof BubbleTesterTwoValues );
     107        });
     108
     109        $newRoot = $( '<div id="#new-theme-controls"></div>' );
     110        wp.customize.utils.setContainerRootElement( $newRoot );
     111
     112        test( 'setContainerRootElement sets the new root' , function() {
     113                ok( wp.customize.utils.getContainerRootElement().is( $newRoot ) );
     114        });
     115
     116});
  • new file tests/qunit/wp-admin/js/customize-controls.js

    diff --git tests/qunit/wp-admin/js/customize-controls.js tests/qunit/wp-admin/js/customize-controls.js
    new file mode 100644
    index 0000000..05fa161
    - +  
     1/* global wp */
     2
     3jQuery( function( $ ) {
     4
     5        var controlId, controlLabel, controlType, controlContent, controlDescription, controlData, mockControl,
     6            mockControlInstance, controlExpectedValues, sectionId, sectionContent, sectionData, mockSection,
     7            sectionInstance, sectionExpectedValues, panelId, panelTitle, panelDescription, panelContent, panelData,
     8            mockPanel, panelExpectedValues, testCustomizerModel;
     9
     10        testCustomizerModel = function( model, expectedValues ) {
     11                var type =  expectedValues.type || "";
     12
     13                if ( expectedValues.hasOwnProperty( 'id' ) ) {
     14                        test( type + ' instance has the right id' , function () {
     15                                equal( model.id , expectedValues.id );
     16                        });
     17                }
     18                if ( expectedValues.hasOwnProperty( 'title') ) {
     19                        test( type + ' instance has the right title.', function () {
     20                                equal( model.params.title , expectedValues.title );
     21                        });
     22                }
     23                if ( expectedValues.hasOwnProperty( 'description' ) ) {
     24                        test( type + ' instance has the right description.', function () {
     25                                equal( model.params.description , expectedValues.description );
     26                        });
     27                }
     28                if ( expectedValues.hasOwnProperty( 'content' ) ) {
     29                        test( type + ' instance has the right content.', function () {
     30                                equal( model.params.content , expectedValues.content );
     31                        });
     32                }
     33                if ( expectedValues.hasOwnProperty( 'priority' ) ) {
     34                        test( type + ' instance has the right priority.', function () {
     35                                equal( model.priority() , expectedValues.priority );
     36                        });
     37                }
     38                if ( expectedValues.textExpanded ) {
     39                        test( type + ' instance is not expanded', function () {
     40                                equal( model.expanded() , false );
     41                        });
     42
     43                        test( type + ' instance is expanded after calling .expanded()', function () {
     44                                model.expand();
     45                                ok( model.expanded() );
     46                        });
     47
     48                        test( type + ' instance is collapsed after calling .collapse()', function () {
     49                                model.collapse();
     50                                equal( model.expanded() , false );
     51                        });
     52                }
     53
     54        };
     55
     56
     57        module( 'Customizer Control Model' );
     58
     59        controlId = 'new_blogname';
     60        controlLabel = 'Site Title';
     61        controlType = 'text';
     62        controlContent = '<li id="customize-control-blogname" class="customize-control customize-control-text"></li>';
     63        controlDescription = 'Test control description';
     64
     65        controlData = {
     66                content : controlContent,
     67                description : controlDescription,
     68                label : controlLabel,
     69                settings : { default : 'blogname' },
     70                type : controlType
     71        };
     72
     73        mockControl = new wp.customize.Control( controlId ,
     74                                                { params : controlData,
     75                                                  previewer : wp.customize.previewer
     76                                                }
     77        );
     78
     79        controlExpectedValues = {
     80                type : 'Control',
     81                content : controlContent,
     82                descrption : controlDescription,
     83                label : controlLabel,
     84                id : controlId,
     85                priority : 10,
     86                textExpanded : false
     87        };
     88
     89        testCustomizerModel( mockControl , controlExpectedValues );
     90
     91        test( 'Control instance does not yet belong to a section.', function () {
     92                equal( mockControl.section() , undefined );
     93        });
     94
     95        test( 'Control instance has the right selector.', function () {
     96                equal( mockControl.selector , '#customize-control-new_blogname' );
     97        });
     98
     99        wp.customize.control.add( controlId , mockControl );
     100
     101        test( 'Control instance was added to the control class.', function () {
     102                ok( wp.customize.control.has( controlId ) );
     103        });
     104
     105        mockControlInstance = wp.customize.control( controlId );
     106
     107        test( 'Control instance has the right id when accessed from api.control().', function () {
     108                equal( mockControlInstance.id , controlId );
     109        });
     110
     111
     112        module( 'Customizer Section Model' );
     113
     114        sectionId = 'mock_title_tagline';
     115        sectionContent = '<li id="accordion-section-title_tagline" class="control-section accordion-section"></li>';
     116        sectionData = {
     117                content : sectionContent
     118        };
     119
     120        mockSection = new wp.customize.Section( sectionId , { params : sectionData } );
     121
     122        sectionExpectedValues = {
     123                type : 'Section',
     124                id : sectionId,
     125                content : sectionContent,
     126                priority : 100,
     127                testExpanded : true
     128        };
     129
     130        testCustomizerModel( mockSection , sectionExpectedValues );
     131
     132        wp.customize.section.add( sectionId , mockSection );
     133
     134        test( 'Section instance added to the wp.customize.section object', function () {
     135                ok( wp.customize.section.has( sectionId ) );
     136        });
     137
     138        sectionInstance = wp.customize.section( sectionId );
     139
     140        test( 'Section instance has right content when accessed from wp.customize.section()', function () {
     141                equal( sectionInstance.params.content , sectionContent );
     142        });
     143
     144
     145        module( 'Customizer Panel Model' );
     146
     147        panelId = 'mockPanelId';
     148        panelTitle = 'Mock Panel Title';
     149        panelDescription = 'Mock panel description';
     150        panelContent = '<li id="accordion-panel-widgets" class="control-section control-panel accordion-section">';
     151        panelData = {
     152                content : panelContent,
     153                title : panelTitle,
     154                description : panelDescription
     155        };
     156
     157        mockPanel = new wp.customize.Panel( panelId , { params : panelData } );
     158
     159        panelExpectedValues = {
     160                type : 'Panel',
     161                id : panelId,
     162                title : panelTitle ,
     163                description : panelDescription,
     164                content : panelContent,
     165                priority : 100,
     166                testExpanded : true
     167        };
     168
     169        testCustomizerModel( mockPanel , panelExpectedValues );
     170
     171        test( 'Panel instance is not contextuallyActive', function () {
     172                equal( mockPanel.isContextuallyActive() , false );
     173        });
     174
     175});
  • tests/qunit/wp-admin/js/customize-header.js

    diff --git tests/qunit/wp-admin/js/customize-header.js tests/qunit/wp-admin/js/customize-header.js
    index d5f0110..31fa14f 100644
    jQuery( function() { 
    128128
    129129                equal(this.model.shouldBeCropped(), false);
    130130        });
     131
    131132});