@atlassian/aui
Version:
Atlassian User Interface Framework
298 lines (240 loc) • 12.8 kB
JavaScript
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(['module', 'exports', '../../jquery', '../../polyfills/custom-event', '../../debounce', '../../i18n', '../skate', 'skatejs-template-html'], factory);
} else if (typeof exports !== "undefined") {
factory(module, exports, require('../../jquery'), require('../../polyfills/custom-event'), require('../../debounce'), require('../../i18n'), require('../skate'), require('skatejs-template-html'));
} else {
var mod = {
exports: {}
};
factory(mod, mod.exports, global.jquery, global.customEvent, global.debounce, global.i18n, global.skate, global.skatejsTemplateHtml);
global.createHeader = mod.exports;
}
})(this, function (module, exports, _jquery, _customEvent, _debounce, _i18n, _skate, _skatejsTemplateHtml) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _jquery2 = _interopRequireDefault(_jquery);
var _customEvent2 = _interopRequireDefault(_customEvent);
var _debounce2 = _interopRequireDefault(_debounce);
var _i18n2 = _interopRequireDefault(_i18n);
var _skate2 = _interopRequireDefault(_skate);
var _skatejsTemplateHtml2 = _interopRequireDefault(_skatejsTemplateHtml);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
var $window = (0, _jquery2.default)(window);
function Header(element) {
var that = this;
this.element = element;
this.$element = (0, _jquery2.default)(element);
this.index = (0, _jquery2.default)('aui-header, .aui-header').index(element);
this.$secondaryNav = this.$element.find('.aui-header-secondary .aui-nav').first();
this.menuItems = [];
this.totalWidth = 0;
this.$moreMenu = undefined;
this.rightMostNavItemIndex = undefined;
this.$applicationLogo = this.$element.find('#logo');
this.moreMenuWidth = 0;
this.primaryButtonsWidth = 0;
// to cache the selector and give .find convenience
this.$headerFind = function () {
var $header = (0, _jquery2.default)(that.$element[0].querySelector('.aui-header-primary'));
return function (selector) {
return $header.find(selector);
};
}();
}
Header.prototype = {
init: function init() {
var that = this;
this.element.setAttribute('data-aui-responsive', 'true');
this.$headerFind('.aui-button').parent().each(function () {
that.primaryButtonsWidth += (0, _jquery2.default)(this).outerWidth(true);
});
// remember the widths of all the menu items
this.$headerFind('.aui-nav > li > a:not(.aui-button)').each(function () {
var $this = (0, _jquery2.default)(this).parent();
var outerWidth = $this.outerWidth(true);
that.totalWidth += outerWidth;
that.menuItems.push({
$element: $this,
outerWidth: outerWidth
});
});
/** The zero based index of the right-most visible nav menu item. */
this.rightMostNavItemIndex = this.menuItems.length - 1;
$window.on('resize', this._resizeHandler = (0, _debounce2.default)(function () {
that.constructResponsiveDropdown();
}, 100));
// So that the header logo doesn't mess things up. (size is unknown before the image loads)
var $logoImg = this.$applicationLogo.find('img');
if ($logoImg.length !== 0) {
$logoImg.attr('data-aui-responsive-header-index', this.index);
$logoImg.on('load', function () {
that.constructResponsiveDropdown();
});
}
this.constructResponsiveDropdown();
// show the aui nav (hidden via css on load)
this.$headerFind('.aui-nav').css('width', 'auto');
},
destroy: function destroy() {
$window.off('resize', this._resizeHandler);
},
// calculate widths based on the current state of the page
calculateAvailableWidth: function calculateAvailableWidth() {
// if there is no secondary nav, use the right of the screen as the boundary instead
var rightMostBoundary = this.$secondaryNav.is(':visible') ? this.$secondaryNav.offset().left : this.$element.outerWidth();
// the right most side of the primary nav, this is assumed to exists if this code is running
var primaryNavRight = this.$applicationLogo.offset().left + this.$applicationLogo.outerWidth(true) + this.primaryButtonsWidth;
return rightMostBoundary - primaryNavRight;
},
showResponsiveDropdown: function showResponsiveDropdown() {
if (this.$moreMenu === undefined) {
this.$moreMenu = this.createResponsiveDropdownTrigger();
}
this.$moreMenu.css('display', '');
},
hideResponsiveDropdown: function hideResponsiveDropdown() {
if (this.$moreMenu !== undefined) {
this.$moreMenu.css('display', 'none');
}
},
constructResponsiveDropdown: function constructResponsiveDropdown() {
if (!this.menuItems.length) {
return;
}
var remainingWidth;
var availableWidth = this.calculateAvailableWidth(this.$element, this.primaryButtonsWidth);
if (availableWidth > this.totalWidth) {
this.showAll();
} else {
this.showResponsiveDropdown();
remainingWidth = availableWidth - this.moreMenuWidth;
// Figure out how many nav menu items fit into the available space.
var newRightMostNavItemIndex = -1;
while (remainingWidth - this.menuItems[newRightMostNavItemIndex + 1].outerWidth >= 0) {
remainingWidth -= this.menuItems[newRightMostNavItemIndex + 1].outerWidth;
newRightMostNavItemIndex++;
}
if (newRightMostNavItemIndex < this.rightMostNavItemIndex) {
this.moveToResponsiveDropdown(this.rightMostNavItemIndex - newRightMostNavItemIndex);
} else if (this.rightMostNavItemIndex < newRightMostNavItemIndex) {
this.moveOutOfResponsiveDropdown(newRightMostNavItemIndex - this.rightMostNavItemIndex);
}
}
},
// creates the trigger and content elements for the show more dropdown
createResponsiveDropdownTrigger: function createResponsiveDropdownTrigger() {
var moreNavItemEl = document.createElement('li');
var dropdownEl = document.createElement('aui-dropdown-menu');
dropdownEl.id = 'aui-responsive-header-dropdown-' + this.index;
_skate2.default.init(dropdownEl);
var dropdownSectionEl = document.createElement('aui-section');
dropdownSectionEl.id = 'aui-responsive-header-dropdown-list-' + this.index;
_skate2.default.init(dropdownSectionEl);
_skatejsTemplateHtml2.default.wrap(dropdownEl).appendChild(dropdownSectionEl);
var triggerEl = createTriggerAndAssociate(dropdownEl);
moreNavItemEl.appendChild(triggerEl);
moreNavItemEl.appendChild(dropdownEl);
// Append the More menu before any primary buttons.
if (this.primaryButtonsWidth === 0) {
this.$headerFind('.aui-nav').append(moreNavItemEl);
} else {
this.$headerFind('.aui-nav > li > .aui-button:first').parent().before(moreNavItemEl);
}
this.moreMenuWidth = (0, _jquery2.default)(moreNavItemEl).outerWidth(true);
return (0, _jquery2.default)(moreNavItemEl);
},
// function that handles moving items out of the show more menu into the app header
moveOutOfResponsiveDropdown: function moveOutOfResponsiveDropdown(numItems) {
if (numItems <= 0) {
return;
}
var $moreDropdown = (0, _jquery2.default)('#aui-responsive-header-dropdown-' + this.index);
// Move items (working top-to-bottom) from the more menu into the nav bar.
var leftMostIndexToMove = this.rightMostNavItemIndex + 1;
var rightMostIndexToMove = this.rightMostNavItemIndex + numItems;
for (var i = leftMostIndexToMove; i <= rightMostIndexToMove; i++) {
var $navItem = this.menuItems[i].$element;
var $navItemTrigger = $navItem.children('a');
if ($navItemTrigger.attr('aria-controls')) {
var $navItemDropdown = (0, _jquery2.default)(document.getElementById($navItemTrigger.attr('aria-controls')));
$navItemDropdown.removeClass('aui-dropdown2-sub-menu');
$navItem.append($navItemDropdown);
}
$moreDropdown.find('aui-item-link:first').remove();
$navItem.insertBefore(this.$moreMenu);
}
this.rightMostNavItemIndex += numItems;
},
// function that handles moving items into the show more menu
moveToResponsiveDropdown: function moveToResponsiveDropdown(numItems) {
if (numItems <= 0) {
return;
}
var moreDropdownSectionEl = _skatejsTemplateHtml2.default.wrap(this.$moreMenu[0].querySelector('aui-section'));
// Move items (working right-to-left) from the nav bar to the more menu.
var rightMostIndexToMove = this.rightMostNavItemIndex;
var leftMostIndexToMove = this.rightMostNavItemIndex - numItems + 1;
for (var i = rightMostIndexToMove; i >= leftMostIndexToMove; i--) {
var $navItem = this.menuItems[i].$element;
var $navItemTrigger = $navItem.children('a');
_skate2.default.init($navItemTrigger); // ensure all triggers have gone through their lifecycle before we check for submenus
var moreDropdownItemEl = document.createElement('aui-item-link');
moreDropdownItemEl.setAttribute('href', $navItemTrigger.attr('href'));
if ($navItemTrigger.attr('aria-controls')) {
var $navItemDropdown = (0, _jquery2.default)(document.getElementById($navItemTrigger.attr('aria-controls')));
moreDropdownItemEl.setAttribute('for', $navItemTrigger.attr('aria-controls'));
$navItemDropdown.addClass('aui-dropdown2-sub-menu');
$navItemDropdown.appendTo('body');
}
_skate2.default.init(moreDropdownItemEl);
_skatejsTemplateHtml2.default.wrap(moreDropdownItemEl).textContent = $navItemTrigger.text();
$navItem.detach();
moreDropdownSectionEl.insertBefore(moreDropdownItemEl, moreDropdownSectionEl.firstChild);
this.element.dispatchEvent(new _customEvent2.default('aui-responsive-menu-item-created', {
bubbles: true,
detail: {
originalItem: $navItem[0],
newItem: moreDropdownItemEl
}
}));
}
this.rightMostNavItemIndex -= numItems;
},
// function that handles show everything
showAll: function showAll() {
this.moveOutOfResponsiveDropdown(this.menuItems.length - 1 - this.rightMostNavItemIndex);
this.hideResponsiveDropdown();
}
};
function createTriggerAndAssociate(dropdown) {
var trigger = document.createElement('a');
trigger.setAttribute('class', 'aui-dropdown2-trigger');
trigger.setAttribute('href', '#');
trigger.id = dropdown.id + '-trigger';
trigger.setAttribute('aria-controls', dropdown.id);
trigger.innerHTML = _i18n2.default.getText('aui.words.more');
return trigger;
}
/**
* Initialise a Header, or return an existing Header for an element.
*/
function createHeader(element) {
var header = element._header;
if (!(header instanceof Header)) {
header = new Header(element);
header.init();
element._header = header;
}
return header;
}
exports.default = createHeader;
module.exports = exports['default'];
});
//# sourceMappingURL=create-header.js.map