baseframe-js
Version:
A suite of useful Javascript plugins and functions to help with Front-end Development on websites
283 lines (282 loc) • 13.1 kB
JavaScript
;
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _cashDom = _interopRequireDefault(require("cash-dom"));
var _helpers = require("./util/helpers");
var _trapFocus = _interopRequireDefault(require("./fn/trapFocus"));
var _transition2 = _interopRequireDefault(require("./fn/transition"));
var _constants = require("./core/constants");
var _Store = _interopRequireDefault(require("./core/Store"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
var VERSION = "3.0.0";
var DATA_NAME = 'NavMobile';
var EVENT_NAME = 'navMobile';
var DEFAULTS = {
enableBtn: '#mobile-nav-btn',
ariaLabel: 'Toggle site navigation',
subMenuText: 'toggle menu for',
insertToggleBtnAfter: 'a',
slideDuration: 400,
outerElement: document.body,
outsideClickClose: true,
animateHeight: true,
cssPrefix: 'menu',
menuBtnCss: 'i i-arrow-b',
menuBtnSkip: false,
afterNavItemOpen: _helpers.noop,
afterNavItemClose: _helpers.noop,
afterOpen: _helpers.noop,
afterClose: _helpers.noop,
doTrapFocus: true,
trapFocusElem: null,
stopPropagation: true,
bkptEnable: null
};
var _transition = /*#__PURE__*/new WeakMap();
var _NavMobile_brand = /*#__PURE__*/new WeakSet();
var NavMobile = exports["default"] = /*#__PURE__*/function () {
function NavMobile(element, options) {
_classCallCheck(this, NavMobile);
_classPrivateMethodInitSpec(this, _NavMobile_brand);
_defineProperty(this, "$element", void 0);
_defineProperty(this, "params", void 0);
_defineProperty(this, "menuOpened", void 0);
_defineProperty(this, "allowClick", void 0);
_defineProperty(this, "cssList", void 0);
_classPrivateFieldInitSpec(this, _transition, (0, _transition2["default"])());
var _s = this;
var dataOptions = (0, _helpers.getDataOptions)(element, EVENT_NAME);
_s.$element = (0, _cashDom["default"])(element);
_s.params = _cashDom["default"].extend({}, NavMobile.defaults, options, dataOptions);
var _s$params = _s.params,
cssPrefix = _s$params.cssPrefix,
menuBtnCss = _s$params.menuBtnCss;
_s.cssList = {
menuOuterOpen: "".concat(cssPrefix, "--outer-open"),
menuHasUL: "".concat(cssPrefix, "__has-ul"),
menuOpen: "".concat(cssPrefix, "--open"),
menuOpening: "".concat(cssPrefix, "--is-opening"),
menuClosing: "".concat(cssPrefix, "--is-closing"),
menuToggling: "".concat(cssPrefix, "--toggling"),
menuBtnCss: "".concat(cssPrefix, "__btn-nav ").concat(menuBtnCss)
};
//run the methods
_s.addChildNavCss();
_s.handleEvents();
_s.checkIfEnabled();
var elemID = element.id || element.className;
(0, _cashDom["default"])(_s.params.enableBtn).attr({
'aria-controls': elemID,
'aria-label': _s.params.ariaLabel
});
return _s;
}
return _createClass(NavMobile, [{
key: "handleEvents",
value: function handleEvents() {
var s = this;
var css = s.cssList;
var $enableBtn = (0, _cashDom["default"])(s.params.enableBtn);
$enableBtn.attr({
'aria-expanded': 'false'
}).on("click.".concat(EVENT_NAME, " ").concat(EVENT_NAME), function (e) {
if (!s.allowClick) return;
_assertClassBrand(_NavMobile_brand, s, _menuToggle).call(s);
e.stopPropagation();
e.preventDefault();
});
(0, _cashDom["default"])(document).on("keydown.".concat(EVENT_NAME), function (e) {
if (e.code === _constants.KEYS.esc && s.$element.hasClass(css.menuOpen) && s.allowClick) {
_assertClassBrand(_NavMobile_brand, s, _menuToggle).call(s);
if ($enableBtn.length) {
$enableBtn[0].focus();
}
}
});
_assertClassBrand(_NavMobile_brand, s, _navToggle).call(s);
_assertClassBrand(_NavMobile_brand, s, _outsideClickClose).call(s);
}
}, {
key: "addChildNavCss",
value: function addChildNavCss() {
var s = this;
var p = s.params;
var css = s.cssList;
(0, _cashDom["default"])('li', s.$element).has('ul').each(function () {
var $this = (0, _cashDom["default"])(this);
var skipUl = false;
if (typeof p.menuBtnSkip === 'function' &&
// condition in function must return false
p.menuBtnSkip(this)) {
skipUl = true;
}
if (!$this.next('button').length && !skipUl) {
var $el = $this.find(p.insertToggleBtnAfter).first();
$el.addClass(css.menuHasUL);
if ($el.length) {
if ($el[0].parentNode.isSameNode(this)) {
// make sure the <el> is a direct child of <li>
$el.after((0, _cashDom["default"])('<button>').attr({
"class": css.menuBtnCss,
type: 'button',
'aria-label': p.subMenuText + ' ' + $el.text().trim()
}));
}
}
}
});
}
}, {
key: "checkIfEnabled",
value: function checkIfEnabled() {
var s = this;
var resizeTimer;
//basically if the navigational button is visible then
//we can allow the click to open the navigation
//this is so it doesn't clash with any other plugins
//and allows for the control of this click via CSS
(0, _cashDom["default"])(window).on("resize.".concat(EVENT_NAME, " ").concat(EVENT_NAME), function (e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function () {
var $enableBtn = (0, _cashDom["default"])(s.params.enableBtn);
s.allowClick = typeof s.params.bkptEnable === 'number' ? (0, _cashDom["default"])(window).width() <= s.params.bkptEnable : $enableBtn.length ? (0, _helpers.isVisible)($enableBtn[0]) : false;
}, e.type === EVENT_NAME ? 0 : 200);
}).trigger(EVENT_NAME);
}
}], [{
key: "remove",
value: function remove(element, plugin) {
(0, _cashDom["default"])(element).each(function () {
var s = plugin || (0, _Store["default"])(this, DATA_NAME);
(0, _cashDom["default"])(s.params.enableBtn).off("click.".concat(EVENT_NAME, " ").concat(EVENT_NAME));
(0, _cashDom["default"])(document).off("keydown.".concat(EVENT_NAME));
s.$element.off("click.".concat(EVENT_NAME, " ").concat(EVENT_NAME)).off("click.".concat(EVENT_NAME, " ").concat(EVENT_NAME));
(0, _cashDom["default"])(document.body).off("click.".concat(EVENT_NAME));
(0, _cashDom["default"])(window).off("resize.".concat(EVENT_NAME, " ").concat(EVENT_NAME));
(0, _Store["default"])(this, DATA_NAME, null);
});
}
}]);
}();
function _menuToggle() {
var s = this;
var p = s.params;
var css = s.cssList;
var trappedFocus = null;
var $enableBtn = (0, _cashDom["default"])(p.enableBtn);
var $elemParent = s.$element.parent();
var doClose = s.menuOpened;
var cssMenuState = "".concat(doClose ? css.menuClosing : css.menuOpening, " ").concat(css.menuToggling);
_classPrivateFieldGet(_transition, s).call(s, function () {
s.menuOpened = !doClose;
s.$element.addClass(cssMenuState);
(0, _cashDom["default"])(p.enableBtn).attr({
'aria-expanded': !doClose + ''
});
(0, _cashDom["default"])(p.outerElement).toggleClass(css.menuOuterOpen, !doClose).addClass(cssMenuState);
if (doClose) {
$elemParent.find(".".concat(css.menuOpen)).removeClass(css.menuOpen).find("[style]").css({
'display': null
});
trappedFocus && trappedFocus.remove();
} else {
if (p.doTrapFocus) {
trappedFocus = (0, _trapFocus["default"])(p.trapFocusElem || s.$element, {
nameSpace: EVENT_NAME
});
}
}
}, function () {
(0, _cashDom["default"])(p.outerElement).removeClass(cssMenuState);
s.$element.removeClass(cssMenuState);
if (!doClose) {
s.$element.addClass(css.menuOpen);
}
s.params[doClose ? 'afterClose' : 'afterOpen'](s.$element, (0, _cashDom["default"])(p.outerElement), $enableBtn);
}, p.slideDuration);
}
function _navToggle() {
var s = this;
var css = s.cssList;
s.$element.on("click.".concat(EVENT_NAME, " ").concat(EVENT_NAME), ".".concat(css.menuBtnCss.replace(/\s/g, '.')), function (e) {
var p = s.params;
var css = s.cssList;
var $li = (0, _cashDom["default"])(this).closest(".".concat(css.menuHasUL));
var doClose = $li.hasClass(css.menuOpen);
var $ul = $li.find('ul').first();
//exit because were in desktop view
if (!s.allowClick) {
return;
}
var cssMenuState = "".concat(css.menuToggling, " ").concat(doClose ? css.menuClosing : css.menuOpening);
s.allowClick = doClose;
_classPrivateFieldGet(_transition, s).call(s, function () {
$li.addClass(cssMenuState).toggleClass(css.menuOpen, !doClose);
$ul.addClass(cssMenuState).toggleClass(css.menuOpen, !doClose);
if (p.animateHeight) {
var openHeight = $ul.length ? $ul[0].scrollHeight : 0;
var height = doClose ? 0 : openHeight;
$ul.css({
height: doClose ? openHeight : 0
});
setTimeout(function () {
$ul.css({
height: height
});
}, 0);
}
}, function () {
$li.removeClass(cssMenuState).toggleClass(css.menuOpen, !doClose);
$ul.removeClass(cssMenuState).toggleClass(css.menuOpen, !doClose);
$ul.css({
height: null
});
if (doClose) {
s.params.afterNavItemClose($li);
} else {
s.params.afterNavItemOpen($li);
}
s.allowClick = true;
}, p.slideDuration);
e.stopPropagation();
});
s.$element.on("click.".concat(EVENT_NAME, " ").concat(EVENT_NAME), 'a', function (e) {
//prohibit closing if an anchor is clicked
if (s.params.stopPropagation) {
e.stopPropagation();
}
});
}
function _outsideClickClose() {
var s = this;
(0, _cashDom["default"])(document.body).on("click.".concat(EVENT_NAME), function (e) {
if (s.params.outsideClickClose) {
if (!s.menuOpened) {
return;
} //lets just exit then..
var menuClicked = e.target ? s.$element.has(e.target).length > 0 : false;
//if the menu item is not clicked and its opened
//the menu button shouldn't register because propogation is prevented to the body
if (!menuClicked && s.menuOpened) {
_assertClassBrand(_NavMobile_brand, s, _menuToggle).call(s);
}
}
});
}
_defineProperty(NavMobile, "defaults", DEFAULTS);
_defineProperty(NavMobile, "version", VERSION);
_defineProperty(NavMobile, "pluginName", DATA_NAME);