(function () {
var Event = YAHOO.util.Event,
Dom = YAHOO.util.Dom,
Lang = YAHOO.lang,
UA = YAHOO.env.ua,
CarouselPrototype = YAHOO.widget.Carousel.prototype,
fnCarouselInitAttributes = CarouselPrototype.initAttributes,
m_oToolbarButtons = {},
m_oCurrentButtonIndex = {},
m_bUseARIA = (UA.gecko && UA.gecko >= 1.9) || (UA.ie && UA.ie >= 8),
m_aFocusableElements = {
"A": true,
"SELECT": true,
"TEXTAREA": true,
"BUTTON": true,
"INPUT": true
},
_USE_ARIA = "usearia",
_ARIA_PREFIX = "aria-",
_HIDDEN = "hidden",
_ASTERIX = "*",
_ID = "id",
_ROLE = "role",
_OPTION = "option",
_LISTBOX = "listbox",
_LI = "li",
_SELECTED_ITEM = "selectedItem",
_SELECTED = "selected",
_TOOLBAR = "toolbar",
_KEY_DOWN = "keydown",
_PRESENTATION = "presentation",
_BUTTON = "button",
_UL = "UL",
_A = "A",
_RENDER = "render",
_SELECTED_ITEM_CHANGE = "selectedItemChange",
_SHOW = "show",
_PAGE_CHANGE = "pageChange",
_KEY_PRESS = "keypress",
_CONTROLS = "controls",
_LABELLED_BY = "labelledby",
_DESCRIBED_BY = "describedby",
_CURRENT_PAGE = " (Current Page)";
var setARIARole = function (element, role) {
element.setAttribute(_ROLE, role);
};
var setARIAProperty = function (element, property, value) {
element.setAttribute((_ARIA_PREFIX + property), value);
};
var getCarouselListElement = function () {
var aCarouselEl = this.getElementsByClassName(this.CLASSES.CAROUSEL_EL);
if (aCarouselEl.length === 1) {
return aCarouselEl[0];
}
};
var getCarouselNavElement = function () {
var aNavigationEl = this.getElementsByClassName(this.CLASSES.NAVIGATION);
if (aNavigationEl.length === 1) {
return aNavigationEl[0];
}
};
var isFocusableElement = function (element) {
return ((element.tabIndex > -1 || m_aFocusableElements[element.nodeName.toUpperCase()]) &&
element.type !== _HIDDEN && !element.disabled);
};
var addToTabIndex = function (element) {
element.tabIndex = 0;
};
var removeFromTabIndex = function (element) {
element.tabIndex = -1;
};
var enableCarouselItem = function (index) {
var oItem = this.getItem(index);
if (oItem) {
Dom.getElementsBy(isFocusableElement, _ASTERIX, oItem.id, addToTabIndex);
}
};
var disableCarouselItem = function (index) {
var oItem = this.getItem(index);
if (oItem) {
Dom.getElementsBy(isFocusableElement, _ASTERIX, oItem.id, removeFromTabIndex);
}
};
var onSelectedItemChange = function (event) {
var nPreviousItemIndex = event.prevValue;
if (Lang.isNumber(nPreviousItemIndex)) {
disableCarouselItem.call(this, nPreviousItemIndex);
}
enableCarouselItem.call(this, event.newValue);
setARIAProperty(this.getElementForItem(event.newValue), _SELECTED, true);
};
var onKeyDown = function (event) {
Event.stopPropagation(event);
var sId = this.get(_ID),
aToolBarButtons = m_oToolbarButtons[sId],
nCurrentButtonIndex = m_oCurrentButtonIndex[sId],
oNextButton,
oCurrentButton;
switch (Event.getCharCode(event)) {
case 0x25: // left arrow
case 0x26: // up arrow
oCurrentButton = aToolBarButtons[nCurrentButtonIndex];
oCurrentButton.tabIndex = -1;
nCurrentButtonIndex = nCurrentButtonIndex - 1;
oNextButton = aToolBarButtons[nCurrentButtonIndex];
if (!oNextButton) {
nCurrentButtonIndex = aToolBarButtons.length - 1;
oNextButton = aToolBarButtons[nCurrentButtonIndex];
}
m_oCurrentButtonIndex[sId] = nCurrentButtonIndex;
oNextButton.tabIndex = 0;
oNextButton.focus();
break;
case 0x27: // right arrow
case 0x28: // down arrow
oCurrentButton = aToolBarButtons[nCurrentButtonIndex];
oCurrentButton.tabIndex = -1;
nCurrentButtonIndex = nCurrentButtonIndex + 1;
oNextButton = aToolBarButtons[nCurrentButtonIndex];
if (!oNextButton) {
nCurrentButtonIndex = 0;
oNextButton = aToolBarButtons[nCurrentButtonIndex];
}
m_oCurrentButtonIndex[sId] = nCurrentButtonIndex;
oNextButton.tabIndex = 0;
oNextButton.focus();
break;
}
};
var addOptionRole = function (element) {
setARIARole(element, _OPTION);
Dom.getElementsBy(isFocusableElement, _ASTERIX, element, removeFromTabIndex);
};
var onRender = function () {
var oList = getCarouselListElement.call(this),
nSelectedItemIndex,
oNavigation;
if (oList) {
setARIARole(oList, _LISTBOX);
Dom.batch(oList.getElementsByTagName(_LI), addOptionRole);
nSelectedItemIndex = this.get(_SELECTED_ITEM);
if (Lang.isNumber(nSelectedItemIndex)) {
setARIAProperty(this.getElementForItem(nSelectedItemIndex), _SELECTED, true);
enableCarouselItem.call(this, nSelectedItemIndex);
}
oNavigation = getCarouselNavElement.call(this);
if (oNavigation) {
setARIARole(oNavigation, _TOOLBAR);
Event.on(oNavigation, _KEY_DOWN, onKeyDown, null, this);
}
}
};
var setupPageButton = function (element, object) {
var oCarousel = object.carousel,
aToolBarButtons = object.toolbarButtons;
setARIARole(element, _PRESENTATION);
var oAnchor = Dom.getFirstChild(element);
setARIARole(oAnchor, _BUTTON);
setARIAProperty(oAnchor, _CONTROLS, object.listID);
var nTabIndex = Dom.hasClass(element, oCarousel.CLASSES.SELECTED_NAV) ? 0 : -1;
oAnchor.tabIndex = nTabIndex;
var nToolBarIndex = aToolBarButtons.length,
oEM = Dom.getFirstChild(oAnchor);
if (nTabIndex === 0) {
m_oCurrentButtonIndex[oCarousel.get(_ID)] = nToolBarIndex;
oEM.innerHTML = oEM.innerHTML + _CURRENT_PAGE;
}
aToolBarButtons[nToolBarIndex] = oAnchor;
};
var setupNextPrevPageButton = function (element, object) {
var aToolbarButtons = object.toolbarButtons;
setARIARole(element, _PRESENTATION);
setARIAProperty(element, _CONTROLS, object.listID);
var oInput = Dom.getFirstChild(element);
if (!oInput.disabled) {
oInput.tabIndex = -1;
aToolbarButtons[aToolbarButtons.length] = oInput;
}
};
var updatePagingNav = function (event) {
var oNavigation = getCarouselNavElement.call(this),
aToolBarButtons = [],
oFirstChild,
oList,
sListID;
if (oNavigation) {
oFirstChild = Dom.getFirstChild(oNavigation);
oList = getCarouselListElement.call(this);
if (oFirstChild && oList) {
sListID = oList.id || Dom.generatId(oList);
if (oFirstChild.nodeName.toUpperCase() === _UL) {
setARIARole(oFirstChild, _PRESENTATION);
Dom.batch(oFirstChild.getElementsByTagName(_LI), setupPageButton,
{ carousel: this, toolbarButtons: aToolBarButtons, listID: sListID });
}
else {
oFirstChild.tabIndex = 0;
setARIAProperty(oFirstChild, _CONTROLS, sListID);
}
Dom.batch(this.getElementsByClassName(this.CLASSES.BUTTON),
setupNextPrevPageButton, { toolbarButtons: aToolBarButtons, listID: sListID });
m_oToolbarButtons[this.get(_ID)] = aToolBarButtons;
}
}
};
var onPageChange = function () {
Lang.later(0, this, updatePagingNav);
};
var onKeyPress = function (event) {
var oTarget = Event.getTarget(event),
nCharCode = Event.getCharCode(event);
if (oTarget.nodeName.toUpperCase() === _A &&
Dom.getAncestorByClassName(oTarget, this.CLASSES.NAVIGATION) &&
(nCharCode === 13 || nCharCode === 32)) {
this._pagerClickHandler(event);
}
};
var setLabelledByOnRender = function (event, id) {
this.set(_LABELLED_BY, id, true);
this.removeListener(_RENDER, setLabelledByOnRender);
};
var setDescribedByOnRender = function (event, id) {
this.set(_DESCRIBED_BY, id, true);
this.removeListener(_RENDER, setDescribedByOnRender);
};
Lang.augmentObject(CarouselPrototype, {
_setLabelledBy: function (id) {
var oNav = getCarouselNavElement.call(this),
oList = getCarouselListElement.call(this);
if (this.get(_USE_ARIA) && oNav && oList) {
setARIAProperty(oNav, _LABELLED_BY, id);
setARIAProperty(oList, _LABELLED_BY, id);
}
else {
this.on(_RENDER, setLabelledByOnRender, id);
}
},
_setDescribedBy: function (id) {
var oNav = getCarouselNavElement.call(this),
oList = getCarouselListElement.call(this);
if (this.get(_USE_ARIA) && oNav && oList) {
setARIAProperty(oNav, _DESCRIBED_BY, id);
setARIAProperty(oList, _DESCRIBED_BY, id);
}
else {
this.on(_RENDER, setDescribedByOnRender, id);
}
},
_setUseARIA: function (p_bUseARIA) {
if (p_bUseARIA) {
this.on(_RENDER, onRender);
this.on(_SELECTED_ITEM_CHANGE, onSelectedItemChange);
this.on(_SHOW, updatePagingNav);
this.on(_PAGE_CHANGE, onPageChange);
this.on(_KEY_PRESS, onKeyPress);
}
},
initAttributes: function (p_oAttributes) {
/**
* @attribute usearia
* @description Boolean indicating if use of the WAI-ARIA Roles and States should
* be enabled.
* @type Boolean
* @default true for Firefox 3 and IE 8, false for all other browsers.
*/
this.setAttributeConfig(_USE_ARIA, {
value: p_oAttributes.usearia || m_bUseARIA,
validator: Lang.isBoolean,
writeOnce: true,
method: this._setUseARIA
});
/**
* @attribute labelledby
* @description String representing the id of the element that labels the Carousel's
* navigation (<div class="yui-carousel-nav">
) and content
* (<div class="yui-carousel-content">
) elements.
* Maps directly to the
* aria-labelledby
attribute.
* @type String
* @default null
*/
this.setAttributeConfig(_LABELLED_BY, {
value: p_oAttributes.labelledby,
validator: Lang.isString,
method: this._setLabelledBy
});
/**
* @attribute describedby
* @description String representing the id of the element that describes the Carousel's
* navigation (<div class="yui-carousel-nav">
) and content
* (<div class="yui-carousel-content">
) elements.
* Maps directly to the
* aria-describedby
attribute.
* @type String
* @default null
*/
this.setAttributeConfig(_DESCRIBED_BY, {
value: p_oAttributes.describedby,
validator: Lang.isString,
method: this._setDescribedBy
});
fnCarouselInitAttributes.apply(this, arguments);
if (m_bUseARIA) {
this.set(_USE_ARIA, true);
}
}
}, "initAttributes", "_setUseARIA", "_setLabelledBy", "_setDescribedBy");
}());
YAHOO.register("carouselariaplugin", YAHOO.widget.Carousel, {version: "@VERSION@", build: "@BUILD@"});