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