PageSourceSearch

https://10billionbeats.com/SpryAssets/SpryAccordion.js

js 10billionbeats.com collected 2026-09-26 17:00:07 UTC 15,354 bytes, 559 lines download raw bytes

1// SpryAccordion.js - version 0.15 - 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.Accordion = function(element, opts)
35{
36	this.element = this.getElement(element);
37	this.defaultPanel = 0;
38	this.hoverClass = "AccordionPanelTabHover";
39	this.openClass = "AccordionPanelOpen";
40	this.closedClass = "AccordionPanelClosed";
41	this.focusedClass = "AccordionFocused";
42	this.enableAnimation = true;
43	this.enableKeyboardNavigation = true;
44	this.currentPanel = null;
45	this.animator = null;
46	this.hasFocus = null;
47
48	this.previousPanelKeyCode = Spry.Widget.Accordion.KEY_UP;
49	this.nextPanelKeyCode = Spry.Widget.Accordion.KEY_DOWN;
50
51	this.useFixedPanelHeights = true;
52	this.fixedPanelHeight = 0;
53
54	Spry.Widget.Accordion.setOptions(this, opts, true);
55
56	this.attachBehaviors();
57};
58
59Spry.Widget.Accordion.prototype.getElement = function(ele)
60{
61	if (ele && typeof ele == "string")
62		return document.getElementById(ele);
63	return ele;
64};
65
66Spry.Widget.Accordion.prototype.addClassName = function(ele, className)
67{
68	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1))
69		return;
70	ele.className += (ele.className ? " " : "") + className;
71};
72
73Spry.Widget.Accordion.prototype.removeClassName = function(ele, className)
74{
75	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1))
76		return;
77	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
78};
79
80Spry.Widget.Accordion.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
81{
82	if (!optionsObj)
83		return;
84	for (var optionName in optionsObj)
85	{
86		if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
87			continue;
88		obj[optionName] = optionsObj[optionName];
89	}
90};
91
92Spry.Widget.Accordion.prototype.onPanelTabMouseOver = function(e, panel)
93{
94	if (panel)
95		this.addClassName(this.getPanelTab(panel), this.hoverClass);
96	return false;
97};
98
99Spry.Widget.Accordion.prototype.onPanelTabMouseOut = function(e, panel)
100{
101	if (panel)
102		this.removeClassName(this.getPanelTab(panel), this.hoverClass);
103	return false;
104};
105
106Spry.Widget.Accordion.prototype.openPanel = function(elementOrIndex)
107{
108	var panelA = this.currentPanel;
109	var panelB;
110
111	if (typeof elementOrIndex == "number")
112		panelB = this.getPanels()[elementOrIndex];
113	else
114		panelB = this.getElement(elementOrIndex);
115	
116	if (!panelB || panelA == panelB)	
117		return null;
118
119	var contentA = panelA ? this.getPanelContent(panelA) : null;
120	var contentB = this.getPanelContent(panelB);
121
122	if (!contentB)
123		return null;
124
125	if (this.useFixedPanelHeights && !this.fixedPanelHeight)
126		this.fixedPanelHeight = (contentA.offsetHeight) ? contentA.offsetHeight : contentA.scrollHeight;
127
128	if (this.enableAnimation)
129	{
130		if (this.animator)
131			this.animator.stop();
132		this.animator = new Spry.Widget.Accordion.PanelAnimator(this, panelB, { duration: this.duration, fps: this.fps, transition: this.transition });
133		this.animator.start();
134	}
135	else
136	{
137		if(contentA)
138		{
139			contentA.style.display = "none";
140			contentA.style.height = "0px";
141		}
142		contentB.style.display = "block";
143		contentB.style.height = this.useFixedPanelHeights ? this.fixedPanelHeight + "px" : "auto";
144	}
145
146	if(panelA)
147	{
148		this.removeClassName(panelA, this.openClass);
149		this.addClassName(panelA, this.closedClass);
150	}
151
152	this.removeClassName(panelB, this.closedClass);
153	this.addClassName(panelB, this.openClass);
154
155	this.currentPanel = panelB;
156
157	return panelB;
158};
159
160Spry.Widget.Accordion.prototype.closePanel = function()
161{
162	// The accordion can only ever have one panel open at any
163	// give time, so this method only closes the current panel.
164	// If the accordion is in fixed panel heights mode, this
165	// method does nothing.
166
167	if (!this.useFixedPanelHeights && this.currentPanel)
168	{
169		var panel = this.currentPanel;
170		var content = this.getPanelContent(panel);
171		if (content)
172		{
173			if (this.enableAnimation)
174			{
175				if (this.animator)
176					this.animator.stop();
177				this.animator = new Spry.Widget.Accordion.PanelAnimator(this, null, { duration: this.duration, fps: this.fps, transition: this.transition });
178				this.animator.start();
179			}
180			else
181			{
182				content.style.display = "none";
183				content.style.height = "0px";
184			}
185		}		
186		this.removeClassName(panel, this.openClass);
187		this.addClassName(panel, this.closedClass);
188		this.currentPanel = null;
189	}
190};
191
192Spry.Widget.Accordion.prototype.openNextPanel = function()
193{
194	return this.openPanel(this.getCurrentPanelIndex() + 1);
195};
196
197Spry.Widget.Accordion.prototype.openPreviousPanel = function()
198{
199	return this.openPanel(this.getCurrentPanelIndex() - 1);
200};
201
202Spry.Widget.Accordion.prototype.openFirstPanel = function()
203{
204	return this.openPanel(0);
205};
206
207Spry.Widget.Accordion.prototype.openLastPanel = function()
208{
209	var panels = this.getPanels();
210	return this.openPanel(panels[panels.length - 1]);
211};
212
213Spry.Widget.Accordion.prototype.onPanelTabClick = function(e, panel)
214{
215	if (panel != this.currentPanel)
216		this.openPanel(panel);
217	else
218		this.closePanel();
219
220	if (this.enableKeyboardNavigation)
221		this.focus();
222
223	if (e.preventDefault) e.preventDefault();
224	else e.returnValue = false;
225	if (e.stopPropagation) e.stopPropagation();
226	else e.cancelBubble = true;
227
228	return false;
229};
230
231Spry.Widget.Accordion.prototype.onFocus = function(e)
232{
233	this.hasFocus = true;
234	this.addClassName(this.element, this.focusedClass);
235	return false;
236};
237
238Spry.Widget.Accordion.prototype.onBlur = function(e)
239{
240	this.hasFocus = false;
241	this.removeClassName(this.element, this.focusedClass);
242	return false;
243};
244
245Spry.Widget.Accordion.KEY_UP = 38;
246Spry.Widget.Accordion.KEY_DOWN = 40;
247
248Spry.Widget.Accordion.prototype.onKeyDown = function(e)
249{
250	var key = e.keyCode;
251	if (!this.hasFocus || (key != this.previousPanelKeyCode && key != this.nextPanelKeyCode))
252		return true;
253	
254	var panels = this.getPanels();
255	if (!panels || panels.length < 1)
256		return false;
257	var currentPanel = this.currentPanel ? this.currentPanel : panels[0];
258	var nextPanel = (key == this.nextPanelKeyCode) ? currentPanel.nextSibling : currentPanel.previousSibling;
259
260	while (nextPanel)
261	{
262		if (nextPanel.nodeType == 1 /* Node.ELEMENT_NODE */)
263			break;
264		nextPanel = (key == this.nextPanelKeyCode) ? nextPanel.nextSibling : nextPanel.previousSibling;
265	}
266
267	if (nextPanel && currentPanel != nextPanel)
268		this.openPanel(nextPanel);
269
270	if (e.preventDefault) e.preventDefault();
271	else e.returnValue = false;
272	if (e.stopPropagation) e.stopPropagation();
273	else e.cancelBubble = true;
274
275	return false;
276};
277
278Spry.Widget.Accordion.prototype.attachPanelHandlers = function(panel)
279{
280	if (!panel)
281		return;
282
283	var tab = this.getPanelTab(panel);
284
285	if (tab)
286	{
287		var self = this;
288		Spry.Widget.Accordion.addEventListener(tab, "click", function(e) { return self.onPanelTabClick(e, panel); }, false);
289		Spry.Widget.Accordion.addEventListener(tab, "mouseover", function(e) { return self.onPanelTabMouseOver(e, panel); }, false);
290		Spry.Widget.Accordion.addEventListener(tab, "mouseout", function(e) { return self.onPanelTabMouseOut(e, panel); }, false);
291	}
292};
293
294Spry.Widget.Accordion.addEventListener = function(element, eventType, handler, capture)
295{
296	try
297	{
298		if (element.addEventListener)
299			element.addEventListener(eventType, handler, capture);
300		else if (element.attachEvent)
301			element.attachEvent("on" + eventType, handler);
302	}
303	catch (e) {}
304};
305
306Spry.Widget.Accordion.prototype.initPanel = function(panel, isDefault)
307{
308	var content = this.getPanelContent(panel);
309	if (isDefault)
310	{
311		this.currentPanel = panel;
312		this.removeClassName(panel, this.closedClass);
313		this.addClassName(panel, this.openClass);
314
315		// Attempt to set up the height of the default panel. We don't want to
316		// do any dynamic panel height calculations here because our accordion
317		// or one of its parent containers may be display:none.
318
319		if (content)
320		{
321			if (this.useFixedPanelHeights)
322			{
323				// We are in fixed panel height mode and the user passed in
324				// a panel height for us to use.
325	
326				if (this.fixedPanelHeight)
327					content.style.height = this.fixedPanelHeight + "px";
328			}
329			else
330			{
331				// We are in variable panel height mode, but since we can't
332				// calculate the panel height here, we just set the height to
333				// auto so that it expands to show all of its content.
334	
335				content.style.height = "auto";
336			}
337		}
338	}
339	else
340	{
341		this.removeClassName(panel, this.openClass);
342		this.addClassName(panel, this.closedClass);
343
344		if (content)
345		{
346			content.style.height = "0px";
347			content.style.display = "none";
348		}
349	}
350	
351	this.attachPanelHandlers(panel);
352};
353
354Spry.Widget.Accordion.prototype.attachBehaviors = function()
355{
356	var panels = this.getPanels();
357	for (var i = 0; i < panels.length; i++)
358		this.initPanel(panels[i], i == this.defaultPanel);
359
360	// Advanced keyboard navigation requires the tabindex attribute
361	// on the top-level element.
362
363	this.enableKeyboardNavigation = (this.enableKeyboardNavigation && this.element.attributes.getNamedItem("tabindex"));
364	if (this.enableKeyboardNavigation)
365	{
366		var self = this;
367		Spry.Widget.Accordion.addEventListener(this.element, "focus", function(e) { return self.onFocus(e); }, false);
368		Spry.Widget.Accordion.addEventListener(this.element, "blur", function(e) { return self.onBlur(e); }, false);
369		Spry.Widget.Accordion.addEventListener(this.element, "keydown", function(e) { return self.onKeyDown(e); }, false);
370	}
371};
372
373Spry.Widget.Accordion.prototype.getPanels = function()
374{
375	return this.getElementChildren(this.element);
376};
377
378Spry.Widget.Accordion.prototype.getCurrentPanel = function()
379{
380	return this.currentPanel;
381};
382
383Spry.Widget.Accordion.prototype.getPanelIndex = function(panel)
384{
385	var panels = this.getPanels();
386	for( var i = 0 ; i < panels.length; i++ )
387	{
388		if( panel == panels[i] )
389			return i;
390	}
391	return -1;
392};
393
394Spry.Widget.Accordion.prototype.getCurrentPanelIndex = function()
395{
396	return this.getPanelIndex(this.currentPanel);
397};
398
399Spry.Widget.Accordion.prototype.getPanelTab = function(panel)
400{
401	if (!panel)
402		return null;
403	return this.getElementChildren(panel)[0];
404};
405
406Spry.Widget.Accordion.prototype.getPanelContent = function(panel)
407{
408	if (!panel)
409		return null;
410	return this.getElementChildren(panel)[1];
411};
412
413Spry.Widget.Accordion.prototype.getElementChildren = function(element)
414{
415	var children = [];
416	var child = element.firstChild;
417	while (child)
418	{
419		if (child.nodeType == 1 /* Node.ELEMENT_NODE */)
420			children.push(child);
421		child = child.nextSibling;
422	}
423	return children;
424};
425
426Spry.Widget.Accordion.prototype.focus = function()
427{
428	if (this.element && this.element.focus)
429		this.element.focus();
430};
431
432Spry.Widget.Accordion.prototype.blur = function()
433{
434	if (this.element && this.element.blur)
435		this.element.blur();
436};
437
438/////////////////////////////////////////////////////
439
440Spry.Widget.Accordion.PanelAnimator = function(accordion, panel, opts)
441{
442	this.timer = null;
443	this.interval = 0;
444
445	this.fps = 60;
446	this.duration = 500;
447	this.startTime = 0;
448
449	this.transition = Spry.Widget.Accordion.PanelAnimator.defaultTransition;
450
451	this.onComplete = null;
452
453	this.panel = panel;
454	this.panelToOpen = accordion.getElement(panel);
455	this.panelData = [];
456	this.useFixedPanelHeights = accordion.useFixedPanelHeights;
457
458	Spry.Widget.Accordion.setOptions(this, opts, true);
459
460	this.interval = Math.floor(1000 / this.fps);
461
462	// Set up the array of panels we want to animate.
463
464	var panels = accordion.getPanels();
465	for (var i = 0; i < panels.length; i++)
466	{
467		var p = panels[i];
468		var c = accordion.getPanelContent(p);
469		if (c)
470		{
471			var h = c.offsetHeight;
472			if (h == undefined)
473				h = 0;
474
475			if (p == panel && h == 0)
476				c.style.display = "block";
477
478			if (p == panel || h > 0)
479			{
480				var obj = new Object;
481				obj.panel = p;
482				obj.content = c;
483				obj.fromHeight = h;
484				obj.toHeight = (p == panel) ? (accordion.useFixedPanelHeights ? accordion.fixedPanelHeight : c.scrollHeight) : 0;
485				obj.distance = obj.toHeight - obj.fromHeight;
486				obj.overflow = c.style.overflow;
487				this.panelData.push(obj);
488
489				c.style.overflow = "hidden";
490				c.style.height = h + "px";
491			}
492		}
493	}
494};
495
496Spry.Widget.Accordion.PanelAnimator.defaultTransition = function(time, begin, finish, duration) { time /= duration; return begin + ((2 - time) * time * finish); };
497
498Spry.Widget.Accordion.PanelAnimator.prototype.start = function()
499{
500	var self = this;
501	this.startTime = (new Date).getTime();
502	this.timer = setTimeout(function() { self.stepAnimation(); }, this.interval);
503};
504
505Spry.Widget.Accordion.PanelAnimator.prototype.stop = function()
506{
507	if (this.timer)
508	{
509		clearTimeout(this.timer);
510
511		// If we're killing the timer, restore the overflow
512		// properties on the panels we were animating!
513
514		for (i = 0; i < this.panelData.length; i++)
515		{
516			obj = this.panelData[i];
517			obj.content.style.overflow = obj.overflow;
518		}
519	}
520
521	this.timer = null;
522};
523
524Spry.Widget.Accordion.PanelAnimator.prototype.stepAnimation = function()
525{
526	var curTime = (new Date).getTime();
527	var elapsedTime = curTime - this.startTime;
528
529	var i, obj;
530
531	if (elapsedTime >= this.duration)
532	{
533		for (i = 0; i < this.panelData.length; i++)
534		{
535			obj = this.panelData[i];
536			if (obj.panel != this.panel)
537			{
538				obj.content.style.display = "none";
539				obj.content.style.height = "0px";
540			}
541			obj.content.style.overflow = obj.overflow;
542			obj.content.style.height = (this.useFixedPanelHeights || obj.toHeight == 0) ? obj.toHeight + "px" : "auto";
543		}
544		if (this.onComplete)
545			this.onComplete();
546		return;
547	}
548
549	for (i = 0; i < this.panelData.length; i++)
550	{
551		obj = this.panelData[i];
552		var ht = this.transition(elapsedTime, obj.fromHeight, obj.distance, this.duration);
553		obj.content.style.height = ((ht < 0) ? 0 : ht) + "px";
554	}
555	
556	var self = this;
557	this.timer = setTimeout(function() { self.stepAnimation(); }, this.interval);
558};
559

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.