Passed
Push — master ( 8a7fa4...223132 )
by Paul
06:19
created

GLSR.search.initEvents   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
/** global: _, GLSR, x, wp */
2
GLSR.search = function( el, options ) {
3
	this.el = Object.prototype.toString.call( el ) === '[object String]' ? x( el ) : el;
4
	this.options = options;
5
	this.searchTerm = null;
6
	this.init();
7
};
8
9
GLSR.search.prototype = {
10
11
	defaults: {
12
		action: null,
13
		exclude: [],
14
		onInit: null,
15
		onResultClick: null,
16
		results: {},
17
		selected: -1,
18
		selectedClass: 'glsr-selected-result',
19
		selectorEntries: '.glsr-strings-table tbody',
20
		selectorResults: '.glsr-search-results',
21
		selectorSearch: '.glsr-search-input',
22
		// entriesEl
23
		// resultsEl
24
		// searchEl
25
	},
26
27
	/** @return void */
28
	init: function() {
29
		this.options = x.extend( {}, this.defaults, this.options );
30
		if( !this.el.length )return;
31
		this.options.entriesEl = this.el.parent().find( this.options.selectorEntries );
32
		this.options.resultsEl = this.el.find( this.options.selectorResults );
33
		this.options.searchEl = this.el.find( this.options.selectorSearch );
34
		this.options.searchEl.attr( 'aria-describedby', 'live-search-desc' );
35
		if( typeof this.options.onInit === 'function' ) {
36
			this.options.onInit.call( this );
37
		}
38
		this.initEvents();
39
	},
40
41
	/** @return void */
42
	initEvents: function() {
43
		this.options.searchEl.on( 'input', _.debounce( this.onSearchInput.bind( this ), 500 ));
44
		this.options.searchEl.on( 'keyup', this.onSearchKeyup.bind( this ));
45
		this.options.searchEl.on( 'keydown keypress', function( ev ) {
46
			if( GLSR.keys.ENTER !== ev.which )return;
47
			ev.preventDefault();
48
		});
49
		x( document ).on( 'click', this.onDocumentClick.bind( this ));
50
		x( document ).on( 'keydown', this.onDocumentKeydown.bind( this ));
51
	},
52
53
	/** @return void */
54
	abort: function() {
55
		if( 'undefined' === typeof this.searchRequest )return;
56
		this.searchRequest.abort();
57
	},
58
59
	/** @return void */
60
	clearResults: function() {
61
		this.abort();
62
		this.options.resultsEl.empty();
63
		this.el.removeClass( 'is-active' );
64
		x( 'body' ).removeClass( 'glsr-focus' );
65
	},
66
67
	/** @return void */// Manage entries
68
	deleteEntry: function( index ) {
69
		var row = this.options.entriesEl.children( 'tr' ).eq( index );
70
		var search = this;
71
		row.find( 'td' ).css({ backgroundColor:'#faafaa' });
72
		row.fadeOut( 350, function() {
73
			x( this ).remove();
74
			search.options.results = {};
75
			search.reindexRows();
76
			search.setVisibility();
77
		});
78
	},
79
80
	/** @return void */
81
	displayResults: function( items ) {
82
		x( 'body' ).addClass( 'glsr-focus' );
83
		this.options.resultsEl.append( items );
84
		this.options.resultsEl.children( 'span' ).on( 'click', this.onResultClick.bind( this ));
85
	},
86
87
	/** @return void */// Manage entries
88
	makeSortable: function() {
89
		this.options.entriesEl.on( 'click', 'a.delete', this.onEntryDelete.bind( this ));
90
		this.options.entriesEl.sortable({
91
			items: 'tr',
92
			tolerance: 'pointer',
93
			start: function( ev, ui ) {
94
				ui.placeholder.height( ui.helper[0].scrollHeight );
95
			},
96
			sort: function( ev, ui ) {
97
				var top = ev.pageY - x( this ).offsetParent().offset().top - ( ui.helper.outerHeight( true ) / 2 );
98
				ui.helper.css({
99
					top: top + 'px',
100
				});
101
			},
102
		});
103
	},
104
105
	/** @return void */
106
	navigateResults: function( diff ) {
107
		this.options.selected += diff;
108
		this.options.results.removeClass( this.options.selectedClass );
109
		if( this.options.selected < 0 ) {
110
			// reached the start (should now allow keydown scroll)
111
			this.options.selected = -1;
112
			this.options.searchEl.focus();
113
		}
114
		if( this.options.selected >= this.options.results.length ) {
115
			// reached the end (should now allow keydown scroll)
116
			this.options.selected = this.options.results.length - 1;
117
		}
118
		if( this.options.selected >= 0 ) {
119
			this.options.results.eq( this.options.selected )
120
				.addClass( this.options.selectedClass )
121
				.focus();
122
		}
123
	},
124
125
	/** @return void */
126
	onDocumentClick: function( ev ) {
127
		if( x( ev.target ).find( this.el ).length && x( 'body' ).hasClass( 'glsr-focus' )) {
128
			this.clearResults();
129
		}
130
	},
131
132
	/** @return void */
133
	onDocumentKeydown: function( ev ) {
134
		if( !this.options.results )return;
135
		if( GLSR.keys.ESC === ev.which ) {
136
			this.clearResults();
137
		}
138
		if( GLSR.keys.ENTER === ev.which || GLSR.keys.SPACE === ev.which ) {
139
			var selected = this.options.resultsEl.find( '.' + this.options.selectedClass );
140
			if( selected ) {
141
				selected.trigger( 'click' );
142
			}
143
		}
144
		if( GLSR.keys.UP === ev.which ) {
145
			ev.preventDefault();
146
			this.navigateResults(-1);
147
		}
148
		if( GLSR.keys.DOWN === ev.which ) {
149
			ev.preventDefault();
150
			this.navigateResults(1);
151
		}
152
	},
153
154
	/** @return void */// Manage entries
155
	onEntryDelete: function( ev ) {
156
		ev.preventDefault();
157
		this.deleteEntry( x( ev.target ).closest( 'tr' ).index() );
158
	},
159
160
	/** @return void */
161
	onResultClick: function( ev ) {
162
		ev.preventDefault();
163
		if( typeof this.options.onResultClick === 'function' ) {
164
			this.options.onResultClick.call( this, ev );
165
		}
166
		this.clearResults();
167
	},
168
169
	/** @return void */
170
	onSearchInput: function( ev ) {
171
		this.abort();
172
		if( this.searchTerm === ev.target.value && this.options.results.length ) {
173
			return this.displayResults( this.options.results );
174
		}
175
		this.options.resultsEl.empty();
176
		this.options.selected = -1;
177
		this.searchTerm = ev.target.value;
178
		if( this.searchTerm === '' ) {
179
			return this.reset();
180
		}
181
		this.el.addClass( 'is-active' );
182
		this.searchRequest = wp.ajax.post( site_reviews.action, {
0 ignored issues
show
Bug introduced by
The variable site_reviews seems to be never declared. If this is a global, consider adding a /** global: site_reviews */ 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...
183
			request: {
184
				action: this.options.action,
185
				exclude: this.options.exclude,
186
				nonce: this.el.find( '#_search_nonce' ).val(),
187
				search: this.searchTerm,
188
			},
189
		}).done( function( response ) {
190
			this.el.removeClass( 'is-active' );
191
			this.displayResults( response.items ? response.items : response.empty );
192
			this.options.results = this.options.resultsEl.children();
193
			delete this.searchRequest;
194
		}.bind( this ));
195
	},
196
197
	/** @return void */
198
	onSearchKeyup: function( ev ) {
199
		if( GLSR.keys.ESC === ev.which ) {
200
			this.reset();
201
		}
202
		if( GLSR.keys.ENTER === ev.which ) {
203
			this.onSearchInput( ev );
204
			ev.preventDefault();
205
		}
206
	},
207
208
	/** @return void */// Manage entries
209
	onUnassign: function( ev ) {
210
		ev.preventDefault();
211
		var assigned = this.el.find( '.description' );
212
		this.el.find( 'input#assigned_to' ).val( '' );
213
		assigned.find( 'a' ).css({ color:'#c00' });
214
		assigned.fadeOut( 'fast', function() {
215
			x( this ).html( '' ).show();
216
		});
217
	},
218
219
	/** @return void */// Manage entries
220
	reindexRows: function() {
221
		var search = this;
222
		this.options.exclude = [];
223
		this.options.entriesEl.children( 'tr' ).each( function( index ) {
224
			x( this ).find( '.glsr-string-td2' ).children().filter( ':input' ).each( function() {
225
				var input = x( this );
226
				var name = input.attr( 'name' ).replace( /\[\d+\]/i, '[' + index + ']' );
227
				input.attr( 'name', name );
228
				if( input.is( '[data-id]' )) {
229
					search.options.exclude.push({ id: input.val() });
230
				}
231
			});
232
		});
233
	},
234
235
	/** @return void */
236
	reset: function() {
237
		this.clearResults();
238
		this.options.results = {};
239
		this.options.searchEl.val( '' );
240
	},
241
242
	/** @return void */// Manage entries
243
	setVisibility: function() {
244
		var action = this.options.entriesEl.children().length > 0 ? 'remove' : 'add';
245
		this.options.entriesEl.parent()[action + 'Class']( 'glsr-hidden' );
246
	},
247
};
248