Passed
Push — add/multiplan ( f03a15...eb47db )
by Chris
04:55
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
eloc 68
c 0
b 0
f 0
dl 0
loc 208
rs 10
wmc 25
mnd 13
bc 13
fnc 12
bpm 1.0833
cpm 2.0833
noi 5
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 ) {
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 ) {
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 ) {
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' ) ) {
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 );
210
211
} )( window, document, jQuery, window.CMB2, window.CMB2.charcounter );
212