resources/assets/switchery/dist/switchery.js   F
last analyzed

Complexity

Total Complexity 305
Complexity/F 2.93

Size

Lines of Code 1956
Function Count 104

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
nc 0
dl 0
loc 1956
rs 2.4
c 0
b 0
f 0
wmc 305
mnd 4
bc 218
fnc 104
bpm 2.0961
cpm 2.9326
noi 14

17 Functions

Rating   Name   Duplication   Size   Complexity  
B require.register(ꞌ[email protected]ꞌ) 0 179 1
B require.register(ꞌ[email protected]ꞌ) 0 45 1
A require.define 0 5 1
A switchery.js ➔ require 0 12 4
B require.register(ꞌ[email protected]ꞌ) 0 37 4
D require.latest 0 41 9
B require.register(ꞌ[email protected]ꞌ) 0 24 1
A require.register(ꞌ[email protected]ꞌ) 0 49 1
B require.register(ꞌswitcheryꞌ) 0 389 1
A require.register(ꞌ[email protected]ꞌ) 0 66 1
B require.register(ꞌ[email protected]ꞌ) 0 187 1
A switchery.js ➔ define(ꞌSwitcheryꞌ) 0 1 1
A require.register(ꞌ[email protected]ꞌ) 0 9 1
A require.register 0 5 1
B require.register(ꞌ[email protected]ꞌ) 0 791 5
C require.helper.semVerSort 0 21 11
A require.register(ꞌ[email protected]ꞌ) 0 22 1

How to fix   Complexity   

Complexity

Complex classes like resources/assets/switchery/dist/switchery.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
2
;(function(){
3
4
/**
5
 * Require the module at `name`.
6
 *
7
 * @param {String} name
8
 * @return {Object} exports
9
 * @api public
10
 */
11
12
function require(name) {
13
  var module = require.modules[name];
14
  if (!module) throw new Error('failed to require "' + name + '"');
15
16
  if (!('exports' in module) && typeof module.definition === 'function') {
17
    module.client = module.component = true;
18
    module.definition.call(this, module.exports = {}, module);
19
    delete module.definition;
20
  }
21
22
  return module.exports;
23
}
24
25
/**
26
 * Meta info, accessible in the global scope unless you use AMD option.
27
 */
28
29
require.loader = 'component';
30
31
/**
32
 * Internal helper object, contains a sorting function for semantiv versioning
33
 */
34
require.helper = {};
35
require.helper.semVerSort = function(a, b) {
36
  var aArray = a.version.split('.');
37
  var bArray = b.version.split('.');
38
  for (var i=0; i<aArray.length; ++i) {
39
    var aInt = parseInt(aArray[i], 10);
40
    var bInt = parseInt(bArray[i], 10);
41
    if (aInt === bInt) {
42
      var aLex = aArray[i].substr((""+aInt).length);
43
      var bLex = bArray[i].substr((""+bInt).length);
44
      if (aLex === '' && bLex !== '') return 1;
45
      if (aLex !== '' && bLex === '') return -1;
46
      if (aLex !== '' && bLex !== '') return aLex > bLex ? 1 : -1;
47
      continue;
0 ignored issues
show
Unused Code introduced by
This continue has no effect on the loop flow and can be removed.
Loading history...
48
    } else if (aInt > bInt) {
49
      return 1;
50
    } else {
51
      return -1;
52
    }
53
  }
54
  return 0;
55
}
56
57
/**
58
 * Find and require a module which name starts with the provided name.
59
 * If multiple modules exists, the highest semver is used.
60
 * This function can only be used for remote dependencies.
61
62
 * @param {String} name - module name: `user~repo`
63
 * @param {Boolean} returnPath - returns the canonical require path if true,
64
 *                               otherwise it returns the epxorted module
65
 */
66
require.latest = function (name, returnPath) {
67
  function showError(name) {
68
    throw new Error('failed to find latest module of "' + name + '"');
69
  }
70
  // only remotes with semvers, ignore local files conataining a '/'
71
  var versionRegexp = /(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/;
72
  var remoteRegexp = /(.*)~(.*)/;
73
  if (!remoteRegexp.test(name)) showError(name);
74
  var moduleNames = Object.keys(require.modules);
75
  var semVerCandidates = [];
76
  var otherCandidates = []; // for instance: name of the git branch
77
  for (var i=0; i<moduleNames.length; i++) {
78
    var moduleName = moduleNames[i];
79
    if (new RegExp(name + '@').test(moduleName)) {
80
        var version = moduleName.substr(name.length+1);
81
        var semVerMatch = versionRegexp.exec(moduleName);
82
        if (semVerMatch != null) {
83
          semVerCandidates.push({version: version, name: moduleName});
84
        } else {
85
          otherCandidates.push({version: version, name: moduleName});
86
        }
87
    }
88
  }
89
  if (semVerCandidates.concat(otherCandidates).length === 0) {
90
    showError(name);
91
  }
92
  if (semVerCandidates.length > 0) {
93
    var module = semVerCandidates.sort(require.helper.semVerSort).pop().name;
94
    if (returnPath === true) {
95
      return module;
96
    }
97
    return require(module);
98
  }
99
  // if the build contains more than one branch of the same module
100
  // you should not use this funciton
101
  var module = otherCandidates.sort(function(a, b) {return a.name > b.name})[0].name;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable module already seems to be declared on line 93. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
102
  if (returnPath === true) {
103
    return module;
104
  }
105
  return require(module);
106
}
107
108
/**
109
 * Registered modules.
110
 */
111
112
require.modules = {};
113
114
/**
115
 * Register module at `name` with callback `definition`.
116
 *
117
 * @param {String} name
118
 * @param {Function} definition
119
 * @api private
120
 */
121
122
require.register = function (name, definition) {
123
  require.modules[name] = {
124
    definition: definition
125
  };
126
};
127
128
/**
129
 * Define a module's exports immediately with `exports`.
130
 *
131
 * @param {String} name
132
 * @param {Generic} exports
133
 * @api private
134
 */
135
136
require.define = function (name, exports) {
137
  require.modules[name] = {
138
    exports: exports
139
  };
140
};
141
require.register("[email protected]", function (exports, module) {
142
143
/**
144
 * Transitionize 0.0.2
145
 * https://github.com/abpetkov/transitionize
146
 *
147
 * Authored by Alexander Petkov
148
 * https://github.com/abpetkov
149
 *
150
 * Copyright 2013, Alexander Petkov
151
 * License: The MIT License (MIT)
152
 * http://opensource.org/licenses/MIT
153
 *
154
 */
155
156
/**
157
 * Expose `Transitionize`.
158
 */
159
160
module.exports = Transitionize;
161
162
/**
163
 * Initialize new Transitionize.
164
 *
165
 * @param {Object} element
166
 * @param {Object} props
167
 * @api public
168
 */
169
170
function Transitionize(element, props) {
171
  if (!(this instanceof Transitionize)) return new Transitionize(element, props);
172
173
  this.element = element;
174
  this.props = props || {};
175
  this.init();
176
}
177
178
/**
179
 * Detect if Safari.
180
 *
181
 * @returns {Boolean}
182
 * @api private
183
 */
184
185
Transitionize.prototype.isSafari = function() {
186
  return (/Safari/).test(navigator.userAgent) && (/Apple Computer/).test(navigator.vendor);
187
};
188
189
/**
190
 * Loop though the object and push the keys and values in an array.
191
 * Apply the CSS3 transition to the element and prefix with -webkit- for Safari.
192
 *
193
 * @api private
194
 */
195
196
Transitionize.prototype.init = function() {
197
  var transitions = [];
198
199
  for (var key in this.props) {
200
    transitions.push(key + ' ' + this.props[key]);
201
  }
202
203
  this.element.style.transition = transitions.join(', ');
204
  if (this.isSafari()) this.element.style.webkitTransition = transitions.join(', ');
205
};
206
});
207
208
require.register("[email protected]", function (exports, module) {
209
/**
210
 * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
211
 *
212
 * @version 0.6.11
213
 * @codingstandard ftlabs-jsv2
214
 * @copyright The Financial Times Limited [All Rights Reserved]
215
 * @license MIT License (see LICENSE.txt)
216
 */
217
218
/*jslint browser:true, node:true*/
219
/*global define, Event, Node*/
220
221
222
/**
223
 * Instantiate fast-clicking listeners on the specificed layer.
224
 *
225
 * @constructor
226
 * @param {Element} layer The layer to listen on
227
 */
228
function FastClick(layer) {
229
	'use strict';
230
	var oldOnClick, self = this;
231
232
233
	/**
234
	 * Whether a click is currently being tracked.
235
	 *
236
	 * @type boolean
237
	 */
238
	this.trackingClick = false;
239
240
241
	/**
242
	 * Timestamp for when when click tracking started.
243
	 *
244
	 * @type number
245
	 */
246
	this.trackingClickStart = 0;
247
248
249
	/**
250
	 * The element being tracked for a click.
251
	 *
252
	 * @type EventTarget
253
	 */
254
	this.targetElement = null;
255
256
257
	/**
258
	 * X-coordinate of touch start event.
259
	 *
260
	 * @type number
261
	 */
262
	this.touchStartX = 0;
263
264
265
	/**
266
	 * Y-coordinate of touch start event.
267
	 *
268
	 * @type number
269
	 */
270
	this.touchStartY = 0;
271
272
273
	/**
274
	 * ID of the last touch, retrieved from Touch.identifier.
275
	 *
276
	 * @type number
277
	 */
278
	this.lastTouchIdentifier = 0;
279
280
281
	/**
282
	 * Touchmove boundary, beyond which a click will be cancelled.
283
	 *
284
	 * @type number
285
	 */
286
	this.touchBoundary = 10;
287
288
289
	/**
290
	 * The FastClick layer.
291
	 *
292
	 * @type Element
293
	 */
294
	this.layer = layer;
295
296
	if (!layer || !layer.nodeType) {
297
		throw new TypeError('Layer must be a document node');
298
	}
299
300
	/** @type function() */
301
	this.onClick = function() { return FastClick.prototype.onClick.apply(self, arguments); };
302
303
	/** @type function() */
304
	this.onMouse = function() { return FastClick.prototype.onMouse.apply(self, arguments); };
305
306
	/** @type function() */
307
	this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); };
308
309
	/** @type function() */
310
	this.onTouchMove = function() { return FastClick.prototype.onTouchMove.apply(self, arguments); };
311
312
	/** @type function() */
313
	this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); };
314
315
	/** @type function() */
316
	this.onTouchCancel = function() { return FastClick.prototype.onTouchCancel.apply(self, arguments); };
317
318
	if (FastClick.notNeeded(layer)) {
319
		return;
320
	}
321
322
	// Set up event handlers as required
323
	if (this.deviceIsAndroid) {
324
		layer.addEventListener('mouseover', this.onMouse, true);
325
		layer.addEventListener('mousedown', this.onMouse, true);
326
		layer.addEventListener('mouseup', this.onMouse, true);
327
	}
328
329
	layer.addEventListener('click', this.onClick, true);
330
	layer.addEventListener('touchstart', this.onTouchStart, false);
331
	layer.addEventListener('touchmove', this.onTouchMove, false);
332
	layer.addEventListener('touchend', this.onTouchEnd, false);
333
	layer.addEventListener('touchcancel', this.onTouchCancel, false);
334
335
	// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
336
	// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
337
	// layer when they are cancelled.
338
	if (!Event.prototype.stopImmediatePropagation) {
339
		layer.removeEventListener = function(type, callback, capture) {
340
			var rmv = Node.prototype.removeEventListener;
341
			if (type === 'click') {
342
				rmv.call(layer, type, callback.hijacked || callback, capture);
343
			} else {
344
				rmv.call(layer, type, callback, capture);
345
			}
346
		};
347
348
		layer.addEventListener = function(type, callback, capture) {
349
			var adv = Node.prototype.addEventListener;
350
			if (type === 'click') {
351
				adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
352
					if (!event.propagationStopped) {
353
						callback(event);
354
					}
355
				}), capture);
356
			} else {
357
				adv.call(layer, type, callback, capture);
358
			}
359
		};
