1/**
2* Gumby Toggles/Switches
3*/
4!function($) {
5
6	'use strict';
7
8	// Toggle constructor
9	function Toggle($el) {
10		this.$el = $($el);
11		this.targets = [];
12		this.on = '';
13		this.className = '';
14		this.self = false;
15
16		if(this.$el.length) {
17			Gumby.debug('Initializing Toggle', $el);
18			this.init();
19		}
20	}
21
22	// Switch constructor
23	function Switch($el) {
24		this.$el = $($el);
25		this.targets = [];
26		this.on = '';
27		this.className = '';
28		this.self = false;
29
30		if(this.$el.length) {
31			Gumby.debug('Initializing Switch', $el);
32			this.init();
33		}
34	}
35
36	// intialise toggles, switches will inherit method
37	Toggle.prototype.init = function() {
38		var scope = this;
39
40		// set up module based on attributes
41		this.setup();
42
43		// bind to specified event and trigger
44		this.$el.on(this.on, function(e) {
45			e.preventDefault();
46			scope.trigger(scope.triggered);
47
48		// listen for gumby.trigger to dynamically trigger toggle/switch
49		}).on('gumby.trigger', function() {
50			Gumby.debug('Trigger event triggered', scope.$el);
51			scope.trigger(scope.triggered);
52		// re-initialize module
53		}).on('gumby.initialize', function() {
54			Gumby.debug('Re-initializing '+scope.constructor, $el);
55			scope.setup();
56		});
57	};
58
59	// set up module based on attributes
60	Toggle.prototype.setup = function() {
61		this.targets = this.parseTargets();
62		this.on = Gumby.selectAttr.apply(this.$el, ['on']) || Gumby.click;
63		this.className = Gumby.selectAttr.apply(this.$el, ['classname']) || 'active';
64		this.self = Gumby.selectAttr.apply(this.$el, ['self']) === 'false';
65	};
66
67	// parse data-for attribute, switches will inherit method
68	Toggle.prototype.parseTargets = function() {
69		var targetStr = Gumby.selectAttr.apply(this.$el, ['trigger']),
70			secondaryTargets = 0,
71			targets = [];
72
73		// no targets so return false
74		if(!targetStr) {
75			return false;
76		}
77
78		secondaryTargets = targetStr.indexOf('|');
79
80		// no secondary targets specified so return single target
81		if(secondaryTargets === -1) {
82			if(!this.checkTargets([targetStr])) {
83				return false;
84			}
85			return [$(targetStr)];
86		}
87
88		// return array of both targets, split and return 0, 1
89		targets = targetStr.split('|');
90		if(!this.checkTargets(targets)) {
91			return false;
92		}
93		return targets.length > 1 ? [$(targets[0]), $(targets[1])] : [$(targets[0])];
94	};
95
96	Toggle.prototype.checkTargets = function(targets) {
97		var i = 0;
98
99		for(i; i < targets.length; i++) {
100			if(targets[i] && !$(targets[i]).length) {
101				Gumby.error('Cannot find '+this.constructor.name+' target: '+targets[i]);
102				return false;
103			}
104		}
105
106		return true;
107	};
108
109	// call triggered event and pass target data
110	Toggle.prototype.triggered = function() {
111		// trigger gumby.onTrigger event and pass array of target status data
112		Gumby.debug('Triggering onTrigger event', this.$el);
113		this.$el.trigger('gumby.onTrigger', [this.$el.hasClass(this.className)]);
114	};
115
116	// Switch object inherits from Toggle
117	Switch.prototype = new Toggle();
118	Switch.prototype.constructor = Switch;
119
120	// Toggle specific trigger method
121	Toggle.prototype.trigger = function(cb) {
122
123		Gumby.debug('Triggering Toggle', this.$el);
124
125		var $target;
126
127		// no targets just toggle active class on toggle
128		if(!this.targets) {
129			this.$el.toggleClass(this.className);
130
131		// combine single target with toggle and toggle active class
132		} else if(this.targets.length == 1) {
133			this.$el.add(this.targets[0]).toggleClass(this.className);
134
135		// if two targets check active state of first
136		// always combine toggle and first target
137		} else if(this.targets.length > 1) {
138			if(this.targets[0].hasClass(this.className)) {
139				$target = this.targets[0];
140
141				// add this element to it unless gumby-self set
142				if(!this.self) {
143					$target = $target.add(this.$el);
144				}
145
146				$target.removeClass(this.className);
147				this.targets[1].addClass(this.className);
148			} else {
149				$target = this.targets[0];
150
151				// add this element to it unless gumby-self set
152				if(!this.self) {
153					$target = $target.add(this.$el);
154				}
155
156				$target.addClass(this.className);
157				this.targets[1].removeClass(this.className);
158			}
159		}
160
161		// call event handler here, applying scope of object Switch/Toggle
162		if(cb && typeof cb === 'function') {
163			cb.apply(this);
164		}
165	};
166
167	// Switch specific trigger method
168	Switch.prototype.trigger = function(cb) {
169
170		Gumby.debug('Triggering Switch', this.$el);
171
172		var $target;
173
174		// no targets just add active class to switch
175		if(!this.targets) {
176			this.$el.addClass(this.className);
177
178		// combine single target with switch and add active class
179		} else if(this.targets.length == 1) {
180			$target = this.targets[0];
181
182			// add this element to it unless gumby-self set
183			if(!this.self) {
184				$target = $target.add(this.$el);
185			}
186
187			$target.addClass(this.className);
188
189		// if two targets check active state of first
190		// always combine switch and first target
191		} else if(this.targets.length > 1) {
192			$target = this.targets[0];
193
194			// add this element to it unless gumby-self set
195			if(!this.self) {
196				$target = $target.add(this.$el);
197			}
198
199			$target.addClass(this.className);
200			this.targets[1].removeClass(this.className);
201		}
202
203		// call event handler here, applying scope of object Switch/Toggle
204		if(cb && typeof cb === 'function') {
205			cb.apply(this);
206		}
207	};
208
209	// add toggle initialisation
210	Gumby.addInitalisation('toggles', function(all) {
211		$('.toggle').each(function() {
212			var $this = $(this);
213
214			// this element has already been initialized
215			// and we're only initializing new modules
216			if($this.data('isToggle') && !all) {
217				return true;
218
219			// this element has already been initialized
220			// and we need to reinitialize it
221			} else if($this.data('isToggle') && all) {
222				$this.trigger('gumby.initialize');
223			}
224
225			// mark element as initialized
226			$this.data('isToggle', true);
227			new Toggle($this);
228		});
229	});
230
231	// add switches initialisation
232	Gumby.addInitalisation('switches', function(all) {
233		$('.switch').each(function() {
234			var $this = $(this);
235
236			// this element has already been initialized
237			// and we're only initializing new modules
238			if($this.data('isSwitch') && !all) {
239				return true;
240
241			// this element has already been initialized
242			// and we need to reinitialize it
243			} else if($this.data('isSwitch') && all) {
244				$this.trigger('gumby.initialize');
245				return true;
246			}
247
248			// mark element as initialized
249			$this.data('isSwitch', true);
250			new Switch($this);
251		});
252	});
253
254	// register UI module
255	Gumby.UIModule({
256		module: 'toggleswitch',
257		events: ['initialize', 'trigger', 'onTrigger'],
258		init: function() {
259			// Run initialize methods
260			Gumby.initialize('switches');
261			Gumby.initialize('toggles');
262		}
263	});
264}(jQuery);
265