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

vendor/CMB2/js/cmb2-char-counter.js   A

Complexity

Total Complexity 25
Complexity/F 2.08

Size

Lines of Code 208
Function Count 12

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 25
eloc 68
mnd 13
bc 13
fnc 12
dl 0
loc 208
rs 10
bpm 1.0833
cpm 2.0833
noi 5
c 0
b 0
f 0
1
/**
2
 * Used for character counters
3
 */
4
window.CMB2 = window.CMB2 || {};
5
window.CMB2.charcounter = window.CMB2.charcounter || {};
6
7
( function(window, document, $, cmb, counter ) {
8
	'use strict';
9
10
	if ( ! wp.utils || ! wp.utils.WordCounter ) {
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...
11
		return cmb.log( 'Cannot find wp.utils!' );
12
	}
13
14
	// Private variables
15
	counter.counters = {};
16
	var counters     = counter.counters;
17
	var wpCounter    = new wp.utils.WordCounter();
18
19
	/**
20
	 * Update a field's character counter
21
	 *
22
	 * @since  2.7.0
23
	 *
24
	 * @param {string} field_id
25
	 *
26
	 * @return {int}
27
	 */
28
	counter.updateCounter = function( field_id ) {
29
		// No counter?
30
		if ( ! counters.hasOwnProperty( field_id ) ) {
31
			return null;
32
		}
33
34
		var instance = counters[ field_id ];
35
		var wysiwyg  = instance.editor && ! instance.editor.isHidden();
36
37
		// Are we dealing with WYSIWYG visual editor, or textarea / WYSIWYG textarea?
38
		var text     = wysiwyg ? instance.editor.getContent( { format: 'raw' } ) : cmb.$id( field_id ).val().trim();
39
		var count    = wpCounter.count( text, instance.type );
40
		var exceeded = instance.max && count > instance.max;
41
42
		// Number remaining when max is defined
43
		var val      = instance.max ? instance.max - count : count;
44
45
		// Over maximum?
46
		instance.$el.parents( '.cmb2-char-counter-wrap' )[ exceeded ? 'addClass' : 'removeClass' ]( 'cmb2-max-exceeded' );
47
48
		// Update counter, and update counter input width.
49
		instance.$el.val( val ).outerWidth( ( ( 8 * String( val ).length ) + 15 ) + 'px' );
50
51
		return count;
52
	};
53
54
	counter.instantiate = function( $el ) {
55
		var data = $el.data();
56
57
		// Add counter details if not already done
58
		if ( ! ( data.fieldId in counters ) ) {
59
60
			var instance = {
61
				$el    : $el,
62
				max    : data.max,
63
				type   : 'words' === data.counterType ? 'words' : 'characters_including_spaces',
64
				editor : false,
65
			};
66
67
			counters[ data.fieldId ] = instance;
68
69
			// Initialise counter
70
			counter.updateCounter( data.fieldId );
71
		}
72
	};
73
74
	/**
75
	 * Initializes all character counters. Hooked to cmb_init.
76
	 *
77
	 * @since  2.7.0
78
	 *
79
	 * @param {bool} init First init?
80
	 *
81
	 * @return {void}
82
	 */
83
	counter.initAll = function() {
84
85
		// Gather counters and initialise
86
		$( '.cmb2-char-counter' ).each( function() {
87
			counter.instantiate( $( this ) );
88
		});
89
	};
90
91
	/**
92
	 * Initializes WYSIWYG editors. Hooked to tinymce-editor-init
93
	 *
94
	 * @since  2.7.0
95
	 *
96
	 * @param {object} evt
97
	 * @param {object} editor
98
	 *
99
	 * @return {void}
100
	 */
101
	counter.initWysiwyg = function( evt, editor ) {
102
103
		// Check if it's one of our WYSIWYGs
104
		// Should have already been registered in counters via hidden textarea
105
		if ( editor.id in counters ) {
106
107
			// Add editor to counter
108
			counters[ editor.id ].editor = editor;
109
110
			// Add nodechange event
111
			editor.on( 'nodechange keyup', counter.countWysiwyg );
112
		}
113
	};
114
115
	/**
116
	 * Initializes after a new repeatable row has been added. Hooked to cmb2_add_row
117
	 *
118
	 * @since  2.7.0
119
	 *
120
	 * @param  {object} evt A jQuery-normalized event object.
121
	 * @param  {object} $row A jQuery dom element object for the group row.
122
	 *
123
	 * @return {void}
124
	 */
125
	counter.addRow = function( evt, $row ) {
126
127
		// Character counters in row?
128
		$row.find( '.cmb2-char-counter' ).each( function() {
129
130
			// Update attributes
131
			var $this    = $( this );
132
			var id       = $this.attr( 'id' );
133
			var field_id = id.replace( /^char-counter-/, '' );
134
			$this.attr( 'data-field-id', field_id ).data( 'field-id', field_id );
135
136
			counter.instantiate( $this );
137
		});
138
	};
139
140
	/**
141
	 * Clean the counters array.
142
	 * Removes counters after a repeatable row has been removed. Hooked to cmb2_remove_row.
143
	 *
144
	 * @since  2.7.0
145
	 *
146
	 * @return {void}
147
	 */
148
	counter.cleanCounters = function() {
149
		var field_id, remove = [];
150
151
		// Got through counters
152
		for ( field_id in counters ) {
153
			// Check for element, gather for removal
154
			if ( ! document.getElementById( field_id ) ) {
155
				remove.push( field_id );
156
			}
157
		}
158
159
		// Anything to remove?
160
		if ( remove.length ) {
161
			_.each( remove, function( field_id ) {
0 ignored issues
show
Bug introduced by
The variable _ seems to be never declared. If this is a global, consider adding a /** global: _ */ 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...
162
				delete counters[ field_id ];
163
			});
164
		}
165
	};
166
167
	/**
168
	 * Counts the value of wysiwyg on the keyup event.
169
	 *
170
	 * @since  2.7.0
171
	 *
172
	 * @param  {object} evt
173
	 *
174
	 * @return {void}
175
	 */
176
	counter.countWysiwyg = _.throttle( function( evt ) {
0 ignored issues
show
Bug introduced by
The variable _ seems to be never declared. If this is a global, consider adding a /** global: _ */ 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...
177
178
		// Init event
179
		if ( evt.hasOwnProperty( 'element' ) ) {
180
			return counter.updateCounter( $( evt.element ).data( 'id' ) );
181
		}
182
183
		// Nodechange event
184
		if ( evt.hasOwnProperty( 'currentTarget' ) ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if evt.hasOwnProperty("currentTarget") 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...
185
			return counter.updateCounter( $( evt.currentTarget ).data( 'id' ) );
186
		}
187
188
	} );
189
190
	/**
191
	 * Counts the value of textarea on the keyup event.
192
	 *
193
	 * @since  2.7.0
194
	 *
195
	 * @param  {object} evt
196
	 *
197
	 * @return {void}
198
	 */
199
	counter.countTextarea = _.throttle( function(evt) {
200
		counter.updateCounter( evt.currentTarget.id );
201
	}, 400 );
202
203
	// Hook in our event callbacks.
204
	$( document )
205
		.on( 'cmb_init', counter.initAll )
206
		.on( 'tinymce-editor-init', counter.initWysiwyg )
207
		.on( 'cmb2_add_row', counter.addRow )
208
		.on( 'cmb2_remove_row', counter.cleanCounters )
209
		.on( 'input keyup', '.cmb2-count-chars', counter.countTextarea );
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...
210
211
} )( window, document, jQuery, window.CMB2, window.CMB2.charcounter );
212