Passed
Branch dev (3fd540)
by Michael
22:28
created

form-collapsible-sections.js ➔ _getButtonContainer   F

Complexity

Conditions 20

Size

Total Lines 13
Code Lines 12

Duplication

Lines 13
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 12
dl 13
loc 13
rs 0
c 0
b 0
f 0
cc 20

How to fix   Complexity   

Complexity

Complex classes like form-collapsible-sections.js ➔ _getButtonContainer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*! Admin Page Framework - Form Collapsible Sections 1.0.1 */
2 View Code Duplication
( function( $ ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
3
4
    $( document ).ready( function() {
5
        $( this ).initializeAdminPageFrameworkCollapsibleSections();
6
    });
7
8
    /**
9
     * Gets triggered when a widget of the framework is saved.
10
     * @since    3.7.0
11
     */
12
    $( document ).on( 'admin-page-framework_saved_widget', function( event, oWidget ){
13
        $( oWidget ).initializeAdminPageFrameworkCollapsibleSections();
14
    });
15
16
    $.fn.initializeAdminPageFrameworkCollapsibleSections = function() {
17
18
        // Expand collapsible sections that are set not to collapse by default
19
        $( this ).find( '.admin-page-framework-collapsible-sections-title[data-is_collapsed=\"0\"]' )
20
            .next( '.admin-page-framework-collapsible-sections-content' )
21
            .slideDown( 'fast' );
22
        $( this ).find( '.admin-page-framework-collapsible-section-title[data-is_collapsed=\"0\"]' )
23
            .closest( '.admin-page-framework-section-table' )
24
            .find( 'tbody' )
25
            .slideDown( 'fast' );
26
27
        // Hide collapsible sections of 'section' containers as they are somehow do not get collapsed by default.
28
        $( this ).find( '.admin-page-framework-collapsible-section-title[data-is_collapsed=\"1\"]' )
29
            .closest( '.admin-page-framework-section-table' )
30
            .find( 'tbody' )
31
            .hide();
32
33
        // Bind the click event to the title element.
34
        $( this ).find( '.admin-page-framework-collapsible-sections-title, .admin-page-framework-collapsible-section-title' )
35
            .enableAdminPageFrameworkCollapsibleButton();
36
37
        // Insert the toggle all button.
38
        $( this ).find( '.admin-page-framework-collapsible-title[data-toggle_all_button!=\"0\"]' ).each( function(){$
39
40
            var _oThis        = $( this ); // to access from inside the below each() method.
41
            var _bForSections = $( this ).hasClass( 'admin-page-framework-collapsible-sections-title' );   // or for the 'section' container.
42
            var _isPositions  = $( this ).data( 'toggle_all_button' );
43
            _isPositions  = 1 === _isPositions
44
                ? 'top-right'   // default
45
                : _isPositions;
46
            var _aPositions   = 'string' === typeof _isPositions
47
                ? _isPositions.split( ',' )
48
                : [ 'top-right' ];
49
50
            var _oButton = _getButtonContainer();
51
52
            $.each( _aPositions, function( iIndex, _sPosition ) {
53
54
                // var _oButton = $( $_sToggleAllButtonHTML ); //@deprecated 3.9.0
55
                var _sLeftOrRight = -1 !== jQuery.inArray( _sPosition, [ 'top-right', 'bottom-right', '0' ] )   // if found
56
                    ? 'right'   // default
57
                    : 'left';
58
                _oButton.find( '.admin-page-framework-collapsible-toggle-all-button' ).css( 'float', _sLeftOrRight );
59
60
                var _sTopOrBottom = -1 !== jQuery.inArray( _sPosition, [ 'top-right', 'top-left', '0' ] )   // if found
61
                    ? 'before'   // default
62
                    : 'after';
63
64
                // Insert the button - there are two versions: for the sections container or the section container.
65
                if ( _bForSections ) {
66
                    var _oTargetElement = 'before' === _sTopOrBottom
67
                        ? _oThis
68
                        : _oThis.next( '.admin-page-framework-collapsible-content' );
69
                        _oTargetElement[ _sTopOrBottom ]( _oButton );
70
                } else {    // for 'section' containers
71
                    _oThis.closest( '.admin-page-framework-section' )[ _sTopOrBottom ]( _oButton );
72
                }
73
74
                // Expand or collapse this panel
75
                $( _oButton ).off( 'click' );       // for initially dropped (created) widgets
76
                _oButton.on( 'click', function(){
77
78
                    var _oButtons = _bForSections
79
                        ? $( this ).closest( '.admin-page-framework-sectionset' ).siblings().addBack().find( '> .admin-page-framework-collapsible-toggle-all-button-container' )
80
                        : $( this ).siblings( '.admin-page-framework-collapsible-toggle-all-button-container' ).addBack();
81
                    _oButtons.toggleClass( 'flipped' );
82
                    if ( _bForSections ) {
83
                        _oButton.parent().parent().children().children( '* > .admin-page-framework-collapsible-title' ).each( function() {
84
                            $( this ).trigger( 'click', [ 'by_toggle_all_button' ] );
85
                        } );
86
                    } else {
87
                        _oButton.closest( '.admin-page-framework-sections' ).children( '.admin-page-framework-section' ).children( '.admin-page-framework-section-table' ).children( 'caption' ).children( '.admin-page-framework-collapsible-title' ).each( function() {
88
                            $( this ).trigger( 'click', [ 'by_toggle_all_button' ] );
89
                        } );
90
                    }
91
92
                } );
93
94
            });
95
96
        } );
97
98
        /**
99
         * @since 3.9.0
100
         * @returns {*|define.amd.jQuery|HTMLElement}
101
         * @private
102
         */
103
        function _getButtonContainer() {
104
            var _sDashIconSort = $.fn.compareVersionNumbers( AdminPageFrameworkScriptFormMain.wpVersion, '3.8' ) >= 0
0 ignored issues
show
Bug introduced by
The variable AdminPageFrameworkScriptFormMain seems to be never declared. If this is a global, consider adding a /** global: AdminPageFrameworkScriptFormMain */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
105
                ? 'dashicons dashicons-sort'
106
                : '';
107
            var _sButtonText   = _sDashIconSort ? '' : AdminPageFrameworkScriptFormMain.messages.toggleAll;
108
            var _oButtonInner = $( '<span class="admin-page-framework-collapsible-toggle-all-button button"></span>' );
109
            _oButtonInner.addClass( _sDashIconSort );
110
            _oButtonInner.attr( 'title', AdminPageFrameworkScriptFormMain.messages.toggleAllCollapsibleSections );
111
            _oButtonInner.text( _sButtonText );
112
            var _oButton = $( '<div class="admin-page-framework-collapsible-toggle-all-button-container"></div>' );
113
            _oButton.append( _oButtonInner );
114
            return _oButton;
115
        }
116
117
    }
118
    /**
119
     * Binds the click event to collapsible buttons.
120
     */
121
    $.fn.enableAdminPageFrameworkCollapsibleButton = function() {
122
123
        /**
124
         * Determines whether the passed node element is of a field element.
125
         * If there are fields in the section title area, clicking on those field elements should not collapse/expand the section.
126
         * @return  boolean
127
         */
128
        function _isFieldElement( nodeTarget ) {
129
130
            if ( $( nodeTarget ).hasClass( 'admin-page-framework-collapsible-button' ) ) {
131
                return false;
132
            }
133
            var _sClickedTag = $( nodeTarget ).prop( 'tagName' ).toLowerCase();
134
            if ( -1 !== jQuery.inArray( _sClickedTag, [ 'input', 'label', 'fieldset', 'span' ] ) ) {
135
                return true;
136
            }
137
            return false;
138
139
        }
140
141
        /**
142
         * Unbind the event first.
143
         * This is for widgets as the initial model widgets placed on the left side is dragged-and-dropped to a sidebar definition container.
144
         * Then the event binding will be lost so it needs to be rebound.
145
         */
146
        $( this ).off( 'click' );
147
        $( this ).on( 'click', function( event, sContext ){
148
149
            if ( _isFieldElement( event.target ) ) {
150
                return true;
151
            }
152
153
            // Expand or collapse this panel
154
            var _oThis = $( this );
155
            var _sContainerType = $( this ).hasClass( 'admin-page-framework-collapsible-sections-title' )
156
                ? 'sections'
157
                : 'section';
158
            var _oTargetContent = 'sections' === _sContainerType
159
                ? $( this ).next( '.admin-page-framework-collapsible-content' ).first()
160
                : $( this ).parent().siblings( 'tbody' );
161
            var _sAction = _oTargetContent.is( ':visible' ) ? 'collapse' : 'expand';
162
163
            _oThis.removeClass( 'collapsed' );
164
            _oTargetContent.slideToggle( 'fast', function(){
165
166
                // For Google Chrome, table-caption will animate smoothly for the 'section' containers (not 'sections' container). For FireFox, 'block' is required. For IE both works.
167
                var _bIsChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
168
                if ( 'expand' === _sAction && 'section' === _sContainerType && ! _bIsChrome ) {
169
                    _oTargetContent.css( 'display', 'block' );
170
                }
171
172
                // Update the class selector.
173
                if ( _oTargetContent.is( ':visible' ) ) {
174
                    _oThis.removeClass( 'collapsed' );
175
                } else {
176
                    _oThis.addClass( 'collapsed' );
177
                }
178
179
            } );
180
181
            // If it is triggered from the toggle all button, do not continue.
182
            if ( 'by_toggle_all_button' === sContext ) {
183
                return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
184
            }
185
186
            // If collapse_others_on_expand argument is true, collapse others
187
            if ( 'expand' === _sAction && _oThis.data( 'collapse_others_on_expand' ) ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if "expand" === _sAction &&...apse_others_on_expand") is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
188
                _oThis.parent().parent().children().children( '* > .admin-page-framework-collapsible-content' ).not( _oTargetContent ).slideUp( 'fast', function() {
189
                    $( this ).prev( '.admin-page-framework-collapsible-title' ).addClass( 'collapsed' );
190
                });
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
191
            }
192
193
        });
194
        
195
    }
196
}( jQuery ));