/* --- script: Fx.Accordion.js description: An Fx.Elements extension which allows you to easily create accordion type controls. license: MIT-style license authors: - Valerio Proietti requires: - core:1.2.4/Element.Event - /Fx.Elements provides: [Fx.Accordion] ... */ Fx.Accordion = new Class({ Extends: Fx.Elements, options: {/* onActive: $empty(toggler, section), onBackground: $empty(toggler, section), fixedHeight: false, fixedWidth: false, */ display: 0, show: false, height: true, width: false, opacity: true, // ########## START: CHANGE ########## //alwaysHide: false, alwaysHide: true, // ########## END: CHANGE ########## // ########## START: EXTEND ########## // additional variables // prefix used for IDs prefix: 'tab_', // a flag, that shows if CTRL is pressed or not ctrl: false, // the current index of added sections index: 0, // the class name of the accordion headers className: '', // the current element with the focus elementWithFocus: null, // the index of the currently selected element currentIndex: 0, // ########## END: EXTEND ########## trigger: 'click', initialDisplayFx: true, returnHeightToAuto: true }, initialize: function(){ var params = Array.link(arguments, { 'container': Element.type, //deprecated 'options': Object.type, 'togglers': $defined, 'elements': $defined }); this.parent(params.elements, params.options); this.togglers = $$(params.togglers); // ########## START: EXTEND ########## //set focus on first accordion header this.togglers[0].setProperty('tabindex', 0); this.className = $$(params.togglers)[0].getProperty('class'); // ########## END: EXTEND ########## this.previous = -1; this.internalChain = new Chain(); if (this.options.alwaysHide) this.options.wait = true; if ($chk(this.options.show)){ this.options.display = false; this.previous = this.options.show; } if (this.options.start){ this.options.display = false; this.options.show = false; } this.effects = {}; if (this.options.opacity) this.effects.opacity = 'fullOpacity'; if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth'; if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight'; for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]); this.elements.each(function(el, i){ if (this.options.show === i){ this.fireEvent('active', [this.togglers[i], el]); } else { //console.log("initialize - SET STYLE: "); //console.log(el); for (var fx in this.effects) el.setStyle(fx, 0); } }, this); // ########## START: CHANGE ########## // Comment this line for being all Tabs collapsed on startup by default. //if ($chk(this.options.display) || this.options.initialDisplayFx === false) this.display(this.options.display, this.options.initialDisplayFx); // ########## END: CHANGE ########## if (this.options.fixedHeight !== false) this.options.returnHeightToAuto = false; this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain)); // ########## START: EXTEND ########## //element, which has currently focus: this.options.elementWithFocus = null; //füge allen Elementen, die den Fokus haben können, die Events "focus" und "blur" hinzu: this.togglers.each(function(el){ el.addEvents({ focus : function(){ //lege das Element fest, das aktuell den Fokus hat: this.options.elementWithFocus = el; el.setProperty('aria-selected', 'true'); }.bind(this), blur : function(){ this.options.elementWithFocus = null; el.setProperty('aria-selected', 'false'); }.bind(this) }); }.bind(this)); // add Role and State for ARIA $(document.body).getElements('#accordion').setProperty('role', 'tablist'); $(document.body).getElements('#accordion').setProperty('aria-multiselectable', 'true'); //false //elements should not be able to reach with tabbing when they are closed: //for(var i=0, l = this.elements.length; i 0 && this.options.height) || el.offsetWidth > 0 && this.options.width)){ hide = true; this.selfHidden = true; } this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]); for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]]; }, this); this.internalChain.chain(function(){ if (this.options.returnHeightToAuto && !this.selfHidden){ var el = this.elements[index]; //console.log('SET STYLE: '); //console.log(el); if (el) el.setStyle('height', 'auto'); }; }.bind(this)); // ########## START: EXTEND ########## // change attributes when panel gets expanded/collapsed var from = {}, to = {}; for (var i in obj){ var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}; for (var p in iProps){ if (p == 'height') { if(iProps[p] == 0){ this.togglers[i].setProperty('aria-expanded', false); this.elements[i].style.visibility = 'hidden'; this.elements[i].setProperty('aria-hidden', true); this.elements[i].setProperty('tabindex', -1); } else if(iProps[p] > 0){ this.togglers[i].setProperty('aria-expanded', true); this.togglers[i].setProperty('tabindex', 0); this.elements[i].style.visibility = 'visible'; this.elements[i].setProperty('aria-hidden', false); this.elements[i].setProperty('tabindex', 0); } } } } // ########## END: EXTEND ########## return useFx ? this.start(obj) : this.set(obj); } // ########## START: EXTEND ########## // Keyevents- and listeners , keys: { KEY_ENTER: 13, KEY_CTRL: 17, KEY_SPACE: 32, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, KEY_END: 35, KEY_HOME: 36, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40 }, getKeyCode: function(event){ var keyCode; // works in IE 8 and FF 3 if(window.event){ keyCode = window.event.keyCode; } else { keyCode = event.code; } return keyCode; }, onKeyDown: function(event){ var keyCode = this.getKeyCode(event); if(this.options.elementWithFocus != null){ this.options.currentIndex = parseInt(event.target.id.replace(this.options.prefix, '')); } var first = this.togglers[0]; var last = this.togglers[this.togglers.length-1]; var next = this.togglers[this.options.currentIndex + 1]; var previous = this.togglers[this.options.currentIndex - 1]; var thiz = this.togglers[this.options.currentIndex]; // NOTE: use the setTimeout-method to call the focus()-method slightly later due to a // known IE-bug where focus is not rendered correctly. // NOTE: Use 'break' to prevent the code from running into the next case automatically. switch (keyCode) { case this.keys.KEY_LEFT: if(this.options.elementWithFocus != null){ if (this.options.ctrl) break; else{ if (previous == null) { setTimeout(function() { last.focus(); }, 0); next.setProperty('tabindex', 0); } else { setTimeout(function() { previous.focus(); }, 0); previous.setProperty('tabindex', 0); } if (thiz != null){ thiz.setProperty('tabindex', -1); } break; } } break; case this.keys.KEY_UP: if (this.options.ctrl) { if(thiz != null) { setTimeout(function() {thiz.focus(); }.bind(this), 0); } break; } else{ if(this.options.elementWithFocus != null){ if (previous == null) { setTimeout(function() { last.focus(); }, 0); next.setProperty('tabindex', 0); } else { setTimeout(function() { previous.focus(); }, 0); previous.setProperty('tabindex', 0); } if (thiz != null){ thiz.setProperty('tabindex', -1); } break; } } break; case this.keys.KEY_DOWN: case this.keys.KEY_RIGHT: if(this.options.elementWithFocus != null){ if (this.options.ctrl) { break; } else { if (next == null) { setTimeout(function() { first.focus(); }, 0); first.setProperty('tabindex', 0); } else { setTimeout(function() { next.focus(); }, 0); next.setProperty('tabindex', 0); } if (thiz != null){ thiz.setProperty('tabindex', -1); } break; } } break; case this.keys.KEY_SPACE: case this.keys.KEY_ENTER: if(this.options.elementWithFocus != null){ if (this.options.ctrl){ break; } event.target.fireEvent('click'); break; } break; case this.keys.KEY_HOME: if(this.options.elementWithFocus != null){ if (this.options.ctrl){ break; } if (first != null) { setTimeout(function() { first.focus(); }, 0); first.setProperty('tabindex', 0); } if (thiz != null) thiz.setProperty('tabindex', -1); break; } break; case this.keys.KEY_END: if(this.options.elementWithFocus != null){ if (this.options.ctrl){ break; } if (last != null) { setTimeout(function() { last.focus(); }, 0); last.setProperty('tabindex', 0); } if (thiz != null){ thiz.setProperty('tabindex', -1); } break; } break; case this.keys.KEY_PAGEUP: if (this.options.ctrl) { if(previous == null) { setTimeout(function() { last.focus(); }, 0); last.setProperty('tabindex', 0); } else { setTimeout(function() { previous.focus(); }, 0); previous.setProperty('tabindex', 0); } if (thiz != null) thiz.setProperty('tabindex', -1); } break; case this.keys.KEY_PAGEDOWN: if (this.options.ctrl) { if(next == null) { setTimeout(function() { first.focus(); }, 0); first.setProperty('tabindex', 0); } else { setTimeout(function() { next.focus(); }, 0); next.setProperty('tabindex', 0); } if (thiz != null) thiz.setProperty('tabindex', -1); } break; case this.keys.KEY_CTRL: this.options.ctrl = true; break; } }, onKeyUp: function(event){ var keyCode = this.getKeyCode(event); if (keyCode == this.keys.KEY_CTRL) { this.options.ctrl = false; return; } } // ########## END: EXTEND ########## }); /* Compatibility with 1.2.0 */ // Created and set free in July of 2007 by Jenna ‘Blueberry’ Fox // Released as public domain, with the request that credit is given for my contribution // Also, I'd love to here where you've used or changed this code to do other interesting things! // Requires MooTools 1.0 or newer with Accordion and Event var AutoAccordion = Accordion.extend({ initialize: function(handles, drawers, options) { this.addEvent('onActive', function(handle, i) { handle.addClass('selected'); }); this.addEvent('onBackground', function(handle, i) { handle.removeClass('selected'); }); // run parent initializer this.parent.apply(this, arguments); // this next part adds the automatic opening magic to each “Handle” this.togglers.each(function(handle, index, array) { // and the magic hover opening dealie! handle.hoverOpenTimer = null handle.getElement('.yt-toggler').addEvents({ mouseover: function(thisHandle) { thisHandle.hoverOpenTimer = $clear(thisHandle.hoverOpenTimer); thisHandle.hoverOpenTimer = this.display.delay(300, this, index); }.bind(this, handle), mouseout: function(thisHandle) { thisHandle.hoverOpenTimer = $clear(thisHandle.hoverOpenTimer); }.bind(this, handle), focus: this.display.pass(index, this) // supports tab based keyboard navigation }); }.bind(this)); } });