1 2/** 3 * jquery.scrollable 0.11. Making HTML elements scroll. 4 * 5 * http://flowplayer.org/tools/scrollable.html 6 * 7 * Copyright (c) 2008 Tero Piirainen ([email protected]) 8 * 9 * Released under the MIT License: 10 * http://www.opensource.org/licenses/mit-license.php 11 * 12 * >> Basically you can do anything you want but leave this header as is << 13 * 14 * Since : 0.01 - 03/01/2008 15 * Version: 0.11 - 05/29/2008 16 */ 17(function($) { 18 19 // plugin initialization 20 $.fn.extend({ 21 scrollable: function(arg1, arg2, arg3) { 22 23 return this.each(function() { 24 if (typeof arg1 == "string") { 25 var el = $.data(this, "scrollable"); 26 el[arg1].apply(el, [arg2, arg3]); 27 28 } else { 29 new $.scrollable(this, arg1, arg2); 30 } 31 }); 32 } 33 }); 34 35 // constructor 36 $.scrollable = function(el, opts) { 37 38 // store this instance 39 $.data(el, "scrollable", this); 40 41 this.init(el, opts); 42 }; 43 44 45 // methods 46 $.extend($.scrollable.prototype, { 47 48 init: function(el, config) { 49 50 // current instance 51 var self = this; 52 53 var opts = { 54 size: 5, 55 horizontal:false, 56 activeClass:'active', 57 speed: 300, 58 onSeek: null, 59 60 // jquery selectors 61 items: '.items', 62 prev:'.prev', 63 next:'.next', 64 navi:'.navi', 65 naviItem:'span' 66 }; 67 68 this.opts = $.extend(opts, config); 69 70 // root / itemRoot 71 var root = this.root = $(el); 72 var itemRoot = $(opts.items, root); 73 if (!itemRoot.length) itemRoot = root; 74 75 // wrap itemRoot.children() inside container 76 itemRoot.css({position:'relative', overflow:'hidden', visibility:'visible'}); 77 itemRoot.children().wrapAll('<div class="__scrollable" style="position:absolute"/>'); 78 79 this.wrap = itemRoot.children(":first"); 80 this.wrap.css(opts.horizontal ? "width" : "height", "200000em").after('<br clear="all"/>'); 81 this.items = this.wrap.children(); 82 this.index = 0; 83 84 85 // set height based on size 86 if (opts.horizontal) { 87 itemRoot.width(opts.size * (this.items.eq(1).offset().left - this.items.eq(0).offset().left) -2); 88 } else { 89 itemRoot.height(opts.size * (this.items.eq(1).offset().top - this.items.eq(0).offset().top) -2); 90 } 91 92 // mousewheel 93 if ($.isFunction($.fn.mousewheel)) { 94 root.bind("mousewheel.scrollable", function(event, delta) { 95 self.move(-delta, 50); 96 return false; 97 }); 98 } 99 100 // keyboard 101 $(window).bind("keypress.scrollable", function(evt) { 102 103 if ($(evt.target).parents(".__scrollable").length) { 104 105 if (opts.horizontal && (evt.keyCode == 37 || evt.keyCode == 39)) { 106 self.move(evt.keyCode == 37 ? -1 : 1); 107 return false; 108 } 109 110 if (!opts.horizontal && (evt.keyCode == 38 || evt.keyCode == 40)) { 111 self.move(evt.keyCode == 38 ? -1 : 1); 112 return false; 113 } 114 } 115 116 return true; 117 118 }); 119 120 121 // item.click() 122 this.items.each(function(index, arg) { 123 $(this).bind("click.scrollable", function() { 124 self.click(index); 125 }); 126 }); 127 128 this.activeIndex = 0; 129 130 // prev 131 $(opts.prev, root).click(function() { self.prev() }); 132 133 134 // next 135 $(opts.next, root).click(function() { self.next() }); 136 137 138 // navi 139 $(opts.navi, root).each(function() { 140 var navi = $(this); 141 142 var status = self.getStatus(); 143 144 // generate new entries 145 if (navi.is(":empty")) { 146 for (var i = 0; i < status.pages; i++) { 147 148 var item = $("<" + opts.naviItem + "/>").attr("page", i).click(function() { 149 var el = $(this); 150 el.parent().children().removeClass(opts.activeClass); 151 el.addClass(opts.activeClass); 152 self.setPage(el.attr("page")); 153 154 }); 155 156 if (i == 0) item.addClass(opts.activeClass); 157 navi.append(item); 158 } 159 160 // assign onClick events to existing entries 161 } else { 162 163 navi.children().each(function(i) { 164 var item = $(this); 165 item.attr("page", i); 166 if (i == 0) item.addClass(opts.activeClass); 167 168 item.click(function() { 169 item.parent().children().removeClass(opts.activeClass); 170 item.addClass(opts.activeClass); 171 self.setPage(item.attr("page")); 172 });
173 174 }); 175 } 176 177 }); 178 179 }, 180 181 182 click: function(index) { 183 184 var item = this.items.eq(index); 185 var klass = this.opts.activeClass; 186 187 if (!item.hasClass(klass) && (index >= 0 || index < this.items.size())) { 188 189 var prev = this.items.eq(this.activeIndex).removeClass(klass); 190 item.addClass(klass); 191 192 this.seekTo(index - Math.floor(this.opts.size / 2)); 193 this.activeIndex = index; 194 } 195 }, 196 197 getStatus: function() { 198 var len = this.items.size(); 199 var s = { 200 length: len, 201 index: this.index, 202 size: this.opts.size, 203 pages: Math.floor(len / this.opts.size), 204 page: Math.floor(this.index / this.opts.size) 205 }; 206 207 return s; 208 }, 209 210 211 // all other seeking functions depend on this generic seeking function 212 seekTo: function(index, time) { 213 214 if (index < 0) index = 0; 215 index = Math.min(index, this.items.length - this.opts.size); 216 217 var item = this.items.eq(index); 218 if (item.size() == 0) return false; 219 this.index = index; 220 221 222 if (this.opts.horizontal) { 223 var left = this.wrap.offset().left - item.offset().left; 224 this.wrap.animate({left: left}, time || this.opts.speed); 225 226 } else { 227 var top = this.wrap.offset().top - item.offset().top; 228 this.wrap.animate({top: top}, time || this.opts.speed); 229 } 230 231 // custom onSeek callback 232 if ($.isFunction(this.opts.onSeek)) { 233 this.opts.onSeek.call(this.getStatus()); 234 } 235 236 // navi status update 237 var navi = $(this.opts.navi, this.root); 238 239 if (navi.length) { 240 var klass = this.opts.activeClass; 241 var page = Math.round(index / this.opts.size); 242 navi.children().removeClass(klass).eq(page).addClass(klass); 243 } 244 245 246 return true; 247 }, 248 249 250 move: function(offset, time) { 251 this.seekTo(this.index + offset, time); 252 }, 253 254 next: function(time) { 255 this.move(1, time); 256 }, 257 258 prev: function(time) { 259 this.move(-1, time); 260 }, 261 262 movePage: function(offset, time) { 263 this.move(this.opts.size * offset, time); 264 }, 265 266 setPage: function(index, time) { 267 this.seekTo(this.opts.size * index, time); 268 }, 269 270 prevPage: function(time) { 271 var page = Math.floor(this.index / this.opts.size); 272 this.seekTo(this.opts.size * (page-1), time); 273 }, 274 275 nextPage: function(time) { 276 var page = Math.floor(this.index / this.opts.size); 277 this.seekTo(this.opts.size * (page+1), time); 278 }, 279 280 begin: function(time) { 281 this.seekTo(0, time); 282 }, 283 284 end: function(time) { 285 this.seekTo(this.items.size() - this.opts.size, time); 286 } 287 288 289 }); 290 291})(jQuery); 292 293 294
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.