360
	}
361
362
	// If a handler is already declared in the element's onclick attribute, it will be fired before
363
	// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
364
	// adding it as listener.
365
	if (typeof layer.onclick === 'function') {
366
367
		// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
368
		// - the old one won't work if passed to addEventListener directly.
369
		oldOnClick = layer.onclick;
370
		layer.addEventListener('click', function(event) {
371
			oldOnClick(event);
372
		}, false);
373
		layer.onclick = null;
374
	}
375
}
376
377
378
/**
379
 * Android requires exceptions.
380
 *
381
 * @type boolean
382
 */
383
FastClick.prototype.deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
384
385
386
/**
387
 * iOS requires exceptions.
388
 *
389
 * @type boolean
390
 */
391
FastClick.prototype.deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent);
392
393
394
/**
395
 * iOS 4 requires an exception for select elements.
396
 *
397
 * @type boolean
398
 */
399
FastClick.prototype.deviceIsIOS4 = FastClick.prototype.deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
400
401
402
/**
403
 * iOS 6.0(+?) requires the target element to be manually derived
404
 *
405
 * @type boolean
406
 */
407
FastClick.prototype.deviceIsIOSWithBadTarget = FastClick.prototype.deviceIsIOS && (/OS ([6-9]|\d{2})_\d/).test(navigator.userAgent);
408
409
410
/**
411
 * Determine whether a given element requires a native click.
412
 *
413
 * @param {EventTarget|Element} target Target DOM element
414
 * @returns {boolean} Returns true if the element needs a native click
415
 */
416
FastClick.prototype.needsClick = function(target) {
417
	'use strict';
418
	switch (target.nodeName.toLowerCase()) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
419
420
	// Don't send a synthetic click to disabled inputs (issue #62)
421
	case 'button':
422
	case 'select':
423
	case 'textarea':
424
		if (target.disabled) {
425
			return true;
426
		}
427
428
		break;
429
	case 'input':
430
431
		// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
432
		if ((this.deviceIsIOS && target.type === 'file') || target.disabled) {
433
			return true;
434
		}
435
436
		break;
437
	case 'label':
438
	case 'video':
439
		return true;
440
	}
441
442
	return (/\bneedsclick\b/).test(target.className);
443
};
444
445
446
/**
447
 * Determine whether a given element requires a call to focus to simulate click into element.
448
 *
449
 * @param {EventTarget|Element} target Target DOM element
450
 * @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
451
 */
