UNPKG

@atlassian/aui

Version:

Atlassian User Interface Framework

1,067 lines (889 loc) 41.5 kB
(function (global, factory) { if (typeof define === "function" && define.amd) { define(['./jquery', 'skatejs-template-html', './internal/deprecation', './internal/log', './debounce', './internal/browser', './internal/alignment', './polyfills/custom-event', './key-code', './layer', './internal/state', './internal/skate', './i18n', './spin'], factory); } else if (typeof exports !== "undefined") { factory(require('./jquery'), require('skatejs-template-html'), require('./internal/deprecation'), require('./internal/log'), require('./debounce'), require('./internal/browser'), require('./internal/alignment'), require('./polyfills/custom-event'), require('./key-code'), require('./layer'), require('./internal/state'), require('./internal/skate'), require('./i18n'), require('./spin')); } else { var mod = { exports: {} }; factory(global.jquery, global.skatejsTemplateHtml, global.deprecation, global.log, global.debounce, global.browser, global.alignment, global.customEvent, global.keyCode, global.layer, global.state, global.skate, global.i18n, global.spin); global.dropdown2 = mod.exports; } })(this, function (_jquery, _skatejsTemplateHtml, _deprecation, _log, _debounce, _browser, _alignment, _customEvent, _keyCode, _layer, _state, _skate) { 'use strict'; var _jquery2 = _interopRequireDefault(_jquery); var _skatejsTemplateHtml2 = _interopRequireDefault(_skatejsTemplateHtml); var deprecate = _interopRequireWildcard(_deprecation); var logger = _interopRequireWildcard(_log); var _alignment2 = _interopRequireDefault(_alignment); var _customEvent2 = _interopRequireDefault(_customEvent); var _keyCode2 = _interopRequireDefault(_keyCode); var _layer2 = _interopRequireDefault(_layer); var _state2 = _interopRequireDefault(_state); var _skate2 = _interopRequireDefault(_skate); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function isChecked(el) { return (0, _jquery2.default)(el).is('.checked, .aui-dropdown2-checked, [aria-checked="true"]'); } function getTrigger(control) { return control._triggeringElement || document.querySelector('[aria-controls="' + control.id + '"]'); } function doIfTrigger(triggerable, callback) { var trigger = getTrigger(triggerable); if (trigger) { callback(trigger); } } function setDropdownTriggerActiveState(trigger, isActive) { var $trigger = (0, _jquery2.default)(trigger); if (isActive) { $trigger.attr('aria-expanded', 'true'); $trigger.addClass('active aui-dropdown2-active'); } else { $trigger.attr('aria-expanded', 'false'); $trigger.removeClass('active aui-dropdown2-active'); } } // LOADING STATES var UNLOADED = 'unloaded'; var LOADING = 'loading'; var ERROR = 'error'; var SUCCESS = 'success'; // ASYNC DROPDOWN FUNCTIONS function makeAsyncDropdownContents(json) { var dropdownContents = json.map(function makeSection(sectionData) { var sectionItemsHtml = sectionData.items.map(function makeSectionItem(itemData) { function makeBooleanAttribute(attr) { return itemData[attr] ? attr + ' ="true"' : ''; } function makeAttribute(attr) { return itemData[attr] ? attr + '="' + itemData[attr] + '"' : ''; } var tagName = 'aui-item-' + itemData.type; var itemHtml = '\n <' + tagName + ' ' + makeAttribute('for') + ' ' + makeAttribute('href') + ' ' + makeBooleanAttribute('interactive') + '\n ' + makeBooleanAttribute('checked') + ' ' + makeBooleanAttribute('disabled') + ' ' + makeBooleanAttribute('hidden') + '>\n ' + itemData.content + '\n </' + tagName + '>'; return itemHtml; }).join(''); var sectionAttributes = sectionData.label ? 'label="' + sectionData.label + '"' : ''; var sectionHtml = '\n <aui-section ' + sectionAttributes + '>\n ' + sectionItemsHtml + '\n </aui-section>'; return sectionHtml; }).join('\n'); return dropdownContents; } function setDropdownContents(dropdown, json) { (0, _state2.default)(dropdown).set('loading-state', SUCCESS); _skatejsTemplateHtml2.default.wrap(dropdown).innerHTML = makeAsyncDropdownContents(json); _skate2.default.init(dropdown); } function setDropdownErrorState(dropdown) { (0, _state2.default)(dropdown).set('loading-state', ERROR); (0, _state2.default)(dropdown).set('hasErrorBeenShown', dropdown.isVisible()); _skatejsTemplateHtml2.default.wrap(dropdown).innerHTML = '\n <div class="aui-message aui-message-error aui-dropdown-error">\n <p>' + AJS.I18n.getText('aui.dropdown.async.error') + '</p>\n </div>\n '; } function setDropdownLoadingState(dropdown) { (0, _state2.default)(dropdown).set('loading-state', LOADING); (0, _state2.default)(dropdown).set('hasErrorBeenShown', false); doIfTrigger(dropdown, function (trigger) { trigger.setAttribute('aria-busy', 'true'); }); _skatejsTemplateHtml2.default.wrap(dropdown).innerHTML = '\n <div class="aui-dropdown-loading">\n <span class="spinner"></span> ' + AJS.I18n.getText('aui.dropdown.async.loading') + '\n </div>\n '; (0, _jquery2.default)(dropdown).find('.spinner').spin(); } function setDropdownLoaded(dropdown) { doIfTrigger(dropdown, function (trigger) { trigger.setAttribute('aria-busy', 'false'); }); } function loadContentsIfAsync(dropdown) { if (!dropdown.src || (0, _state2.default)(dropdown).get('loading-state') === LOADING) { return; } setDropdownLoadingState(dropdown); _jquery2.default.ajax(dropdown.src).done(function (json, status, xhr) { var isValidStatus = xhr.status === 200; if (isValidStatus) { setDropdownContents(dropdown, json); } else { setDropdownErrorState(dropdown); } }).fail(function () { setDropdownErrorState(dropdown); }).always(function () { setDropdownLoaded(dropdown); }); } function loadContentWhenMouseEnterTrigger(dropdown) { var isDropdownUnloaded = (0, _state2.default)(dropdown).get('loading-state') === UNLOADED; var hasCurrentErrorBeenShown = (0, _state2.default)(dropdown).get('hasErrorBeenShown'); if (isDropdownUnloaded || hasCurrentErrorBeenShown && !dropdown.isVisible()) { loadContentsIfAsync(dropdown); } } function loadContentWhenMenuShown(dropdown) { var isDropdownUnloaded = (0, _state2.default)(dropdown).get('loading-state') === UNLOADED; var hasCurrentErrorBeenShown = (0, _state2.default)(dropdown).get('hasErrorBeenShown'); if (isDropdownUnloaded || hasCurrentErrorBeenShown) { loadContentsIfAsync(dropdown); } if ((0, _state2.default)(dropdown).get('loading-state') === ERROR) { (0, _state2.default)(dropdown).set('hasErrorBeenShown', true); } } // The dropdown's trigger // ---------------------- function triggerCreated(trigger) { var dropdownID = trigger.getAttribute('aria-controls'); if (!dropdownID) { dropdownID = trigger.getAttribute('aria-owns'); if (!dropdownID) { logger.error('Dropdown triggers need either a "aria-owns" or "aria-controls" attribute'); } else { trigger.removeAttribute('aria-owns'); trigger.setAttribute('aria-controls', dropdownID); } } trigger.setAttribute('aria-haspopup', true); trigger.setAttribute('aria-expanded', false); var shouldSetHref = trigger.nodeName === 'A' && !trigger.href; if (shouldSetHref) { trigger.setAttribute('href', '#' + dropdownID); } function handleIt(e) { e.preventDefault(); if (!trigger.isEnabled()) { return; } var dropdown = document.getElementById(dropdownID); // AUI-4271 - Maintains legacy integration with parent elements. var $trigger = (0, _jquery2.default)(trigger); if ($trigger.parent().hasClass('aui-buttons')) { dropdown.classList.add('aui-dropdown2-in-buttons'); } if ($trigger.parents().hasClass('aui-header')) { dropdown.classList.add('aui-dropdown2-in-header'); } dropdown.toggle(e); dropdown.isSubmenu = trigger.hasSubmenu(); return dropdown; } function handleMouseEnter(e) { e.preventDefault(); if (!trigger.isEnabled()) { return; } var dropdown = document.getElementById(dropdownID); loadContentWhenMouseEnterTrigger(dropdown); if (trigger.hasSubmenu()) { dropdown.show(e); dropdown.isSubmenu = trigger.hasSubmenu(); } return dropdown; } function handleKeydown(e) { var normalInvoke = e.keyCode === _keyCode2.default.ENTER || e.keyCode === _keyCode2.default.SPACE; var submenuInvoke = e.keyCode === _keyCode2.default.RIGHT && trigger.hasSubmenu(); var rootMenuInvoke = (e.keyCode === _keyCode2.default.UP || e.keyCode === _keyCode2.default.DOWN) && !trigger.hasSubmenu(); if (normalInvoke || submenuInvoke || rootMenuInvoke) { var dropdown = handleIt(e); if (dropdown) { dropdown.focusItem(0); } } } (0, _jquery2.default)(trigger).on('aui-button-invoke', handleIt).on('click', handleIt).on('keydown', handleKeydown).on('mouseenter', handleMouseEnter); } var triggerPrototype = { disable: function disable() { this.setAttribute('aria-disabled', 'true'); }, enable: function enable() { this.setAttribute('aria-disabled', 'false'); }, isEnabled: function isEnabled() { return this.getAttribute('aria-disabled') !== 'true'; }, hasSubmenu: function hasSubmenu() { var triggerClasses = (this.className || '').split(/\s+/); return triggerClasses.indexOf('aui-dropdown2-sub-trigger') !== -1; } }; (0, _skate2.default)('aui-dropdown2-trigger', { type: _skate2.default.type.CLASSNAME, created: triggerCreated, prototype: triggerPrototype }); //To remove at a later date. Some dropdown triggers initialise lazily, so we need to listen for mousedown //and synchronously init before the click event is fired. //TODO: delete in AUI 8.0.0, see AUI-2868 function bindLazyTriggerInitialisation() { (0, _jquery2.default)(document).on('mousedown', '.aui-dropdown2-trigger', function () { var isElementSkated = this.hasAttribute('resolved'); if (!isElementSkated) { _skate2.default.init(this); var lazyDeprecate = deprecate.getMessageLogger('Dropdown2 lazy initialisation', { removeInVersion: '8.0.0', alternativeName: 'initialisation on DOM insertion', sinceVersion: '5.8.0', extraInfo: 'Dropdown2 triggers should have all necessary attributes on DOM insertion', deprecationType: 'JS' }); lazyDeprecate(); } }); } bindLazyTriggerInitialisation(); (0, _skate2.default)('aui-dropdown2-sub-trigger', { type: _skate2.default.type.CLASSNAME, created: function created(trigger) { trigger.className += ' aui-dropdown2-trigger'; _skate2.default.init(trigger); } }); // Dropdown trigger groups // ----------------------- (0, _jquery2.default)(document).on('mouseenter', '.aui-dropdown2-trigger-group a, .aui-dropdown2-trigger-group button', function (e) { var $item = (0, _jquery2.default)(e.currentTarget); if ($item.is('.aui-dropdown2-active')) { return; // No point doing anything if we're hovering over the already-active item trigger. } if ($item.closest('.aui-dropdown2').length) { return; // We don't want to deal with dropdown items, just the potential triggers in the group. } var $triggerGroup = $item.closest('.aui-dropdown2-trigger-group'); var $groupActiveTrigger = $triggerGroup.find('.aui-dropdown2-active'); if ($groupActiveTrigger.length && $item.is('.aui-dropdown2-trigger')) { $groupActiveTrigger.blur(); // Remove focus from the previously opened menu. $item.trigger('aui-button-invoke'); // Open this trigger's menu. e.preventDefault(); } var $groupFocusedTrigger = $triggerGroup.find(':focus'); if ($groupFocusedTrigger.length && $item.is('.aui-dropdown2-trigger')) { $groupFocusedTrigger.blur(); } }); // Dropdown items // -------------- function getDropdownItems(dropdown, filter) { return (0, _jquery2.default)(dropdown).find([ // Legacy markup. '> ul > li', '> .aui-dropdown2-section > ul > li', // Accessible markup. '> div[role] > .aui-dropdown2-section > div[role="group"] > ul[role] > li[role]', // Web component. 'aui-item-link', 'aui-item-checkbox', 'aui-item-radio'].join(', ')).filter(filter).children('a, button, [role="checkbox"], [role="menuitemcheckbox"], [role="radio"], [role="menuitemradio"]'); } function getAllDropdownItems(dropdown) { return getDropdownItems(dropdown, function () { return true; }); } function getVisibleDropdownItems(dropdown) { return getDropdownItems(dropdown, function () { return this.className.indexOf('hidden') === -1 && !this.hasAttribute('hidden'); }); } function amendDropdownItem(item) { var $item = (0, _jquery2.default)(item); $item.attr('tabindex', '-1'); /** * Honouring the documentation. * @link https://docs.atlassian.com/aui/latest/docs/dropdown2.html */ if ($item.hasClass('aui-dropdown2-disabled') || $item.parent().hasClass('aui-dropdown2-hidden')) { $item.attr('aria-disabled', true); } } function amendDropdownContent(dropdown) { // Add assistive semantics to each dropdown item getAllDropdownItems(dropdown).each(function () { amendDropdownItem(this); }); } /** * Honours behaviour for code written using only the legacy class names. * To maintain old behaviour (i.e., remove the 'hidden' class and the item will become un-hidden) * whilst allowing our code to only depend on the new classes, we need to * keep the state of the DOM in sync with legacy classes. * * Calling this function will add the new namespaced classes to elements with legacy names. * @returns {Function} a function to remove the new namespaced classes, only from the elements they were added to. */ function migrateAndSyncLegacyClassNames(dropdown) { var $dropdown = (0, _jquery2.default)(dropdown); // Migrate away from legacy class names var $hiddens = $dropdown.find('.hidden').addClass('aui-dropdown2-hidden'); var $disableds = $dropdown.find('.disabled').addClass('aui-dropdown2-disabled'); var $interactives = $dropdown.find('.interactive').addClass('aui-dropdown2-interactive'); return function revertToOriginalMarkup() { $hiddens.removeClass('aui-dropdown2-hidden'); $disableds.removeClass('aui-dropdown2-disabled'); $interactives.removeClass('aui-dropdown2-interactive'); }; } // The Dropdown itself // ------------------- function setLayerAlignment(dropdown, trigger) { var hasSubmenu = trigger && trigger.hasSubmenu && trigger.hasSubmenu(); var hasSubmenuAlignment = dropdown.getAttribute('data-aui-alignment') === 'submenu auto'; if (!hasSubmenu && hasSubmenuAlignment) { restorePreviousAlignment(dropdown); } var hasAnyAlignment = dropdown.hasAttribute('data-aui-alignment'); if (hasSubmenu && !hasSubmenuAlignment) { saveCurrentAlignment(dropdown); dropdown.setAttribute('data-aui-alignment', 'submenu auto'); dropdown.setAttribute('data-aui-alignment-static', true); } else if (!hasAnyAlignment) { dropdown.setAttribute('data-aui-alignment', 'bottom auto'); dropdown.setAttribute('data-aui-alignment-static', true); } if (dropdown._auiAlignment) { dropdown._auiAlignment.destroy(); } dropdown._auiAlignment = new _alignment2.default(dropdown, trigger); dropdown._auiAlignment.enable(); } function saveCurrentAlignment(dropdown) { var $dropdown = (0, _jquery2.default)(dropdown); if (dropdown.hasAttribute('data-aui-alignment')) { $dropdown.data('previous-data-aui-alignment', dropdown.getAttribute('data-aui-alignment')); } $dropdown.data('had-data-aui-alignment-static', dropdown.hasAttribute('data-aui-alignment-static')); } function restorePreviousAlignment(dropdown) { var $dropdown = (0, _jquery2.default)(dropdown); var previousAlignment = $dropdown.data('previous-data-aui-alignment'); if (previousAlignment) { dropdown.setAttribute('data-aui-alignment', previousAlignment); } else { dropdown.removeAttribute('data-aui-alignment'); } $dropdown.removeData('previous-data-aui-alignment'); if (!$dropdown.data('had-data-aui-alignment-static')) { dropdown.removeAttribute('data-aui-alignment-static'); } $dropdown.removeData('had-data-aui-alignment-static'); } function getDropdownHideLocation(dropdown, trigger) { var possibleHome = trigger.getAttribute('data-dropdown2-hide-location'); return document.getElementById(possibleHome) || dropdown.parentNode; } var keyboardClose = false; function keyboardCloseDetected() { keyboardClose = true; } function wasProbablyClosedViaKeyboard() { var result = keyboardClose === true; keyboardClose = false; return result; } function bindDropdownBehaviourToLayer(dropdown) { (0, _layer2.default)(dropdown); dropdown.addEventListener('aui-layer-show', function () { (0, _jquery2.default)(dropdown).trigger('aui-dropdown2-show'); dropdown._syncClasses = migrateAndSyncLegacyClassNames(dropdown); amendDropdownContent(this); doIfTrigger(dropdown, function (trigger) { setDropdownTriggerActiveState(trigger, true); dropdown._returnTo = getDropdownHideLocation(dropdown, trigger); }); }); dropdown.addEventListener('aui-layer-hide', function () { (0, _jquery2.default)(dropdown).trigger('aui-dropdown2-hide'); if (dropdown._syncClasses) { dropdown._syncClasses(); delete dropdown._syncClasses; } if (dropdown._auiAlignment) { dropdown._auiAlignment.disable(); dropdown._auiAlignment.destroy(); } if (dropdown._returnTo) { if (dropdown.parentNode && dropdown.parentNode !== dropdown._returnTo) { dropdown._returnTo.appendChild(dropdown); } } (0, _jquery2.default)(dropdown).removeClass('aui-dropdown2-in-buttons'); getVisibleDropdownItems(dropdown).removeClass('active aui-dropdown2-active'); doIfTrigger(dropdown, function (trigger) { if (wasProbablyClosedViaKeyboard()) { trigger.focus(); setDropdownTriggerActiveState(trigger, trigger.hasSubmenu && trigger.hasSubmenu()); } else { setDropdownTriggerActiveState(trigger, false); } }); // Gets set by submenu trigger invocation. Bad coupling point? delete dropdown.isSubmenu; dropdown._triggeringElement = null; }); } function bindItemInteractionBehaviourToDropdown(dropdown) { var $dropdown = (0, _jquery2.default)(dropdown); $dropdown.on('keydown', function (e) { if (e.keyCode === _keyCode2.default.DOWN) { dropdown.focusNext(); e.preventDefault(); } else if (e.keyCode === _keyCode2.default.UP) { dropdown.focusPrevious(); e.preventDefault(); } else if (e.keyCode === _keyCode2.default.LEFT) { if (dropdown.isSubmenu) { keyboardCloseDetected(); dropdown.hide(e); e.preventDefault(); } } else if (e.keyCode === _keyCode2.default.ESCAPE) { // The closing will be handled by the LayerManager! keyboardCloseDetected(); } else if (e.keyCode === _keyCode2.default.TAB) { keyboardCloseDetected(); dropdown.hide(e); } }); var hideIfNotSubmenuAndNotInteractive = function hideIfNotSubmenuAndNotInteractive(e) { var $item = (0, _jquery2.default)(e.currentTarget); if ($item.attr('aria-disabled') === 'true') { e.preventDefault(); return; } var isSubmenuTrigger = e.currentTarget.hasSubmenu && e.currentTarget.hasSubmenu(); if (!isSubmenuTrigger && !$item.is('.aui-dropdown2-interactive')) { var theMenu = dropdown; do { var dd = (0, _layer2.default)(theMenu); theMenu = (0, _layer2.default)(theMenu).below(); if (dd.$el.is('.aui-dropdown2')) { dd.hide(e); } } while (theMenu); } }; $dropdown.on('click keydown', 'a, button, [role="menuitem"], [role="menuitemcheckbox"], [role="checkbox"], [role="menuitemradio"], [role="radio"]', function (e) { var item = e.currentTarget; var $item = (0, _jquery2.default)(item); var eventKeyCode = e.keyCode; var isEnter = eventKeyCode === _keyCode2.default.ENTER; var isSpace = eventKeyCode === _keyCode2.default.SPACE; // AUI-4283: Accessibility - need to ignore enter on links/buttons so // that the dropdown remains visible to allow the click event to eventually fire. var itemIgnoresEnter = isEnter && $item.is('a[href], button'); if (!itemIgnoresEnter && (e.type === 'click' || isEnter || isSpace)) { hideIfNotSubmenuAndNotInteractive(e); } }); // close a submenus when the mouse moves over items other than its trigger $dropdown.on('mouseenter', 'a, button, [role="menuitem"], [role="menuitemcheckbox"], [role="checkbox"], [role="menuitemradio"], [role="radio"]', function (e) { var item = e.currentTarget; var hasSubmenu = item.hasSubmenu && item.hasSubmenu(); if (!e.isDefaultPrevented() && !hasSubmenu) { var maybeALayer = (0, _layer2.default)(dropdown).above(); if (maybeALayer) { (0, _layer2.default)(maybeALayer).hide(); } } }); } (0, _jquery2.default)(window).on('resize', (0, _debounce.debounceImmediate)(function () { (0, _jquery2.default)('.aui-dropdown2').each(function (index, dropdown) { _skate2.default.init(dropdown); if (dropdown.isVisible()) { dropdown.hide(); } }); }, 1000)); // Dropdowns // --------- function dropdownCreated(dropdown) { var $dropdown = (0, _jquery2.default)(dropdown); $dropdown.addClass('aui-dropdown2'); // swap the inner div to presentation as application is only needed for Windows if ((0, _browser.supportsVoiceOver)()) { $dropdown.find('> div[role="application"]').attr('role', 'presentation'); } if (dropdown.hasAttribute('data-container')) { $dropdown.attr('data-aui-alignment-container', $dropdown.attr('data-container')); $dropdown.removeAttr('data-container'); } bindDropdownBehaviourToLayer(dropdown); bindItemInteractionBehaviourToDropdown(dropdown); dropdown.hide(); (0, _jquery2.default)(dropdown).delegate('.aui-dropdown2-checkbox:not(.disabled):not(.aui-dropdown2-disabled)', 'click keydown', function (e) { if (e.type === 'click' || e.keyCode === _keyCode2.default.ENTER || e.keyCode === _keyCode2.default.SPACE) { var checkbox = this; if (e.isDefaultPrevented()) { return; } if (checkbox.isInteractive()) { e.preventDefault(); } if (checkbox.isEnabled()) { // toggle the checked state if (checkbox.isChecked()) { checkbox.uncheck(); } else { checkbox.check(); } } } }); (0, _jquery2.default)(dropdown).delegate('.aui-dropdown2-radio:not(.checked):not(.aui-dropdown2-checked):not(.disabled):not(.aui-dropdown2-disabled)', 'click keydown', function (e) { if (e.type === 'click' || e.keyCode === _keyCode2.default.ENTER || e.keyCode === _keyCode2.default.SPACE) { var radio = this; if (e.isDefaultPrevented()) { return; } if (radio.isInteractive()) { e.preventDefault(); } var $radio = (0, _jquery2.default)(this); if (this.isEnabled() && this.isChecked() === false) { // toggle the checked state $radio.closest('ul,[role=group]').find('.aui-dropdown2-checked').not(this).each(function () { this.uncheck(); }); radio.check(); } } }); } var dropdownPrototype = { /** * Toggles the visibility of the dropdown menu */ toggle: function toggle(e) { if (this.isVisible()) { this.hide(e); } else { this.show(e); } }, /** * Explicitly shows the menu * * @returns {HTMLElement} */ show: function show(e) { if (e && e.currentTarget && e.currentTarget.classList.contains('aui-dropdown2-trigger')) { this._triggeringElement = e.currentTarget; } (0, _layer2.default)(this).show(); var dropdown = this; doIfTrigger(dropdown, function (trigger) { setLayerAlignment(dropdown, trigger); }); return this; }, /** * Explicitly hides the menu * * @returns {HTMLElement} */ hide: function hide() { (0, _layer2.default)(this).hide(); return this; }, /** * Shifts explicit focus to the next available item in the menu * * @returns {undefined} */ focusNext: function focusNext() { var $items = getVisibleDropdownItems(this); var selected = document.activeElement; var idx; if ($items.last()[0] !== selected) { idx = $items.toArray().indexOf(selected); this.focusItem($items.get(idx + 1)); } }, /** * Shifts explicit focus to the previous available item in the menu * * @returns {undefined} */ focusPrevious: function focusPrevious() { var $items = getVisibleDropdownItems(this); var selected = document.activeElement; var idx; if ($items.first()[0] !== selected) { idx = $items.toArray().indexOf(selected); this.focusItem($items.get(idx - 1)); } }, /** * Shifts explicit focus to the menu item matching the index param */ focusItem: function focusItem(item) { var $items = getVisibleDropdownItems(this); var $item; if (typeof item === 'number') { item = $items.get(item); } $item = (0, _jquery2.default)(item); $item.focus(); $items.removeClass('active aui-dropdown2-active'); $item.addClass('active aui-dropdown2-active'); }, /** * Checks whether or not the menu is currently displayed * * @returns {Boolean} */ isVisible: function isVisible() { return (0, _layer2.default)(this).isVisible(); } }; // Web component API for dropdowns // ------------------------------- var disabledAttributeHandler = { created: function created(element) { var a = element.children[0]; a.setAttribute('aria-disabled', 'true'); a.className += ' aui-dropdown2-disabled'; }, removed: function removed(element) { var a = element.children[0]; a.setAttribute('aria-disabled', 'false'); (0, _jquery2.default)(a).removeClass('aui-dropdown2-disabled'); } }; var interactiveAttributeHandler = { created: function created(element) { var a = element.children[0]; a.className += ' aui-dropdown2-interactive'; }, removed: function removed(element) { var a = element.children[0]; (0, _jquery2.default)(a).removeClass('aui-dropdown2-interactive'); } }; var checkedAttributeHandler = { created: function created(element) { var a = element.children[0]; (0, _jquery2.default)(a).addClass('checked aui-dropdown2-checked'); a.setAttribute('aria-checked', true); element.dispatchEvent(new _customEvent2.default('change', { bubbles: true })); }, removed: function removed(element) { var a = element.children[0]; (0, _jquery2.default)(a).removeClass('checked aui-dropdown2-checked'); a.setAttribute('aria-checked', false); element.dispatchEvent(new _customEvent2.default('change', { bubbles: true })); } }; var hiddenAttributeHandler = { created: function created(element) { disabledAttributeHandler.created(element); }, removed: function removed(element) { disabledAttributeHandler.removed(element); } }; (0, _skate2.default)('aui-item-link', { template: (0, _skatejsTemplateHtml2.default)('<a role="menuitem" tabindex="-1"><content></content></a>'), attributes: { disabled: disabledAttributeHandler, interactive: interactiveAttributeHandler, hidden: hiddenAttributeHandler, href: { created: function created(element, change) { var a = element.children[0]; a.setAttribute('href', change.newValue); }, updated: function updated(element, change) { var a = element.children[0]; a.setAttribute('href', change.newValue); }, removed: function removed(element) { var a = element.children[0]; a.removeAttribute('href'); } }, for: { created: function created(element) { var anchor = element.children[0]; anchor.setAttribute('aria-controls', element.getAttribute('for')); (0, _jquery2.default)(anchor).addClass('aui-dropdown2-sub-trigger'); }, updated: function updated(element) { var anchor = element.children[0]; anchor.setAttribute('aria-controls', element.getAttribute('for')); }, removed: function removed(element) { var anchor = element.children[0]; anchor.removeAttribute('aria-controls'); (0, _jquery2.default)(anchor).removeClass('aui-dropdown2-sub-trigger'); } } } }); (0, _skate2.default)('aui-item-checkbox', { template: (0, _skatejsTemplateHtml2.default)('<span role="checkbox" class="aui-dropdown2-checkbox" tabindex="-1"><content></content></span>'), attributes: { disabled: disabledAttributeHandler, interactive: interactiveAttributeHandler, checked: checkedAttributeHandler, hidden: hiddenAttributeHandler } }); (0, _skate2.default)('aui-item-radio', { template: (0, _skatejsTemplateHtml2.default)('<span role="radio" class="aui-dropdown2-radio" tabindex="-1"><content></content></span>'), attributes: { disabled: disabledAttributeHandler, interactive: interactiveAttributeHandler, checked: checkedAttributeHandler, hidden: hiddenAttributeHandler } }); (0, _skate2.default)('aui-section', { template: (0, _skatejsTemplateHtml2.default)('\n <strong aria-role="presentation" class="aui-dropdown2-heading"></strong>\n <div role="group">\n <content></content>\n </div>\n '), attributes: { label: function label(element, data) { var headingElement = element.children[0]; var groupElement = element.children[1]; headingElement.textContent = data.newValue; groupElement.setAttribute('aria-label', data.newValue); } }, created: function created(element) { element.className += ' aui-dropdown2-section'; element.setAttribute('role', 'presentation'); } }); (0, _skate2.default)('aui-dropdown-menu', { template: (0, _skatejsTemplateHtml2.default)('\n <div role="application">\n <content></content>\n </div>\n '), created: function created(dropdown) { dropdown.setAttribute('role', 'menu'); dropdown.className = 'aui-dropdown2 aui-style-default aui-layer'; (0, _state2.default)(dropdown).set('loading-state', UNLOADED); // Now skate the .aui-dropdown2 behaviour. _skate2.default.init(dropdown); }, attributes: { src: {} }, prototype: dropdownPrototype, events: { 'aui-layer-show': loadContentWhenMenuShown } }); // Legacy dropdown inits // --------------------- (0, _skate2.default)('aui-dropdown2', { type: _skate2.default.type.CLASSNAME, created: dropdownCreated, prototype: dropdownPrototype }); (0, _skate2.default)('data-aui-dropdown2', { type: _skate2.default.type.ATTRIBUTE, created: dropdownCreated, prototype: dropdownPrototype }); // Checkboxes and radios // --------------------- (0, _skate2.default)('aui-dropdown2-checkbox', { type: _skate2.default.type.CLASSNAME, created: function created(checkbox) { var checked = isChecked(checkbox); if (checked) { (0, _jquery2.default)(checkbox).addClass('checked aui-dropdown2-checked'); } checkbox.setAttribute('aria-checked', checked); checkbox.setAttribute('tabindex', '0'); // swap from menuitemcheckbox to just plain checkbox for VoiceOver if ((0, _browser.supportsVoiceOver)()) { checkbox.setAttribute('role', 'checkbox'); } }, prototype: { isEnabled: function isEnabled() { return !(this.getAttribute('aria-disabled') !== null && this.getAttribute('aria-disabled') === 'true'); }, isChecked: function isChecked() { return this.getAttribute('aria-checked') !== null && this.getAttribute('aria-checked') === 'true'; }, isInteractive: function isInteractive() { return (0, _jquery2.default)(this).hasClass('aui-dropdown2-interactive'); }, uncheck: function uncheck() { if (this.parentNode.tagName.toLowerCase() === 'aui-item-checkbox') { this.parentNode.removeAttribute('checked'); } this.setAttribute('aria-checked', 'false'); (0, _jquery2.default)(this).removeClass('checked aui-dropdown2-checked'); (0, _jquery2.default)(this).trigger('aui-dropdown2-item-uncheck'); }, check: function check() { if (this.parentNode.tagName.toLowerCase() === 'aui-item-checkbox') { this.parentNode.setAttribute('checked', ''); } this.setAttribute('aria-checked', 'true'); (0, _jquery2.default)(this).addClass('checked aui-dropdown2-checked'); (0, _jquery2.default)(this).trigger('aui-dropdown2-item-check'); } } }); (0, _skate2.default)('aui-dropdown2-radio', { type: _skate2.default.type.CLASSNAME, created: function created(radio) { // add a dash of ARIA var checked = isChecked(radio); if (checked) { (0, _jquery2.default)(radio).addClass('checked aui-dropdown2-checked'); } radio.setAttribute('aria-checked', checked); radio.setAttribute('tabindex', '0'); // swap from menuitemradio to just plain radio for VoiceOver if ((0, _browser.supportsVoiceOver)()) { radio.setAttribute('role', 'radio'); } }, prototype: { isEnabled: function isEnabled() { return !(this.getAttribute('aria-disabled') !== null && this.getAttribute('aria-disabled') === 'true'); }, isChecked: function isChecked() { return this.getAttribute('aria-checked') !== null && this.getAttribute('aria-checked') === 'true'; }, isInteractive: function isInteractive() { return (0, _jquery2.default)(this).hasClass('aui-dropdown2-interactive'); }, uncheck: function uncheck() { if (this.parentNode.tagName.toLowerCase() === 'aui-item-radio') { this.parentNode.removeAttribute('checked'); } this.setAttribute('aria-checked', 'false'); (0, _jquery2.default)(this).removeClass('checked aui-dropdown2-checked'); (0, _jquery2.default)(this).trigger('aui-dropdown2-item-uncheck'); }, check: function check() { if (this.parentNode.tagName.toLowerCase() === 'aui-item-radio') { this.parentNode.setAttribute('checked', ''); } this.setAttribute('aria-checked', 'true'); (0, _jquery2.default)(this).addClass('checked aui-dropdown2-checked'); (0, _jquery2.default)(this).trigger('aui-dropdown2-item-check'); } } }); }); //# sourceMappingURL=dropdown2.js.map