1/* 2 * jQuery Open/Close plugin 3 */ 4// opens /closes block on click 5 6;(function($) { 7 function OpenClose(options) { 8 this.options = $.extend({ 9 addClassBeforeAnimation: true, 10 hideOnClickOutside: false, 11 activeClass:'active', 12 opener:'.opener', 13 slider:'.slide', 14 animSpeed: 400, 15 effect:'fade', 16 event:'click' 17 }, options); 18 this.init(); 19 } 20 OpenClose.prototype = { 21 init: function() { 22 if (this.options.holder) { 23 this.findElements(); 24 this.attachEvents(); 25 this.makeCallback('onInit', this); 26 } 27 }, 28 findElements: function() { 29 this.holder = $(this.options.holder); 30 this.opener = this.holder.find(this.options.opener); 31 this.slider = this.holder.find(this.options.slider); 32 }, 33 attachEvents: function() { 34 // add handler 35 var self = this; 36 this.eventHandler = function(e) { 37 e.preventDefault(); 38 if (self.slider.hasClass(slideHiddenClass)) { 39 self.showSlide(); 40 } else { 41 self.hideSlide(); 42 } 43 }; 44 self.opener.bind(self.options.event, this.eventHandler); 45 46 // hover mode handler 47 if (self.options.event === 'over') { 48 self.opener.bind('mouseenter', function() { 49 if (!self.holder.hasClass(self.options.activeClass)){ 50 self.showSlide(); 51 } 52 }); 53 self.holder.bind('mouseleave', function() { 54 self.hideSlide(); 55 }); 56 } 57 58 // outside click handler 59 self.outsideClickHandler = function(e) { 60 if (self.options.hideOnClickOutside) { 61 var target = $(e.target); 62 if (!target.is(self.holder) && !target.closest(self.holder).length) { 63 self.hideSlide(); 64 } 65 } 66 }; 67 68 // set initial styles 69 if (this.holder.hasClass(this.options.activeClass)) { 70 $(document).bind('click touchstart', self.outsideClickHandler); 71 } else { 72 this.slider.addClass(slideHiddenClass); 73 } 74 }, 75 showSlide: function() { 76 var self = this; 77 if (self.options.addClassBeforeAnimation) { 78 self.holder.addClass(self.options.activeClass); 79 } 80 self.slider.removeClass(slideHiddenClass); 81 $(document).bind('click touchstart', self.outsideClickHandler); 82 83 self.makeCallback('animStart', true); 84 toggleEffects[self.options.effect].show({ 85 box: self.slider, 86 speed: self.options.animSpeed, 87 complete: function() { 88 if (!self.options.addClassBeforeAnimation) { 89 self.holder.addClass(self.options.activeClass); 90 } 91 self.makeCallback('animEnd', true); 92 } 93 }); 94 }, 95 hideSlide: function() { 96 var self = this; 97 if (self.options.addClassBeforeAnimation) { 98 self.holder.removeClass(self.options.activeClass); 99 } 100 $(document).unbind('click touchstart', self.outsideClickHandler); 101 102 self.makeCallback('animStart', false); 103 toggleEffects[self.options.effect].hide({ 104 box: self.slider, 105 speed: self.options.animSpeed, 106 complete: function() { 107 if (!self.options.addClassBeforeAnimation) { 108 self.holder.removeClass(self.options.activeClass); 109 } 110 self.slider.addClass(slideHiddenClass); 111 self.makeCallback('animEnd', false); 112 } 113 }); 114 }, 115 destroy: function() { 116 this.slider.removeClass(slideHiddenClass).css({ display:'' }); 117 this.opener.unbind(this.options.event, this.eventHandler); 118 this.holder.removeClass(this.options.activeClass).removeData('OpenClose'); 119 $(document).unbind('click touchstart', this.outsideClickHandler); 120 }, 121 makeCallback: function(name) { 122 if (typeof this.options[name] === 'function') { 123 var args = Array.prototype.slice.call(arguments); 124 args.shift(); 125 this.options[name].apply(this, args); 126 } 127 } 128 }; 129 130 // add stylesheet for slide on DOMReady 131 var slideHiddenClass = 'js-slide-hidden'; 132 (function() { 133 var tabStyleSheet = $('<style type="text/css">')[0]; 134 var tabStyleRule = '.' + slideHiddenClass; 135 tabStyleRule += '{position:absolute !important;left:-9999px !important;top:-9999px !important;display:block !important}'; 136 if (tabStyleSheet.styleSheet) { 137 tabStyleSheet.styleSheet.cssText = tabStyleRule; 138 } else { 139 tabStyleSheet.appendChild(document.createTextNode(tabStyleRule)); 140 } 141 $('head').append(tabStyleSheet); 142 }()); 143 144 // animation effects 145 var toggleEffects = { 146 slide: { 147 show: function(o) { 148 o.box.stop(true).hide().slideDown(o.speed, o.complete); 149 }, 150 hide: function(o) {
151 o.box.stop(true).slideUp(o.speed, o.complete); 152 } 153 }, 154 fade: { 155 show: function(o) { 156 o.box.stop(true).hide().fadeIn(o.speed, o.complete); 157 }, 158 hide: function(o) { 159 o.box.stop(true).fadeOut(o.speed, o.complete); 160 } 161 }, 162 none: { 163 show: function(o) { 164 o.box.hide().show(0, o.complete); 165 }, 166 hide: function(o) { 167 o.box.hide(0, o.complete); 168 } 169 } 170 }; 171 172 // jQuery plugin interface 173 $.fn.openClose = function(opt) { 174 return this.each(function() { 175 jQuery(this).data('OpenClose', new OpenClose($.extend(opt, { holder: this }))); 176 }); 177 }; 178}(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.