452
FastClick.prototype.needsFocus = function(target) {
453
	'use strict';
454
	switch (target.nodeName.toLowerCase()) {
455
	case 'textarea':
456
		return true;
457
	case 'select':
458
		return !this.deviceIsAndroid;
459
	case 'input':
460
		switch (target.type) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
461
		case 'button':
462
		case 'checkbox':
463
		case 'file':
464
		case 'image':
465
		case 'radio':
466
		case 'submit':
467
			return false;
468
		}
469
470
		// No point in attempting to focus disabled inputs
471
		return !target.disabled && !target.readOnly;
472
	default:
473
		return (/\bneedsfocus\b/).test(target.className);
474
	}
475
};
476
477
478
/**
479
 * Send a click event to the specified element.
480
 *
481
 * @param {EventTarget|Element} targetElement
482
 * @param {Event} event
483
 */
484
FastClick.prototype.sendClick = function(targetElement, event) {
485
	'use strict';
486
	var clickEvent, touch;
487
488
	// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
489
	if (document.activeElement && document.activeElement !== targetElement) {
490
		document.activeElement.blur();
491
	}
492
493
	touch = event.changedTouches[0];
494
495
	// Synthesise a click event, with an extra attribute so it can be tracked
496
	clickEvent = document.createEvent('MouseEvents');
497
	clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
498
	clickEvent.forwardedTouchEvent = true;
499
	targetElement.dispatchEvent(clickEvent);
500
};
501
502
FastClick.prototype.determineEventType = function(targetElement) {
503
	'use strict';
504
505
	//Issue #159: Android Chrome Select Box does not open with a synthetic click event
506
	if (this.deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
507
		return 'mousedown';
508
	}
509
510
	return 'click';
511
};
512
513
514
/**
515
 * @param {EventTarget|Element} targetElement
516
 */
517
FastClick.prototype.focus = function(targetElement) {
518
	'use strict';
519
	var length;
520
521
	// Issue #160: on iOS 7, some input elements (e.g. date datetime) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
522
	if (this.deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time') {
523
		length = targetElement.value.length;
524
		targetElement.setSelectionRange(length, length);
525
	} else {
526
		targetElement.focus();
527
	}
528
};
529
530
531
/**
532
 * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
533
 *
534
 * @param {EventTarget|Element} targetElement
535
 */
536
FastClick.prototype.updateScrollParent = function(targetElement) {
537
	'use strict';
538
	var scrollParent, parentElement;
539
540
	scrollParent = targetElement.fastClickScrollParent;
541
542
	// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
543
	// target element was moved to another parent.
544
	if (!scrollParent || !scrollParent.contains(targetElement)) {
545
		parentElement = targetElement;
546
		do {
547
			if (parentElement.scrollHeight > parentElement.offsetHeight) {
548
				scrollParent = parentElement;
549
				targetElement.fastClickScrollParent = parentElement;
550
				break;
551
			}
552
553
			parentElement = parentElement.parentElement;
554
		} while (parentElement);
555
	}
556
557
	// Always update the scroll top tracker if possible.
558
	if (scrollParent) {
559
		scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
560
	}
561
};
562
563
564
/**
565
 * @param {EventTarget} targetElement
0 ignored issues
show
Documentation introduced by
The parameter targetElement does not exist. Did you maybe forget to remove this comment?
Loading history...
566
 * @returns {Element|EventTarget}
567
 */
568
FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
569
	'use strict';
570
571
	// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
572
	if (eventTarget.nodeType === Node.TEXT_NODE) {
573
		return eventTarget.parentNode;
574
	}
575
576
	return eventTarget;
577
};
578
579
580
/**
581
 * On touch start, record the position and scroll offset.
582
 *
583
 * @param {Event} event
584
 * @returns {boolean}
585
 */
586
FastClick.prototype.onTouchStart = function(event) {
587
	'use strict';
588
	var targetElement, touch, selection;
589
590
	// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
591
	if (event.targetTouches.length > 1) {
592
		return true;
593
	}
594
595
	targetElement = this.getTargetElementFromEventTarget(event.target);
596
	touch = event.targetTouches[0];
597
598
	if (this.deviceIsIOS) {
599
600
		// Only trusted events will deselect text on iOS (issue #49)
601
		selection = window.getSelection();
602
		if (selection.rangeCount && !selection.isCollapsed) {
603
			return true;
604
		}
605
606
		if (!this.deviceIsIOS4) {
607
608
			// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
609
			// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
610
			// with the same identifier as the touch event that previously triggered the click that triggered the alert.
611
			// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
612
			// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
613
			if (touch.identifier === this.lastTouchIdentifier) {
614
				event.preventDefault();
615
				return false;
616
			}
617
618
			this.lastTouchIdentifier = touch.identifier;
619
620
			// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
621
			// 1) the user does a fling scroll on the scrollable layer
622
			// 2) the user stops the fling scroll with another tap
623
			// then the event.target of the last 'touchend' event will be the element that was under the user's finger
624
			// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
625
			// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
626
			this.updateScrollParent(targetElement);
627
		}
628
	}
629
630
	this.trackingClick = true;
631
	this.trackingClickStart = event.timeStamp;
632
	this.targetElement = targetElement;
633
634
	this.touchStartX = touch.pageX;
635
	this.touchStartY = touch.pageY;
636
637
	// Prevent phantom clicks on fast double-tap (issue #36)
638
	if ((event.timeStamp - this.lastClickTime) < 200) {
639
		event.preventDefault();
640
	}
641
642
	return true;
643
};
644
645
646
/**
647
 * Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
648
 *
649
 * @param {Event} event
650
 * @returns {boolean}
651
 */
652
FastClick.prototype.touchHasMoved = function(event) {
653
	'use strict';
654
	var touch = event.changedTouches[0], boundary = this.touchBoundary;
655
656
	if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
657
		return true;
658
	}
659
660
	return false;
661
};
662
663
664
/**
665
 * Update the last position.
666
 *
667
 * @param {Event} event
668
 * @returns {boolean}
669
 */
670
FastClick.prototype.onTouchMove = function(event) {
671
	'use strict';
672
	if (!this.trackingClick) {
673
		return true;
674
	}
675
676
	// If the touch has moved, cancel the click tracking
677
	if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
678
		this.trackingClick = false;
679
		this.targetElement = null;
680
	}
681
682
	return true;
683
};
684
685
686
/**
687
 * Attempt to find the labelled control for the given label element.
688
 *
689
 * @param {EventTarget|HTMLLabelElement} labelElement
690
 * @returns {Element|null}
691
 */
692
FastClick.prototype.findControl = function(labelElement) {
693
	'use strict';
694
695
	// Fast path for newer browsers supporting the HTML5 control attribute
696
	if (labelElement.control !== undefined) {
697
		return labelElement.control;
698
	}
699
700
	// All browsers under test that support touch events also support the HTML5 htmlFor attribute
701
	if (labelElement.htmlFor) {
702
		return document.getElementById(labelElement.htmlFor);
703
	}
704
705
	// If no for attribute exists, attempt to retrieve the first labellable descendant element
706
	// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
707
	return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
708
};
709
710
711
/**
712
 * On touch end, determine whether to send a click event at once.
713
 *
714
 * @param {Event} event
715
 * @returns {boolean}
716
 */
