source: other-projects/nz-flag-design/trunk/main-form/js/liteaccordion-with-resize.jquery.js@ 29617

Last change on this file since 29617 was 29617, checked in by davidb, 9 years ago

Version from a branch on github that has been extended to allow a resize method to be called

File size: 17.3 KB
Line 
1/*************************************************!
2*
3* project: liteAccordion - a horizontal accordion plugin for jQuery
4* author: Nicola Hibbert
5* url: http://nicolahibbert.com/liteaccordion-v2/
6* demo: http://www.nicolahibbert.com/demo/liteAccordion/
7*
8* Version: 2.2.0
9* Copyright: (c) 2010-2013 Nicola Hibbert
10* Licence: MIT
11*
12**************************************************/
13
14;(function($) {
15
16 var LiteAccordion = function(elem, options) {
17
18 var defaults = {
19 containerWidth : 960, // fixed (px)
20 containerHeight : 320, // fixed (px)
21 headerWidth : 48, // fixed (px)
22
23 activateOn : 'click', // click or mouseover
24 firstSlide : 1, // displays slide (n) on page load
25 slideSpeed : 800, // slide animation speed
26 onTriggerSlide : function(e) {}, // callback on slide activate
27 onSlideAnimComplete : function() {}, // callback on slide anim complete
28
29 autoPlay : false, // automatically cycle through slides
30 pauseOnHover : false, // pause on hover
31 cycleSpeed : 6000, // time between slide cycles
32 easing : 'swing', // custom easing function
33
34 theme : 'basic', // basic, dark, light, or stitch
35 rounded : false, // square or rounded corners
36 enumerateSlides : false, // put numbers on slides
37 linkable : false // link slides via hash
38 },
39
40 // merge defaults with options in new settings object
41 settings = $.extend({}, defaults, options),
42
43 // 'globals'
44 slides = elem.children('ol').children('li'),
45 header = slides.children(':first-child'),
46 slideLen = slides.length,
47 slideWidth = settings.containerWidth - slideLen * settings.headerWidth,
48
49 // public methods
50 methods = {
51
52 // start elem animation
53 play : function(index) {
54 console.log(index);
55 var next = core.nextSlide(index && index);
56
57 if (core.playing) return;
58
59 // start autoplay
60 core.playing = setInterval(function() {
61 header.eq(next()).trigger('click.liteAccordion');
62 }, settings.cycleSpeed);
63 },
64
65 // stop elem animation
66 stop : function() {
67 clearInterval(core.playing);
68 core.playing = 0;
69 },
70
71 // trigger next slide
72 next : function() {
73 methods.stop();
74 header.eq(core.currentSlide === slideLen - 1 ? 0 : core.currentSlide + 1).trigger('click.liteAccordion');
75 },
76
77 // trigger previous slide
78 prev : function() {
79 methods.stop();
80 header.eq(core.currentSlide - 1).trigger('click.liteAccordion');
81 },
82
83 // destroy plugin instance
84 destroy : function() {
85 // stop autoplay
86 methods.stop();
87
88 // remove hashchange event bound to window
89 $(window).off('.liteAccordion');
90
91 // remove generated styles, classes, data, events
92 elem
93 .attr('style', '')
94 .removeClass('liteAccordion basic dark light stitch')
95 .removeData('liteAccordion')
96 .off('.liteAccordion')
97 .find('li > :first-child')
98 .off('.liteAccordion')
99 .filter('.selected')
100 .removeClass('selected')
101 .end()
102 .find('b')
103 .remove();
104
105 slides
106 .removeClass('slide')
107 .children()
108 .attr('style', '');
109 },
110
111 // poke around the internals (NOT CHAINABLE)
112 debug : function() {
113 return {
114 elem : elem,
115 defaults : defaults,
116 settings : settings,
117 methods : methods,
118 core : core
119 };
120 },
121 resize:function(data){
122 settings = $.extend({}, defaults, data),
123 slides = elem.children('ol').children('li'),
124 header = slides.children(':first-child'),
125 slideLen = slides.length,
126 slideWidth = settings.containerWidth - slideLen * settings.headerWidth;
127
128
129 core.setStyles();
130 }
131 },
132
133 // core utility and animation methods
134 core = {
135
136 // set style properties
137 setStyles : function() {
138 // set container height and width, theme and corner style
139 elem
140 .width(settings.containerWidth)
141 .height(settings.containerHeight)
142 .addClass('liteAccordion')
143 .addClass(settings.rounded && 'rounded')
144 .addClass(settings.theme);
145
146 // set slide heights
147 slides
148 .addClass('slide')
149 .children(':first-child')
150 .height(settings.headerWidth);
151
152 // set slide positions
153 core.setSlidePositions();
154 },
155
156 // set initial positions for each slide
157 setSlidePositions : function() {
158 var selected = header.filter('.selected');
159
160 // account for already selected slide
161 if (!selected.length) header.eq(settings.firstSlide - 1).addClass('selected');
162
163 header.each(function(index) {
164 var $this = $(this),
165 left = index * settings.headerWidth,
166 margin = header.first().next(),
167 offset = parseInt(margin.css('marginLeft'), 10) || parseInt(margin.css('marginRight'), 10) || 0;
168
169 // compensate for already selected slide on resize
170 if (selected.length) {
171 if (index > header.index(selected)) left += slideWidth;
172 } else {
173 if (index >= settings.firstSlide) left += slideWidth;
174 }
175
176 // set each slide position
177 $this
178 .css('left', left)
179 .width(settings.containerHeight)
180 .next()
181 .width(slideWidth - offset)
182 .css({ left : left, paddingLeft : settings.headerWidth });
183
184 // add number to bottom of tab
185 settings.enumerateSlides && $this.append('<b>' + (index + 1) + '</b>');
186
187 });
188 },
189
190 // bind events
191 bindEvents : function() {
192 // bind click and mouseover events
193 if (settings.activateOn === 'click') {
194 header.on('click.liteAccordion', core.triggerSlide);
195 } else if (settings.activateOn === 'mouseover') {
196 header.on('click.liteAccordion mouseover.liteAccordion', core.triggerSlide);
197 }
198
199 // bind hashchange event
200 if (settings.linkable) {
201 $(window).on('hashchange.liteAccordion', function(e) {
202 var url = slides.filter(function() {
203 return $(this).attr('data-slide-name') === window.location.hash.split('#')[1];
204 });
205
206 // if slide name exists
207 if (url.length) {
208 // trigger slide
209 core.triggerSlide.call(url.children('h2')[0], e);
210 }
211 });
212 }
213
214 // pause on hover (can't use custom events with $.hover())
215 if (settings.pauseOnHover && settings.autoPlay) {
216 elem
217 .on('mouseover.liteAccordion', function() {
218 core.playing && methods.stop();
219 })
220 .on('mouseout.liteAccordion', function() {
221 !core.playing && methods.play(core.currentSlide);
222 });
223 }
224 },
225
226 // counter for autoPlay (zero index firstSlide on init)
227 currentSlide : settings.firstSlide - 1,
228
229 // next slide index
230 nextSlide : function(index) {
231 var next = index + 1 || core.currentSlide + 1;
232
233 // closure
234 return function() {
235 return next++ % slideLen;
236 };
237 },
238
239 // holds interval counter
240 playing : 0,
241
242 slideAnimCompleteFlag : false,
243
244 // trigger slide animation
245 triggerSlide : function(e) {
246 var $this = $(this),
247 tab = {
248 elem : $this,
249 index : header.index($this),
250 next : $this.next(),
251 prev : $this.parent().prev().children('h2'),
252 parent : $this.parent()
253 };
254
255 // current hash not correct?
256 if (settings.linkable && tab.parent.attr('data-slide-name')) {
257 if (tab.parent.attr('data-slide-name') !== window.location.hash.split('#')[1]) {
258 // exit early and try again (prevents double trigger (issue #60))
259 return window.location.hash = '#' + tab.parent.attr('data-slide-name');
260 }
261 }
262
263 // update core.currentSlide
264 core.currentSlide = tab.index;
265
266 // reset onSlideAnimComplete callback flag
267 core.slideAnimCompleteFlag = false;
268
269 // trigger callback in context of sibling div (jQuery wrapped)
270 settings.onTriggerSlide.call(tab.next, $this);
271
272 // animate
273 if ($this.hasClass('selected') && $this.position().left < slideWidth / 2) {
274 // animate single selected tab
275 core.animSlide.call(tab);
276 } else {
277 // animate groups
278 core.animSlideGroup(tab);
279 }
280
281 // stop autoplay, reset current slide index in core.nextSlide closure
282 if (settings.autoPlay) {
283 methods.stop();
284 methods.play(header.index(header.filter('.selected')));
285 }
286 },
287
288 animSlide : function(triggerTab) {
289 var _this = this;
290
291 // set pos for single selected tab
292 if (typeof this.pos === 'undefined') this.pos = slideWidth;
293
294 // remove, then add selected class
295 header.removeClass('selected').filter(this.elem).addClass('selected');
296
297 // if slide index not zero
298 if (!!this.index) {
299 this.elem
300 .add(this.next)
301 .stop(true)
302 .animate({
303 left : this.pos + this.index * settings.headerWidth
304 },
305 settings.slideSpeed,
306 settings.easing,
307 function() {
308 // flag ensures that fn is only called one time per triggerSlide
309 if (!core.slideAnimCompleteFlag) {
310 // trigger onSlideAnimComplete callback in context of sibling div (jQuery wrapped)
311 settings.onSlideAnimComplete.call(triggerTab ? triggerTab.next : _this.prev.next());
312 core.slideAnimCompleteFlag = true;
313 }
314 });
315
316 // remove, then add selected class
317 header.removeClass('selected').filter(this.prev).addClass('selected');
318
319 }
320 },
321
322 // animates left and right groups of slides
323 animSlideGroup : function(triggerTab) {
324 var group = ['left', 'right'];
325
326 $.each(group, function(index, side) {
327 var filterExpr, left;
328
329 if (side === 'left') {
330 filterExpr = ':lt(' + (triggerTab.index + 1) + ')';
331 left = 0;
332 } else {
333 filterExpr = ':gt(' + triggerTab.index + ')';
334 left = slideWidth;
335 }
336
337 slides
338 .filter(filterExpr)
339 .children('h2')
340 .each(function() {
341 var $this = $(this),
342 tab = {
343 elem : $this,
344 index : header.index($this),
345 next : $this.next(),
346 prev : $this.parent().prev().children('h2'),
347 pos : left
348 };
349
350 // trigger item anim, pass original trigger context for callback fn
351 core.animSlide.call(tab, triggerTab);
352 });
353
354 });
355
356 // remove, then add selected class
357 header.removeClass('selected').filter(triggerTab.elem).addClass('selected');
358 },
359
360 ieClass : function(version) {
361 if (version < 7) methods.destroy();
362 if (version >= 10) return;
363 if (version === 7 || version === 8) {
364 slides.each(function(index) {
365 $(this).addClass('slide-' + index);
366 });
367 }
368
369 elem.addClass('ie ie' + version);
370 },
371
372 init : function() {
373 var ua = navigator.userAgent,
374 index = ua.indexOf('MSIE');
375
376 // test for ie
377 if (index !== -1) {
378 ua = ua.slice(index + 5, index + 7);
379 core.ieClass(+ua);
380 }
381
382 // init styles and events
383 core.setStyles();
384 core.bindEvents();
385
386 // check slide speed is not faster than cycle speed
387 if (settings.cycleSpeed < settings.slideSpeed) settings.cycleSpeed = settings.slideSpeed;
388
389 // init autoplay
390 settings.autoPlay && methods.play();
391 }
392 };
393
394 // init plugin
395 core.init();
396
397 // expose methods
398 return methods;
399
400 };
401
402 $.fn.liteAccordion = function() {
403 var method=arguments[0];
404 var elem = this,
405 instance = elem.data('liteAccordion');
406
407 // if creating a new instance
408 if (typeof method === 'object' || !method) {
409 return elem.each(function() {
410 var liteAccordion;
411
412 // if plugin already instantiated, return
413 if (instance) return;
414
415 // otherwise create a new instance
416 liteAccordion = new LiteAccordion(elem, method);
417 elem.data('liteAccordion', liteAccordion);
418 });
419
420 // otherwise, call method on current instance
421 } else if (typeof method === 'string' && instance[method]) {
422 arguments = Array.prototype.slice.call(arguments, 1);
423 // debug method isn't chainable b/c we need the debug object to be returned
424 if (method === 'debug') {
425 return instance[method].call(elem);
426 } else { // the rest of the methods are chainable though
427 instance[method].apply(elem, arguments);
428
429 return elem;
430 }
431 }
432 };
433
434})(jQuery);
Note: See TracBrowser for help on using the repository browser.