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

form-tooltip.js ➔ initialize   D

Complexity

Conditions 12

Size

Total Lines 34
Code Lines 22

Duplication

Lines 34
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 22
dl 34
loc 34
rs 4.8
c 0
b 0
f 0
cc 12

How to fix   Complexity   

Complexity

Complex classes like form-tooltip.js ➔ initialize 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
/**
2
 * Displays tips for fields in a tooltip.
3
 *
4
 * It provides the $[ 'admin-page-framework-tooltip' ]( options ) jQuery plugin method.
5
 * The name uses hyphens for the user's text domain to be replaced. So the compiled framework script will be entirely ported with without the keyword of `admin-page-framework`.
6
 *
7
 * To use the method,
8
 * ```
9
 * $( '.my-tooltip' )[ 'admin-page-framework-form-tooltip' ]( 'Hi, this is a tooltip content!' );
10
 * ```
11
 * Or have a text message enclosed in an element with a class `admin-page-framework-form-tooltip-content`.
12
 * ```
13
 *    <span class="my-tooltip dashicons dashicons-editor-help">
14
 *      <span class="admin-page-framework-form-tooltip-content">
15
 *        Some text
16
 *      </span>
17
 *    </span>
18
 * ```
19
 * Then, call it like
20
 * ```
21
 * $( '.my-tooltip' )[ 'admin-page-framework-form-tooltip' ]();
22
 * ```
23
 * Or
24
 * ```
25
 *    <span class="my-tooltip dashicons dashicons-editor-help" data-tooltip-content="Hello"></span>
26
 * ```
27
 *
28
 * If it the script is loaded, elements with the .admin-page-framework-from-tooltip class will be automatically parsed.
29
 * So not to call the `[ 'admin-page-framework-form-tooltip' ]()` method, just create an element with the selector
30
 * and it should automatically have a tooltip.
31
 *
32
 *
33
 * When the framework file is compiled, replace the keyword `admin-page-framework` with your text domain.
34
 */
