Passed
Push — master ( 78492a...4f268f )
by Paul
04:26
created

+/scripts/admin/shortcode.js   C

Complexity

Total Complexity 53
Complexity/F 2.12

Size

Lines of Code 229
Function Count 25

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 0
nc 16
dl 0
loc 229
rs 6.96
c 2
b 0
f 0
wmc 53
mnd 2
bc 38
fnc 25
bpm 1.52
cpm 2.12
noi 0

20 Functions

Rating   Name   Duplication   Size   Complexity  
A Shortcode.initTinymceEditor_ 0 3 1
A Shortcode.close_ 0 4 1
A Shortcode.normalizeCount_ 0 4 3
A Shortcode.onClose_ 0 4 2
A Shortcode.normalizeId_ 0 4 2
A Shortcode.open_ 0 4 1
A Shortcode.destroy_ 0 7 2
A Shortcode.normalizeHide_ 0 9 4
A Shortcode.onTrigger_ 0 14 3
A Shortcode.response_ 0 16 4
A Shortcode.normalize_ 0 11 3
A Shortcode.initQuicktagsEditor_ 0 15 2
A Shortcode.onToggle_ 0 8 2
A Shortcode.responsePopup_ 0 11 1
A Shortcode.init_ 0 7 1
A Shortcode.sendToEditor_ 0 10 4
A Shortcode.validateAttributes_ 0 14 4
A Shortcode.submitShortcode_ 0 5 2
A Shortcode.responseButtons_ 0 10 1
A shortcode.js ➔ Shortcode 0 19 4

How to fix   Complexity   

Complexity

