baseframe-js
Version:
A suite of useful Javascript plugins and functions to help with Front-end Development on websites
308 lines (307 loc) • 15 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 _helpers = require("./util/helpers");
var _cashDom = _interopRequireDefault(require("cash-dom"));
var _Store = _interopRequireDefault(require("./core/Store"));
var _UrlState = _interopRequireDefault(require("./core/UrlState"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
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 _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 _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 _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
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 = "1.0.1";
var DATA_NAME = 'ScrollSpy';
var EVENT_NAME = 'scrollSpy';
var DEFAULTS = {
observerOptions: {
rootMargin: "0px",
threshold: 1
},
cssPrefix: 'scroll-spy',
spyNavElems: 'a',
spyBody: '.scroll-spy-body',
spyElems: 'h2',
setActiveCssToLi: true,
locationFilter: null,
urlFilterType: 'hash',
historyType: 'push',
loadLocation: true
};
var _pairedElems = /*#__PURE__*/new WeakMap();
var _lastSpyElem = /*#__PURE__*/new WeakMap();
var _observer = /*#__PURE__*/new WeakMap();
var _ScrollSpy_brand = /*#__PURE__*/new WeakSet();
var ScrollSpy = exports["default"] = /*#__PURE__*/function () {
function ScrollSpy(element, options) {
_classCallCheck(this, ScrollSpy);
_classPrivateMethodInitSpec(this, _ScrollSpy_brand);
_classPrivateFieldInitSpec(this, _pairedElems, new Map());
_defineProperty(this, "inViewEntries", new Set());
_defineProperty(this, "backUpInViewEntry", void 0);
_classPrivateFieldInitSpec(this, _lastSpyElem, null);
_classPrivateFieldInitSpec(this, _observer, null);
_defineProperty(this, "params", void 0);
_defineProperty(this, "element", void 0);
_defineProperty(this, "$spyBody", void 0);
_defineProperty(this, "spyContents", void 0);
var _s = this;
var dataOptions = (0, _helpers.getDataOptions)(element, EVENT_NAME);
_s.element = element;
_s.params = _cashDom["default"].extend({}, ScrollSpy.defaults, options, dataOptions);
_s.$spyBody = (0, _cashDom["default"])(_s.params.spyBody);
_s.spyContents = Array.from(_s.$spyBody.find(_s.params.spyElems)).filter(function (el) {
return (0, _helpers.isVisible)(el) && el.id;
});
if (_s.spyContents.length > 0) {
(0, _cashDom["default"])(element).addClass("".concat(_s.params.cssPrefix, "-nav"));
_s.$spyBody.addClass("".concat(_s.params.cssPrefix, "-body"));
_classPrivateFieldSet(_lastSpyElem, _s, _s.spyContents[_s.spyContents.length - 1]);
_s.backUpInViewEntry = _assertClassBrand(_ScrollSpy_brand, _s, _getInitialBackUpInViewEntry).call(_s);
_assertClassBrand(_ScrollSpy_brand, _s, _pairElementsToNavEls).call(_s);
_s.handleEvents();
} else {
console.warn("there is nothing to spy, check your 'spyBody' for those elements", _s.params.spyBody);
}
return _s;
}
return _createClass(ScrollSpy, [{
key: "handleEvents",
value: function handleEvents() {
var s = this;
var p = s.params;
var observerProcess = function observerProcess(entries) {
_assertClassBrand(_ScrollSpy_brand, s, _setInViewEntries).call(s, entries);
_assertClassBrand(_ScrollSpy_brand, s, _spyElements).call(s);
};
s.loadFromUrl();
_classPrivateFieldSet(_observer, s, new IntersectionObserver(observerProcess, p.observerOptions));
var _iterator = _createForOfIteratorHelper(s.spyContents),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var elem = _step.value;
_classPrivateFieldGet(_observer, s).observe(elem);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
(0, _cashDom["default"])(s.element).on("click.".concat(EVENT_NAME), p.spyNavElems, function (e) {
var clickElem = this;
var paramVal = (this.nodeName === 'A' ? this.hash : clickElem.dataset.hash).replace(/^\#/, '');
var $bodyElem = s.scrollToElement(paramVal, 'smooth');
if ($bodyElem.length) {
if (typeof p.urlFilterType === 'string') {
if (p.locationFilter) {
if (p.urlFilterType === 'hashVal') {
_UrlState["default"].setHashVal(paramVal, p.historyType);
} else if (p.urlFilterType === 'hash' || p.urlFilterType === 'search') {
_UrlState["default"].set(p.urlFilterType, p.locationFilter, paramVal, p.historyType);
}
}
}
e.preventDefault();
}
});
}
}, {
key: "scrollToElement",
value: function scrollToElement(elemId, behavior) {
var s = this;
var p = s.params;
var scrollRoot = p.observerOptions.root || window;
var observerOffsetTop = parseFloat(p.observerOptions.rootMargin.split(' ')[0]) || 0;
var $bodyElem = (0, _cashDom["default"])(elemId ? '#' + elemId : document.body);
if ($bodyElem.length) {
scrollRoot.scrollTo({
top: $bodyElem.offset().top - observerOffsetTop,
behavior: behavior
});
}
return $bodyElem;
}
}, {
key: "loadFromUrl",
value: function loadFromUrl() {
var s = this;
var p = s.params;
if (p.locationFilter !== null && p.loadLocation && p.urlFilterType !== 'none') {
var spyId = _UrlState["default"].get(p.urlFilterType, p.locationFilter);
if (spyId) {
s.scrollToElement(spyId, 'instant');
}
}
}
}], [{
key: "remove",
value: function remove(element, plugin) {
(0, _cashDom["default"])(element).each(function () {
var s = plugin || (0, _Store["default"])(this, DATA_NAME);
var _iterator2 = _createForOfIteratorHelper(s.spyContents),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var elem = _step2.value;
_assertClassBrand(_ScrollSpy_brand, s, _toggleActiveCss).call(s, elem, 'remove');
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
(0, _cashDom["default"])(s.element).off("click.".concat(EVENT_NAME)).removeClass("".concat(s.params.cssPrefix, "-nav"));
s.$spyBody.removeClass("".concat(s.params.cssPrefix, "-body"));
_classPrivateFieldGet(_observer, s).disconnect();
(0, _Store["default"])(this, DATA_NAME, null);
});
}
}]);
}();
function _getInitialBackUpInViewEntry() {
var s = this;
var sortedByTop = s.spyContents.map(function (el) {
return {
el: el,
top: el.getBoundingClientRect().top
};
}).sort(function (a, b) {
return a.top < b.top ? -1 : 1;
});
for (var i = 0, l = sortedByTop.length; i < l; i++) {
var curr = sortedByTop[i];
var prev = sortedByTop[i - 1];
if (curr.top >= 0) {
if (prev) {
return prev.el;
}
return curr.el;
}
}
}
function _pairElementsToNavEls() {
var s = this;
var _s$params = s.params,
spyNavElems = _s$params.spyNavElems,
setActiveCssToLi = _s$params.setActiveCssToLi;
(0, _cashDom["default"])(s.element).find(spyNavElems).each(function () {
var clickEl = this;
var hash = this.nodeName === 'A' ? clickEl.hash : clickEl.dataset.hash;
if (hash) {
var foundElem = s.spyContents.find(function (el) {
return el.id && el.id === hash.replace('#', '');
});
if (foundElem) {
var pairedElem = setActiveCssToLi ? clickEl.closest('li') || clickEl : clickEl;
_classPrivateFieldGet(_pairedElems, s).set(foundElem, pairedElem);
_classPrivateFieldGet(_pairedElems, s).set(clickEl, foundElem);
}
}
});
}
function _setInViewEntries(entries) {
var s = this;
var _iterator3 = _createForOfIteratorHelper(entries),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var entry = _step3.value;
var target = entry.target;
if (entry.isIntersecting) {
s.inViewEntries.add(target);
} else {
if (s.inViewEntries.has(target)) {
s.backUpInViewEntry = target;
s.inViewEntries["delete"](target);
_assertClassBrand(_ScrollSpy_brand, s, _toggleActiveCss).call(s, target, 'remove');
}
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
function _toggleActiveCss(target, type) {
var s = this;
var cssPrefix = s.params.cssPrefix;
var clickElem = _classPrivateFieldGet(_pairedElems, s).get(target);
if (clickElem) {
clickElem.classList[type]("".concat(cssPrefix, "-nav__active"));
target.classList[type]("".concat(cssPrefix, "-body__active"));
}
}
function _spyElements() {
var s = this;
var hasInViewEntries = s.inViewEntries.size > 0;
var topMostEntries = hasInViewEntries ? [] : [s.backUpInViewEntry];
var _iterator4 = _createForOfIteratorHelper(s.inViewEntries),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var entry = _step4.value;
if (topMostEntries.length) {
var elTop = entry.getBoundingClientRect().top;
for (var i = 0, l = topMostEntries.length; i < l; i++) {
var tmEntry = topMostEntries[i];
var tmElTop = tmEntry.getBoundingClientRect().top;
if (elTop < tmElTop && elTop >= 0) {
topMostEntries.splice(i, 1, entry);
_assertClassBrand(_ScrollSpy_brand, s, _toggleActiveCss).call(s, tmEntry, 'remove');
}
var isLastEntry = _classPrivateFieldGet(_lastSpyElem, s).isSameNode(entry);
if (isLastEntry) {
var remainingBodyScroll = document.body.scrollHeight - window.scrollY;
var canScrollAmount = window.innerHeight;
if (canScrollAmount > remainingBodyScroll) {
// if we can't get to the last scroll element
// then highlight once in the screen
topMostEntries.push(entry);
}
}
if (elTop === tmElTop) {
topMostEntries.push(entry);
}
}
} else {
topMostEntries.push(entry);
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
if (hasInViewEntries) {
_assertClassBrand(_ScrollSpy_brand, s, _toggleActiveCss).call(s, s.backUpInViewEntry, 'remove');
}
for (var _i = 0, _topMostEntries = topMostEntries; _i < _topMostEntries.length; _i++) {
var elem = _topMostEntries[_i];
_assertClassBrand(_ScrollSpy_brand, s, _toggleActiveCss).call(s, elem, 'add');
}
if (s.params.callback) {
var navEntries = topMostEntries.map(function (el) {
return _classPrivateFieldGet(_pairedElems, s).get(el);
});
s.params.callback(topMostEntries, navEntries);
}
}
_defineProperty(ScrollSpy, "defaults", DEFAULTS);
_defineProperty(ScrollSpy, "version", VERSION);
_defineProperty(ScrollSpy, "pluginName", DATA_NAME);