35 View Code Duplication
(function($){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
36
37
  // Initialize
38
  $( document ).ready( function() {
39
    $( '.admin-page-framework-form-tooltip' ).each( function() {
40
      $( this )[ 'admin-page-framework-form-tooltip' ]();
41
    } );
42
  } );
43
44
  $.fn[ 'admin-page-framework-form-tooltip' ] = function( options ) {
45
    if ( 'string' === typeof options ) {
46
      options = {
47
        content: isHTML( options ) ? options : "<span>" + options + "</span>"
48
      }
49
    }
50
    initialize( this, options )
51
  };
52
53
  function initialize( target, options ) {
54
55
    var _this = $( target );
56
    var _content = $( target ).attr( 'data-tooltip-content' );
57
    _content = _content ? _content : undefined;
58
59
    // Format options
60
    options = 'undefined' === typeof options ? {} : options;
61
    options = $.extend( {}, {
62
      pointerClass: 'admin-page-framework-form-tooltip-balloon',
63
      width: $( target ).data( 'width' ) || options.width || 340,
64
      height: $( target ).data( 'height' ) || options.height,
65
      shown: false,        // initial visibility
66
      content: _content,
67
      oneOff: false,
68
      // whether to close the tooltip automatically when the mouse leaves. do not turn on when the oneOff is on, it will disappear immediately
69
      autoClose: true,
70
      noArrow: false,
71
    }, options );
72
    options.pointerClass += options.noArrow ? ' no-arrow' : '';
73
74
    // Disable the CSS default tooltip
75
    $( _this ).removeClass( 'no-js' );
76
77
    if ( options.shown ) {
78
      handleTooltip( target, options );
79
    }
80
81
    var _pointerTooltip = $( _this );
82
    if ( ! options.oneOff ) {
83
      _pointerTooltip.on( 'mouseover touchend', options, handleTooltipCallback );
84
    }
85
86
  }
87
88
  function handleTooltipCallback( event ) {
89
    handleTooltip( this, event.data );
90
  }
91
  function handleTooltip( self, options ) {
92
93
    var _body      = $( 'body' );
94
    var _width     = options.width;
95
    var _content   = 'undefined' !== typeof options.content
96
      ? $( isHTML( options.content ) ? options.content : "<span>" + options.content + "</span>" )
97
      : $( self ).find( '.admin-page-framework-form-tooltip-content' ).clone();
98
    var _offscreen  = $( self ).offset().left + $( self ).width() + _width > _body.offset().left + _body.width();
99
100
    // Open the tooltip
101
    var _options    = $.extend( true, {}, options, {
102
      pointerWidth: _width,
103
      pointerHeight: options.height,
104
      content: function() {
105
        return _content.html();
106
      },
107
      position: {
108
        edge: _offscreen ? 'top' : 'left',
109
        align: _offscreen ? 'center' : 'left',
110
        within: _offscreen ? _body : $( self ).closest( '.admin-page-framework-field, .admin-page-framework-fieldrow, .admin-page-framework-section' ),
111
      },
112
      buttons: function() {},
113
      close: function() {},
114
    }, options );
115
    _options.pointerClass += _offscreen ? ' offscreen' : '';
116
117
    debugLog( 'Tooltip', _options );
118
    $( self ).pointerTooltip( _options )
119
      .pointerTooltip( 'open' );
120
121
    // Handle toolitip closing
122
    var _self    = self;
123
    if ( options.autoClose ) {
124
      handleAutoClose( _self, _content );
125
    } else {
126
      setTimeout( function() {
127
        handleCloseOnEmptySpace( _self, _content, options );
128
      }, 200 );
129
    }
130
    /// For mobile devices
131
    setTimeout( function() {
132
      handleCloseOnMobile( _self, _content );
133
    }, 200 );
134
135
  }
136
137
  function handleCloseOnEmptySpace( self, content, options ) {
138
139
    var _class = options.pointerClass.split( ' ' )[ 0 ];
140
    var _emptySpace = $( 'body' ).not( '.' + _class );
141
    _emptySpace.on( 'click', ':not(.' + _class + ')', _closeTooltipOnEmptySpace );
142
    function _closeTooltipOnEmptySpace( event ) {
0 ignored issues
show
Unused Code introduced by
The parameter event is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
143
      if ( $( this ).closest( '.' + _class ).length ) {
144
        return;
145
      }
146
      _emptySpace.off( 'click', _closeTooltipOnEmptySpace );
147
      $( self ).pointerTooltip( 'close' );
148
      content.remove();
149
    }
150
  }
151
152
  function handleCloseOnMobile( self, content ) {
153
    var _body = $( 'body' );
154
    _body.on( 'touchstart', _closeTooltipMobile );
155
    function _closeTooltipMobile( event ) {
0 ignored issues
show
Unused Code introduced by
The parameter event is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
156
      _body.off( 'touchstart', _closeTooltipMobile );
157
      $( self ).pointerTooltip( 'close' );
158
      content.remove();
159
    }
160
  }
161
  function handleAutoClose( self, content ) {
162
      /// For non-mobile devices
163
      $( self ).add( '.admin-page-framework-form-tooltip-balloon' ).on( 'mouseleave', function( event ){
0 ignored issues
show
Unused Code introduced by
The parameter event is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
164
        var _selfMouseLeave = this;
165
        // Set a timeout for the tooltip to close, allowing us to clear this trigger if the mouse comes back over
166
        var _timeoutId = setTimeout(function(){
167
          $( self ).pointerTooltip( 'close' );
168
          content.remove();
169
          $( self ).off( 'mouseleave' );
170
          $( _selfMouseLeave ).off( 'mouseleave' );
171
          $( self ).off( 'mouseenter' );
172
          $( _selfMouseLeave ).off( 'mouseenter' );
173
        }, 1000 );
174
        $( self ).data( 'timeoutId', _timeoutId );
175
176
      } );
177
      $( self ).add( '.admin-page-framework-form-tooltip-balloon' ).on( 'mouseenter', function(){
178
        clearTimeout( $( self ).data('timeoutId' ) );
179
      });
180
  }
181
182
  function isHTML(str) {
183
    var a = document.createElement('div');
184
    a.innerHTML = str;
185
    for (var c = a.childNodes, i = c.length; i--; ) {
186
      if ( 1 === c[ i ].nodeType) {
187
        return true;
188
      }
189
    }
190
    return false;
191
  }
192
193
  function debugLog( ...message ) {
194
    if ( ! parseInt( AdminPageFrameworkScriptFormMain.debugMode ) ) {
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...
195
      return;
196
    }
197
    console.log( '[APF]', ...message );
1 ignored issue
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
198
  }
199
200
}(jQuery));