PluginProbe
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) / 1.0.3
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) v1.0.3
9.1.2 9.1.1 9.1.0 9.0.2 9.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 All 153 releases
wp-analytify / js / selectFx.js

selectFx.js in Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) 1.0.3, at js/selectFx.js

325 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * selectFx.js v1.0.0
3 * http://www.codrops.com
4 *
5 * Licensed under the MIT license.
6 * http://www.opensource.org/licenses/mit-license.php
7 *
8 * Copyright 2014, Codrops
9 * http://www.codrops.com
10 */
11 ;( function( window ) {
12
13 'use strict';
14
15 /**
16 * based on from https://github.com/inuyaksa/jquery.nicescroll/blob/master/jquery.nicescroll.js
17 */
18 function hasParent( e, p ) {
19 if (!e) return false;
20 var el = e.target||e.srcElement||e||false;
21 while (el && el != p) {
22 el = el.parentNode||false;
23 }
24 return (el!==false);
25 };
26
27 /**
28 * extend obj function
29 */
30 function extend( a, b ) {
31 for( var key in b ) {
32 if( b.hasOwnProperty( key ) ) {
33 a[key] = b[key];
34 }
35 }
36 return a;
37 }
38
39 /**
40 * SelectFx function
41 */
42 function SelectFx( el, options ) {
43 this.el = el;
44 this.options = extend( {}, this.options );
45 extend( this.options, options );
46 this._init();
47 }
48
49 /**
50 * SelectFx options
51 */
52 SelectFx.prototype.options = {
53 // if true all the links will open in a new tab.
54 // if we want to be redirected when we click an option, we need to define a data-link attr on the option of the native select element
55 newTab : true,
56 // when opening the select element, the default placeholder (if any) is shown
57 stickyPlaceholder : true,
58 // callback when changing the value
59 onChange : function( val ) { return false; }
60 }
61
62 /**
63 * init function
64 * initialize and cache some vars
65 */
66 SelectFx.prototype._init = function() {
67 // check if we are using a placeholder for the native select box
68 // we assume the placeholder is disabled and selected by default
69 var selectedOpt = this.el.querySelector( 'option[selected]' );
70 this.hasDefaultPlaceholder = selectedOpt && selectedOpt.disabled;
71
72 // get selected option (either the first option with attr selected or just the first option)
73 this.selectedOpt = selectedOpt || this.el.querySelector( 'option' );
74
75 // create structure
76 this._createSelectEl();
77
78 // all options
79 this.selOpts = [].slice.call( this.selEl.querySelectorAll( 'li[data-option]' ) );
80
81 // total options
82 this.selOptsCount = this.selOpts.length;
83
84 // current index
85 this.current = this.selOpts.indexOf( this.selEl.querySelector( 'li.cs-selected' ) ) || -1;
86
87 // placeholder elem
88 this.selPlaceholder = this.selEl.querySelector( 'span.cs-placeholder' );
89
90 // init events
91 this._initEvents();
92 }
93
94 /**
95 * creates the structure for the select element
96 */
97 SelectFx.prototype._createSelectEl = function() {
98 var self = this, options = '', createOptionHTML = function(el) {
99 var optclass = '', classes = '', link = '';
100
101 if( el.selectedOpt && !this.foundSelected && !this.hasDefaultPlaceholder ) {
102 classes += 'cs-selected ';
103 this.foundSelected = true;
104 }
105 // extra classes
106 if( el.getAttribute( 'data-class' ) ) {
107 classes += el.getAttribute( 'data-class' );
108 }
109 // link options
110 if( el.getAttribute( 'data-link' ) ) {
111 link = 'data-link=' + el.getAttribute( 'data-link' );
112 }
113
114 if( classes !== '' ) {
115 optclass = 'class="' + classes + '" ';
116 }
117
118 return '<li ' + optclass + link + ' data-option data-value="' + el.value + '"><a href="#nogo" data-target="' + el.getAttribute( 'data-model' ) +'"><span>' + el.textContent + '</span></a></li>';
119 };
120
121 [].slice.call( this.el.children ).forEach( function(el) {
122 if( el.disabled ) { return; }
123
124 var tag = el.tagName.toLowerCase();
125
126 if( tag === 'option' ) {
127 options += createOptionHTML(el);
128 }
129 else if( tag === 'optgroup' ) {
130 options += '<li class="cs-optgroup"><span>' + el.label + '</span><ul>';
131 [].slice.call( el.children ).forEach( function(opt) {
132 options += createOptionHTML(opt);
133 } )
134 options += '</ul></li>';
135 }
136 } );
137
138 var opts_el = '<div class="cs-options"><ul>' + options + '</ul></div>';
139 this.selEl = document.createElement( 'div' );
140 this.selEl.className = this.el.className;
141 this.selEl.tabIndex = this.el.tabIndex;
142 this.selEl.innerHTML = '<span class="cs-placeholder btn analitify_btn btn-default">' + this.selectedOpt.textContent + '</span>' + opts_el;
143 this.el.parentNode.appendChild( this.selEl );
144 this.selEl.appendChild( this.el );
145 }
146
147 /**
148 * initialize the events
149 */
150 SelectFx.prototype._initEvents = function() {
151 var self = this;
152
153 // open/close select
154 this.selPlaceholder.addEventListener( 'click', function() {
155 self._toggleSelect();
156 } );
157
158 // clicking the options
159 this.selOpts.forEach( function(opt, idx) {
160 opt.addEventListener( 'click', function() {
161 self.current = idx;
162 self._changeOption();
163 // close select elem
164 self._toggleSelect();
165 } );
166 } );
167
168 // close the select element if the target it´s not the select element or one of its descendants..
169 document.addEventListener( 'click', function(ev) {
170 var target = ev.target;
171 if( self._isOpen() && target !== self.selEl && !hasParent( target, self.selEl ) ) {
172 self._toggleSelect();
173 }
174 } );
175
176 // keyboard navigation events
177 this.selEl.addEventListener( 'keydown', function( ev ) {
178 var keyCode = ev.keyCode || ev.which;
179
180 switch (keyCode) {
181 // up key
182 case 38:
183 ev.preventDefault();
184 self._navigateOpts('prev');
185 break;
186 // down key
187 case 40:
188 ev.preventDefault();
189 self._navigateOpts('next');
190 break;
191 // space key
192 case 32:
193 ev.preventDefault();
194 if( self._isOpen() && typeof self.preSelCurrent != 'undefined' && self.preSelCurrent !== -1 ) {
195 self._changeOption();
196 }
197 self._toggleSelect();
198 break;
199 // enter key
200 case 13:
201 ev.preventDefault();
202 if( self._isOpen() && typeof self.preSelCurrent != 'undefined' && self.preSelCurrent !== -1 ) {
203 self._changeOption();
204 self._toggleSelect();
205 }
206 break;
207 // esc key
208 case 27:
209 ev.preventDefault();
210 if( self._isOpen() ) {
211 self._toggleSelect();
212 }
213 break;
214 }
215 } );
216 }
217
218 /**
219 * navigate with up/dpwn keys
220 */
221 SelectFx.prototype._navigateOpts = function(dir) {
222 if( !this._isOpen() ) {
223 this._toggleSelect();
224 }
225
226 var tmpcurrent = typeof this.preSelCurrent != 'undefined' && this.preSelCurrent !== -1 ? this.preSelCurrent : this.current;
227
228 if( dir === 'prev' && tmpcurrent > 0 || dir === 'next' && tmpcurrent < this.selOptsCount - 1 ) {
229 // save pre selected current - if we click on option, or press enter, or press space this is going to be the index of the current option
230 this.preSelCurrent = dir === 'next' ? tmpcurrent + 1 : tmpcurrent - 1;
231 // remove focus class if any..
232 this._removeFocus();
233 // add class focus - track which option we are navigating
234 classie.add( this.selOpts[this.preSelCurrent], 'cs-focus' );
235 }
236 }
237
238 /**
239 * open/close select
240 * when opened show the default placeholder if any
241 */
242 SelectFx.prototype._toggleSelect = function() {
243 // remove focus class if any..
244 this._removeFocus();
245
246 if( this._isOpen() ) {
247 if( this.current !== -1 ) {
248 // update placeholder text
249 this.selPlaceholder.textContent = this.selOpts[ this.current ].textContent;
250 }
251 classie.remove( this.selEl, 'cs-active' );
252 }
253 else {
254 if( this.hasDefaultPlaceholder && this.options.stickyPlaceholder ) {
255 // everytime we open we wanna see the default placeholder text
256 this.selPlaceholder.textContent = this.selectedOpt.textContent;
257 }
258 classie.add( this.selEl, 'cs-active' );
259 }
260 }
261
262 /**
263 * change option - the new value is set
264 */
265 SelectFx.prototype._changeOption = function() {
266 // if pre selected current (if we navigate with the keyboard)...
267 if( typeof this.preSelCurrent != 'undefined' && this.preSelCurrent !== -1 ) {
268 this.current = this.preSelCurrent;
269 this.preSelCurrent = -1;
270 }
271
272 // current option
273 var opt = this.selOpts[ this.current ];
274
275 // update current selected value
276 this.selPlaceholder.textContent = opt.textContent;
277
278 // change native select element´s value
279 this.el.value = opt.getAttribute( 'data-value' );
280
281 // remove class cs-selected from old selected option and add it to current selected option
282 var oldOpt = this.selEl.querySelector( 'li.cs-selected' );
283 if( oldOpt ) {
284 classie.remove( oldOpt, 'cs-selected' );
285 }
286 classie.add( opt, 'cs-selected' );
287
288 // if there´s a link defined
289 if( opt.getAttribute( 'data-link' ) ) {
290 // open in new tab?
291 if( this.options.newTab ) {
292 window.open( opt.getAttribute( 'data-link' ), '_blank' );
293 }
294 else {
295 window.location = opt.getAttribute( 'data-link' );
296 }
297 }
298
299 // callback
300 this.options.onChange( this.el.value );
301 }
302
303 /**
304 * returns true if select element is opened
305 */
306 SelectFx.prototype._isOpen = function(opt) {
307 return classie.has( this.selEl, 'cs-active' );
308 }
309
310 /**
311 * removes the focus class from the option
312 */
313 SelectFx.prototype._removeFocus = function(opt) {
314 var focusEl = this.selEl.querySelector( 'li.cs-focus' )
315 if( focusEl ) {
316 classie.remove( focusEl, 'cs-focus' );
317 }
318 }
319
320 /**
321 * add to global namespace
322 */
323 window.SelectFx = SelectFx;
324
325 } )( window );