Complex classes like +/scripts/admin/shortcode.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: GLSR, jQuery */
2
;(function( editor, tinymce, x ) {
3
4
	'use strict';
5
6
	var Shortcode = function( selector ) {
7
		this.el = document.querySelector( selector );
8
		if( !this.el )return;
9
		this.current = null; // this.current is used by scForm to trigger the correct popup
10
		this.editor = null;
11
		this.button = this.el.querySelector( 'button' );
12
		this.menuItems = this.el.querySelectorAll( '.mce-menu-item' );
13
		if( !this.button || !this.menuItems.length )return;
14
		this.create = function( editor_id ) {
15
			this.editor = tinymce.get( editor_id );
16
			if( !this.editor )return;
17
			var request = {
18
				action: 'mce-shortcode',
19
				shortcode: this.current,
20
			};
21
			(new GLSR.Ajax( request )).post( this.response_.bind( this ));
22
		};
23
		this.init_();
24
	};
25
26
	Shortcode.prototype = {
27
		attributes_: {},
28
		hiddenKeys_: [],
29
30
		/** @return void */
31
		init_: function() {
32
			document.addEventListener( 'click', this.onClose_.bind( this ));
33
			this.button.addEventListener( 'click', this.onToggle_.bind( this ));
34
			this.menuItems.forEach( function( item ) {
35
				item.addEventListener( 'click', this.onTrigger_.bind( this ));
36
			}.bind( this ));
37
		},
38
39
		/** @return void */
40
		initTinymceEditor_: function() {
41
			tinymce.execCommand( 'GLSR_Shortcode' );
42
		},
43
44
		/** @return void */
45
		initQuicktagsEditor_: function() {
46
			if( x( '#scTemp' ).length ) {
47
				this.initTinymceEditor_();
48
				return;
49
			}
50
			x( 'body' ).append( '<textarea id="scTemp" style="display:none!important;"/>' );
51
			tinymce.init({
52
				elements: 'scTemp',
53
				mode: 'exact',
54
				plugins: ['glsr_shortcode', 'wplink'],
55
			});
56
			setTimeout( function() {
57
				this.initTinymceEditor_();
58
			}, 200 );
59
		},
60
61
		/** @return void */
62
		close_: function() {
63
			x( this.button ).removeClass( 'active' );
64
			x( this.el ).find( '.glsr-mce-menu' ).hide();
65
		},
66
67
		/** @return void */
68
		destroy_: function() {
69
			var tmp = x( '#scTemp' );
70
			if( tmp.length ) {
71
				tinymce.get( 'scTemp' ).remove();
72
				tmp.remove();
73
			}
74
		},
75
76
		/** @return void */
77
		normalize_: function( attributes ) {
78
			this.attributes_ = attributes;
79
			this.hiddenKeys_ = [];
80
			for( var key in attributes ) {
81
				if( !attributes.hasOwnProperty( key ))continue;
82
				this.normalizeCount_( key );
83
				this.normalizeHide_( key );
84
				this.normalizeId_( key );
85
			}
86
			this.attributes_.hide = this.hiddenKeys_.join( ',' );
87
		},
88
89
		/** @return void */
90
		normalizeCount_: function( key ) {
91
			if( key !== 'count' || x.isNumeric( this.attributes_[key] ))return;
92
			this.attributes_[key] = '';
93
		},
94
95
		/** @return void */
96
		normalizeHide_: function( key ) {
97
			if( !GLSR.hiddenkeys.hasOwnProperty( this.current ))return;
98
			var value = key.substring('hide_'.length);
99
			if( GLSR.hiddenkeys[this.current].indexOf( value ) === -1 )return;
100
			if( this.attributes_[key] ) {
101
				this.hiddenKeys_.push( value );
102
			}
103
			delete this.attributes_[key];
104
		},
105
106
		/** @return void */
107
		normalizeId_: function( key ) {
108
			if( key !== 'id' )return;
109
			this.attributes_[key] = (+new Date()).toString(36);
110
		},
111
112
		/** @return void */
113
		onClose_: function( ev ) {
114
			if( x( ev.target ).closest( x( this.el )).length )return;
115
			this.close_();
116
		},
117
118
		/** @return void */
119
		onToggle_: function( ev ) {
120
			ev.preventDefault();
121
			if( ev.target.classList.contains( 'active' )) {
122
				this.close_();
123
				return;
124
			}
125
			this.open_();
126
		},
127
128
		/** @return void */
129
		onTrigger_: function( ev ) {
130
			ev.preventDefault();
131
			this.current = ev.target.dataset.shortcode;
132
			if( !this.current )return;
133
			if( tinymce.get( window.wpActiveEditor )) {
134
				this.initTinymceEditor_();
135
			}
136
			else {
137
				this.initQuicktagsEditor_();
138
			}
139
			setTimeout( function() {
140
				this.close_();
141
			}.bind( this ), 100 );
142
		},
143
144
		/** @return void */
145
		open_: function() {
146
			x( this.button ).addClass( 'active' );
147
			x( this.el ).find( '.glsr-mce-menu' ).show();
148
		},
149
150
		/** @return void */
151
		response_: function( response ) {
152
			if( !response )return;
153
			if( response.body.length === 0 ) {
154
				window.send_to_editor( '[' + response.shortcode + ']' );
155
				this.destroy_();
156
				return;
157
			}
158
			var popup = this.responsePopup_( response );
159
			// Change the buttons if server-side validation failed
160
			if( response.ok.constructor === Array ) {
161
				popup.buttons[0].text = response.ok[0];
162
				popup.buttons[0].onclick = 'close';
163
				delete popup.buttons[1];
164
			}
165
			this.editor.windowManager.open( popup );
166
		},
167
168
		/** @return array */
169
		responseButtons_: function( response ) {
170
			return [{
171
				classes: 'btn glsr-btn primary',
172
				onclick: this.submitShortcode_.bind( this ),
173
				text: response.ok,
174
			},{
175
				onclick: 'close',
176
				text: response.close,
177
			}];
178
		},
179
180
		/** @return object */
181
		responsePopup_: function( response ) {
182
			return {
183
				title: response.title,
184
				body: response.body,
185
				classes: 'glsr-mce-popup',
186
				minWidth: 320,
187
				buttons: this.responseButtons_( response ),
188
				onsubmit: this.sendToEditor_.bind( this, response ),
189
				onclose: this.destroy_.bind( this ),
190
			};
191
		},
192
193
		/** @return void */
194
		sendToEditor_: function( response, ev ) {
195
			var attributes = '';
196
			this.normalize_( ev.data );
197
			for( var key in this.attributes_ ) {
198
				if( this.attributes_.hasOwnProperty( key ) && this.attributes_[key] !== '' ) {
199
					attributes += ' ' + key + '="' + this.attributes_[key] + '"';
200
				}
201
			}
202
			window.send_to_editor( '[' + response.shortcode + attributes + ']' );
203
		},
204
205
		/** @return void */
206
		submitShortcode_: function() {
207
			var currentWindow = this.editor.windowManager.getWindows()[0];
208
			if( !this.validateAttributes_( currentWindow ))return;
209
			currentWindow.submit();
210
		},
211
212
		/** @return bool */
213
		validateAttributes_: function( currentWindow ) {
214
			var field;
215
			var is_valid = true;
216
			var requiredAttributes = GLSR.shortcodes[this.current];
217
			for( var id in requiredAttributes ) {
218
				field = currentWindow.find( '#' + id )[0];
219
				if( typeof field !== 'undefined' && field.state.data.value === '' ) {
220
					is_valid = false;
221
					alert( requiredAttributes[id] );
222
					break;
223
				}
224
			}
225
			return is_valid;
226
		},
227
	};
228
229
	GLSR.Shortcode = Shortcode;
230
})( window.editor, window.tinymce, jQuery );
231