alpine-turbo-drive-adapter
Version:
Bridge library to enable full support for Alpine components in pages using Turbolinks/Turbo Drive
205 lines (196 loc) • 8.8 kB
JavaScript
(function (factory) {
typeof define === 'function' && define.amd ? define(factory) :
factory();
})((function () { 'use strict';
function _classCallCheck(a, n) {
if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
}
function _defineProperties(e, r) {
for (var t = 0; t < r.length; t++) {
var o = r[t];
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
}
}
function _createClass(e, r, t) {
return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
writable: !1
}), e;
}
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 _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function isValidVersion(required, current) {
var requiredArray = required.split('.');
var currentArray = current.split('.');
for (var i = 0; i < requiredArray.length; i++) {
if (currentArray[i] && currentArray[i] > requiredArray[i]) {
return true;
}
}
return currentArray[requiredArray.length - 1] === requiredArray[requiredArray.length - 1];
}
function dispatch(el, name) {
var detail = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
el.dispatchEvent(new CustomEvent(name, {
detail: detail,
bubbles: true,
composed: true,
cancelable: true
}));
}
var Bridge = /*#__PURE__*/function () {
function Bridge() {
_classCallCheck(this, Bridge);
}
return _createClass(Bridge, [{
key: "init",
value: function init() {
if (!window.Alpine.version || !isValidVersion('3.0.0', window.Alpine.version)) {
throw new Error('Invalid Alpine version. Please use Alpine 3.0.0 or above');
}
// Tag all cloaked elements on first page load.
window.Alpine.mutateDom(function () {
document.body.querySelectorAll('[x-cloak]').forEach(function (el) {
var _el$getAttribute;
el.setAttribute('data-alpine-was-cloaked', (_el$getAttribute = el.getAttribute('x-cloak')) !== null && _el$getAttribute !== void 0 ? _el$getAttribute : '');
});
});
this.configureEventHandlers();
this.monkeyPatchDomSetAttributeToAllowAtSymbols();
}
}, {
key: "configureEventHandlers",
value: function configureEventHandlers() {
var renderCallback = function renderCallback(event) {
if (event.detail.renderMethod === 'morph') return;
if (document.documentElement.hasAttribute('data-turbo-preview')) {
return;
}
dispatch(document, 'alpine:init');
dispatch(document, 'alpine:initializing');
window.Alpine.flushAndStopDeferringMutations();
dispatch(document, 'alpine:initialised');
window.Alpine.mutateDom(function () {
document.querySelectorAll('[data-alpine-ignored]').forEach(function (el) {
el.removeAttribute('x-ignore');
el.removeAttribute('data-alpine-ignored');
});
});
};
var beforeRenderCallback = function beforeRenderCallback(event) {
if (event.detail.renderMethod === 'morph') return;
window.Alpine.mutateDom(function () {
if (document.documentElement.hasAttribute('data-turbo-preview')) {
return;
}
event.detail.newBody.querySelectorAll('[data-alpine-generated-me],[x-cloak]').forEach(function (el) {
if (el.hasAttribute('x-cloak')) {
var _el$getAttribute2;
el.setAttribute('data-alpine-was-cloaked', (_el$getAttribute2 = el.getAttribute('x-cloak')) !== null && _el$getAttribute2 !== void 0 ? _el$getAttribute2 : '');
}
if (el.hasAttribute('data-alpine-generated-me')) {
el.removeAttribute('data-alpine-generated-me');
el.remove();
}
});
});
window.Alpine.deferMutations();
};
var beforeCacheCallback = function beforeCacheCallback(event) {
window.Alpine.mutateDom(function () {
document.body.querySelectorAll('[x-for],[x-if],[x-teleport],[data-alpine-was-cloaked]').forEach(function (el) {
if (el.hasAttribute('data-alpine-was-cloaked')) {
var _el$getAttribute3;
el.setAttribute('x-cloak', (_el$getAttribute3 = el.getAttribute('data-alpine-was-cloaked')) !== null && _el$getAttribute3 !== void 0 ? _el$getAttribute3 : '');
el.removeAttribute('data-alpine-was-cloaked');
}
if (el.hasAttribute('x-for') && el._x_lookup) {
Object.values(el._x_lookup).forEach(function (el) {
return el.setAttribute('data-alpine-generated-me', true);
});
}
if (el.hasAttribute('x-if') && el._x_currentIfEl) {
el._x_currentIfEl.setAttribute('data-alpine-generated-me', true);
}
if (el.hasAttribute('x-teleport') && el._x_teleport) {
el._x_teleport.setAttribute('data-alpine-generated-me', true);
}
});
});
document.querySelectorAll('[data-turbo-permanent]').forEach(function (el) {
window.Alpine.mutateDom(function () {
if (!el.hasAttribute('x-ignore')) {
el.setAttribute('x-ignore', true);
el.setAttribute('data-alpine-ignored', true);
}
el.querySelectorAll('[data-alpine-generated-me]').forEach(function (sub) {
sub.removeAttribute('data-alpine-generated-me');
});
});
});
};
// This tricks Alpine into reinitializing a already-initialized
// tree, allowing us to avoid destroying the tree first.
var beforeMorphElementCallback = function beforeMorphElementCallback(_ref) {
var target = _ref.target,
newElement = _ref.detail.newElement;
if (!newElement && target._x_dataStack) {
return window.Alpine.destroyTree(target);
}
delete target._x_marker;
};
var morphElementCallback = function morphElementCallback(_ref2) {
var target = _ref2.target,
newElement = _ref2.detail.newElement;
newElement && target._x_dataStack && window.Alpine.initTree(target);
};
document.addEventListener('turbo:render', renderCallback);
document.addEventListener('turbo:before-render', beforeRenderCallback);
document.addEventListener('turbo:before-cache', beforeCacheCallback);
document.addEventListener('turbo:before-morph-element', beforeMorphElementCallback);
document.addEventListener('turbo:morph-element', morphElementCallback);
}
// Taken from https://github.com/alpinejs/alpine/blob/e363181057b3e71e5c03d2b88db576d5094be1c8/packages/morph/src/morph.js#L493
// Turbo/Idiomorph uses Element.setAttribute to morph attributes, which doesn't allow "@" symbols
}, {
key: "monkeyPatchDomSetAttributeToAllowAtSymbols",
value: function monkeyPatchDomSetAttributeToAllowAtSymbols() {
var original = Element.prototype.setAttribute;
var hostDiv = document.createElement('div');
Element.prototype.setAttribute = function newSetAttribute(name, value) {
if (!name.includes('@')) {
return original.call(this, name, value);
}
hostDiv.innerHTML = "<span ".concat(name, "=\"").concat(value, "\"></span>");
var attr = hostDiv.firstElementChild.getAttributeNode(name);
hostDiv.firstElementChild.removeAttributeNode(attr);
this.setAttributeNode(attr);
};
}
}]);
}();
if (window.Alpine) {
console.error('Alpine-turbo-drive-adapter must be included before AlpineJs');
}
// Polyfill for legacy browsers
if (!Object.getOwnPropertyDescriptor(NodeList.prototype, 'forEach')) {
Object.defineProperty(NodeList.prototype, 'forEach', Object.getOwnPropertyDescriptor(Array.prototype, 'forEach'));
}
document.addEventListener('alpine:init', function () {
var bridge = new Bridge();
bridge.init();
}, {
once: true
});
}));