1// SprySlidingPanels.js - version 0.5 - Spry Pre-Release 1.6.1 2// 3// Copyright (c) 2006. Adobe Systems Incorporated. 4// All rights reserved. 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are met: 8// 9// * Redistributions of source code must retain the above copyright notice, 10// this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above copyright notice, 12// this list of conditions and the following disclaimer in the documentation 13// and/or other materials provided with the distribution. 14// * Neither the name of Adobe Systems Incorporated nor the names of its 15// contributors may be used to endorse or promote products derived from this 16// software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28// POSSIBILITY OF SUCH DAMAGE. 29 30var Spry; 31if (!Spry) Spry = {}; 32if (!Spry.Widget) Spry.Widget = {}; 33 34Spry.Widget.SlidingPanels = function(element, opts) 35{ 36 this.element = this.getElement(element); 37 this.enableAnimation = true; 38 this.currentPanel = null; 39 this.enableKeyboardNavigation = true; 40 this.hasFocus = false; 41 this.previousPanelKeyCode = Spry.Widget.SlidingPanels.KEY_LEFT; 42 this.nextPanelKeyCode = Spry.Widget.SlidingPanels.KEY_RIGHT; 43 44 this.currentPanelClass = "SlidingPanelsCurrentPanel"; 45 this.focusedClass = "SlidingPanelsFocused"; 46 this.animatingClass = "SlidingPanelsAnimating"; 47 48 Spry.Widget.SlidingPanels.setOptions(this, opts); 49 50 if (this.element) 51 this.element.style.overflow = "hidden"; 52 53 // Developers can specify the default panel as an index, 54 // id or an actual element node. Make sure to normalize 55 // it into an element node because that is what we expect 56 // internally. 57 58 if (this.defaultPanel) 59 { 60 if (typeof this.defaultPanel == "number") 61 this.currentPanel = this.getContentPanels()[this.defaultPanel]; 62 else 63 this.currentPanel = this.getElement(this.defaultPanel); 64 } 65 66 // If we still don't have a current panel, use the first one! 67 68 if (!this.currentPanel) 69 this.currentPanel = this.getContentPanels()[0]; 70 71 // Since we rely on the positioning information of the 72 // panels, we need to wait for the onload event to fire before 73 // we can attempt to show the initial panel. Once the onload 74 // fires, we know that all CSS files have loaded. This is 75 // especially important for Safari. 76 77 if (Spry.Widget.SlidingPanels.onloadDidFire) 78 this.attachBehaviors(); 79 else 80 Spry.Widget.SlidingPanels.loadQueue.push(this); 81}; 82 83Spry.Widget.SlidingPanels.prototype.onFocus = function(e) 84{ 85 this.hasFocus = true; 86 this.addClassName(this.element, this.focusedClass); 87 return false; 88}; 89 90Spry.Widget.SlidingPanels.prototype.onBlur = function(e) 91{ 92 this.hasFocus = false; 93 this.removeClassName(this.element, this.focusedClass); 94 return false; 95}; 96 97Spry.Widget.SlidingPanels.KEY_LEFT = 37; 98Spry.Widget.SlidingPanels.KEY_UP = 38; 99Spry.Widget.SlidingPanels.KEY_RIGHT = 39; 100Spry.Widget.SlidingPanels.KEY_DOWN = 40; 101 102Spry.Widget.SlidingPanels.prototype.onKeyDown = function(e) 103{ 104 var key = e.keyCode; 105 if (!this.hasFocus || (key != this.previousPanelKeyCode && key != this.nextPanelKeyCode)) 106 return true; 107 108 if (key == this.nextPanelKeyCode) 109 this.showNextPanel();
110 else /* if (key == this.previousPanelKeyCode) */ 111 this.showPreviousPanel(); 112 113 if (e.preventDefault) e.preventDefault(); 114 else e.returnValue = false; 115 if (e.stopPropagation) e.stopPropagation(); 116 else e.cancelBubble = true; 117 118 return false; 119}; 120 121Spry.Widget.SlidingPanels.prototype.attachBehaviors = function() 122{ 123 var ele = this.element; 124 if (!ele) 125 return; 126 127 if (this.enableKeyboardNavigation) 128 { 129 var focusEle = null; 130 var tabIndexAttr = ele.attributes.getNamedItem("tabindex"); 131 if (tabIndexAttr || ele.nodeName.toLowerCase() == "a") 132 focusEle = ele; 133 134 if (focusEle) 135 { 136 var self = this; 137 Spry.Widget.SlidingPanels.addEventListener(focusEle, "focus", function(e) { return self.onFocus(e || window.event); }, false); 138 Spry.Widget.SlidingPanels.addEventListener(focusEle, "blur", function(e) { return self.onBlur(e || window.event); }, false); 139 Spry.Widget.SlidingPanels.addEventListener(focusEle, "keydown", function(e) { return self.onKeyDown(e || window.event); }, false); 140 } 141 } 142 143 if (this.currentPanel) 144 { 145 // Temporarily turn off animation when showing the 146 // initial panel. 147 148 var ea = this.enableAnimation; 149 this.enableAnimation = false; 150 this.showPanel(this.currentPanel); 151 this.enableAnimation = ea; 152 } 153}; 154 155Spry.Widget.SlidingPanels.prototype.getElement = function(ele) 156{ 157 if (ele && typeof ele == "string") 158 return document.getElementById(ele); 159 return ele; 160}; 161 162Spry.Widget.SlidingPanels.prototype.addClassName = function(ele, className) 163{ 164 if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1)) 165 return; 166 ele.className += (ele.className ? " " : "") + className; 167}; 168 169Spry.Widget.SlidingPanels.prototype.removeClassName = function(ele, className) 170{ 171 if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)) 172 return; 173 ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), ""); 174}; 175 176Spry.Widget.SlidingPanels.setOptions = function(obj, optionsObj, ignoreUndefinedProps) 177{ 178 if (!optionsObj) 179 return; 180 for (var optionName in optionsObj) 181 { 182 if (ignoreUndefinedProps && optionsObj[optionName] == undefined) 183 continue; 184 obj[optionName] = optionsObj[optionName]; 185 } 186}; 187 188Spry.Widget.SlidingPanels.prototype.getElementChildren = function(element) 189{ 190 var children = []; 191 var child = element.firstChild; 192 while (child) 193 { 194 if (child.nodeType == 1 /* Node.ELEMENT_NODE */) 195 children.push(child); 196 child = child.nextSibling; 197 } 198 return children; 199}; 200 201Spry.Widget.SlidingPanels.prototype.getCurrentPanel = function() 202{ 203 return this.currentPanel; 204}; 205 206Spry.Widget.SlidingPanels.prototype.getContentGroup = function() 207{ 208 return this.getElementChildren(this.element)[0]; 209}; 210 211Spry.Widget.SlidingPanels.prototype.getContentPanels = function() 212{ 213 return this.getElementChildren(this.getContentGroup()); 214}; 215 216Spry.Widget.SlidingPanels.prototype.getContentPanelsCount = function() 217{ 218 return this.getContentPanels().length; 219}; 220 221Spry.Widget.SlidingPanels.onloadDidFire = false; 222Spry.Widget.SlidingPanels.loadQueue = []; 223 224Spry.Widget.SlidingPanels.addLoadListener = function(handler) 225{ 226 if (typeof window.addEventListener != 'undefined') 227 window.addEventListener('load', handler, false); 228 else if (typeof document.addEventListener != 'undefined') 229 document.addEventListener('load', handler, false); 230 else if (typeof window.attachEvent != 'undefined') 231 window.attachEvent('onload', handler); 232}; 233 234Spry.Widget.SlidingPanels.processLoadQueue = function(handler) 235{ 236 Spry.Widget.SlidingPanels.onloadDidFire = true; 237 var q = Spry.Widget.SlidingPanels.loadQueue; 238 var qlen = q.length; 239 for (var i = 0; i < qlen; i++) 240 q[i].attachBehaviors(); 241}; 242 243Spry.Widget.SlidingPanels.addLoadListener(Spry.Widget.SlidingPanels.processLoadQueue); 244 245Spry.Widget.SlidingPanels.addEventListener = function(element, eventType, handler, capture) 246{ 247 try 248 { 249 if (element.addEventListener) 250 element.addEventListener(eventType, handler, capture); 251 else if (element.attachEvent) 252 element.attachEvent("on" + eventType, handler); 253 } 254 catch (e) {} 255}; 256 257Spry.Widget.SlidingPanels.prototype.getContentPanelIndex = function(ele) 258{ 259 if (ele) 260 { 261 ele = this.getElement(ele); 262 var panels = this.getContentPanels(); 263 var numPanels = panels.length; 264 for (var i = 0; i < numPanels; i++) 265 { 266 if (panels[i] == ele) 267 return i; 268 } 269 } 270 return -1; 271};
272 273Spry.Widget.SlidingPanels.prototype.showPanel = function(elementOrIndex) 274{ 275 var pIndex = -1; 276 277 if (typeof elementOrIndex == "number") 278 pIndex = elementOrIndex; 279 else // Must be the element for the content panel. 280 pIndex = this.getContentPanelIndex(elementOrIndex); 281 282 var numPanels = this.getContentPanelsCount(); 283 if (numPanels > 0) 284 pIndex = (pIndex >= numPanels) ? numPanels - 1 : pIndex; 285 else 286 pIndex = 0; 287 288 var panel = this.getContentPanels()[pIndex]; 289 var contentGroup = this.getContentGroup(); 290 291 if (panel && contentGroup) 292 { 293 if (this.currentPanel) 294 this.removeClassName(this.currentPanel, this.currentPanelClass); 295 this.currentPanel = panel; 296 297 var nx = -panel.offsetLeft; 298 var ny = -panel.offsetTop; 299 300 if (this.enableAnimation) 301 { 302 if (this.animator) 303 this.animator.stop(); 304 var cx = contentGroup.offsetLeft; 305 var cy = contentGroup.offsetTop; 306 if (cx != nx || cy != ny) 307 { 308 var self = this; 309 this.addClassName(this.element, this.animatingClass); 310 this.animator = new Spry.Widget.SlidingPanels.PanelAnimator(contentGroup, cx, cy, nx, ny, { duration: this.duration, fps: this.fps, transition: this.transition, finish: function() 311 { 312 self.removeClassName(self.element, self.animatingClass); 313 self.addClassName(panel, self.currentPanelClass); 314 } }); 315 this.animator.start(); 316 } 317 } 318 else 319 { 320 contentGroup.style.left = nx + "px"; 321 contentGroup.style.top = ny + "px"; 322 this.addClassName(panel, this.currentPanelClass); 323 } 324 } 325 326 return panel; 327}; 328 329Spry.Widget.SlidingPanels.prototype.showFirstPanel = function() 330{ 331 return this.showPanel(0); 332}; 333 334Spry.Widget.SlidingPanels.prototype.showLastPanel = function() 335{ 336 return this.showPanel(this.getContentPanels().length - 1); 337}; 338 339Spry.Widget.SlidingPanels.prototype.showPreviousPanel = function() 340{ 341 return this.showPanel(this.getContentPanelIndex(this.currentPanel) - 1); 342}; 343 344Spry.Widget.SlidingPanels.prototype.showNextPanel = function() 345{ 346 return this.showPanel(this.getContentPanelIndex(this.currentPanel) + 1); 347}; 348 349Spry.Widget.SlidingPanels.PanelAnimator = function(ele, curX, curY, dstX, dstY, opts) 350{ 351 this.element = ele; 352 353 this.curX = curX; 354 this.curY = curY; 355 this.dstX = dstX; 356 this.dstY = dstY; 357 this.fps = 60; 358 this.duration = 500; 359 this.transition = Spry.Widget.SlidingPanels.PanelAnimator.defaultTransition; 360 this.startTime = 0; 361 this.timerID = 0; 362 this.finish = null; 363 364 var self = this; 365 this.intervalFunc = function() { self.step(); }; 366 367 Spry.Widget.SlidingPanels.setOptions(this, opts, true); 368 369 this.interval = 1000/this.fps; 370};
371 372Spry.Widget.SlidingPanels.PanelAnimator.defaultTransition = function(time, begin, finish, duration) { time /= duration; return begin + ((2 - time) * time * finish); }; 373 374Spry.Widget.SlidingPanels.PanelAnimator.prototype.start = function() 375{ 376 this.stop(); 377 this.startTime = (new Date()).getTime(); 378 this.timerID = setTimeout(this.intervalFunc, this.interval); 379}; 380 381Spry.Widget.SlidingPanels.PanelAnimator.prototype.stop = function() 382{ 383 if (this.timerID) 384 clearTimeout(this.timerID); 385 this.timerID = 0; 386}; 387 388Spry.Widget.SlidingPanels.PanelAnimator.prototype.step = function() 389{ 390 var elapsedTime = (new Date()).getTime() - this.startTime; 391 var done = elapsedTime >= this.duration; 392 var x, y; 393 394 if (done) 395 { 396 x = this.curX = this.dstX; 397 y = this.curY = this.dstY; 398 } 399 else 400 { 401 x = this.transition(elapsedTime, this.curX, this.dstX - this.curX, this.duration); 402 y = this.transition(elapsedTime, this.curY, this.dstY - this.curY, this.duration); 403 } 404 405 this.element.style.left = x + "px"; 406 this.element.style.top = y + "px"; 407 408 if (!done) 409 this.timerID = setTimeout(this.intervalFunc, this.interval); 410 else if (this.finish) 411 this.finish(); 412}; 413
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.