Passed
Branch master (40a760)
by Chris
07:38
created

vendor/CMB2/js/cmb2-wysiwyg.js   B

Complexity

Total Complexity 43
Complexity/F 2.26

Size

Lines of Code 342
Function Count 19

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 43
eloc 128
mnd 24
bc 24
fnc 19
dl 0
loc 342
rs 8.96
bpm 1.263
cpm 2.2631
noi 9
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
A cmb2-wysiwyg.js ➔ getGroupData 0 22 2
A cmb2-wysiwyg.js ➔ delayedInit 0 12 4
B cmb2-wysiwyg.js ➔ initOptions 0 31 7
A cmb2-wysiwyg.js ➔ delayedDestroy 0 6 2

How to fix   Complexity   

Complexity

Complex classes like vendor/CMB2/js/cmb2-wysiwyg.js 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
 * Used for WYSIWYG logic
3
 */
4
window.CMB2 = window.CMB2 || {};
5
window.CMB2.wysiwyg = window.CMB2.wysiwyg || {};
6
7
( function(window, document, $, cmb, wysiwyg, undefined ) {
0 ignored issues
show
Unused Code introduced by
The parameter undefined 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...
8
	'use strict';
9
10
	// Private variables
11
	var toBeDestroyed = [];
12
	var toBeInitialized = [];
13
	var all = wysiwyg.all = {};
14
15
	// Private functions
16
17
	/**
18
	 * Initializes any editors that weren't initialized because they didn't exist yet.
19
	 *
20
	 * @since  2.2.3
21
	 *
22
	 * @return {void}
23
	 */
24
	function delayedInit() {
25
26
		// Don't initialize until they've all been destroyed.
27
		if ( 0 === toBeDestroyed.length ) {
28
			toBeInitialized.forEach( function ( toInit ) {
29
				toBeInitialized.splice( toBeInitialized.indexOf( toInit ), 1 );
30
				wysiwyg.init.apply( wysiwyg, toInit );
31
			} );
32
		} else {
33
			window.setTimeout( delayedInit, 100 );
34
		}
35
	}
36
37
	/**
38
	 * Destroys any editors that weren't destroyed because they didn't exist yet.
39
	 *
40
	 * @since  2.2.3
41
	 *
42
	 * @return {void}
43
	 */
44
	function delayedDestroy() {
45
		toBeDestroyed.forEach( function( id ) {
46
			toBeDestroyed.splice( toBeDestroyed.indexOf( id ), 1 );
47
			wysiwyg.destroy( id );
48
		} );
49
	}
50
51
	/**
52
	 * Gets the option data for a group (and initializes that data if it doesn't exist).
53
	 *
54
	 * @since  2.2.3
55
	 *
56
	 * @param  {object} data The group/field data.
57
	 *
58
	 * @return {object}      Options data object for a group.
59
	 */
60
	function getGroupData( data ) {
61
		var groupid = data.groupid;
62
		var fieldid = data.fieldid;
63
64
		if ( ! all[ groupid ] || ! all[ groupid ][ fieldid ] ) {
65
			all[ groupid ] = all[ groupid ] || {};
66
			all[ groupid ][ fieldid ] = {
67
				template : wp.template( 'cmb2-wysiwyg-' + groupid + '-' + fieldid ),
0 ignored issues
show
Bug introduced by
The variable wp seems to be never declared. If this is a global, consider adding a /** global: wp */ 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...
68
				defaults : {
69
70
					// Get the data from the template-wysiwyg initiation.
71
					mce : $.extend( {}, tinyMCEPreInit.mceInit[ 'cmb2_i_' + groupid + fieldid ] ),
0 ignored issues
show
Bug introduced by
The variable tinyMCEPreInit seems to be never declared. If this is a global, consider adding a /** global: tinyMCEPreInit */ 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...
72
					qt  : $.extend( {}, tinyMCEPreInit.qtInit[ 'cmb2_i_' + groupid + fieldid ] )
73
				}
74
			};
75
			// This is the template-wysiwyg data, and we do not want that to be initiated.
76
			delete tinyMCEPreInit.mceInit[ 'cmb2_i_' + groupid + fieldid ];
77
			delete tinyMCEPreInit.qtInit[ 'cmb2_i_' + groupid + fieldid ];
78
		}
79
80
		return all[ groupid ][ fieldid ];
81
	}
82
83
	/**
84
	 * Initiates the tinyMCEPreInit options for a wysiwyg editor instance.
85
	 *
86
	 * @since  2.2.3
87
	 *
88
	 * @param  {object} options Options data object for the wysiwyg editor instance.
89
	 *
90
	 * @return {void}
91
	 */
92
	function initOptions( options ) {
93
		var nameRegex = new RegExp( 'cmb2_n_' + options.groupid + options.fieldid, 'g' );
94
		var idRegex   = new RegExp( 'cmb2_i_' + options.groupid + options.fieldid, 'g' );
95
		var prop, newSettings, newQTS;
96
97
		// If no settings for this field. Clone from placeholder.
98
		if ( 'undefined' === typeof( tinyMCEPreInit.mceInit[ options.id ] ) ) {
0 ignored issues
show
Bug introduced by
The variable tinyMCEPreInit seems to be never declared. If this is a global, consider adding a /** global: tinyMCEPreInit */ 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...
99
			newSettings = $.extend( {}, options.defaults.mce );
100
			for ( prop in newSettings ) {
101
				if ( 'string' === typeof( newSettings[ prop ] ) ) {
102
					newSettings[ prop ] = newSettings[ prop ]
103
						.replace( idRegex, options.id )
104
						.replace( nameRegex, options.name );
105
				}
106
			}
107
			tinyMCEPreInit.mceInit[ options.id ] = newSettings;
108
		}
109
110
		// If no Quicktag settings for this field. Clone from placeholder.
111
		if ( 'undefined' === typeof( tinyMCEPreInit.qtInit[ options.id ] ) ) {
112
			newQTS = $.extend( {}, options.defaults.qt );
113
			for ( prop in newQTS ) {
114
				if ( 'string' === typeof( newQTS[ prop ] ) ) {
115
					newQTS[ prop ] = newQTS[ prop ]
116
						.replace( idRegex, options.id )
117
						.replace( nameRegex, options.name );
118
				}
119
			}
120
			tinyMCEPreInit.qtInit[ options.id ] = newQTS;
121
		}
122
	}
123
124
	/**
125
	 * Initializes all group wysiwyg editors. Hooked to cmb_init.
126
	 *
127
	 * @since  2.2.3
128
	 *
129
	 * @return {void}
130
	 */
131
	wysiwyg.initAll = function() {
132
		var $this,data,initiated;
133
134
		$( '.cmb2-wysiwyg-placeholder' ).each( function() {
135
			$this = $( this );
136
			data  = $this.data();
137
138
			if ( data.groupid ) {
139
140
				data.id    = $this.attr( 'id' );
141
				data.name  = $this.attr( 'name' );
142
				data.value = $this.val();
143
144
				wysiwyg.init( $this, data, false );
145
				initiated = true;
146
			}
147
		} );
148
149
		if ( true === initiated ) {
150
			if ( 'undefined' !== typeof window.QTags ) {
151
				window.QTags._buttonsInit();
152
			}
153
154
			// Hook in our event callbacks.
155
			$( document )
156
				.on( 'cmb2_add_row', wysiwyg.addRow )
157
				.on( 'cmb2_remove_group_row_start', wysiwyg.destroyRowEditors )
158
				.on( 'cmb2_shift_rows_start', wysiwyg.shiftStart )
159
				.on( 'cmb2_shift_rows_complete', wysiwyg.shiftComplete );
160
		}
161
	};
162
163
	/**
164
	 * Initiates wysiwyg editors in a new group row. Hooked to cmb2_add_row.
165
	 *
166
	 * @since  2.2.3
167
	 *
168
	 * @param  {object} evt A jQuery-normalized event object.
169
	 * @param  {object} $row A jQuery dom element object for the group row.
170
	 *
171
	 * @return {void}
172
	 */
173
	wysiwyg.addRow = function( evt, $row ) {
174
		wysiwyg.initRow( $row, evt );
175
	};
176
177
	/**
178
	 * Destroys wysiwyg editors in a group row when that row is removed. Hooked to cmb2_remove_group_row_start.
179
	 *
180
	 * @since  2.2.3
181
	 *
182
	 * @param  {object} evt A jQuery-normalized event object.
183
	 * @param  {object} $btn A jQuery dom element object for the remove-row button.
184
	 *
185
	 * @return {void}
186
	 */
187
	wysiwyg.destroyRowEditors = function( evt, $btn ) {
188
		wysiwyg.destroy( $btn.parents( '.cmb-repeatable-grouping' ).find( '.wp-editor-area' ).attr( 'id' ) );
189
	};
190
191
	/**
192
	 * When a row-shift starts, we need to destroy the wysiwyg editors for the group-rows being shuffled.
193
	 *
194
	 * @since  2.2.3
195
	 *
196
	 * @param  {object} evt   A jQuery-normalized event object.
197
	 * @param  {object} $btn  A jQuery dom element object for the remove-row button.
198
	 * @param  {object} $from A jQuery dom element object for the row being shifted from.
199
	 * @param  {object} $to   A jQuery dom element object for the row being shifted to.
200
	 *
201
	 * @return {void}
202
	 */
203
	wysiwyg.shiftStart = function( evt, $btn, $from, $to ) {
204
		$from.add( $to ).find( '.wp-editor-wrap textarea' ).each( function() {
205
			wysiwyg.destroy( $( this ).attr( 'id' ) );
206
		} );
207
	};
208
209
	/**
210
	 * When a row-shift completes, we need to re-init the wysiwyg editors for the group-rows being shuffled.
211
	 *
212
	 * @since  2.2.3
213
	 *
214
	 * @param  {object} evt   A jQuery-normalized event object.
215
	 * @param  {object} $btn  A jQuery dom element object for the remove-row button.
216
	 * @param  {object} $from A jQuery dom element object for the row being shifted from.
217
	 * @param  {object} $to   A jQuery dom element object for the row being shifted to.
218
	 *
219
	 * @return {void}
220
	 */
221
	wysiwyg.shiftComplete = function( evt, $btn, $from, $to ) {
222
		$from.add( $to ).each( function() {
223
			wysiwyg.initRow( $( this ), evt );
224
		} );
225
	};
226
227
	/**
228
	 * Initializes editors for a new CMB row.
229
	 *
230
	 * @since  2.2.3
231
	 *
232
	 * @param  {object} $row A jQuery dom element object for the group row.
233
	 * @param  {object} evt  A jQuery-normalized event object.
234
	 *
235
	 * @return {void}
236
	 */
237
	wysiwyg.initRow = function( $row, evt ) {
238
		var $toReplace, data, defVal;
239
240
		$row.find( '.cmb2-wysiwyg-inner-wrap' ).each( function() {
241
			$toReplace    = $( this );
242
			data          = $toReplace.data();
243
			defVal        = cmb.getFieldArg( data.hash, 'default', '' );
244
			defVal        = 'undefined' !== typeof defVal && false !== defVal ? defVal : '';
245
246
			data.iterator = $row.data( 'iterator' );
247
			data.fieldid  = data.id;
248
			data.id       = data.groupid + '_' + data.iterator + '_' + data.fieldid;
249
			data.name     = data.groupid + '[' + data.iterator + '][' + data.fieldid + ']';
250
			data.value    = 'cmb2_add_row' !== evt.type && $toReplace.find( '.wp-editor-area' ).length ? $toReplace.find( '.wp-editor-area' ).val() : defVal;
251
252
			// The destroys might not have happened yet.  Don't init until they have.
253
			if ( 0 === toBeDestroyed.length ) {
254
255
				wysiwyg.init( $toReplace, data );
256
257
			} else {
258
				toBeInitialized.push( [$toReplace, data] );
259
				window.setTimeout( delayedInit, 100 );
260
			}
261
		} );
262
263
	};
264
265
	/**
266
	 * Initiates a wysiwyg editor instance and replaces the passed dom element w/ the editor html.
267
	 *
268
	 * @since  2.2.3
269
	 *
270
	 * @param  {object} $toReplace A jQuery dom element which will be replaced with the wysiwyg editor.
271
	 * @param  {object} data        Data used to initate the editor.
272
	 * @param  {bool}   buttonsInit Whether to run QTags._buttonsInit()
273
	 *
274
	 * @return {void}
275
	 */
276
	wysiwyg.init = function( $toReplace, data, buttonsInit ) {
277
		if ( ! data.groupid ) {
278
			return false;
279
		}
280
281
		var mceActive = cmb.canTinyMCE();
282
		var qtActive = 'function' === typeof window.quicktags;
283
		$.extend( data, getGroupData( data ) );
284
285
		initOptions( data );
286
287
		$toReplace.replaceWith( data.template( data ) );
288
289
		if ( mceActive ) {
290
			window.tinyMCE.init( tinyMCEPreInit.mceInit[ data.id ] );
0 ignored issues
show
Bug introduced by
The variable tinyMCEPreInit seems to be never declared. If this is a global, consider adding a /** global: tinyMCEPreInit */ 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...
291
		}
292
293
		if ( qtActive ) {
294
			window.quicktags( tinyMCEPreInit.qtInit[ data.id ] );
295
		}
296
297
		if ( mceActive ) {
298
			$( document.getElementById( data.id ) ).parents( '.wp-editor-wrap' ).removeClass( 'html-active' ).addClass( 'tmce-active' );
299
		}
300
301
		if ( false !== buttonsInit && 'undefined' !== typeof window.QTags ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if false !== buttonsInit &&...== typeof window.QTags 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...
302
			window.QTags._buttonsInit();
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...
303
		}
304
305
	};
306
307
	/**
308
	 * Destroys a wysiwyg editor instance.
309
	 *
310
	 * @since  2.2.3
311
	 *
312
	 * @param  {string} id Editor id.
313
	 *
314
	 * @return {void}
315
	 */
316
	wysiwyg.destroy = function( id ) {
317
		if ( ! cmb.canTinyMCE() ) {
318
			// Nothing to see here.
319
			return;
320
		}
321
322
		// The editor might not be initialized yet.  But we need to destroy it once it is.
323
		var editor = tinyMCE.get( id );
0 ignored issues
show
Bug introduced by
The variable tinyMCE seems to be never declared. If this is a global, consider adding a /** global: tinyMCE */ 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...
324
325
		if ( editor !== null && typeof( editor ) !== 'undefined' ) {
326
			editor.destroy();
327
328
			if ( 'undefined' === typeof( tinyMCEPreInit.mceInit[ id ] ) ) {
0 ignored issues
show
Bug introduced by
The variable tinyMCEPreInit seems to be never declared. If this is a global, consider adding a /** global: tinyMCEPreInit */ 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...
329
				delete tinyMCEPreInit.mceInit[ id ];
330
			}
331
332
			if ( 'undefined' === typeof( tinyMCEPreInit.qtInit[ id ] ) ) {
333
				delete tinyMCEPreInit.qtInit[ id ];
334
			}
335
336
		} else if ( -1 === toBeDestroyed.indexOf( id ) ) {
337
			toBeDestroyed.push( id );
338
			window.setTimeout( delayedDestroy, 100 );
339
		}
340
	};
341
342
	// Hook in our event callbacks.
343
	$( document ).on( 'cmb_init', wysiwyg.initAll );
344
345
} )( window, document, jQuery, window.CMB2, window.CMB2.wysiwyg );
346