717
FastClick.prototype.onTouchEnd = function(event) {
718
	'use strict';
719
	var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
720
721
	if (!this.trackingClick) {
722
		return true;
723
	}
724
725
	// Prevent phantom clicks on fast double-tap (issue #36)
726
	if ((event.timeStamp - this.lastClickTime) < 200) {
727
		this.cancelNextClick = true;
728
		return true;
729
	}
730
731
	// Reset to prevent wrong click cancel on input (issue #156).
732
	this.cancelNextClick = false;
733
734
	this.lastClickTime = event.timeStamp;
735
736
	trackingClickStart = this.trackingClickStart;
737
	this.trackingClick = false;
738
	this.trackingClickStart = 0;
739
740
	// On some iOS devices, the targetElement supplied with the event is invalid if the layer
741
	// is performing a transition or scroll, and has to be re-detected manually. Note that
742
	// for this to function correctly, it must be called *after* the event target is checked!
743
	// See issue #57; also filed as rdar://13048589 .
744
	if (this.deviceIsIOSWithBadTarget) {
745
		touch = event.changedTouches[0];
746
747
		// In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
748
		targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
749
		targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
750
	}
751
752
	targetTagName = targetElement.tagName.toLowerCase();
753
	if (targetTagName === 'label') {
754
		forElement = this.findControl(targetElement);
755
		if (forElement) {
756
			this.focus(targetElement);
757
			if (this.deviceIsAndroid) {
758
				return false;
759
			}
760
761
			targetElement = forElement;
762
		}
763
	} else if (this.needsFocus(targetElement)) {
764
765
		// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
766
		// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
767
		if ((event.timeStamp - trackingClickStart) > 100 || (this.deviceIsIOS && window.top !== window && targetTagName === 'input')) {
768
			this.targetElement = null;
769
			return false;
770
		}
771
772
		this.focus(targetElement);
773
774
		// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
775
		if (!this.deviceIsIOS4 || targetTagName !== 'select') {
776
			this.targetElement = null;
777
			event.preventDefault();
778
		}
779
780
		return false;
781
	}
782
783
	if (this.deviceIsIOS && !this.deviceIsIOS4) {
784
785
		// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
786
		// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
787
		scrollParent = targetElement.fastClickScrollParent;
788
		if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
789
			return true;
790
		}
791
	}
792
793
	// Prevent the actual click from going though - unless the target node is marked as requiring
794
	// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
795
	if (!this.needsClick(targetElement)) {
796
		event.preventDefault();
797
		this.sendClick(targetElement, event);
798
	}
799
800
	return false;
801
};
802
803
804
/**
805
 * On touch cancel, stop tracking the click.
806
 *
807
 * @returns {void}
808
 */
809
FastClick.prototype.onTouchCancel = function() {
810
	'use strict';
811
	this.trackingClick = false;
812
	this.targetElement = null;
813
};
814
815
816
/**
817
 * Determine mouse events which should be permitted.
818
 *
819
 * @param {Event} event
820
 * @returns {boolean}
821
 */
822
FastClick.prototype.onMouse = function(event) {
823
	'use strict';
824
825
	// If a target element was never set (because a touch event was never fired) allow the event
826
	if (!this.targetElement) {
827
		return true;
828
	}
829
830
	if (event.forwardedTouchEvent) {
831
		return true;
832
	}
833
834
	// Programmatically generated events targeting a specific element should be permitted
835
	if (!event.cancelable) {
836
		return true;
837
	}
838
839
	// Derive and check the target element to see whether the mouse event needs to be permitted;
840
	// unless explicitly enabled, prevent non-touch click events from triggering actions,
841
	// to prevent ghost/doubleclicks.
842
	if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
843
844
		// Prevent any user-added listeners declared on FastClick element from being fired.
845
		if (event.stopImmediatePropagation) {
846
			event.stopImmediatePropagation();
847
		} else {
848
849
			// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
850
			event.propagationStopped = true;
851
		}
852
853
		// Cancel the event
854
		event.stopPropagation();
855
		event.preventDefault();
856
857
		return false;
858
	}
859
860
	// If the mouse event is permitted, return true for the action to go through.
861
	return true;
862
};
863
864
865
/**
866
 * On actual clicks, determine whether this is a touch-generated click, a click action occurring
867
 * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
868
 * an actual click which should be permitted.
869
 *
870
 * @param {Event} event
871
 * @returns {boolean}
872
 */
873
FastClick.prototype.onClick = function(event) {
874
	'use strict';
875
	var permitted;
876
877
	// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
878
	if (this.trackingClick) {
879
		this.targetElement = null;
880
		this.trackingClick = false;
881
		return true;
882
	}
883
884
	// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
885
	if (event.target.type === 'submit' && event.detail === 0) {
886
		return true;
887
	}
888
889
	permitted = this.onMouse(event);
890
891
	// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
892
	if (!permitted) {
893
		this.targetElement = null;
894
	}
895
896
	// If clicks are permitted, return true for the action to go through.
897
	return permitted;
898
};
899
900
901
/**
902
 * Remove all FastClick's event listeners.
903
 *
904
 * @returns {void}
905
 */
906
FastClick.prototype.destroy = function() {
907
	'use strict';
908
	var layer = this.layer;
909
910
	if (this.deviceIsAndroid) {
911
		layer.removeEventListener('mouseover', this.onMouse, true);
912
		layer.removeEventListener('mousedown', this.onMouse, true);
913
		layer.removeEventListener('mouseup', this.onMouse, true);
914
	}
915
916
	layer.removeEventListener('click', this.onClick, true);
917
	layer.removeEventListener('touchstart', this.onTouchStart, false);
918
	layer.removeEventListener('touchmove', this.onTouchMove, false);
919
	layer.removeEventListener('touchend', this.onTouchEnd, false);
920
	layer.removeEventListener('touchcancel', this.onTouchCancel, false);
921
};
922
923
924
/**
925
 * Check whether FastClick is needed.
926
 *
927
 * @param {Element} layer The layer to listen on
928
 */
929
FastClick.notNeeded = function(layer) {
930
	'use strict';
931
	var metaViewport;
932
	var chromeVersion;
933
934
	// Devices that don't support touch don't need FastClick
935
	if (typeof window.ontouchstart === 'undefined') {
936
		return true;
937
	}
938
939
	// Chrome version - zero for other browsers
940
	chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
0 ignored issues
show
introduced by
There are two consecutive commas which insert an implicit undefined value. If this is indeed intended, consider adding undefined explicitly like so , undefined,.
Loading history...
941
942
	if (chromeVersion) {
943
944
		if (FastClick.prototype.deviceIsAndroid) {
945
			metaViewport = document.querySelector('meta[name=viewport]');
946
947
			if (metaViewport) {
948
				// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
949
				if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
950
					return true;
951
				}
952
				// Chrome 32 and above with width=device-width or less don't need FastClick
953
				if (chromeVersion > 31 && window.innerWidth <= window.screen.width) {
954
					return true;
955
				}
956
			}
957
958
		// Chrome desktop doesn't need FastClick (issue #15)
959
		} else {
960
			return true;
961
		}
962
	}
963
964
	// IE10 with -ms-touch-action: none, which disables double-tap-to-zoom (issue #97)
