Total Complexity | 72 |
Complexity/F | 2.12 |
Lines of Code | 422 |
Function Count | 34 |
Duplicated Lines | 198 |
Ratio | 46.92 % |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like controls/js/src/typography-legacy.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 | /* global kirkiControlLoader, kirkiAllFonts */ |
||
2 | wp.customize.controlConstructor['kirki-typography'] = wp.customize.Control.extend({ |
||
3 | |||
4 | // When we're finished loading continue processing |
||
5 | ready: function() { |
||
6 | |||
7 | 'use strict'; |
||
8 | |||
9 | var control = this; |
||
|
|||
10 | |||
11 | // Init the control. |
||
12 | if ( ! _.isUndefined( window.kirkiControlLoader ) && _.isFunction( kirkiControlLoader ) ) { |
||
13 | kirkiControlLoader( control ); |
||
14 | } else { |
||
15 | control.initKirkiControl(); |
||
16 | } |
||
17 | }, |
||
18 | |||
19 | View Code Duplication | initKirkiControl: function() { |
|
20 | |||
21 | 'use strict'; |
||
22 | |||
23 | var control = this, |
||
24 | value = control.getValue(), |
||
25 | picker; |
||
26 | |||
27 | control.renderFontSelector(); |
||
28 | control.renderBackupFontSelector(); |
||
29 | control.renderVariantSelector(); |
||
30 | control.renderSubsetSelector(); |
||
31 | |||
32 | // Font-size. |
||
33 | if ( control.params['default']['font-size'] ) { |
||
34 | this.container.on( 'change keyup paste', '.font-size input', function() { |
||
35 | control.saveValue( 'font-size', jQuery( this ).val() ); |
||
36 | }); |
||
37 | } |
||
38 | |||
39 | // Line-height. |
||
40 | if ( control.params['default']['line-height'] ) { |
||
41 | this.container.on( 'change keyup paste', '.line-height input', function() { |
||
42 | control.saveValue( 'line-height', jQuery( this ).val() ); |
||
43 | }); |
||
44 | } |
||
45 | |||
46 | // Margin-top. |
||
47 | if ( control.params['default']['margin-top'] ) { |
||
48 | this.container.on( 'change keyup paste', '.margin-top input', function() { |
||
49 | control.saveValue( 'margin-top', jQuery( this ).val() ); |
||
50 | }); |
||
51 | } |
||
52 | |||
53 | // Margin-bottom. |
||
54 | if ( control.params['default']['margin-bottom'] ) { |
||
55 | this.container.on( 'change keyup paste', '.margin-bottom input', function() { |
||
56 | control.saveValue( 'margin-bottom', jQuery( this ).val() ); |
||
57 | }); |
||
58 | } |
||
59 | |||
60 | // Letter-spacing. |
||
61 | if ( control.params['default']['letter-spacing'] ) { |
||
62 | value['letter-spacing'] = ( jQuery.isNumeric( value['letter-spacing'] ) ) ? value['letter-spacing'] + 'px' : value['letter-spacing']; |
||
63 | this.container.on( 'change keyup paste', '.letter-spacing input', function() { |
||
64 | value['letter-spacing'] = ( jQuery.isNumeric( jQuery( this ).val() ) ) ? jQuery( this ).val() + 'px' : jQuery( this ).val(); |
||
65 | control.saveValue( 'letter-spacing', value['letter-spacing'] ); |
||
66 | }); |
||
67 | } |
||
68 | |||
69 | // Word-spacing. |
||
70 | if ( control.params['default']['word-spacing'] ) { |
||
71 | this.container.on( 'change keyup paste', '.word-spacing input', function() { |
||
72 | control.saveValue( 'word-spacing', jQuery( this ).val() ); |
||
73 | }); |
||
74 | } |
||
75 | |||
76 | // Text-align. |
||
77 | if ( control.params['default']['text-align'] ) { |
||
78 | this.container.on( 'change', '.text-align input', function() { |
||
79 | control.saveValue( 'text-align', jQuery( this ).val() ); |
||
80 | }); |
||
81 | } |
||
82 | |||
83 | // Text-transform. |
||
84 | if ( control.params['default']['text-transform'] ) { |
||
85 | jQuery( control.selector + ' .text-transform select' ).selectWoo().on( 'change', function() { |
||
86 | control.saveValue( 'text-transform', jQuery( this ).val() ); |
||
87 | }); |
||
88 | } |
||
89 | |||
90 | // Color. |
||
91 | if ( control.params['default'].color ) { |
||
92 | picker = this.container.find( '.kirki-color-control' ); |
||
93 | picker.wpColorPicker({ |
||
94 | change: function() { |
||
95 | setTimeout( function() { |
||
96 | control.saveValue( 'color', picker.val() ); |
||
97 | }, 100 ); |
||
98 | } |
||
99 | }); |
||
100 | } |
||
101 | }, |
||
102 | |||
103 | /** |
||
104 | * Adds the font-families to the font-family dropdown |
||
105 | * and instantiates selectWoo. |
||
106 | */ |
||
107 | View Code Duplication | renderFontSelector: function() { |
|
108 | |||
109 | var control = this, |
||
110 | selector = control.selector + ' .font-family select', |
||
111 | data = [], |
||
112 | standardFonts = [], |
||
113 | googleFonts = [], |
||
114 | value = control.getValue(), |
||
115 | fonts = control.getFonts(), |
||
116 | fontSelect; |
||
117 | |||
118 | // Format standard fonts as an array. |
||
119 | if ( ! _.isUndefined( fonts.standard ) ) { |
||
120 | _.each( fonts.standard, function( font ) { |
||
121 | standardFonts.push({ |
||
122 | id: font.family.replace( /"/g, ''' ), |
||
123 | text: font.label |
||
124 | }); |
||
125 | }); |
||
126 | } |
||
127 | |||
128 | // Format google fonts as an array. |
||
129 | if ( ! _.isUndefined( fonts.standard ) ) { |
||
130 | _.each( fonts.google, function( font ) { |
||
131 | googleFonts.push({ |
||
132 | id: font.family, |
||
133 | text: font.label |
||
134 | }); |
||
135 | }); |
||
136 | } |
||
137 | |||
138 | // Combine forces and build the final data. |
||
139 | data = [ |
||
140 | { text: 'Standard Fonts', children: standardFonts }, |
||
141 | { text: 'Google Fonts', children: googleFonts } |
||
142 | ]; |
||
143 | |||
144 | // Instantiate selectWoo with the data. |
||
145 | fontSelect = jQuery( selector ).selectWoo({ |
||
146 | data: data |
||
147 | }); |
||
148 | |||
149 | // Set the initial value. |
||
150 | if ( value['font-family'] ) { |
||
151 | fontSelect.val( value['font-family'].replace( /'/g, '"' ) ).trigger( 'change' ); |
||
152 | } |
||
153 | |||
154 | // When the value changes |
||
155 | fontSelect.on( 'change', function() { |
||
156 | |||
157 | // Set the value. |
||
158 | control.saveValue( 'font-family', jQuery( this ).val() ); |
||
159 | |||
160 | // Re-init the font-backup selector. |
||
161 | control.renderBackupFontSelector(); |
||
162 | |||
163 | // Re-init variants selector. |
||
164 | control.renderVariantSelector(); |
||
165 | |||
166 | // Re-init subsets selector. |
||
167 | control.renderSubsetSelector(); |
||
168 | }); |
||
169 | }, |
||
170 | |||
171 | /** |
||
172 | * Adds the font-families to the font-family dropdown |
||
173 | * and instantiates selectWoo. |
||
174 | */ |
||
175 | renderBackupFontSelector: function() { |
||
176 | |||
177 | var control = this, |
||
178 | selector = control.selector + ' .font-backup select', |
||
179 | standardFonts = [], |
||
180 | value = control.getValue(), |
||
181 | fontFamily = value['font-family'], |
||
182 | variants = control.getVariants( fontFamily ), |
||
183 | fonts = control.getFonts(), |
||
184 | fontSelect; |
||
185 | |||
186 | if ( _.isUndefined( value['font-backup'] ) || null === value['font-backup'] ) { |
||
187 | value['font-backup'] = ''; |
||
188 | } |
||
189 | |||
190 | // Hide if we're not on a google-font. |
||
191 | if ( false !== variants ) { |
||
192 | jQuery( control.selector + ' .font-backup' ).show(); |
||
193 | } else { |
||
194 | jQuery( control.selector + ' .font-backup' ).hide(); |
||
195 | } |
||
196 | |||
197 | // Format standard fonts as an array. |
||
198 | if ( ! _.isUndefined( fonts.standard ) ) { |
||
199 | _.each( fonts.standard, function( font ) { |
||
200 | standardFonts.push({ |
||
201 | id: font.family.replace( /"/g, ''' ), |
||
202 | text: font.label |
||
203 | }); |
||
204 | }); |
||
205 | } |
||
206 | |||
207 | // Instantiate selectWoo with the data. |
||
208 | fontSelect = jQuery( selector ).selectWoo({ |
||
209 | data: standardFonts |
||
210 | }); |
||
211 | |||
212 | // Set the initial value. |
||
213 | if ( 'undefined' !== typeof value['font-backup'] ) { |
||
214 | fontSelect.val( value['font-backup'].replace( /'/g, '"' ) ).trigger( 'change' ); |
||
215 | } |
||
216 | |||
217 | // When the value changes |
||
218 | fontSelect.on( 'change', function() { |
||
219 | |||
220 | // Set the value. |
||
221 | control.saveValue( 'font-backup', jQuery( this ).val() ); |
||
222 | }); |
||
223 | }, |
||
224 | |||
225 | /** |
||
226 | * Renders the variants selector using selectWoo |
||
227 | * Displays font-variants for the currently selected font-family. |
||
228 | */ |
||
229 | View Code Duplication | renderVariantSelector: function() { |
|
230 | |||
231 | var control = this, |
||
232 | value = control.getValue(), |
||
233 | fontFamily = value['font-family'], |
||
234 | variants = control.getVariants( fontFamily ), |
||
235 | selector = control.selector + ' .variant select', |
||
236 | data = [], |
||
237 | isValid = false, |
||
238 | fontWeight, |
||
239 | variantSelector, |
||
240 | fontStyle; |
||
241 | |||
242 | if ( false !== variants ) { |
||
243 | jQuery( control.selector + ' .variant' ).show(); |
||
244 | _.each( variants, function( variant ) { |
||
245 | if ( value.variant === variant.id ) { |
||
246 | isValid = true; |
||
247 | } |
||
248 | data.push({ |
||
249 | id: variant.id, |
||
250 | text: variant.label |
||
251 | }); |
||
252 | }); |
||
253 | if ( ! isValid ) { |
||
254 | value.variant = 'regular'; |
||
255 | } |
||
256 | |||
257 | if ( jQuery( selector ).hasClass( 'select2-hidden-accessible' ) ) { |
||
258 | jQuery( selector ).selectWoo( 'destroy' ); |
||
259 | jQuery( selector ).empty(); |
||
260 | } |
||
261 | |||
262 | // Instantiate selectWoo with the data. |
||
263 | variantSelector = jQuery( selector ).selectWoo({ |
||
264 | data: data |
||
265 | }); |
||
266 | variantSelector.val( value.variant ).trigger( 'change' ); |
||
267 | variantSelector.on( 'change', function() { |
||
268 | control.saveValue( 'variant', jQuery( this ).val() ); |
||
269 | |||
270 | fontWeight = ( ! _.isString( value.variant ) ) ? '400' : value.variant.match( /\d/g ); |
||
271 | fontWeight = ( ! _.isObject( fontWeight ) ) ? '400' : fontWeight.join( '' ); |
||
272 | fontStyle = ( -1 !== value.variant.indexOf( 'italic' ) ) ? 'italic' : 'normal'; |
||
273 | |||
274 | control.saveValue( 'font-weight', fontWeight ); |
||
275 | control.saveValue( 'font-style', fontStyle ); |
||
276 | }); |
||
277 | } else { |
||
278 | jQuery( control.selector + ' .variant' ).hide(); |
||
279 | } |
||
280 | }, |
||
281 | |||
282 | /** |
||
283 | * Renders the subsets selector using selectWoo |
||
284 | * Displays font-subsets for the currently selected font-family. |
||
285 | */ |
||
286 | renderSubsetSelector: function() { |
||
287 | |||
288 | var control = this, |
||
289 | value = control.getValue(), |
||
290 | fontFamily = value['font-family'], |
||
291 | subsets = control.getSubsets( fontFamily ), |
||
292 | selector = control.selector + ' .subsets select', |
||
293 | data = [], |
||
294 | validValue = value.subsets, |
||
295 | subsetSelector; |
||
296 | |||
297 | if ( false !== subsets ) { |
||
298 | jQuery( control.selector + ' .subsets' ).show(); |
||
299 | _.each( subsets, function( subset ) { |
||
300 | |||
301 | if ( _.isObject( validValue ) ) { |
||
302 | if ( -1 === validValue.indexOf( subset.id ) ) { |
||
303 | validValue = _.reject( validValue, function( subValue ) { |
||
304 | return subValue === subset.id; |
||
305 | }); |
||
306 | } |
||
307 | } |
||
308 | |||
309 | data.push({ |
||
310 | id: subset.id, |
||
311 | text: subset.label |
||
312 | }); |
||
313 | }); |
||
314 | |||
315 | } else { |
||
316 | jQuery( control.selector + ' .subsets' ).hide(); |
||
317 | } |
||
318 | |||
319 | if ( jQuery( selector ).hasClass( 'select2-hidden-accessible' ) ) { |
||
320 | jQuery( selector ).selectWoo( 'destroy' ); |
||
321 | jQuery( selector ).empty(); |
||
322 | } |
||
323 | |||
324 | // Instantiate selectWoo with the data. |
||
325 | subsetSelector = jQuery( selector ).selectWoo({ |
||
326 | data: data |
||
327 | }); |
||
328 | subsetSelector.val( validValue ).trigger( 'change' ); |
||
329 | subsetSelector.on( 'change', function() { |
||
330 | control.saveValue( 'subsets', jQuery( this ).val() ); |
||
331 | }); |
||
332 | }, |
||
333 | |||
334 | /** |
||
335 | * Get fonts. |
||
336 | */ |
||
337 | getFonts: function() { |
||
338 | var control = this; |
||
339 | |||
340 | if ( ! _.isUndefined( window[ 'kirkiFonts' + control.id ] ) ) { |
||
341 | return window[ 'kirkiFonts' + control.id ]; |
||
342 | } |
||
343 | if ( 'undefined' !== typeof kirkiAllFonts ) { |
||
344 | return kirkiAllFonts; |
||
345 | } |
||
346 | return { |
||
347 | google: [], |
||
348 | standard: [] |
||
349 | }; |
||
350 | }, |
||
351 | |||
352 | /** |
||
353 | * Get variants for a font-family. |
||
354 | */ |
||
355 | getVariants: function( fontFamily ) { |
||
356 | var control = this, |
||
357 | fonts = control.getFonts(); |
||
358 | |||
359 | var variants = false; |
||
360 | _.each( fonts.standard, function( font ) { |
||
361 | if ( fontFamily && font.family === fontFamily.replace( /'/g, '"' ) ) { |
||
362 | variants = font.variants; |
||
363 | return font.variants; |
||
364 | } |
||
365 | }); |
||
366 | |||
367 | _.each( fonts.google, function( font ) { |
||
368 | if ( font.family === fontFamily ) { |
||
369 | variants = font.variants; |
||
370 | return font.variants; |
||
371 | } |
||
372 | }); |
||
373 | return variants; |
||
374 | }, |
||
375 | |||
376 | /** |
||
377 | * Get subsets for a font-family. |
||
378 | */ |
||
379 | getSubsets: function( fontFamily ) { |
||
380 | |||
381 | var control = this, |
||
382 | subsets = false, |
||
383 | fonts = control.getFonts(); |
||
384 | |||
385 | _.each( fonts.google, function( font ) { |
||
386 | if ( font.family === fontFamily ) { |
||
387 | subsets = font.subsets; |
||
388 | } |
||
389 | }); |
||
390 | return subsets; |
||
391 | }, |
||
392 | |||
393 | /** |
||
394 | * Gets the value. |
||
395 | */ |
||
396 | getValue: function() { |
||
397 | |||
398 | 'use strict'; |
||
399 | |||
400 | var control = this, |
||
401 | input = control.container.find( '.typography-hidden-value' ), |
||
402 | valueJSON = jQuery( input ).val(); |
||
403 | |||
404 | return JSON.parse( valueJSON ); |
||
405 | }, |
||
406 | |||
407 | /** |
||
408 | * Saves the value. |
||
409 | */ |
||
410 | saveValue: function( property, value ) { |
||
411 | |||
412 | 'use strict'; |
||
413 | |||
414 | var control = this, |
||
415 | input = control.container.find( '.typography-hidden-value' ), |
||
416 | valueJSON = jQuery( input ).val(), |
||
417 | valueObj = JSON.parse( valueJSON ); |
||
418 | |||
419 | valueObj[ property ] = value; |
||
420 | wp.customize.control( control.id ).setting.set( valueObj ); |
||
421 | jQuery( input ).attr( 'value', JSON.stringify( valueObj ) ).trigger( 'change' ); |
||
422 | } |
||
423 | }); |
||
424 |
Since ECMAScript 6, you can create block-scoped vars or constants with the keywords
let
orconst
. These variables/constants are only valid in the code block where they have been declared.Consider the following two pieces of code:
and
The variable is not defined otuside of its block. This limits bleeding of variables into other contexts.
To know more about this ECMA6 feature, look at the MDN pages on let and const.