965
	if (layer.style.msTouchAction === 'none') {
966
		return true;
967
	}
968
969
	return false;
970
};
971
972
973
/**
974
 * Factory method for creating a FastClick object
975
 *
976
 * @param {Element} layer The layer to listen on
977
 */
978
FastClick.attach = function(layer) {
979
	'use strict';
980
	return new FastClick(layer);
981
};
982
983
984
if (typeof define !== 'undefined' && define.amd) {
985
986
	// AMD. Register as an anonymous module.
987
	define(function() {
988
		'use strict';
989
		return FastClick;
990
	});
991
} else if (typeof module !== 'undefined' && module.exports) {
992
	module.exports = FastClick.attach;
993
	module.exports.FastClick = FastClick;
994
} else {
995
	window.FastClick = FastClick;
996
}
997
998
});
999
1000
require.register("[email protected]", function (exports, module) {
1001
module.exports = function(arr, obj){
1002
  if (arr.indexOf) return arr.indexOf(obj);
1003
  for (var i = 0; i < arr.length; ++i) {
1004
    if (arr[i] === obj) return i;
1005
  }
1006
  return -1;
1007
};
1008
});
1009
1010
require.register("[email protected]", function (exports, module) {
1011
/**
1012
 * Module dependencies.
1013
 */
1014
1015
var index = require('[email protected]');
1016
1017
/**
1018
 * Whitespace regexp.
1019
 */
1020
1021
var re = /\s+/;
1022
1023
/**
1024
 * toString reference.
1025
 */
1026
1027
var toString = Object.prototype.toString;
1028
1029
/**
1030
 * Wrap `el` in a `ClassList`.
1031
 *
1032
 * @param {Element} el
1033
 * @return {ClassList}
1034
 * @api public
1035
 */
1036
1037
module.exports = function(el){
1038
  return new ClassList(el);
1039
};
1040
1041
/**
1042
 * Initialize a new ClassList for `el`.
1043
 *
1044
 * @param {Element} el
1045
 * @api private
1046
 */
1047
1048
function ClassList(el) {
1049
  if (!el) throw new Error('A DOM element reference is required');
1050
  this.el = el;
1051
  this.list = el.classList;
1052
}
1053
1054
/**
1055
 * Add class `name` if not already present.
1056
 *
1057
 * @param {String} name
1058
 * @return {ClassList}
1059
 * @api public
1060
 */
1061
1062
ClassList.prototype.add = function(name){
1063
  // classList
1064
  if (this.list) {
1065
    this.list.add(name);
1066
    return this;
1067
  }
1068
1069
  // fallback
1070
  var arr = this.array();
1071
  var i = index(arr, name);
1072
  if (!~i) arr.push(name);
1073
  this.el.className = arr.join(' ');
1074
  return this;
1075
};
1076
1077
/**
1078
 * Remove class `name` when present, or
1079
 * pass a regular expression to remove
1080
 * any which match.
1081
 *
1082
 * @param {String|RegExp} name
1083
 * @return {ClassList}
1084
 * @api public
1085
 */
1086
1087
ClassList.prototype.remove = function(name){
1088
  if ('[object RegExp]' == toString.call(name)) {
1089
    return this.removeMatching(name);
1090
  }
1091
1092
  // classList
1093
  if (this.list) {
1094
    this.list.remove(name);
1095
    return this;
1096
  }
1097
1098
  // fallback
1099
  var arr = this.array();
1100
  var i = index(arr, name);
1101
  if (~i) arr.splice(i, 1);
1102
  this.el.className = arr.join(' ');
1103
  return this;
1104
};
1105
1106
/**
1107
 * Remove all classes matching `re`.
1108
 *
1109
 * @param {RegExp} re
1110
 * @return {ClassList}
1111
 * @api private
1112
 */
1113
1114
ClassList.prototype.removeMatching = function(re){
1115
  var arr = this.array();
1116
  for (var i = 0; i < arr.length; i++) {
1117
    if (re.test(arr[i])) {
1118
      this.remove(arr[i]);
1119
    }
1120
  }
1121
  return this;
1122
};
1123
1124
/**
1125
 * Toggle class `name`, can force state via `force`.
1126
 *
1127
 * For browsers that support classList, but do not support `force` yet,
1128
 * the mistake will be detected and corrected.
1129
 *
1130
 * @param {String} name
1131
 * @param {Boolean} force
1132
 * @return {ClassList}
1133
 * @api public
1134
 */
1135
1136
ClassList.prototype.toggle = function(name, force){
1137
  // classList
1138
  if (this.list) {
1139
    if ("undefined" !== typeof force) {
1140
      if (force !== this.list.toggle(name, force)) {
1141
        this.list.toggle(name); // toggle again to correct
1142
      }
1143
    } else {
1144
      this.list.toggle(name);
1145
    }
1146
    return this;
1147
  }
1148
1149
  // fallback
1150
  if ("undefined" !== typeof force) {
1151
    if (!force) {
1152
      this.remove(name);
1153
    } else {
1154
      this.add(name);
1155
    }
1156
  } else {
1157
    if (this.has(name)) {
1158
      this.remove(name);
1159
    } else {
1160
      this.add(name);
1161
    }
1162
  }
1163
1164
  return this;
1165
};
1166
1167
/**
1168
 * Return an array of classes.
1169
 *
1170
 * @return {Array}
1171
 * @api public
1172
 */
1173
1174
ClassList.prototype.array = function(){
1175
  var str = this.el.className.replace(/^\s+|\s+$/g, '');
1176
  var arr = str.split(re);
1177
  if ('' === arr[0]) arr.shift();
1178
  return arr;
1179
};
1180
1181
/**
1182
 * Check if class `name` is present.
1183
 *
1184
 * @param {String} name
1185
 * @return {ClassList}
1186
 * @api public
1187
 */
1188
1189
ClassList.prototype.has =
1190
ClassList.prototype.contains = function(name){
1191
  return this.list
1192
    ? this.list.contains(name)
1193
    : !! ~index(this.array(), name);
1194
};
1195
1196
});
1197
1198
require.register("[email protected]", function (exports, module) {
0 ignored issues
show
Unused Code introduced by
The parameter module is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1199
var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
1200
    unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
1201
    prefix = bind !== 'addEventListener' ? 'on' : '';
1202
1203
/**
1204
 * Bind `el` event `type` to `fn`.
1205
 *
1206
 * @param {Element} el
1207
 * @param {String} type
1208
 * @param {Function} fn
1209
 * @param {Boolean} capture
1210
 * @return {Function}
1211
 * @api public
1212
 */
1213
1214
exports.bind = function(el, type, fn, capture){
1215
  el[bind](prefix + type, fn, capture || false);
1216
  return fn;
1217
};
1218
1219
/**
1220
 * Unbind `el` event `type`'s callback `fn`.
1221
 *
1222
 * @param {Element} el
1223
 * @param {String} type
1224
 * @param {Function} fn
1225
 * @param {Boolean} capture
1226
 * @return {Function}
1227
 * @api public
1228
 */
1229
1230
exports.unbind = function(el, type, fn, capture){
1231
  el[unbind](prefix + type, fn, capture || false);
1232
  return fn;
1233
};
1234
});
1235
1236
require.register("[email protected]", function (exports, module) {
1237
function one(selector, el) {
1238
  return el.querySelector(selector);
1239
}
1240
1241
exports = module.exports = function(selector, el){
1242
  el = el || document;
1243
  return one(selector, el);
1244
};
1245
1246
exports.all = function(selector, el){
1247
  el = el || document;
1248
  return el.querySelectorAll(selector);
1249
};
1250
1251
exports.engine = function(obj){
1252
  if (!obj.one) throw new Error('.one callback required');
1253
  if (!obj.all) throw new Error('.all callback required');
1254
  one = obj.one;
0 ignored issues
show
Comprehensibility introduced by
It seems like you are trying to overwrite a function name here. one is already defined in line 1237 as a function. While this will work, it can be very confusing.
Loading history...
1255
  exports.all = obj.all;
1256
  return exports;
1257
};
1258
1259
});
1260
1261
require.register("[email protected]", function (exports, module) {
1262
/**
1263
 * Module dependencies.
1264
 */
1265
1266
var query = require('[email protected]');
1267
1268
/**
1269
 * Element prototype.
1270
 */
1271
1272
var proto = Element.prototype;
0 ignored issues
show
Bug introduced by
The variable Element seems to be never declared. If this is a global, consider adding a /** global: Element */ 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...
1273
1274
/**
1275
 * Vendor function.
1276
 */
1277
1278
var vendor = proto.matches
1279
  || proto.webkitMatchesSelector
1280
  || proto.mozMatchesSelector
1281
  || proto.msMatchesSelector
1282
  || proto.oMatchesSelector;
1283
1284
/**
1285
 * Expose `match()`.
1286
 */
1287
1288
module.exports = match;
1289
1290
/**
1291
 * Match `el` to `selector`.
1292
 *
1293
 * @param {Element} el
1294
 * @param {String} selector
1295
 * @return {Boolean}
1296
 * @api public
1297
 */
1298
1299
function match(el, selector) {
1300
  if (!el || el.nodeType !== 1) return false;
1301
  if (vendor) return vendor.call(el, selector);
1302
  var nodes = query.all(selector, el.parentNode);
1303
  for (var i = 0; i < nodes.length; ++i) {
1304
    if (nodes[i] == el) return true;
1305
  }
1306
  return false;
1307
}
1308
1309
});
1310
1311
require.register("[email protected]", function (exports, module) {
1312
var matches = require('[email protected]')
1313
1314
module.exports = function (element, selector, checkYoSelf, root) {
1315
  element = checkYoSelf ? {parentNode: element} : element
1316
1317
  root = root || document
1318
1319
  // Make sure `element !== document` and `element != null`
1320
  // otherwise we get an illegal invocation
1321
  while ((element = element.parentNode) && element !== document) {
1322
    if (matches(element, selector))
1323
      return element
1324
    // After `matches` on the edge case that
1325
    // the selector matches the root
1326
    // (when the root is not the document)
1327
    if (element === root)
1328
      return
1329
  }
1330
}
1331
1332
});
1333
1334
require.register("[email protected]", function (exports, module) {
0 ignored issues
show
Unused Code introduced by
The parameter module is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1335
/**
1336
 * Module dependencies.
1337
 */
1338
1339
var closest = require('[email protected]')
1340
  , event = require('[email protected]');
1341
1342
/**
1343
 * Delegate event `type` to `selector`
1344
 * and invoke `fn(e)`. A callback function
1345
 * is returned which may be passed to `.unbind()`.
1346
 *
1347
 * @param {Element} el
1348
 * @param {String} selector
1349
 * @param {String} type
1350
 * @param {Function} fn
1351
 * @param {Boolean} capture
1352
 * @return {Function}
1353
 * @api public
1354
 */
1355
1356
exports.bind = function(el, selector, type, fn, capture){
1357
  return event.bind(el, type, function(e){
1358
    var target = e.target || e.srcElement;
1359
    e.delegateTarget = closest(target, selector, true, el);
1360
    if (e.delegateTarget) fn.call(el, e);
1361
  }, capture);
1362
};
1363
1364
/**
1365
 * Unbind event `type`'s callback `fn`.
1366
 *
1367
 * @param {Element} el
1368
 * @param {String} type
1369
 * @param {Function} fn
1370
 * @param {Boolean} capture
1371
 * @api public
1372
 */
1373
1374
exports.unbind = function(el, type, fn, capture){
1375
  event.unbind(el, type, fn, capture);
1376
};
1377
1378
});
1379
1380
require.register("[email protected]", function (exports, module) {
1381
1382
/**
1383
 * Module dependencies.
1384
 */
1385
1386
var events = require('[email protected]');
1387
var delegate = require('[email protected]');
1388
1389
/**
1390
 * Expose `Events`.
1391
 */
1392
1393
module.exports = Events;
1394
1395
/**
1396
 * Initialize an `Events` with the given
1397
 * `el` object which events will be bound to,
1398
 * and the `obj` which will receive method calls.
1399
 *
1400
 * @param {Object} el
1401
 * @param {Object} obj
1402
 * @api public
1403
 */
1404
1405
function Events(el, obj) {
1406
  if (!(this instanceof Events)) return new Events(el, obj);
1407
  if (!el) throw new Error('element required');
1408
  if (!obj) throw new Error('object required');
1409
  this.el = el;
1410
  this.obj = obj;
1411
  this._events = {};
1412
}
1413
1414
/**
1415
 * Subscription helper.
1416
 */
1417
1418
Events.prototype.sub = function(event, method, cb){
1419
  this._events[event] = this._events[event] || {};
1420
  this._events[event][method] = cb;
1421
};
1422
1423
/**
1424
 * Bind to `event` with optional `method` name.
1425
 * When `method` is undefined it becomes `event`
1426
 * with the "on" prefix.
1427
 *
1428
 * Examples:
1429
 *
1430
 *  Direct event handling:
1431
 *
1432
 *    events.bind('click') // implies "onclick"
1433
 *    events.bind('click', 'remove')
1434
 *    events.bind('click', 'sort', 'asc')
1435
 *
1436
 *  Delegated event handling:
1437
 *
1438
 *    events.bind('click li > a')
1439
 *    events.bind('click li > a', 'remove')
1440
 *    events.bind('click a.sort-ascending', 'sort', 'asc')
1441
 *    events.bind('click a.sort-descending', 'sort', 'desc')
1442
 *
1443
 * @param {String} event
1444
 * @param {String|function} [method]
1445
 * @return {Function} callback
1446
 * @api public
1447
 */
1448
1449
Events.prototype.bind = function(event, method){
1450
  var e = parse(event);
1451
  var el = this.el;
1452
  var obj = this.obj;
1453
  var name = e.name;
1454
  var method = method || 'on' + name;
1455
  var args = [].slice.call(arguments, 2);
1456
1457
  // callback
1458
  function cb(){
1459
    var a = [].slice.call(arguments).concat(args);
1460
    obj[method].apply(obj, a);
1461
  }
1462
1463
  // bind
1464
  if (e.selector) {
1465
    cb = delegate.bind(el, e.selector, name, cb);
0 ignored issues
show
Comprehensibility introduced by
It seems like you are trying to overwrite a function name here. cb is already defined in line 1458 as a function. While this will work, it can be very confusing.
Loading history...
1466
  } else {
1467
    events.bind(el, name, cb);
1468
  }
1469
1470
  // subscription for unbinding
1471
  this.sub(name, method, cb);
1472
1473
  return cb;
1474
};
1475
1476
/**
1477
 * Unbind a single binding, all bindings for `event`,
1478
 * or all bindings within the manager.
1479
 *
1480
 * Examples:
1481
 *
1482
 *  Unbind direct handlers:
1483
 *
1484
 *     events.unbind('click', 'remove')
1485
 *     events.unbind('click')
1486
 *     events.unbind()
1487
 *
1488
 * Unbind delegate handlers:
1489
 *
1490
 *     events.unbind('click', 'remove')
1491
 *     events.unbind('click')
1492
 *     events.unbind()
1493
 *
1494
 * @param {String|Function} [event]
1495
 * @param {String|Function} [method]
1496
 * @api public
1497
 */
1498
1499
Events.prototype.unbind = function(event, method){
1500
  if (0 == arguments.length) return this.unbindAll();
1501
  if (1 == arguments.length) return this.unbindAllOf(event);
1502
1503
  // no bindings for this event
1504
  var bindings = this._events[event];
1505
  if (!bindings) return;
1506
1507
  // no bindings for this method
1508
  var cb = bindings[method];
1509
  if (!cb) return;
1510
1511
  events.unbind(this.el, event, cb);
1512
};
1513
1514
/**
1515
 * Unbind all events.
1516
 *
1517
 * @api private
1518
 */
1519
1520
Events.prototype.unbindAll = function(){
1521
  for (var event in this._events) {
1522
    this.unbindAllOf(event);
1523
  }
1524
};
1525
1526
/**
1527
 * Unbind all events for `event`.
1528
 *
1529
 * @param {String} event
1530
 * @api private
1531
 */
1532
1533
Events.prototype.unbindAllOf = function(event){
1534
  var bindings = this._events[event];
1535
  if (!bindings) return;
1536
1537
  for (var method in bindings) {
1538
    this.unbind(event, method);
1539
  }
1540
};
1541
1542
/**
1543
 * Parse `event`.
1544
 *
1545
 * @param {String} event
1546
 * @return {Object}
1547
 * @api private
1548
 */
1549
1550
function parse(event) {
1551
  var parts = event.split(/ +/);
1552
  return {
1553
    name: parts.shift(),
1554
    selector: parts.join(' ')
1555
  }
1556
}
1557
1558
});
1559
1560
require.register("switchery", function (exports, module) {
1561
/**
1562
 * Switchery 0.8.1
1563
 * http://abpetkov.github.io/switchery/
1564
 *
1565
 * Authored by Alexander Petkov
1566
 * https://github.com/abpetkov
1567
 *
1568
 * Copyright 2013-2015, Alexander Petkov
1569
 * License: The MIT License (MIT)
1570
 * http://opensource.org/licenses/MIT
1571
 *
1572
 */
1573
1574
/**
1575
 * External dependencies.
1576
 */
1577
1578
var transitionize = require('[email protected]')
1579
  , fastclick = require('[email protected]')
1580
  , classes = require('[email protected]')
1581
  , events = require('[email protected]');
1582
1583
/**
1584
 * Expose `Switchery`.
1585
 */
1586
1587
module.exports = Switchery;
1588
1589
/**
1590
 * Set Switchery default values.
1591
 *
1592
 * @api public
1593
 */
1594
1595
var defaults = {
1596
    color             : '#64bd63'
1597
  , secondaryColor    : '#dfdfdf'
1598
  , jackColor         : '#fff'
1599
  , jackSecondaryColor: null
1600
  , className         : 'switchery'
1601
  , disabled          : false
1602
  , disabledOpacity   : 0.5
1603
  , speed             : '0.4s'
1604
  , size              : 'default'
1605
};
1606
1607
/**
1608
 * Create Switchery object.
1609
 *
1610
 * @param {Object} element
1611
 * @param {Object} options
1612
 * @api public
1613
 */
1614
1615
function Switchery(element, options) {
1616
  if (!(this instanceof Switchery)) return new Switchery(element, options);
1617
1618
  this.element = element;
1619
  this.options = options || {};
1620
1621
  for (var i in defaults) {
1622
    if (this.options[i] == null) {
1623
      this.options[i] = defaults[i];
1624
    }
1625
  }
1626
1627
  if (this.element != null && this.element.type == 'checkbox') this.init();
1628
  if (this.isDisabled() === true) this.disable();
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if this.isDisabled() === true 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...
1629
}
1630
1631
/**
1632
 * Hide the target element.
1633
 *
1634
 * @api private
1635
 */
1636
1637
Switchery.prototype.hide = function() {
1638
  this.element.style.display = 'none';
1639
};
1640
1641
/**
1642
 * Show custom switch after the target element.
1643
 *
1644
 * @api private
1645
 */
1646
1647
Switchery.prototype.show = function() {
1648
  var switcher = this.create();
1649
  this.insertAfter(this.element, switcher);
1650
};
1651
1652
/**
1653
 * Create custom switch.
1654
 *
1655
 * @returns {Object} this.switcher
1656
 * @api private
1657
 */
1658
1659
Switchery.prototype.create = function() {
1660
  this.switcher = document.createElement('span');
1661
  this.jack = document.createElement('small');
1662
  this.switcher.appendChild(this.jack);
1663
  this.switcher.className = this.options.className;
1664
  this.events = events(this.switcher, this);
1665
1666
  return this.switcher;
1667
};
1668
1669
/**
1670
 * Insert after element after another element.
1671
 *
1672
 * @param {Object} reference
1673
 * @param {Object} target
1674
 * @api private
1675
 */
1676
1677
Switchery.prototype.insertAfter = function(reference, target) {
1678
  reference.parentNode.insertBefore(target, reference.nextSibling);
1679
};
1680
1681
/**
1682
 * Set switch jack proper position.
1683
 *
1684
 * @param {Boolean} clicked - we need this in order to uncheck the input when the switch is clicked
1685
 * @api private
1686
 */
1687
1688
Switchery.prototype.setPosition = function (clicked) {
1689
  var checked = this.isChecked()
1690
    , switcher = this.switcher
1691
    , jack = this.jack;
1692
1693
  if (clicked && checked) checked = false;
1694
  else if (clicked && !checked) checked = true;
1695
1696
  if (checked === true) {
1697
    this.element.checked = true;
1698
1699
    if (window.getComputedStyle) jack.style.left = parseInt(window.getComputedStyle(switcher).width) - parseInt(window.getComputedStyle(jack).width) + 'px';
1700
    else jack.style.left = parseInt(switcher.currentStyle['width']) - parseInt(jack.currentStyle['width']) + 'px';
1701
1702
    if (this.options.color) this.colorize();
1703
    this.setSpeed();
1704
  } else {
1705
    jack.style.left = 0;
1706
    this.element.checked = false;
1707
    this.switcher.style.boxShadow = 'inset 0 0 0 0 ' + this.options.secondaryColor;
1708
    this.switcher.style.borderColor = this.options.secondaryColor;
1709
    this.switcher.style.backgroundColor = (this.options.secondaryColor !== defaults.secondaryColor) ? this.options.secondaryColor : '#fff';
1710
    this.jack.style.backgroundColor = (this.options.jackSecondaryColor !== this.options.jackColor) ? this.options.jackSecondaryColor : this.options.jackColor;
1711
    this.setSpeed();
1712
  }
1713
};
1714
1715
/**
1716
 * Set speed.
1717
 *
1718
 * @api private
1719
 */
1720
1721
Switchery.prototype.setSpeed = function() {
1722
  var switcherProp = {}
0 ignored issues
show
Unused Code introduced by
The assignment to variable switcherProp seems to be never used. Consider removing it.
Loading history...
1723
    , jackProp = {
1724
        'background-color': this.options.speed
1725
      , 'left': this.options.speed.replace(/[a-z]/, '') / 2 + 's'
1726
    };
1727
1728
  if (this.isChecked()) {
1729
    switcherProp = {
1730
        'border': this.options.speed
1731
      , 'box-shadow': this.options.speed
1732
      , 'background-color': this.options.speed.replace(/[a-z]/, '') * 3 + 's'
1733
    };
1734
  } else {
1735
    switcherProp = {
1736
        'border': this.options.speed
1737
      , 'box-shadow': this.options.speed
1738
    };
1739
  }
1740
1741
  transitionize(this.switcher, switcherProp);
1742
  transitionize(this.jack, jackProp);
1743
};
1744
1745
/**
1746
 * Set switch size.
1747
 *
1748
 * @api private
1749
 */
1750
1751
Switchery.prototype.setSize = function() {
1752
  var small = 'switchery-small'
1753
    , normal = 'switchery-default'
1754
    , large = 'switchery-large';
1755
1756
  switch (this.options.size) {
1757
    case 'small':
1758
      classes(this.switcher).add(small)
1759
      break;
1760
    case 'large':
1761
      classes(this.switcher).add(large)
1762
      break;
1763
    default:
1764
      classes(this.switcher).add(normal)
1765
      break;
1766
  }
1767
};
1768
1769
/**
1770
 * Set switch color.
1771
 *
1772
 * @api private
1773
 */
1774
1775
Switchery.prototype.colorize = function() {
1776
  var switcherHeight = this.switcher.offsetHeight / 2;
1777
1778
  this.switcher.style.backgroundColor = this.options.color;
1779
  this.switcher.style.borderColor = this.options.color;
1780
  this.switcher.style.boxShadow = 'inset 0 0 0 ' + switcherHeight + 'px ' + this.options.color;
1781
  this.jack.style.backgroundColor = this.options.jackColor;
1782
};
1783
1784
/**
1785
 * Handle the onchange event.
1786
 *
1787
 * @param {Boolean} state
1788
 * @api private
1789
 */
1790
1791
Switchery.prototype.handleOnchange = function(state) {
0 ignored issues
show
Unused Code introduced by
The parameter state is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1792
  if (document.dispatchEvent) {
1793
    var event = document.createEvent('HTMLEvents');
1794
    event.initEvent('change', true, true);
1795
    this.element.dispatchEvent(event);
1796
  } else {
1797
    this.element.fireEvent('onchange');
1798
  }
1799
};
1800
1801
/**
1802
 * Handle the native input element state change.
1803
 * A `change` event must be fired in order to detect the change.
1804
 *
1805
 * @api private
1806
 */
1807
1808
Switchery.prototype.handleChange = function() {
1809
  var self = this
1810
    , el = this.element;
1811
1812
  if (el.addEventListener) {
1813
    el.addEventListener('change', function() {
1814
      self.setPosition();
1815
    });
1816
  } else {
1817
    el.attachEvent('onchange', function() {
1818
      self.setPosition();
1819
    });
1820
  }
1821
};
1822
1823
/**
1824
 * Handle the switch click event.
1825
 *
1826
 * @api private
1827
 */
1828
1829
Switchery.prototype.handleClick = function() {
1830
  var switcher = this.switcher;
1831
1832
  fastclick(switcher);
1833
  this.events.bind('click', 'bindClick');
1834
};
1835
1836
/**
1837
 * Attach all methods that need to happen on switcher click.
1838
 *
1839
 * @api private
1840
 */
1841
1842
Switchery.prototype.bindClick = function() {
1843
  var parent = this.element.parentNode.tagName.toLowerCase()
1844
    , labelParent = (parent === 'label') ? false : true;
1845
1846
  this.setPosition(labelParent);
1847
  this.handleOnchange(this.element.checked);
1848
};
1849
1850
/**
1851
 * Mark an individual switch as already handled.
1852
 *
1853
 * @api private
1854
 */
1855
1856
Switchery.prototype.markAsSwitched = function() {
1857
  this.element.setAttribute('data-switchery', true);
1858
};
1859
1860
/**
1861
 * Check if an individual switch is already handled.
1862
 *
1863
 * @api private
1864
 */
1865
1866
Switchery.prototype.markedAsSwitched = function() {
1867
  return this.element.getAttribute('data-switchery');
1868
};
1869
1870
/**
1871
 * Initialize Switchery.
1872
 *
1873
 * @api private
1874
 */
1875
1876
Switchery.prototype.init = function() {
1877
  this.hide();
1878
  this.show();
1879
  this.setSize();
1880
  this.setPosition();
1881
  this.markAsSwitched();
1882
  this.handleChange();
1883
  this.handleClick();
1884
};
1885
1886
/**
1887
 * See if input is checked.
1888
 *
1889
 * @returns {Boolean}
1890
 * @api public
1891
 */
1892
1893
Switchery.prototype.isChecked = function() {
1894
  return this.element.checked;
1895
};
1896
1897
/**
1898
 * See if switcher should be disabled.
1899
 *
1900
 * @returns {Boolean}
1901
 * @api public
1902
 */
1903
1904
Switchery.prototype.isDisabled = function() {
1905
  return this.options.disabled || this.element.disabled || this.element.readOnly;
1906
};
1907
1908
/**
1909
 * Destroy all event handlers attached to the switch.
1910
 *
1911
 * @api public
1912
 */
1913
1914
Switchery.prototype.destroy = function() {
1915
  this.events.unbind();
1916
};
1917
1918
/**
1919
 * Enable disabled switch element.
1920
 *
1921
 * @api public
1922
 */
1923
1924
Switchery.prototype.enable = function() {
1925
  if (!this.options.disabled) return;
1926
  if (this.options.disabled) this.options.disabled = false;
1927
  if (this.element.disabled) this.element.disabled = false;
1928
  if (this.element.readOnly) this.element.readOnly = false;
1929
  this.switcher.style.opacity = 1;
1930
  this.events.bind('click', 'bindClick');
1931
};
1932
1933
/**
1934
 * Disable switch element.
1935
 *
1936
 * @api public
1937
 */
1938
1939
Switchery.prototype.disable = function() {
1940
  if (this.options.disabled) return;
1941
  if (!this.options.disabled) this.options.disabled = true;
1942
  if (!this.element.disabled) this.element.disabled = true;
1943
  if (!this.element.readOnly) this.element.readOnly = true;
1944
  this.switcher.style.opacity = this.options.disabledOpacity;
1945
  this.destroy();
1946
};
1947
1948
});
1949
1950
if (typeof exports == "object") {
1951
  module.exports = require("switchery");
1952
} else if (typeof define == "function" && define.amd) {
1953
  define("Switchery", [], function(){ return require("switchery"); });
1954
} else {
1955
  (this || window)["Switchery"] = require("switchery");
1956
}
1957
})();
1958