mirror of
https://github.com/archtechx/laravel-tips.git
synced 2025-12-12 13:24:03 +00:00
5057 lines
No EOL
178 KiB
JavaScript
Vendored
5057 lines
No EOL
178 KiB
JavaScript
Vendored
/******/ (() => { // webpackBootstrap
|
||
/******/ var __webpack_modules__ = ({
|
||
|
||
/***/ "./node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js":
|
||
/*!***************************************************************!*\
|
||
!*** ./node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js ***!
|
||
\***************************************************************/
|
||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||
|
||
"use strict";
|
||
__webpack_require__.r(__webpack_exports__);
|
||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||
/* harmony export */ "clearCache": () => (/* binding */ clearCache),
|
||
/* harmony export */ "connectStreamSource": () => (/* binding */ connectStreamSource),
|
||
/* harmony export */ "disconnectStreamSource": () => (/* binding */ disconnectStreamSource),
|
||
/* harmony export */ "navigator": () => (/* binding */ navigator),
|
||
/* harmony export */ "registerAdapter": () => (/* binding */ registerAdapter),
|
||
/* harmony export */ "renderStreamMessage": () => (/* binding */ renderStreamMessage),
|
||
/* harmony export */ "setProgressBarDelay": () => (/* binding */ setProgressBarDelay),
|
||
/* harmony export */ "start": () => (/* binding */ start),
|
||
/* harmony export */ "visit": () => (/* binding */ visit)
|
||
/* harmony export */ });
|
||
/*
|
||
Turbo 7.0.0-beta.4
|
||
Copyright © 2021 Basecamp, LLC
|
||
*/
|
||
(function () {
|
||
if (window.Reflect === undefined || window.customElements === undefined ||
|
||
window.customElements.polyfillWrapFlushCallback) {
|
||
return;
|
||
}
|
||
const BuiltInHTMLElement = HTMLElement;
|
||
const wrapperForTheName = {
|
||
'HTMLElement': function HTMLElement() {
|
||
return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
|
||
}
|
||
};
|
||
window.HTMLElement =
|
||
wrapperForTheName['HTMLElement'];
|
||
HTMLElement.prototype = BuiltInHTMLElement.prototype;
|
||
HTMLElement.prototype.constructor = HTMLElement;
|
||
Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
|
||
})();
|
||
|
||
const submittersByForm = new WeakMap;
|
||
function findSubmitterFromClickTarget(target) {
|
||
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
||
const candidate = element ? element.closest("input, button") : null;
|
||
return (candidate === null || candidate === void 0 ? void 0 : candidate.type) == "submit" ? candidate : null;
|
||
}
|
||
function clickCaptured(event) {
|
||
const submitter = findSubmitterFromClickTarget(event.target);
|
||
if (submitter && submitter.form) {
|
||
submittersByForm.set(submitter.form, submitter);
|
||
}
|
||
}
|
||
(function () {
|
||
if ("SubmitEvent" in window)
|
||
return;
|
||
addEventListener("click", clickCaptured, true);
|
||
Object.defineProperty(Event.prototype, "submitter", {
|
||
get() {
|
||
if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
||
return submittersByForm.get(this.target);
|
||
}
|
||
}
|
||
});
|
||
})();
|
||
|
||
var FrameLoadingStyle;
|
||
(function (FrameLoadingStyle) {
|
||
FrameLoadingStyle["eager"] = "eager";
|
||
FrameLoadingStyle["lazy"] = "lazy";
|
||
})(FrameLoadingStyle || (FrameLoadingStyle = {}));
|
||
class FrameElement extends HTMLElement {
|
||
constructor() {
|
||
super();
|
||
this.loaded = Promise.resolve();
|
||
this.delegate = new FrameElement.delegateConstructor(this);
|
||
}
|
||
static get observedAttributes() {
|
||
return ["loading", "src"];
|
||
}
|
||
connectedCallback() {
|
||
this.delegate.connect();
|
||
}
|
||
disconnectedCallback() {
|
||
this.delegate.disconnect();
|
||
}
|
||
attributeChangedCallback(name) {
|
||
if (name == "loading") {
|
||
this.delegate.loadingStyleChanged();
|
||
}
|
||
else if (name == "src") {
|
||
this.delegate.sourceURLChanged();
|
||
}
|
||
}
|
||
get src() {
|
||
return this.getAttribute("src");
|
||
}
|
||
set src(value) {
|
||
if (value) {
|
||
this.setAttribute("src", value);
|
||
}
|
||
else {
|
||
this.removeAttribute("src");
|
||
}
|
||
}
|
||
get loading() {
|
||
return frameLoadingStyleFromString(this.getAttribute("loading") || "");
|
||
}
|
||
set loading(value) {
|
||
if (value) {
|
||
this.setAttribute("loading", value);
|
||
}
|
||
else {
|
||
this.removeAttribute("loading");
|
||
}
|
||
}
|
||
get disabled() {
|
||
return this.hasAttribute("disabled");
|
||
}
|
||
set disabled(value) {
|
||
if (value) {
|
||
this.setAttribute("disabled", "");
|
||
}
|
||
else {
|
||
this.removeAttribute("disabled");
|
||
}
|
||
}
|
||
get autoscroll() {
|
||
return this.hasAttribute("autoscroll");
|
||
}
|
||
set autoscroll(value) {
|
||
if (value) {
|
||
this.setAttribute("autoscroll", "");
|
||
}
|
||
else {
|
||
this.removeAttribute("autoscroll");
|
||
}
|
||
}
|
||
get complete() {
|
||
return !this.delegate.isLoading;
|
||
}
|
||
get isActive() {
|
||
return this.ownerDocument === document && !this.isPreview;
|
||
}
|
||
get isPreview() {
|
||
var _a, _b;
|
||
return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
|
||
}
|
||
}
|
||
function frameLoadingStyleFromString(style) {
|
||
switch (style.toLowerCase()) {
|
||
case "lazy": return FrameLoadingStyle.lazy;
|
||
default: return FrameLoadingStyle.eager;
|
||
}
|
||
}
|
||
|
||
function expandURL(locatable) {
|
||
const anchor = document.createElement("a");
|
||
anchor.href = locatable.toString();
|
||
return new URL(anchor.href);
|
||
}
|
||
function getAnchor(url) {
|
||
let anchorMatch;
|
||
if (url.hash) {
|
||
return url.hash.slice(1);
|
||
}
|
||
else if (anchorMatch = url.href.match(/#(.*)$/)) {
|
||
return anchorMatch[1];
|
||
}
|
||
else {
|
||
return "";
|
||
}
|
||
}
|
||
function getExtension(url) {
|
||
return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
|
||
}
|
||
function isHTML(url) {
|
||
return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml))$/);
|
||
}
|
||
function isPrefixedBy(baseURL, url) {
|
||
const prefix = getPrefix(url);
|
||
return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix);
|
||
}
|
||
function toCacheKey(url) {
|
||
const anchorLength = url.hash.length;
|
||
if (anchorLength < 2) {
|
||
return url.href;
|
||
}
|
||
else {
|
||
return url.href.slice(0, -anchorLength);
|
||
}
|
||
}
|
||
function getPathComponents(url) {
|
||
return url.pathname.split("/").slice(1);
|
||
}
|
||
function getLastPathComponent(url) {
|
||
return getPathComponents(url).slice(-1)[0];
|
||
}
|
||
function getPrefix(url) {
|
||
return addTrailingSlash(url.origin + url.pathname);
|
||
}
|
||
function addTrailingSlash(value) {
|
||
return value.endsWith("/") ? value : value + "/";
|
||
}
|
||
|
||
class FetchResponse {
|
||
constructor(response) {
|
||
this.response = response;
|
||
}
|
||
get succeeded() {
|
||
return this.response.ok;
|
||
}
|
||
get failed() {
|
||
return !this.succeeded;
|
||
}
|
||
get clientError() {
|
||
return this.statusCode >= 400 && this.statusCode <= 499;
|
||
}
|
||
get serverError() {
|
||
return this.statusCode >= 500 && this.statusCode <= 599;
|
||
}
|
||
get redirected() {
|
||
return this.response.redirected;
|
||
}
|
||
get location() {
|
||
return expandURL(this.response.url);
|
||
}
|
||
get isHTML() {
|
||
return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/);
|
||
}
|
||
get statusCode() {
|
||
return this.response.status;
|
||
}
|
||
get contentType() {
|
||
return this.header("Content-Type");
|
||
}
|
||
get responseText() {
|
||
return this.response.text();
|
||
}
|
||
get responseHTML() {
|
||
if (this.isHTML) {
|
||
return this.response.text();
|
||
}
|
||
else {
|
||
return Promise.resolve(undefined);
|
||
}
|
||
}
|
||
header(name) {
|
||
return this.response.headers.get(name);
|
||
}
|
||
}
|
||
|
||
function dispatch(eventName, { target, cancelable, detail } = {}) {
|
||
const event = new CustomEvent(eventName, { cancelable, bubbles: true, detail });
|
||
void (target || document.documentElement).dispatchEvent(event);
|
||
return event;
|
||
}
|
||
function nextAnimationFrame() {
|
||
return new Promise(resolve => requestAnimationFrame(() => resolve()));
|
||
}
|
||
function nextEventLoopTick() {
|
||
return new Promise(resolve => setTimeout(() => resolve(), 0));
|
||
}
|
||
function nextMicrotask() {
|
||
return Promise.resolve();
|
||
}
|
||
function parseHTMLDocument(html = "") {
|
||
return new DOMParser().parseFromString(html, "text/html");
|
||
}
|
||
function unindent(strings, ...values) {
|
||
const lines = interpolate(strings, values).replace(/^\n/, "").split("\n");
|
||
const match = lines[0].match(/^\s+/);
|
||
const indent = match ? match[0].length : 0;
|
||
return lines.map(line => line.slice(indent)).join("\n");
|
||
}
|
||
function interpolate(strings, values) {
|
||
return strings.reduce((result, string, i) => {
|
||
const value = values[i] == undefined ? "" : values[i];
|
||
return result + string + value;
|
||
}, "");
|
||
}
|
||
function uuid() {
|
||
return Array.apply(null, { length: 36 }).map((_, i) => {
|
||
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
||
return "-";
|
||
}
|
||
else if (i == 14) {
|
||
return "4";
|
||
}
|
||
else if (i == 19) {
|
||
return (Math.floor(Math.random() * 4) + 8).toString(16);
|
||
}
|
||
else {
|
||
return Math.floor(Math.random() * 15).toString(16);
|
||
}
|
||
}).join("");
|
||
}
|
||
|
||
var FetchMethod;
|
||
(function (FetchMethod) {
|
||
FetchMethod[FetchMethod["get"] = 0] = "get";
|
||
FetchMethod[FetchMethod["post"] = 1] = "post";
|
||
FetchMethod[FetchMethod["put"] = 2] = "put";
|
||
FetchMethod[FetchMethod["patch"] = 3] = "patch";
|
||
FetchMethod[FetchMethod["delete"] = 4] = "delete";
|
||
})(FetchMethod || (FetchMethod = {}));
|
||
function fetchMethodFromString(method) {
|
||
switch (method.toLowerCase()) {
|
||
case "get": return FetchMethod.get;
|
||
case "post": return FetchMethod.post;
|
||
case "put": return FetchMethod.put;
|
||
case "patch": return FetchMethod.patch;
|
||
case "delete": return FetchMethod.delete;
|
||
}
|
||
}
|
||
class FetchRequest {
|
||
constructor(delegate, method, location, body = new URLSearchParams) {
|
||
this.abortController = new AbortController;
|
||
this.delegate = delegate;
|
||
this.method = method;
|
||
if (this.isIdempotent) {
|
||
this.url = mergeFormDataEntries(location, [...body.entries()]);
|
||
}
|
||
else {
|
||
this.body = body;
|
||
this.url = location;
|
||
}
|
||
}
|
||
get location() {
|
||
return this.url;
|
||
}
|
||
get params() {
|
||
return this.url.searchParams;
|
||
}
|
||
get entries() {
|
||
return this.body ? Array.from(this.body.entries()) : [];
|
||
}
|
||
cancel() {
|
||
this.abortController.abort();
|
||
}
|
||
async perform() {
|
||
const { fetchOptions } = this;
|
||
dispatch("turbo:before-fetch-request", { detail: { fetchOptions } });
|
||
try {
|
||
this.delegate.requestStarted(this);
|
||
const response = await fetch(this.url.href, fetchOptions);
|
||
return await this.receive(response);
|
||
}
|
||
catch (error) {
|
||
this.delegate.requestErrored(this, error);
|
||
throw error;
|
||
}
|
||
finally {
|
||
this.delegate.requestFinished(this);
|
||
}
|
||
}
|
||
async receive(response) {
|
||
const fetchResponse = new FetchResponse(response);
|
||
const event = dispatch("turbo:before-fetch-response", { cancelable: true, detail: { fetchResponse } });
|
||
if (event.defaultPrevented) {
|
||
this.delegate.requestPreventedHandlingResponse(this, fetchResponse);
|
||
}
|
||
else if (fetchResponse.succeeded) {
|
||
this.delegate.requestSucceededWithResponse(this, fetchResponse);
|
||
}
|
||
else {
|
||
this.delegate.requestFailedWithResponse(this, fetchResponse);
|
||
}
|
||
return fetchResponse;
|
||
}
|
||
get fetchOptions() {
|
||
return {
|
||
method: FetchMethod[this.method].toUpperCase(),
|
||
credentials: "same-origin",
|
||
headers: this.headers,
|
||
redirect: "follow",
|
||
body: this.body,
|
||
signal: this.abortSignal
|
||
};
|
||
}
|
||
get isIdempotent() {
|
||
return this.method == FetchMethod.get;
|
||
}
|
||
get headers() {
|
||
const headers = Object.assign({}, this.defaultHeaders);
|
||
if (typeof this.delegate.prepareHeadersForRequest == "function") {
|
||
this.delegate.prepareHeadersForRequest(headers, this);
|
||
}
|
||
return headers;
|
||
}
|
||
get abortSignal() {
|
||
return this.abortController.signal;
|
||
}
|
||
get defaultHeaders() {
|
||
return {
|
||
"Accept": "text/html, application/xhtml+xml"
|
||
};
|
||
}
|
||
}
|
||
function mergeFormDataEntries(url, entries) {
|
||
const currentSearchParams = new URLSearchParams(url.search);
|
||
for (const [name, value] of entries) {
|
||
if (value instanceof File)
|
||
continue;
|
||
if (currentSearchParams.has(name)) {
|
||
currentSearchParams.delete(name);
|
||
url.searchParams.set(name, value);
|
||
}
|
||
else {
|
||
url.searchParams.append(name, value);
|
||
}
|
||
}
|
||
return url;
|
||
}
|
||
|
||
class AppearanceObserver {
|
||
constructor(delegate, element) {
|
||
this.started = false;
|
||
this.intersect = entries => {
|
||
const lastEntry = entries.slice(-1)[0];
|
||
if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
|
||
this.delegate.elementAppearedInViewport(this.element);
|
||
}
|
||
};
|
||
this.delegate = delegate;
|
||
this.element = element;
|
||
this.intersectionObserver = new IntersectionObserver(this.intersect);
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
this.started = true;
|
||
this.intersectionObserver.observe(this.element);
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
this.started = false;
|
||
this.intersectionObserver.unobserve(this.element);
|
||
}
|
||
}
|
||
}
|
||
|
||
class StreamMessage {
|
||
constructor(html) {
|
||
this.templateElement = document.createElement("template");
|
||
this.templateElement.innerHTML = html;
|
||
}
|
||
static wrap(message) {
|
||
if (typeof message == "string") {
|
||
return new this(message);
|
||
}
|
||
else {
|
||
return message;
|
||
}
|
||
}
|
||
get fragment() {
|
||
const fragment = document.createDocumentFragment();
|
||
for (const element of this.foreignElements) {
|
||
fragment.appendChild(document.importNode(element, true));
|
||
}
|
||
return fragment;
|
||
}
|
||
get foreignElements() {
|
||
return this.templateChildren.reduce((streamElements, child) => {
|
||
if (child.tagName.toLowerCase() == "turbo-stream") {
|
||
return [...streamElements, child];
|
||
}
|
||
else {
|
||
return streamElements;
|
||
}
|
||
}, []);
|
||
}
|
||
get templateChildren() {
|
||
return Array.from(this.templateElement.content.children);
|
||
}
|
||
}
|
||
StreamMessage.contentType = "text/vnd.turbo-stream.html";
|
||
|
||
var FormSubmissionState;
|
||
(function (FormSubmissionState) {
|
||
FormSubmissionState[FormSubmissionState["initialized"] = 0] = "initialized";
|
||
FormSubmissionState[FormSubmissionState["requesting"] = 1] = "requesting";
|
||
FormSubmissionState[FormSubmissionState["waiting"] = 2] = "waiting";
|
||
FormSubmissionState[FormSubmissionState["receiving"] = 3] = "receiving";
|
||
FormSubmissionState[FormSubmissionState["stopping"] = 4] = "stopping";
|
||
FormSubmissionState[FormSubmissionState["stopped"] = 5] = "stopped";
|
||
})(FormSubmissionState || (FormSubmissionState = {}));
|
||
var FormEnctype;
|
||
(function (FormEnctype) {
|
||
FormEnctype["urlEncoded"] = "application/x-www-form-urlencoded";
|
||
FormEnctype["multipart"] = "multipart/form-data";
|
||
FormEnctype["plain"] = "text/plain";
|
||
})(FormEnctype || (FormEnctype = {}));
|
||
function formEnctypeFromString(encoding) {
|
||
switch (encoding.toLowerCase()) {
|
||
case FormEnctype.multipart: return FormEnctype.multipart;
|
||
case FormEnctype.plain: return FormEnctype.plain;
|
||
default: return FormEnctype.urlEncoded;
|
||
}
|
||
}
|
||
class FormSubmission {
|
||
constructor(delegate, formElement, submitter, mustRedirect = false) {
|
||
this.state = FormSubmissionState.initialized;
|
||
this.delegate = delegate;
|
||
this.formElement = formElement;
|
||
this.submitter = submitter;
|
||
this.formData = buildFormData(formElement, submitter);
|
||
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body);
|
||
this.mustRedirect = mustRedirect;
|
||
}
|
||
get method() {
|
||
var _a;
|
||
const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || "";
|
||
return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
|
||
}
|
||
get action() {
|
||
var _a;
|
||
return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formaction")) || this.formElement.action;
|
||
}
|
||
get location() {
|
||
return expandURL(this.action);
|
||
}
|
||
get body() {
|
||
if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
|
||
return new URLSearchParams(this.stringFormData);
|
||
}
|
||
else {
|
||
return this.formData;
|
||
}
|
||
}
|
||
get enctype() {
|
||
var _a;
|
||
return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
|
||
}
|
||
get stringFormData() {
|
||
return [...this.formData].reduce((entries, [name, value]) => {
|
||
return entries.concat(typeof value == "string" ? [[name, value]] : []);
|
||
}, []);
|
||
}
|
||
async start() {
|
||
const { initialized, requesting } = FormSubmissionState;
|
||
if (this.state == initialized) {
|
||
this.state = requesting;
|
||
return this.fetchRequest.perform();
|
||
}
|
||
}
|
||
stop() {
|
||
const { stopping, stopped } = FormSubmissionState;
|
||
if (this.state != stopping && this.state != stopped) {
|
||
this.state = stopping;
|
||
this.fetchRequest.cancel();
|
||
return true;
|
||
}
|
||
}
|
||
prepareHeadersForRequest(headers, request) {
|
||
if (!request.isIdempotent) {
|
||
const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
|
||
if (token) {
|
||
headers["X-CSRF-Token"] = token;
|
||
}
|
||
headers["Accept"] = [StreamMessage.contentType, headers["Accept"]].join(", ");
|
||
}
|
||
}
|
||
requestStarted(request) {
|
||
this.state = FormSubmissionState.waiting;
|
||
dispatch("turbo:submit-start", { target: this.formElement, detail: { formSubmission: this } });
|
||
this.delegate.formSubmissionStarted(this);
|
||
}
|
||
requestPreventedHandlingResponse(request, response) {
|
||
this.result = { success: response.succeeded, fetchResponse: response };
|
||
}
|
||
requestSucceededWithResponse(request, response) {
|
||
if (response.clientError || response.serverError) {
|
||
this.delegate.formSubmissionFailedWithResponse(this, response);
|
||
}
|
||
else if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) {
|
||
const error = new Error("Form responses must redirect to another location");
|
||
this.delegate.formSubmissionErrored(this, error);
|
||
}
|
||
else {
|
||
this.state = FormSubmissionState.receiving;
|
||
this.result = { success: true, fetchResponse: response };
|
||
this.delegate.formSubmissionSucceededWithResponse(this, response);
|
||
}
|
||
}
|
||
requestFailedWithResponse(request, response) {
|
||
this.result = { success: false, fetchResponse: response };
|
||
this.delegate.formSubmissionFailedWithResponse(this, response);
|
||
}
|
||
requestErrored(request, error) {
|
||
this.result = { success: false, error };
|
||
this.delegate.formSubmissionErrored(this, error);
|
||
}
|
||
requestFinished(request) {
|
||
this.state = FormSubmissionState.stopped;
|
||
dispatch("turbo:submit-end", { target: this.formElement, detail: Object.assign({ formSubmission: this }, this.result) });
|
||
this.delegate.formSubmissionFinished(this);
|
||
}
|
||
requestMustRedirect(request) {
|
||
return !request.isIdempotent && this.mustRedirect;
|
||
}
|
||
}
|
||
function buildFormData(formElement, submitter) {
|
||
const formData = new FormData(formElement);
|
||
const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("name");
|
||
const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("value");
|
||
if (name && formData.get(name) != value) {
|
||
formData.append(name, value || "");
|
||
}
|
||
return formData;
|
||
}
|
||
function getCookieValue(cookieName) {
|
||
if (cookieName != null) {
|
||
const cookies = document.cookie ? document.cookie.split("; ") : [];
|
||
const cookie = cookies.find((cookie) => cookie.startsWith(cookieName));
|
||
if (cookie) {
|
||
const value = cookie.split("=").slice(1).join("=");
|
||
return value ? decodeURIComponent(value) : undefined;
|
||
}
|
||
}
|
||
}
|
||
function getMetaContent(name) {
|
||
const element = document.querySelector(`meta[name="${name}"]`);
|
||
return element && element.content;
|
||
}
|
||
function responseSucceededWithoutRedirect(response) {
|
||
return response.statusCode == 200 && !response.redirected;
|
||
}
|
||
|
||
class Snapshot {
|
||
constructor(element) {
|
||
this.element = element;
|
||
}
|
||
get children() {
|
||
return [...this.element.children];
|
||
}
|
||
hasAnchor(anchor) {
|
||
return this.getElementForAnchor(anchor) != null;
|
||
}
|
||
getElementForAnchor(anchor) {
|
||
try {
|
||
return this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`);
|
||
}
|
||
catch (_a) {
|
||
return null;
|
||
}
|
||
}
|
||
get firstAutofocusableElement() {
|
||
return this.element.querySelector("[autofocus]");
|
||
}
|
||
get permanentElements() {
|
||
return [...this.element.querySelectorAll("[id][data-turbo-permanent]")];
|
||
}
|
||
getPermanentElementById(id) {
|
||
return this.element.querySelector(`#${id}[data-turbo-permanent]`);
|
||
}
|
||
getPermanentElementsPresentInSnapshot(snapshot) {
|
||
return this.permanentElements.filter(({ id }) => snapshot.getPermanentElementById(id));
|
||
}
|
||
}
|
||
|
||
class FormInterceptor {
|
||
constructor(delegate, element) {
|
||
this.submitBubbled = ((event) => {
|
||
if (event.target instanceof HTMLFormElement) {
|
||
const form = event.target;
|
||
const submitter = event.submitter || undefined;
|
||
if (this.delegate.shouldInterceptFormSubmission(form, submitter)) {
|
||
event.preventDefault();
|
||
event.stopImmediatePropagation();
|
||
this.delegate.formSubmissionIntercepted(form, submitter);
|
||
}
|
||
}
|
||
});
|
||
this.delegate = delegate;
|
||
this.element = element;
|
||
}
|
||
start() {
|
||
this.element.addEventListener("submit", this.submitBubbled);
|
||
}
|
||
stop() {
|
||
this.element.removeEventListener("submit", this.submitBubbled);
|
||
}
|
||
}
|
||
|
||
class View {
|
||
constructor(delegate, element) {
|
||
this.delegate = delegate;
|
||
this.element = element;
|
||
}
|
||
scrollToAnchor(anchor) {
|
||
const element = this.snapshot.getElementForAnchor(anchor);
|
||
if (element) {
|
||
this.scrollToElement(element);
|
||
}
|
||
else {
|
||
this.scrollToPosition({ x: 0, y: 0 });
|
||
}
|
||
}
|
||
scrollToElement(element) {
|
||
element.scrollIntoView();
|
||
}
|
||
scrollToPosition({ x, y }) {
|
||
this.scrollRoot.scrollTo(x, y);
|
||
}
|
||
get scrollRoot() {
|
||
return window;
|
||
}
|
||
async render(renderer) {
|
||
if (this.renderer) {
|
||
throw new Error("rendering is already in progress");
|
||
}
|
||
const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;
|
||
if (shouldRender) {
|
||
try {
|
||
this.renderer = renderer;
|
||
this.prepareToRenderSnapshot(renderer);
|
||
this.delegate.viewWillRenderSnapshot(snapshot, isPreview);
|
||
await this.renderSnapshot(renderer);
|
||
this.delegate.viewRenderedSnapshot(snapshot, isPreview);
|
||
this.finishRenderingSnapshot(renderer);
|
||
}
|
||
finally {
|
||
delete this.renderer;
|
||
}
|
||
}
|
||
else {
|
||
this.invalidate();
|
||
}
|
||
}
|
||
invalidate() {
|
||
this.delegate.viewInvalidated();
|
||
}
|
||
prepareToRenderSnapshot(renderer) {
|
||
this.markAsPreview(renderer.isPreview);
|
||
renderer.prepareToRender();
|
||
}
|
||
markAsPreview(isPreview) {
|
||
if (isPreview) {
|
||
this.element.setAttribute("data-turbo-preview", "");
|
||
}
|
||
else {
|
||
this.element.removeAttribute("data-turbo-preview");
|
||
}
|
||
}
|
||
async renderSnapshot(renderer) {
|
||
await renderer.render();
|
||
}
|
||
finishRenderingSnapshot(renderer) {
|
||
renderer.finishRendering();
|
||
}
|
||
}
|
||
|
||
class FrameView extends View {
|
||
invalidate() {
|
||
this.element.innerHTML = "";
|
||
}
|
||
get snapshot() {
|
||
return new Snapshot(this.element);
|
||
}
|
||
}
|
||
|
||
class LinkInterceptor {
|
||
constructor(delegate, element) {
|
||
this.clickBubbled = (event) => {
|
||
if (this.respondsToEventTarget(event.target)) {
|
||
this.clickEvent = event;
|
||
}
|
||
else {
|
||
delete this.clickEvent;
|
||
}
|
||
};
|
||
this.linkClicked = ((event) => {
|
||
if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
|
||
if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url)) {
|
||
this.clickEvent.preventDefault();
|
||
event.preventDefault();
|
||
this.delegate.linkClickIntercepted(event.target, event.detail.url);
|
||
}
|
||
}
|
||
delete this.clickEvent;
|
||
});
|
||
this.willVisit = () => {
|
||
delete this.clickEvent;
|
||
};
|
||
this.delegate = delegate;
|
||
this.element = element;
|
||
}
|
||
start() {
|
||
this.element.addEventListener("click", this.clickBubbled);
|
||
document.addEventListener("turbo:click", this.linkClicked);
|
||
document.addEventListener("turbo:before-visit", this.willVisit);
|
||
}
|
||
stop() {
|
||
this.element.removeEventListener("click", this.clickBubbled);
|
||
document.removeEventListener("turbo:click", this.linkClicked);
|
||
document.removeEventListener("turbo:before-visit", this.willVisit);
|
||
}
|
||
respondsToEventTarget(target) {
|
||
const element = target instanceof Element
|
||
? target
|
||
: target instanceof Node
|
||
? target.parentElement
|
||
: null;
|
||
return element && element.closest("turbo-frame, html") == this.element;
|
||
}
|
||
}
|
||
|
||
class Renderer {
|
||
constructor(currentSnapshot, newSnapshot, isPreview) {
|
||
this.currentSnapshot = currentSnapshot;
|
||
this.newSnapshot = newSnapshot;
|
||
this.isPreview = isPreview;
|
||
this.promise = new Promise((resolve, reject) => this.resolvingFunctions = { resolve, reject });
|
||
}
|
||
get shouldRender() {
|
||
return true;
|
||
}
|
||
prepareToRender() {
|
||
return;
|
||
}
|
||
finishRendering() {
|
||
if (this.resolvingFunctions) {
|
||
this.resolvingFunctions.resolve();
|
||
delete this.resolvingFunctions;
|
||
}
|
||
}
|
||
createScriptElement(element) {
|
||
if (element.getAttribute("data-turbo-eval") == "false") {
|
||
return element;
|
||
}
|
||
else {
|
||
const createdScriptElement = document.createElement("script");
|
||
createdScriptElement.textContent = element.textContent;
|
||
createdScriptElement.async = false;
|
||
copyElementAttributes(createdScriptElement, element);
|
||
return createdScriptElement;
|
||
}
|
||
}
|
||
preservingPermanentElements(callback) {
|
||
const placeholders = relocatePermanentElements(this.currentSnapshot, this.newSnapshot);
|
||
callback();
|
||
replacePlaceholderElementsWithClonedPermanentElements(placeholders);
|
||
}
|
||
focusFirstAutofocusableElement() {
|
||
const element = this.newSnapshot.firstAutofocusableElement;
|
||
if (elementIsFocusable(element)) {
|
||
element.focus();
|
||
}
|
||
}
|
||
get currentElement() {
|
||
return this.currentSnapshot.element;
|
||
}
|
||
get newElement() {
|
||
return this.newSnapshot.element;
|
||
}
|
||
}
|
||
function replaceElementWithElement(fromElement, toElement) {
|
||
const parentElement = fromElement.parentElement;
|
||
if (parentElement) {
|
||
return parentElement.replaceChild(toElement, fromElement);
|
||
}
|
||
}
|
||
function copyElementAttributes(destinationElement, sourceElement) {
|
||
for (const { name, value } of [...sourceElement.attributes]) {
|
||
destinationElement.setAttribute(name, value);
|
||
}
|
||
}
|
||
function createPlaceholderForPermanentElement(permanentElement) {
|
||
const element = document.createElement("meta");
|
||
element.setAttribute("name", "turbo-permanent-placeholder");
|
||
element.setAttribute("content", permanentElement.id);
|
||
return { element, permanentElement };
|
||
}
|
||
function replacePlaceholderElementsWithClonedPermanentElements(placeholders) {
|
||
for (const { element, permanentElement } of placeholders) {
|
||
const clonedElement = permanentElement.cloneNode(true);
|
||
replaceElementWithElement(element, clonedElement);
|
||
}
|
||
}
|
||
function relocatePermanentElements(currentSnapshot, newSnapshot) {
|
||
return currentSnapshot.getPermanentElementsPresentInSnapshot(newSnapshot).reduce((placeholders, permanentElement) => {
|
||
const newElement = newSnapshot.getPermanentElementById(permanentElement.id);
|
||
if (newElement) {
|
||
const placeholder = createPlaceholderForPermanentElement(permanentElement);
|
||
replaceElementWithElement(permanentElement, placeholder.element);
|
||
replaceElementWithElement(newElement, permanentElement);
|
||
return [...placeholders, placeholder];
|
||
}
|
||
else {
|
||
return placeholders;
|
||
}
|
||
}, []);
|
||
}
|
||
function elementIsFocusable(element) {
|
||
return element && typeof element.focus == "function";
|
||
}
|
||
|
||
class FrameRenderer extends Renderer {
|
||
get shouldRender() {
|
||
return true;
|
||
}
|
||
async render() {
|
||
await nextAnimationFrame();
|
||
this.preservingPermanentElements(() => {
|
||
this.loadFrameElement();
|
||
});
|
||
this.scrollFrameIntoView();
|
||
await nextAnimationFrame();
|
||
this.focusFirstAutofocusableElement();
|
||
}
|
||
loadFrameElement() {
|
||
var _a;
|
||
const destinationRange = document.createRange();
|
||
destinationRange.selectNodeContents(this.currentElement);
|
||
destinationRange.deleteContents();
|
||
const frameElement = this.newElement;
|
||
const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
|
||
if (sourceRange) {
|
||
sourceRange.selectNodeContents(frameElement);
|
||
this.currentElement.appendChild(sourceRange.extractContents());
|
||
}
|
||
}
|
||
scrollFrameIntoView() {
|
||
if (this.currentElement.autoscroll || this.newElement.autoscroll) {
|
||
const element = this.currentElement.firstElementChild;
|
||
const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end");
|
||
if (element) {
|
||
element.scrollIntoView({ block });
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
function readScrollLogicalPosition(value, defaultValue) {
|
||
if (value == "end" || value == "start" || value == "center" || value == "nearest") {
|
||
return value;
|
||
}
|
||
else {
|
||
return defaultValue;
|
||
}
|
||
}
|
||
|
||
class FrameController {
|
||
constructor(element) {
|
||
this.resolveVisitPromise = () => { };
|
||
this.element = element;
|
||
this.view = new FrameView(this, this.element);
|
||
this.appearanceObserver = new AppearanceObserver(this, this.element);
|
||
this.linkInterceptor = new LinkInterceptor(this, this.element);
|
||
this.formInterceptor = new FormInterceptor(this, this.element);
|
||
}
|
||
connect() {
|
||
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
||
this.appearanceObserver.start();
|
||
}
|
||
this.linkInterceptor.start();
|
||
this.formInterceptor.start();
|
||
}
|
||
disconnect() {
|
||
this.appearanceObserver.stop();
|
||
this.linkInterceptor.stop();
|
||
this.formInterceptor.stop();
|
||
}
|
||
sourceURLChanged() {
|
||
if (this.loadingStyle == FrameLoadingStyle.eager) {
|
||
this.loadSourceURL();
|
||
}
|
||
}
|
||
loadingStyleChanged() {
|
||
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
||
this.appearanceObserver.start();
|
||
}
|
||
else {
|
||
this.appearanceObserver.stop();
|
||
this.loadSourceURL();
|
||
}
|
||
}
|
||
async loadSourceURL() {
|
||
if (this.isActive && this.sourceURL && this.sourceURL != this.loadingURL) {
|
||
try {
|
||
this.loadingURL = this.sourceURL;
|
||
this.element.loaded = this.visit(this.sourceURL);
|
||
this.appearanceObserver.stop();
|
||
await this.element.loaded;
|
||
}
|
||
finally {
|
||
delete this.loadingURL;
|
||
}
|
||
}
|
||
}
|
||
async loadResponse(response) {
|
||
try {
|
||
const html = await response.responseHTML;
|
||
if (html) {
|
||
const { body } = parseHTMLDocument(html);
|
||
const snapshot = new Snapshot(await this.extractForeignFrameElement(body));
|
||
const renderer = new FrameRenderer(this.view.snapshot, snapshot, false);
|
||
await this.view.render(renderer);
|
||
}
|
||
}
|
||
catch (error) {
|
||
console.error(error);
|
||
this.view.invalidate();
|
||
}
|
||
}
|
||
elementAppearedInViewport(element) {
|
||
this.loadSourceURL();
|
||
}
|
||
shouldInterceptLinkClick(element, url) {
|
||
return this.shouldInterceptNavigation(element);
|
||
}
|
||
linkClickIntercepted(element, url) {
|
||
this.navigateFrame(element, url);
|
||
}
|
||
shouldInterceptFormSubmission(element) {
|
||
return this.shouldInterceptNavigation(element);
|
||
}
|
||
formSubmissionIntercepted(element, submitter) {
|
||
if (this.formSubmission) {
|
||
this.formSubmission.stop();
|
||
}
|
||
this.formSubmission = new FormSubmission(this, element, submitter);
|
||
if (this.formSubmission.fetchRequest.isIdempotent) {
|
||
this.navigateFrame(element, this.formSubmission.fetchRequest.url.href);
|
||
}
|
||
else {
|
||
this.formSubmission.start();
|
||
}
|
||
}
|
||
prepareHeadersForRequest(headers, request) {
|
||
headers["Turbo-Frame"] = this.id;
|
||
}
|
||
requestStarted(request) {
|
||
this.element.setAttribute("busy", "");
|
||
}
|
||
requestPreventedHandlingResponse(request, response) {
|
||
this.resolveVisitPromise();
|
||
}
|
||
async requestSucceededWithResponse(request, response) {
|
||
await this.loadResponse(response);
|
||
this.resolveVisitPromise();
|
||
}
|
||
requestFailedWithResponse(request, response) {
|
||
console.error(response);
|
||
this.resolveVisitPromise();
|
||
}
|
||
requestErrored(request, error) {
|
||
console.error(error);
|
||
this.resolveVisitPromise();
|
||
}
|
||
requestFinished(request) {
|
||
this.element.removeAttribute("busy");
|
||
}
|
||
formSubmissionStarted(formSubmission) {
|
||
}
|
||
formSubmissionSucceededWithResponse(formSubmission, response) {
|
||
const frame = this.findFrameElement(formSubmission.formElement);
|
||
frame.delegate.loadResponse(response);
|
||
}
|
||
formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
|
||
this.element.delegate.loadResponse(fetchResponse);
|
||
}
|
||
formSubmissionErrored(formSubmission, error) {
|
||
}
|
||
formSubmissionFinished(formSubmission) {
|
||
}
|
||
viewWillRenderSnapshot(snapshot, isPreview) {
|
||
}
|
||
viewRenderedSnapshot(snapshot, isPreview) {
|
||
}
|
||
viewInvalidated() {
|
||
}
|
||
async visit(url) {
|
||
const request = new FetchRequest(this, FetchMethod.get, expandURL(url));
|
||
return new Promise(resolve => {
|
||
this.resolveVisitPromise = () => {
|
||
this.resolveVisitPromise = () => { };
|
||
resolve();
|
||
};
|
||
request.perform();
|
||
});
|
||
}
|
||
navigateFrame(element, url) {
|
||
const frame = this.findFrameElement(element);
|
||
frame.src = url;
|
||
}
|
||
findFrameElement(element) {
|
||
var _a;
|
||
const id = element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
|
||
return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
|
||
}
|
||
async extractForeignFrameElement(container) {
|
||
let element;
|
||
const id = CSS.escape(this.id);
|
||
if (element = activateElement(container.querySelector(`turbo-frame#${id}`))) {
|
||
return element;
|
||
}
|
||
if (element = activateElement(container.querySelector(`turbo-frame[src][recurse~=${id}]`))) {
|
||
await element.loaded;
|
||
return await this.extractForeignFrameElement(element);
|
||
}
|
||
console.error(`Response has no matching <turbo-frame id="${id}"> element`);
|
||
return new FrameElement();
|
||
}
|
||
shouldInterceptNavigation(element) {
|
||
const id = element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
|
||
if (!this.enabled || id == "_top") {
|
||
return false;
|
||
}
|
||
if (id) {
|
||
const frameElement = getFrameElementById(id);
|
||
if (frameElement) {
|
||
return !frameElement.disabled;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
get id() {
|
||
return this.element.id;
|
||
}
|
||
get enabled() {
|
||
return !this.element.disabled;
|
||
}
|
||
get sourceURL() {
|
||
return this.element.src;
|
||
}
|
||
get loadingStyle() {
|
||
return this.element.loading;
|
||
}
|
||
get isLoading() {
|
||
return this.formSubmission !== undefined || this.loadingURL !== undefined;
|
||
}
|
||
get isActive() {
|
||
return this.element.isActive;
|
||
}
|
||
}
|
||
function getFrameElementById(id) {
|
||
if (id != null) {
|
||
const element = document.getElementById(id);
|
||
if (element instanceof FrameElement) {
|
||
return element;
|
||
}
|
||
}
|
||
}
|
||
function activateElement(element) {
|
||
if (element && element.ownerDocument !== document) {
|
||
element = document.importNode(element, true);
|
||
}
|
||
if (element instanceof FrameElement) {
|
||
return element;
|
||
}
|
||
}
|
||
|
||
const StreamActions = {
|
||
append() {
|
||
var _a;
|
||
(_a = this.targetElement) === null || _a === void 0 ? void 0 : _a.append(this.templateContent);
|
||
},
|
||
prepend() {
|
||
var _a;
|
||
(_a = this.targetElement) === null || _a === void 0 ? void 0 : _a.prepend(this.templateContent);
|
||
},
|
||
remove() {
|
||
var _a;
|
||
(_a = this.targetElement) === null || _a === void 0 ? void 0 : _a.remove();
|
||
},
|
||
replace() {
|
||
var _a;
|
||
(_a = this.targetElement) === null || _a === void 0 ? void 0 : _a.replaceWith(this.templateContent);
|
||
},
|
||
update() {
|
||
if (this.targetElement) {
|
||
this.targetElement.innerHTML = "";
|
||
this.targetElement.append(this.templateContent);
|
||
}
|
||
}
|
||
};
|
||
|
||
class StreamElement extends HTMLElement {
|
||
async connectedCallback() {
|
||
try {
|
||
await this.render();
|
||
}
|
||
catch (error) {
|
||
console.error(error);
|
||
}
|
||
finally {
|
||
this.disconnect();
|
||
}
|
||
}
|
||
async render() {
|
||
var _a;
|
||
return (_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {
|
||
if (this.dispatchEvent(this.beforeRenderEvent)) {
|
||
await nextAnimationFrame();
|
||
this.performAction();
|
||
}
|
||
})());
|
||
}
|
||
disconnect() {
|
||
try {
|
||
this.remove();
|
||
}
|
||
catch (_a) { }
|
||
}
|
||
get performAction() {
|
||
if (this.action) {
|
||
const actionFunction = StreamActions[this.action];
|
||
if (actionFunction) {
|
||
return actionFunction;
|
||
}
|
||
this.raise("unknown action");
|
||
}
|
||
this.raise("action attribute is missing");
|
||
}
|
||
get targetElement() {
|
||
var _a;
|
||
if (this.target) {
|
||
return (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.getElementById(this.target);
|
||
}
|
||
this.raise("target attribute is missing");
|
||
}
|
||
get templateContent() {
|
||
return this.templateElement.content;
|
||
}
|
||
get templateElement() {
|
||
if (this.firstElementChild instanceof HTMLTemplateElement) {
|
||
return this.firstElementChild;
|
||
}
|
||
this.raise("first child element must be a <template> element");
|
||
}
|
||
get action() {
|
||
return this.getAttribute("action");
|
||
}
|
||
get target() {
|
||
return this.getAttribute("target");
|
||
}
|
||
raise(message) {
|
||
throw new Error(`${this.description}: ${message}`);
|
||
}
|
||
get description() {
|
||
var _a, _b;
|
||
return (_b = ((_a = this.outerHTML.match(/<[^>]+>/)) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : "<turbo-stream>";
|
||
}
|
||
get beforeRenderEvent() {
|
||
return new CustomEvent("turbo:before-stream-render", { bubbles: true, cancelable: true });
|
||
}
|
||
}
|
||
|
||
FrameElement.delegateConstructor = FrameController;
|
||
customElements.define("turbo-frame", FrameElement);
|
||
customElements.define("turbo-stream", StreamElement);
|
||
|
||
(() => {
|
||
let element = document.currentScript;
|
||
if (!element)
|
||
return;
|
||
if (element.hasAttribute("data-turbo-suppress-warning"))
|
||
return;
|
||
while (element = element.parentElement) {
|
||
if (element == document.body) {
|
||
return console.warn(unindent `
|
||
You are loading Turbo from a <script> element inside the <body> element. This is probably not what you meant to do!
|
||
|
||
Load your application’s JavaScript bundle inside the <head> element instead. <script> elements in <body> are evaluated with each page change.
|
||
|
||
For more information, see: https://turbo.hotwire.dev/handbook/building#working-with-script-elements
|
||
|
||
——
|
||
Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
|
||
`, element.outerHTML);
|
||
}
|
||
}
|
||
})();
|
||
|
||
class ProgressBar {
|
||
constructor() {
|
||
this.hiding = false;
|
||
this.value = 0;
|
||
this.visible = false;
|
||
this.trickle = () => {
|
||
this.setValue(this.value + Math.random() / 100);
|
||
};
|
||
this.stylesheetElement = this.createStylesheetElement();
|
||
this.progressElement = this.createProgressElement();
|
||
this.installStylesheetElement();
|
||
this.setValue(0);
|
||
}
|
||
static get defaultCSS() {
|
||
return unindent `
|
||
.turbo-progress-bar {
|
||
position: fixed;
|
||
display: block;
|
||
top: 0;
|
||
left: 0;
|
||
height: 3px;
|
||
background: #0076ff;
|
||
z-index: 9999;
|
||
transition:
|
||
width ${ProgressBar.animationDuration}ms ease-out,
|
||
opacity ${ProgressBar.animationDuration / 2}ms ${ProgressBar.animationDuration / 2}ms ease-in;
|
||
transform: translate3d(0, 0, 0);
|
||
}
|
||
`;
|
||
}
|
||
show() {
|
||
if (!this.visible) {
|
||
this.visible = true;
|
||
this.installProgressElement();
|
||
this.startTrickling();
|
||
}
|
||
}
|
||
hide() {
|
||
if (this.visible && !this.hiding) {
|
||
this.hiding = true;
|
||
this.fadeProgressElement(() => {
|
||
this.uninstallProgressElement();
|
||
this.stopTrickling();
|
||
this.visible = false;
|
||
this.hiding = false;
|
||
});
|
||
}
|
||
}
|
||
setValue(value) {
|
||
this.value = value;
|
||
this.refresh();
|
||
}
|
||
installStylesheetElement() {
|
||
document.head.insertBefore(this.stylesheetElement, document.head.firstChild);
|
||
}
|
||
installProgressElement() {
|
||
this.progressElement.style.width = "0";
|
||
this.progressElement.style.opacity = "1";
|
||
document.documentElement.insertBefore(this.progressElement, document.body);
|
||
this.refresh();
|
||
}
|
||
fadeProgressElement(callback) {
|
||
this.progressElement.style.opacity = "0";
|
||
setTimeout(callback, ProgressBar.animationDuration * 1.5);
|
||
}
|
||
uninstallProgressElement() {
|
||
if (this.progressElement.parentNode) {
|
||
document.documentElement.removeChild(this.progressElement);
|
||
}
|
||
}
|
||
startTrickling() {
|
||
if (!this.trickleInterval) {
|
||
this.trickleInterval = window.setInterval(this.trickle, ProgressBar.animationDuration);
|
||
}
|
||
}
|
||
stopTrickling() {
|
||
window.clearInterval(this.trickleInterval);
|
||
delete this.trickleInterval;
|
||
}
|
||
refresh() {
|
||
requestAnimationFrame(() => {
|
||
this.progressElement.style.width = `${10 + (this.value * 90)}%`;
|
||
});
|
||
}
|
||
createStylesheetElement() {
|
||
const element = document.createElement("style");
|
||
element.type = "text/css";
|
||
element.textContent = ProgressBar.defaultCSS;
|
||
return element;
|
||
}
|
||
createProgressElement() {
|
||
const element = document.createElement("div");
|
||
element.className = "turbo-progress-bar";
|
||
return element;
|
||
}
|
||
}
|
||
ProgressBar.animationDuration = 300;
|
||
|
||
class HeadSnapshot extends Snapshot {
|
||
constructor() {
|
||
super(...arguments);
|
||
this.detailsByOuterHTML = this.children.reduce((result, element) => {
|
||
const { outerHTML } = element;
|
||
const details = outerHTML in result
|
||
? result[outerHTML]
|
||
: {
|
||
type: elementType(element),
|
||
tracked: elementIsTracked(element),
|
||
elements: []
|
||
};
|
||
return Object.assign(Object.assign({}, result), { [outerHTML]: Object.assign(Object.assign({}, details), { elements: [...details.elements, element] }) });
|
||
}, {});
|
||
}
|
||
get trackedElementSignature() {
|
||
return Object.keys(this.detailsByOuterHTML)
|
||
.filter(outerHTML => this.detailsByOuterHTML[outerHTML].tracked)
|
||
.join("");
|
||
}
|
||
getScriptElementsNotInSnapshot(snapshot) {
|
||
return this.getElementsMatchingTypeNotInSnapshot("script", snapshot);
|
||
}
|
||
getStylesheetElementsNotInSnapshot(snapshot) {
|
||
return this.getElementsMatchingTypeNotInSnapshot("stylesheet", snapshot);
|
||
}
|
||
getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) {
|
||
return Object.keys(this.detailsByOuterHTML)
|
||
.filter(outerHTML => !(outerHTML in snapshot.detailsByOuterHTML))
|
||
.map(outerHTML => this.detailsByOuterHTML[outerHTML])
|
||
.filter(({ type }) => type == matchedType)
|
||
.map(({ elements: [element] }) => element);
|
||
}
|
||
get provisionalElements() {
|
||
return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
|
||
const { type, tracked, elements } = this.detailsByOuterHTML[outerHTML];
|
||
if (type == null && !tracked) {
|
||
return [...result, ...elements];
|
||
}
|
||
else if (elements.length > 1) {
|
||
return [...result, ...elements.slice(1)];
|
||
}
|
||
else {
|
||
return result;
|
||
}
|
||
}, []);
|
||
}
|
||
getMetaValue(name) {
|
||
const element = this.findMetaElementByName(name);
|
||
return element
|
||
? element.getAttribute("content")
|
||
: null;
|
||
}
|
||
findMetaElementByName(name) {
|
||
return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
|
||
const { elements: [element] } = this.detailsByOuterHTML[outerHTML];
|
||
return elementIsMetaElementWithName(element, name) ? element : result;
|
||
}, undefined);
|
||
}
|
||
}
|
||
function elementType(element) {
|
||
if (elementIsScript(element)) {
|
||
return "script";
|
||
}
|
||
else if (elementIsStylesheet(element)) {
|
||
return "stylesheet";
|
||
}
|
||
}
|
||
function elementIsTracked(element) {
|
||
return element.getAttribute("data-turbo-track") == "reload";
|
||
}
|
||
function elementIsScript(element) {
|
||
const tagName = element.tagName.toLowerCase();
|
||
return tagName == "script";
|
||
}
|
||
function elementIsStylesheet(element) {
|
||
const tagName = element.tagName.toLowerCase();
|
||
return tagName == "style" || (tagName == "link" && element.getAttribute("rel") == "stylesheet");
|
||
}
|
||
function elementIsMetaElementWithName(element, name) {
|
||
const tagName = element.tagName.toLowerCase();
|
||
return tagName == "meta" && element.getAttribute("name") == name;
|
||
}
|
||
|
||
class PageSnapshot extends Snapshot {
|
||
constructor(element, headSnapshot) {
|
||
super(element);
|
||
this.headSnapshot = headSnapshot;
|
||
}
|
||
static fromHTMLString(html = "") {
|
||
return this.fromDocument(parseHTMLDocument(html));
|
||
}
|
||
static fromElement(element) {
|
||
return this.fromDocument(element.ownerDocument);
|
||
}
|
||
static fromDocument({ head, body }) {
|
||
return new this(body, new HeadSnapshot(head));
|
||
}
|
||
clone() {
|
||
return new PageSnapshot(this.element.cloneNode(true), this.headSnapshot);
|
||
}
|
||
get headElement() {
|
||
return this.headSnapshot.element;
|
||
}
|
||
get rootLocation() {
|
||
var _a;
|
||
const root = (_a = this.getSetting("root")) !== null && _a !== void 0 ? _a : "/";
|
||
return expandURL(root);
|
||
}
|
||
get cacheControlValue() {
|
||
return this.getSetting("cache-control");
|
||
}
|
||
get isPreviewable() {
|
||
return this.cacheControlValue != "no-preview";
|
||
}
|
||
get isCacheable() {
|
||
return this.cacheControlValue != "no-cache";
|
||
}
|
||
get isVisitable() {
|
||
return this.getSetting("visit-control") != "reload";
|
||
}
|
||
getSetting(name) {
|
||
return this.headSnapshot.getMetaValue(`turbo-${name}`);
|
||
}
|
||
}
|
||
|
||
var TimingMetric;
|
||
(function (TimingMetric) {
|
||
TimingMetric["visitStart"] = "visitStart";
|
||
TimingMetric["requestStart"] = "requestStart";
|
||
TimingMetric["requestEnd"] = "requestEnd";
|
||
TimingMetric["visitEnd"] = "visitEnd";
|
||
})(TimingMetric || (TimingMetric = {}));
|
||
var VisitState;
|
||
(function (VisitState) {
|
||
VisitState["initialized"] = "initialized";
|
||
VisitState["started"] = "started";
|
||
VisitState["canceled"] = "canceled";
|
||
VisitState["failed"] = "failed";
|
||
VisitState["completed"] = "completed";
|
||
})(VisitState || (VisitState = {}));
|
||
const defaultOptions = {
|
||
action: "advance",
|
||
historyChanged: false
|
||
};
|
||
var SystemStatusCode;
|
||
(function (SystemStatusCode) {
|
||
SystemStatusCode[SystemStatusCode["networkFailure"] = 0] = "networkFailure";
|
||
SystemStatusCode[SystemStatusCode["timeoutFailure"] = -1] = "timeoutFailure";
|
||
SystemStatusCode[SystemStatusCode["contentTypeMismatch"] = -2] = "contentTypeMismatch";
|
||
})(SystemStatusCode || (SystemStatusCode = {}));
|
||
class Visit {
|
||
constructor(delegate, location, restorationIdentifier, options = {}) {
|
||
this.identifier = uuid();
|
||
this.timingMetrics = {};
|
||
this.followedRedirect = false;
|
||
this.historyChanged = false;
|
||
this.scrolled = false;
|
||
this.snapshotCached = false;
|
||
this.state = VisitState.initialized;
|
||
this.delegate = delegate;
|
||
this.location = location;
|
||
this.restorationIdentifier = restorationIdentifier || uuid();
|
||
const { action, historyChanged, referrer, snapshotHTML, response } = Object.assign(Object.assign({}, defaultOptions), options);
|
||
this.action = action;
|
||
this.historyChanged = historyChanged;
|
||
this.referrer = referrer;
|
||
this.snapshotHTML = snapshotHTML;
|
||
this.response = response;
|
||
}
|
||
get adapter() {
|
||
return this.delegate.adapter;
|
||
}
|
||
get view() {
|
||
return this.delegate.view;
|
||
}
|
||
get history() {
|
||
return this.delegate.history;
|
||
}
|
||
get restorationData() {
|
||
return this.history.getRestorationDataForIdentifier(this.restorationIdentifier);
|
||
}
|
||
start() {
|
||
if (this.state == VisitState.initialized) {
|
||
this.recordTimingMetric(TimingMetric.visitStart);
|
||
this.state = VisitState.started;
|
||
this.adapter.visitStarted(this);
|
||
this.delegate.visitStarted(this);
|
||
}
|
||
}
|
||
cancel() {
|
||
if (this.state == VisitState.started) {
|
||
if (this.request) {
|
||
this.request.cancel();
|
||
}
|
||
this.cancelRender();
|
||
this.state = VisitState.canceled;
|
||
}
|
||
}
|
||
complete() {
|
||
if (this.state == VisitState.started) {
|
||
this.recordTimingMetric(TimingMetric.visitEnd);
|
||
this.state = VisitState.completed;
|
||
this.adapter.visitCompleted(this);
|
||
this.delegate.visitCompleted(this);
|
||
}
|
||
}
|
||
fail() {
|
||
if (this.state == VisitState.started) {
|
||
this.state = VisitState.failed;
|
||
this.adapter.visitFailed(this);
|
||
}
|
||
}
|
||
changeHistory() {
|
||
var _a;
|
||
if (!this.historyChanged) {
|
||
const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? "replace" : this.action;
|
||
const method = this.getHistoryMethodForAction(actionForHistory);
|
||
this.history.update(method, this.location, this.restorationIdentifier);
|
||
this.historyChanged = true;
|
||
}
|
||
}
|
||
issueRequest() {
|
||
if (this.hasPreloadedResponse()) {
|
||
this.simulateRequest();
|
||
}
|
||
else if (this.shouldIssueRequest() && !this.request) {
|
||
this.request = new FetchRequest(this, FetchMethod.get, this.location);
|
||
this.request.perform();
|
||
}
|
||
}
|
||
simulateRequest() {
|
||
if (this.response) {
|
||
this.startRequest();
|
||
this.recordResponse();
|
||
this.finishRequest();
|
||
}
|
||
}
|
||
startRequest() {
|
||
this.recordTimingMetric(TimingMetric.requestStart);
|
||
this.adapter.visitRequestStarted(this);
|
||
}
|
||
recordResponse(response = this.response) {
|
||
this.response = response;
|
||
if (response) {
|
||
const { statusCode } = response;
|
||
if (isSuccessful(statusCode)) {
|
||
this.adapter.visitRequestCompleted(this);
|
||
}
|
||
else {
|
||
this.adapter.visitRequestFailedWithStatusCode(this, statusCode);
|
||
}
|
||
}
|
||
}
|
||
finishRequest() {
|
||
this.recordTimingMetric(TimingMetric.requestEnd);
|
||
this.adapter.visitRequestFinished(this);
|
||
}
|
||
loadResponse() {
|
||
if (this.response) {
|
||
const { statusCode, responseHTML } = this.response;
|
||
this.render(async () => {
|
||
this.cacheSnapshot();
|
||
if (isSuccessful(statusCode) && responseHTML != null) {
|
||
await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML));
|
||
this.adapter.visitRendered(this);
|
||
this.complete();
|
||
}
|
||
else {
|
||
await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML));
|
||
this.adapter.visitRendered(this);
|
||
this.fail();
|
||
}
|
||
});
|
||
}
|
||
}
|
||
getCachedSnapshot() {
|
||
const snapshot = this.view.getCachedSnapshotForLocation(this.location) || this.getPreloadedSnapshot();
|
||
if (snapshot && (!getAnchor(this.location) || snapshot.hasAnchor(getAnchor(this.location)))) {
|
||
if (this.action == "restore" || snapshot.isPreviewable) {
|
||
return snapshot;
|
||
}
|
||
}
|
||
}
|
||
getPreloadedSnapshot() {
|
||
if (this.snapshotHTML) {
|
||
return PageSnapshot.fromHTMLString(this.snapshotHTML);
|
||
}
|
||
}
|
||
hasCachedSnapshot() {
|
||
return this.getCachedSnapshot() != null;
|
||
}
|
||
loadCachedSnapshot() {
|
||
const snapshot = this.getCachedSnapshot();
|
||
if (snapshot) {
|
||
const isPreview = this.shouldIssueRequest();
|
||
this.render(async () => {
|
||
this.cacheSnapshot();
|
||
await this.view.renderPage(snapshot);
|
||
this.adapter.visitRendered(this);
|
||
if (!isPreview) {
|
||
this.complete();
|
||
}
|
||
});
|
||
}
|
||
}
|
||
followRedirect() {
|
||
if (this.redirectedToLocation && !this.followedRedirect) {
|
||
this.location = this.redirectedToLocation;
|
||
this.history.replace(this.redirectedToLocation, this.restorationIdentifier);
|
||
this.followedRedirect = true;
|
||
}
|
||
}
|
||
requestStarted() {
|
||
this.startRequest();
|
||
}
|
||
requestPreventedHandlingResponse(request, response) {
|
||
}
|
||
async requestSucceededWithResponse(request, response) {
|
||
const responseHTML = await response.responseHTML;
|
||
if (responseHTML == undefined) {
|
||
this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch });
|
||
}
|
||
else {
|
||
this.redirectedToLocation = response.redirected ? response.location : undefined;
|
||
this.recordResponse({ statusCode: response.statusCode, responseHTML });
|
||
}
|
||
}
|
||
async requestFailedWithResponse(request, response) {
|
||
const responseHTML = await response.responseHTML;
|
||
if (responseHTML == undefined) {
|
||
this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch });
|
||
}
|
||
else {
|
||
this.recordResponse({ statusCode: response.statusCode, responseHTML });
|
||
}
|
||
}
|
||
requestErrored(request, error) {
|
||
this.recordResponse({ statusCode: SystemStatusCode.networkFailure });
|
||
}
|
||
requestFinished() {
|
||
this.finishRequest();
|
||
}
|
||
performScroll() {
|
||
if (!this.scrolled) {
|
||
if (this.action == "restore") {
|
||
this.scrollToRestoredPosition() || this.scrollToTop();
|
||
}
|
||
else {
|
||
this.scrollToAnchor() || this.scrollToTop();
|
||
}
|
||
this.scrolled = true;
|
||
}
|
||
}
|
||
scrollToRestoredPosition() {
|
||
const { scrollPosition } = this.restorationData;
|
||
if (scrollPosition) {
|
||
this.view.scrollToPosition(scrollPosition);
|
||
return true;
|
||
}
|
||
}
|
||
scrollToAnchor() {
|
||
if (getAnchor(this.location) != null) {
|
||
this.view.scrollToAnchor(getAnchor(this.location));
|
||
return true;
|
||
}
|
||
}
|
||
scrollToTop() {
|
||
this.view.scrollToPosition({ x: 0, y: 0 });
|
||
}
|
||
recordTimingMetric(metric) {
|
||
this.timingMetrics[metric] = new Date().getTime();
|
||
}
|
||
getTimingMetrics() {
|
||
return Object.assign({}, this.timingMetrics);
|
||
}
|
||
getHistoryMethodForAction(action) {
|
||
switch (action) {
|
||
case "replace": return history.replaceState;
|
||
case "advance":
|
||
case "restore": return history.pushState;
|
||
}
|
||
}
|
||
hasPreloadedResponse() {
|
||
return typeof this.response == "object";
|
||
}
|
||
shouldIssueRequest() {
|
||
return this.action == "restore"
|
||
? !this.hasCachedSnapshot()
|
||
: true;
|
||
}
|
||
cacheSnapshot() {
|
||
if (!this.snapshotCached) {
|
||
this.view.cacheSnapshot();
|
||
this.snapshotCached = true;
|
||
}
|
||
}
|
||
async render(callback) {
|
||
this.cancelRender();
|
||
await new Promise(resolve => {
|
||
this.frame = requestAnimationFrame(() => resolve());
|
||
});
|
||
callback();
|
||
delete this.frame;
|
||
this.performScroll();
|
||
}
|
||
cancelRender() {
|
||
if (this.frame) {
|
||
cancelAnimationFrame(this.frame);
|
||
delete this.frame;
|
||
}
|
||
}
|
||
}
|
||
function isSuccessful(statusCode) {
|
||
return statusCode >= 200 && statusCode < 300;
|
||
}
|
||
|
||
class BrowserAdapter {
|
||
constructor(session) {
|
||
this.progressBar = new ProgressBar;
|
||
this.showProgressBar = () => {
|
||
this.progressBar.show();
|
||
};
|
||
this.session = session;
|
||
}
|
||
visitProposedToLocation(location, options) {
|
||
this.navigator.startVisit(location, uuid(), options);
|
||
}
|
||
visitStarted(visit) {
|
||
visit.issueRequest();
|
||
visit.changeHistory();
|
||
visit.loadCachedSnapshot();
|
||
}
|
||
visitRequestStarted(visit) {
|
||
this.progressBar.setValue(0);
|
||
if (visit.hasCachedSnapshot() || visit.action != "restore") {
|
||
this.showProgressBarAfterDelay();
|
||
}
|
||
else {
|
||
this.showProgressBar();
|
||
}
|
||
}
|
||
visitRequestCompleted(visit) {
|
||
visit.loadResponse();
|
||
}
|
||
visitRequestFailedWithStatusCode(visit, statusCode) {
|
||
switch (statusCode) {
|
||
case SystemStatusCode.networkFailure:
|
||
case SystemStatusCode.timeoutFailure:
|
||
case SystemStatusCode.contentTypeMismatch:
|
||
return this.reload();
|
||
default:
|
||
return visit.loadResponse();
|
||
}
|
||
}
|
||
visitRequestFinished(visit) {
|
||
this.progressBar.setValue(1);
|
||
this.hideProgressBar();
|
||
}
|
||
visitCompleted(visit) {
|
||
visit.followRedirect();
|
||
}
|
||
pageInvalidated() {
|
||
this.reload();
|
||
}
|
||
visitFailed(visit) {
|
||
}
|
||
visitRendered(visit) {
|
||
}
|
||
showProgressBarAfterDelay() {
|
||
this.progressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
|
||
}
|
||
hideProgressBar() {
|
||
this.progressBar.hide();
|
||
if (this.progressBarTimeout != null) {
|
||
window.clearTimeout(this.progressBarTimeout);
|
||
delete this.progressBarTimeout;
|
||
}
|
||
}
|
||
reload() {
|
||
window.location.reload();
|
||
}
|
||
get navigator() {
|
||
return this.session.navigator;
|
||
}
|
||
}
|
||
|
||
class FormSubmitObserver {
|
||
constructor(delegate) {
|
||
this.started = false;
|
||
this.submitCaptured = () => {
|
||
removeEventListener("submit", this.submitBubbled, false);
|
||
addEventListener("submit", this.submitBubbled, false);
|
||
};
|
||
this.submitBubbled = ((event) => {
|
||
if (!event.defaultPrevented) {
|
||
const form = event.target instanceof HTMLFormElement ? event.target : undefined;
|
||
const submitter = event.submitter || undefined;
|
||
if (form) {
|
||
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.method;
|
||
if (method != "dialog" && this.delegate.willSubmitForm(form, submitter)) {
|
||
event.preventDefault();
|
||
this.delegate.formSubmitted(form, submitter);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
this.delegate = delegate;
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
addEventListener("submit", this.submitCaptured, true);
|
||
this.started = true;
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
removeEventListener("submit", this.submitCaptured, true);
|
||
this.started = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
class FrameRedirector {
|
||
constructor(element) {
|
||
this.element = element;
|
||
this.linkInterceptor = new LinkInterceptor(this, element);
|
||
this.formInterceptor = new FormInterceptor(this, element);
|
||
}
|
||
start() {
|
||
this.linkInterceptor.start();
|
||
this.formInterceptor.start();
|
||
}
|
||
stop() {
|
||
this.linkInterceptor.stop();
|
||
this.formInterceptor.stop();
|
||
}
|
||
shouldInterceptLinkClick(element, url) {
|
||
return this.shouldRedirect(element);
|
||
}
|
||
linkClickIntercepted(element, url) {
|
||
const frame = this.findFrameElement(element);
|
||
if (frame) {
|
||
frame.src = url;
|
||
}
|
||
}
|
||
shouldInterceptFormSubmission(element, submitter) {
|
||
return this.shouldRedirect(element, submitter);
|
||
}
|
||
formSubmissionIntercepted(element, submitter) {
|
||
const frame = this.findFrameElement(element);
|
||
if (frame) {
|
||
frame.delegate.formSubmissionIntercepted(element, submitter);
|
||
}
|
||
}
|
||
shouldRedirect(element, submitter) {
|
||
const frame = this.findFrameElement(element);
|
||
return frame ? frame != element.closest("turbo-frame") : false;
|
||
}
|
||
findFrameElement(element) {
|
||
const id = element.getAttribute("data-turbo-frame");
|
||
if (id && id != "_top") {
|
||
const frame = this.element.querySelector(`#${id}:not([disabled])`);
|
||
if (frame instanceof FrameElement) {
|
||
return frame;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
class History {
|
||
constructor(delegate) {
|
||
this.restorationIdentifier = uuid();
|
||
this.restorationData = {};
|
||
this.started = false;
|
||
this.pageLoaded = false;
|
||
this.onPopState = (event) => {
|
||
if (this.shouldHandlePopState()) {
|
||
const { turbo } = event.state || {};
|
||
if (turbo) {
|
||
this.location = new URL(window.location.href);
|
||
const { restorationIdentifier } = turbo;
|
||
this.restorationIdentifier = restorationIdentifier;
|
||
this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);
|
||
}
|
||
}
|
||
};
|
||
this.onPageLoad = async (event) => {
|
||
await nextMicrotask();
|
||
this.pageLoaded = true;
|
||
};
|
||
this.delegate = delegate;
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
addEventListener("popstate", this.onPopState, false);
|
||
addEventListener("load", this.onPageLoad, false);
|
||
this.started = true;
|
||
this.replace(new URL(window.location.href));
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
removeEventListener("popstate", this.onPopState, false);
|
||
removeEventListener("load", this.onPageLoad, false);
|
||
this.started = false;
|
||
}
|
||
}
|
||
push(location, restorationIdentifier) {
|
||
this.update(history.pushState, location, restorationIdentifier);
|
||
}
|
||
replace(location, restorationIdentifier) {
|
||
this.update(history.replaceState, location, restorationIdentifier);
|
||
}
|
||
update(method, location, restorationIdentifier = uuid()) {
|
||
const state = { turbo: { restorationIdentifier } };
|
||
method.call(history, state, "", location.href);
|
||
this.location = location;
|
||
this.restorationIdentifier = restorationIdentifier;
|
||
}
|
||
getRestorationDataForIdentifier(restorationIdentifier) {
|
||
return this.restorationData[restorationIdentifier] || {};
|
||
}
|
||
updateRestorationData(additionalData) {
|
||
const { restorationIdentifier } = this;
|
||
const restorationData = this.restorationData[restorationIdentifier];
|
||
this.restorationData[restorationIdentifier] = Object.assign(Object.assign({}, restorationData), additionalData);
|
||
}
|
||
assumeControlOfScrollRestoration() {
|
||
var _a;
|
||
if (!this.previousScrollRestoration) {
|
||
this.previousScrollRestoration = (_a = history.scrollRestoration) !== null && _a !== void 0 ? _a : "auto";
|
||
history.scrollRestoration = "manual";
|
||
}
|
||
}
|
||
relinquishControlOfScrollRestoration() {
|
||
if (this.previousScrollRestoration) {
|
||
history.scrollRestoration = this.previousScrollRestoration;
|
||
delete this.previousScrollRestoration;
|
||
}
|
||
}
|
||
shouldHandlePopState() {
|
||
return this.pageIsLoaded();
|
||
}
|
||
pageIsLoaded() {
|
||
return this.pageLoaded || document.readyState == "complete";
|
||
}
|
||
}
|
||
|
||
class LinkClickObserver {
|
||
constructor(delegate) {
|
||
this.started = false;
|
||
this.clickCaptured = () => {
|
||
removeEventListener("click", this.clickBubbled, false);
|
||
addEventListener("click", this.clickBubbled, false);
|
||
};
|
||
this.clickBubbled = (event) => {
|
||
if (this.clickEventIsSignificant(event)) {
|
||
const link = this.findLinkFromClickTarget(event.target);
|
||
if (link) {
|
||
const location = this.getLocationForLink(link);
|
||
if (this.delegate.willFollowLinkToLocation(link, location)) {
|
||
event.preventDefault();
|
||
this.delegate.followedLinkToLocation(link, location);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
this.delegate = delegate;
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
addEventListener("click", this.clickCaptured, true);
|
||
this.started = true;
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
removeEventListener("click", this.clickCaptured, true);
|
||
this.started = false;
|
||
}
|
||
}
|
||
clickEventIsSignificant(event) {
|
||
return !((event.target && event.target.isContentEditable)
|
||
|| event.defaultPrevented
|
||
|| event.which > 1
|
||
|| event.altKey
|
||
|| event.ctrlKey
|
||
|| event.metaKey
|
||
|| event.shiftKey);
|
||
}
|
||
findLinkFromClickTarget(target) {
|
||
if (target instanceof Element) {
|
||
return target.closest("a[href]:not([target^=_]):not([download])");
|
||
}
|
||
}
|
||
getLocationForLink(link) {
|
||
return expandURL(link.getAttribute("href") || "");
|
||
}
|
||
}
|
||
|
||
class Navigator {
|
||
constructor(delegate) {
|
||
this.delegate = delegate;
|
||
}
|
||
proposeVisit(location, options = {}) {
|
||
if (this.delegate.allowsVisitingLocation(location)) {
|
||
this.delegate.visitProposedToLocation(location, options);
|
||
}
|
||
}
|
||
startVisit(locatable, restorationIdentifier, options = {}) {
|
||
this.stop();
|
||
this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({ referrer: this.location }, options));
|
||
this.currentVisit.start();
|
||
}
|
||
submitForm(form, submitter) {
|
||
this.stop();
|
||
this.formSubmission = new FormSubmission(this, form, submitter, true);
|
||
if (this.formSubmission.fetchRequest.isIdempotent) {
|
||
this.proposeVisit(this.formSubmission.fetchRequest.url);
|
||
}
|
||
else {
|
||
this.formSubmission.start();
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.formSubmission) {
|
||
this.formSubmission.stop();
|
||
delete this.formSubmission;
|
||
}
|
||
if (this.currentVisit) {
|
||
this.currentVisit.cancel();
|
||
delete this.currentVisit;
|
||
}
|
||
}
|
||
get adapter() {
|
||
return this.delegate.adapter;
|
||
}
|
||
get view() {
|
||
return this.delegate.view;
|
||
}
|
||
get history() {
|
||
return this.delegate.history;
|
||
}
|
||
formSubmissionStarted(formSubmission) {
|
||
}
|
||
async formSubmissionSucceededWithResponse(formSubmission, fetchResponse) {
|
||
if (formSubmission == this.formSubmission) {
|
||
const responseHTML = await fetchResponse.responseHTML;
|
||
if (responseHTML) {
|
||
if (formSubmission.method != FetchMethod.get) {
|
||
this.view.clearSnapshotCache();
|
||
}
|
||
const { statusCode } = fetchResponse;
|
||
const visitOptions = { response: { statusCode, responseHTML } };
|
||
this.proposeVisit(fetchResponse.location, visitOptions);
|
||
}
|
||
}
|
||
}
|
||
async formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
|
||
const responseHTML = await fetchResponse.responseHTML;
|
||
if (responseHTML) {
|
||
const snapshot = PageSnapshot.fromHTMLString(responseHTML);
|
||
await this.view.renderPage(snapshot);
|
||
this.view.clearSnapshotCache();
|
||
}
|
||
}
|
||
formSubmissionErrored(formSubmission, error) {
|
||
}
|
||
formSubmissionFinished(formSubmission) {
|
||
}
|
||
visitStarted(visit) {
|
||
this.delegate.visitStarted(visit);
|
||
}
|
||
visitCompleted(visit) {
|
||
this.delegate.visitCompleted(visit);
|
||
}
|
||
get location() {
|
||
return this.history.location;
|
||
}
|
||
get restorationIdentifier() {
|
||
return this.history.restorationIdentifier;
|
||
}
|
||
}
|
||
|
||
var PageStage;
|
||
(function (PageStage) {
|
||
PageStage[PageStage["initial"] = 0] = "initial";
|
||
PageStage[PageStage["loading"] = 1] = "loading";
|
||
PageStage[PageStage["interactive"] = 2] = "interactive";
|
||
PageStage[PageStage["complete"] = 3] = "complete";
|
||
})(PageStage || (PageStage = {}));
|
||
class PageObserver {
|
||
constructor(delegate) {
|
||
this.stage = PageStage.initial;
|
||
this.started = false;
|
||
this.interpretReadyState = () => {
|
||
const { readyState } = this;
|
||
if (readyState == "interactive") {
|
||
this.pageIsInteractive();
|
||
}
|
||
else if (readyState == "complete") {
|
||
this.pageIsComplete();
|
||
}
|
||
};
|
||
this.pageWillUnload = () => {
|
||
this.delegate.pageWillUnload();
|
||
};
|
||
this.delegate = delegate;
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
if (this.stage == PageStage.initial) {
|
||
this.stage = PageStage.loading;
|
||
}
|
||
document.addEventListener("readystatechange", this.interpretReadyState, false);
|
||
addEventListener("pagehide", this.pageWillUnload, false);
|
||
this.started = true;
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
document.removeEventListener("readystatechange", this.interpretReadyState, false);
|
||
removeEventListener("pagehide", this.pageWillUnload, false);
|
||
this.started = false;
|
||
}
|
||
}
|
||
pageIsInteractive() {
|
||
if (this.stage == PageStage.loading) {
|
||
this.stage = PageStage.interactive;
|
||
this.delegate.pageBecameInteractive();
|
||
}
|
||
}
|
||
pageIsComplete() {
|
||
this.pageIsInteractive();
|
||
if (this.stage == PageStage.interactive) {
|
||
this.stage = PageStage.complete;
|
||
this.delegate.pageLoaded();
|
||
}
|
||
}
|
||
get readyState() {
|
||
return document.readyState;
|
||
}
|
||
}
|
||
|
||
class ScrollObserver {
|
||
constructor(delegate) {
|
||
this.started = false;
|
||
this.onScroll = () => {
|
||
this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset });
|
||
};
|
||
this.delegate = delegate;
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
addEventListener("scroll", this.onScroll, false);
|
||
this.onScroll();
|
||
this.started = true;
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
removeEventListener("scroll", this.onScroll, false);
|
||
this.started = false;
|
||
}
|
||
}
|
||
updatePosition(position) {
|
||
this.delegate.scrollPositionChanged(position);
|
||
}
|
||
}
|
||
|
||
class StreamObserver {
|
||
constructor(delegate) {
|
||
this.sources = new Set;
|
||
this.started = false;
|
||
this.inspectFetchResponse = ((event) => {
|
||
const response = fetchResponseFromEvent(event);
|
||
if (response && fetchResponseIsStream(response)) {
|
||
event.preventDefault();
|
||
this.receiveMessageResponse(response);
|
||
}
|
||
});
|
||
this.receiveMessageEvent = (event) => {
|
||
if (this.started && typeof event.data == "string") {
|
||
this.receiveMessageHTML(event.data);
|
||
}
|
||
};
|
||
this.delegate = delegate;
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
this.started = true;
|
||
addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
|
||
}
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
this.started = false;
|
||
removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
|
||
}
|
||
}
|
||
connectStreamSource(source) {
|
||
if (!this.streamSourceIsConnected(source)) {
|
||
this.sources.add(source);
|
||
source.addEventListener("message", this.receiveMessageEvent, false);
|
||
}
|
||
}
|
||
disconnectStreamSource(source) {
|
||
if (this.streamSourceIsConnected(source)) {
|
||
this.sources.delete(source);
|
||
source.removeEventListener("message", this.receiveMessageEvent, false);
|
||
}
|
||
}
|
||
streamSourceIsConnected(source) {
|
||
return this.sources.has(source);
|
||
}
|
||
async receiveMessageResponse(response) {
|
||
const html = await response.responseHTML;
|
||
if (html) {
|
||
this.receiveMessageHTML(html);
|
||
}
|
||
}
|
||
receiveMessageHTML(html) {
|
||
this.delegate.receivedMessageFromStream(new StreamMessage(html));
|
||
}
|
||
}
|
||
function fetchResponseFromEvent(event) {
|
||
var _a;
|
||
const fetchResponse = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchResponse;
|
||
if (fetchResponse instanceof FetchResponse) {
|
||
return fetchResponse;
|
||
}
|
||
}
|
||
function fetchResponseIsStream(response) {
|
||
var _a;
|
||
const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : "";
|
||
return contentType.startsWith(StreamMessage.contentType);
|
||
}
|
||
|
||
function isAction(action) {
|
||
return action == "advance" || action == "replace" || action == "restore";
|
||
}
|
||
|
||
class ErrorRenderer extends Renderer {
|
||
async render() {
|
||
this.replaceHeadAndBody();
|
||
this.activateScriptElements();
|
||
}
|
||
replaceHeadAndBody() {
|
||
const { documentElement, head, body } = document;
|
||
documentElement.replaceChild(this.newHead, head);
|
||
documentElement.replaceChild(this.newElement, body);
|
||
}
|
||
activateScriptElements() {
|
||
for (const replaceableElement of this.scriptElements) {
|
||
const parentNode = replaceableElement.parentNode;
|
||
if (parentNode) {
|
||
const element = this.createScriptElement(replaceableElement);
|
||
parentNode.replaceChild(element, replaceableElement);
|
||
}
|
||
}
|
||
}
|
||
get newHead() {
|
||
return this.newSnapshot.headSnapshot.element;
|
||
}
|
||
get scriptElements() {
|
||
return [...document.documentElement.querySelectorAll("script")];
|
||
}
|
||
}
|
||
|
||
class PageRenderer extends Renderer {
|
||
get shouldRender() {
|
||
return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical;
|
||
}
|
||
prepareToRender() {
|
||
this.mergeHead();
|
||
}
|
||
async render() {
|
||
this.replaceBody();
|
||
}
|
||
finishRendering() {
|
||
super.finishRendering();
|
||
if (this.isPreview) {
|
||
this.focusFirstAutofocusableElement();
|
||
}
|
||
}
|
||
get currentHeadSnapshot() {
|
||
return this.currentSnapshot.headSnapshot;
|
||
}
|
||
get newHeadSnapshot() {
|
||
return this.newSnapshot.headSnapshot;
|
||
}
|
||
get newElement() {
|
||
return this.newSnapshot.element;
|
||
}
|
||
mergeHead() {
|
||
this.copyNewHeadStylesheetElements();
|
||
this.copyNewHeadScriptElements();
|
||
this.removeCurrentHeadProvisionalElements();
|
||
this.copyNewHeadProvisionalElements();
|
||
}
|
||
replaceBody() {
|
||
this.preservingPermanentElements(() => {
|
||
this.activateNewBody();
|
||
this.assignNewBody();
|
||
});
|
||
}
|
||
get trackedElementsAreIdentical() {
|
||
return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature;
|
||
}
|
||
copyNewHeadStylesheetElements() {
|
||
for (const element of this.newHeadStylesheetElements) {
|
||
document.head.appendChild(element);
|
||
}
|
||
}
|
||
copyNewHeadScriptElements() {
|
||
for (const element of this.newHeadScriptElements) {
|
||
document.head.appendChild(this.createScriptElement(element));
|
||
}
|
||
}
|
||
removeCurrentHeadProvisionalElements() {
|
||
for (const element of this.currentHeadProvisionalElements) {
|
||
document.head.removeChild(element);
|
||
}
|
||
}
|
||
copyNewHeadProvisionalElements() {
|
||
for (const element of this.newHeadProvisionalElements) {
|
||
document.head.appendChild(element);
|
||
}
|
||
}
|
||
activateNewBody() {
|
||
document.adoptNode(this.newElement);
|
||
this.activateNewBodyScriptElements();
|
||
}
|
||
activateNewBodyScriptElements() {
|
||
for (const inertScriptElement of this.newBodyScriptElements) {
|
||
const activatedScriptElement = this.createScriptElement(inertScriptElement);
|
||
replaceElementWithElement(inertScriptElement, activatedScriptElement);
|
||
}
|
||
}
|
||
assignNewBody() {
|
||
if (document.body && this.newElement instanceof HTMLBodyElement) {
|
||
replaceElementWithElement(document.body, this.newElement);
|
||
}
|
||
else {
|
||
document.documentElement.appendChild(this.newElement);
|
||
}
|
||
}
|
||
get newHeadStylesheetElements() {
|
||
return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
|
||
}
|
||
get newHeadScriptElements() {
|
||
return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot);
|
||
}
|
||
get currentHeadProvisionalElements() {
|
||
return this.currentHeadSnapshot.provisionalElements;
|
||
}
|
||
get newHeadProvisionalElements() {
|
||
return this.newHeadSnapshot.provisionalElements;
|
||
}
|
||
get newBodyScriptElements() {
|
||
return [...this.newElement.querySelectorAll("script")];
|
||
}
|
||
}
|
||
|
||
class SnapshotCache {
|
||
constructor(size) {
|
||
this.keys = [];
|
||
this.snapshots = {};
|
||
this.size = size;
|
||
}
|
||
has(location) {
|
||
return toCacheKey(location) in this.snapshots;
|
||
}
|
||
get(location) {
|
||
if (this.has(location)) {
|
||
const snapshot = this.read(location);
|
||
this.touch(location);
|
||
return snapshot;
|
||
}
|
||
}
|
||
put(location, snapshot) {
|
||
this.write(location, snapshot);
|
||
this.touch(location);
|
||
return snapshot;
|
||
}
|
||
clear() {
|
||
this.snapshots = {};
|
||
}
|
||
read(location) {
|
||
return this.snapshots[toCacheKey(location)];
|
||
}
|
||
write(location, snapshot) {
|
||
this.snapshots[toCacheKey(location)] = snapshot;
|
||
}
|
||
touch(location) {
|
||
const key = toCacheKey(location);
|
||
const index = this.keys.indexOf(key);
|
||
if (index > -1)
|
||
this.keys.splice(index, 1);
|
||
this.keys.unshift(key);
|
||
this.trim();
|
||
}
|
||
trim() {
|
||
for (const key of this.keys.splice(this.size)) {
|
||
delete this.snapshots[key];
|
||
}
|
||
}
|
||
}
|
||
|
||
class PageView extends View {
|
||
constructor() {
|
||
super(...arguments);
|
||
this.snapshotCache = new SnapshotCache(10);
|
||
this.lastRenderedLocation = new URL(location.href);
|
||
}
|
||
renderPage(snapshot, isPreview = false) {
|
||
const renderer = new PageRenderer(this.snapshot, snapshot, isPreview);
|
||
return this.render(renderer);
|
||
}
|
||
renderError(snapshot) {
|
||
const renderer = new ErrorRenderer(this.snapshot, snapshot, false);
|
||
this.render(renderer);
|
||
}
|
||
clearSnapshotCache() {
|
||
this.snapshotCache.clear();
|
||
}
|
||
async cacheSnapshot() {
|
||
if (this.shouldCacheSnapshot) {
|
||
this.delegate.viewWillCacheSnapshot();
|
||
const { snapshot, lastRenderedLocation: location } = this;
|
||
await nextEventLoopTick();
|
||
this.snapshotCache.put(location, snapshot.clone());
|
||
}
|
||
}
|
||
getCachedSnapshotForLocation(location) {
|
||
return this.snapshotCache.get(location);
|
||
}
|
||
get snapshot() {
|
||
return PageSnapshot.fromElement(this.element);
|
||
}
|
||
get shouldCacheSnapshot() {
|
||
return this.snapshot.isCacheable;
|
||
}
|
||
}
|
||
|
||
class Session {
|
||
constructor() {
|
||
this.navigator = new Navigator(this);
|
||
this.history = new History(this);
|
||
this.view = new PageView(this, document.documentElement);
|
||
this.adapter = new BrowserAdapter(this);
|
||
this.pageObserver = new PageObserver(this);
|
||
this.linkClickObserver = new LinkClickObserver(this);
|
||
this.formSubmitObserver = new FormSubmitObserver(this);
|
||
this.scrollObserver = new ScrollObserver(this);
|
||
this.streamObserver = new StreamObserver(this);
|
||
this.frameRedirector = new FrameRedirector(document.documentElement);
|
||
this.enabled = true;
|
||
this.progressBarDelay = 500;
|
||
this.started = false;
|
||
}
|
||
start() {
|
||
if (!this.started) {
|
||
this.pageObserver.start();
|
||
this.linkClickObserver.start();
|
||
this.formSubmitObserver.start();
|
||
this.scrollObserver.start();
|
||
this.streamObserver.start();
|
||
this.frameRedirector.start();
|
||
this.history.start();
|
||
this.started = true;
|
||
this.enabled = true;
|
||
}
|
||
}
|
||
disable() {
|
||
this.enabled = false;
|
||
}
|
||
stop() {
|
||
if (this.started) {
|
||
this.pageObserver.stop();
|
||
this.linkClickObserver.stop();
|
||
this.formSubmitObserver.stop();
|
||
this.scrollObserver.stop();
|
||
this.streamObserver.stop();
|
||
this.frameRedirector.stop();
|
||
this.history.stop();
|
||
this.started = false;
|
||
}
|
||
}
|
||
registerAdapter(adapter) {
|
||
this.adapter = adapter;
|
||
}
|
||
visit(location, options = {}) {
|
||
this.navigator.proposeVisit(expandURL(location), options);
|
||
}
|
||
connectStreamSource(source) {
|
||
this.streamObserver.connectStreamSource(source);
|
||
}
|
||
disconnectStreamSource(source) {
|
||
this.streamObserver.disconnectStreamSource(source);
|
||
}
|
||
renderStreamMessage(message) {
|
||
document.documentElement.appendChild(StreamMessage.wrap(message).fragment);
|
||
}
|
||
clearCache() {
|
||
this.view.clearSnapshotCache();
|
||
}
|
||
setProgressBarDelay(delay) {
|
||
this.progressBarDelay = delay;
|
||
}
|
||
get location() {
|
||
return this.history.location;
|
||
}
|
||
get restorationIdentifier() {
|
||
return this.history.restorationIdentifier;
|
||
}
|
||
historyPoppedToLocationWithRestorationIdentifier(location) {
|
||
if (this.enabled) {
|
||
this.navigator.proposeVisit(location, { action: "restore", historyChanged: true });
|
||
}
|
||
else {
|
||
this.adapter.pageInvalidated();
|
||
}
|
||
}
|
||
scrollPositionChanged(position) {
|
||
this.history.updateRestorationData({ scrollPosition: position });
|
||
}
|
||
willFollowLinkToLocation(link, location) {
|
||
return this.elementIsNavigable(link)
|
||
&& this.locationIsVisitable(location)
|
||
&& this.applicationAllowsFollowingLinkToLocation(link, location);
|
||
}
|
||
followedLinkToLocation(link, location) {
|
||
const action = this.getActionForLink(link);
|
||
this.visit(location.href, { action });
|
||
}
|
||
allowsVisitingLocation(location) {
|
||
return this.applicationAllowsVisitingLocation(location);
|
||
}
|
||
visitProposedToLocation(location, options) {
|
||
extendURLWithDeprecatedProperties(location);
|
||
this.adapter.visitProposedToLocation(location, options);
|
||
}
|
||
visitStarted(visit) {
|
||
extendURLWithDeprecatedProperties(visit.location);
|
||
this.notifyApplicationAfterVisitingLocation(visit.location);
|
||
}
|
||
visitCompleted(visit) {
|
||
this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());
|
||
}
|
||
willSubmitForm(form, submitter) {
|
||
return this.elementIsNavigable(form) && this.elementIsNavigable(submitter);
|
||
}
|
||
formSubmitted(form, submitter) {
|
||
this.navigator.submitForm(form, submitter);
|
||
}
|
||
pageBecameInteractive() {
|
||
this.view.lastRenderedLocation = this.location;
|
||
this.notifyApplicationAfterPageLoad();
|
||
}
|
||
pageLoaded() {
|
||
this.history.assumeControlOfScrollRestoration();
|
||
}
|
||
pageWillUnload() {
|
||
this.history.relinquishControlOfScrollRestoration();
|
||
}
|
||
receivedMessageFromStream(message) {
|
||
this.renderStreamMessage(message);
|
||
}
|
||
viewWillCacheSnapshot() {
|
||
this.notifyApplicationBeforeCachingSnapshot();
|
||
}
|
||
viewWillRenderSnapshot({ element }, isPreview) {
|
||
this.notifyApplicationBeforeRender(element);
|
||
}
|
||
viewRenderedSnapshot(snapshot, isPreview) {
|
||
this.view.lastRenderedLocation = this.history.location;
|
||
this.notifyApplicationAfterRender();
|
||
}
|
||
viewInvalidated() {
|
||
this.adapter.pageInvalidated();
|
||
}
|
||
applicationAllowsFollowingLinkToLocation(link, location) {
|
||
const event = this.notifyApplicationAfterClickingLinkToLocation(link, location);
|
||
return !event.defaultPrevented;
|
||
}
|
||
applicationAllowsVisitingLocation(location) {
|
||
const event = this.notifyApplicationBeforeVisitingLocation(location);
|
||
return !event.defaultPrevented;
|
||
}
|
||
notifyApplicationAfterClickingLinkToLocation(link, location) {
|
||
return dispatch("turbo:click", { target: link, detail: { url: location.href }, cancelable: true });
|
||
}
|
||
notifyApplicationBeforeVisitingLocation(location) {
|
||
return dispatch("turbo:before-visit", { detail: { url: location.href }, cancelable: true });
|
||
}
|
||
notifyApplicationAfterVisitingLocation(location) {
|
||
return dispatch("turbo:visit", { detail: { url: location.href } });
|
||
}
|
||
notifyApplicationBeforeCachingSnapshot() {
|
||
return dispatch("turbo:before-cache");
|
||
}
|
||
notifyApplicationBeforeRender(newBody) {
|
||
return dispatch("turbo:before-render", { detail: { newBody } });
|
||
}
|
||
notifyApplicationAfterRender() {
|
||
return dispatch("turbo:render");
|
||
}
|
||
notifyApplicationAfterPageLoad(timing = {}) {
|
||
return dispatch("turbo:load", { detail: { url: this.location.href, timing } });
|
||
}
|
||
getActionForLink(link) {
|
||
const action = link.getAttribute("data-turbo-action");
|
||
return isAction(action) ? action : "advance";
|
||
}
|
||
elementIsNavigable(element) {
|
||
const container = element === null || element === void 0 ? void 0 : element.closest("[data-turbo]");
|
||
if (container) {
|
||
return container.getAttribute("data-turbo") != "false";
|
||
}
|
||
else {
|
||
return true;
|
||
}
|
||
}
|
||
locationIsVisitable(location) {
|
||
return isPrefixedBy(location, this.snapshot.rootLocation) && isHTML(location);
|
||
}
|
||
get snapshot() {
|
||
return this.view.snapshot;
|
||
}
|
||
}
|
||
function extendURLWithDeprecatedProperties(url) {
|
||
Object.defineProperties(url, deprecatedLocationPropertyDescriptors);
|
||
}
|
||
const deprecatedLocationPropertyDescriptors = {
|
||
absoluteURL: {
|
||
get() {
|
||
return this.toString();
|
||
}
|
||
}
|
||
};
|
||
|
||
const session = new Session;
|
||
const { navigator } = session;
|
||
function start() {
|
||
session.start();
|
||
}
|
||
function registerAdapter(adapter) {
|
||
session.registerAdapter(adapter);
|
||
}
|
||
function visit(location, options) {
|
||
session.visit(location, options);
|
||
}
|
||
function connectStreamSource(source) {
|
||
session.connectStreamSource(source);
|
||
}
|
||
function disconnectStreamSource(source) {
|
||
session.disconnectStreamSource(source);
|
||
}
|
||
function renderStreamMessage(message) {
|
||
session.renderStreamMessage(message);
|
||
}
|
||
function clearCache() {
|
||
session.clearCache();
|
||
}
|
||
function setProgressBarDelay(delay) {
|
||
session.setProgressBarDelay(delay);
|
||
}
|
||
|
||
start();
|
||
|
||
|
||
//# sourceMappingURL=turbo.es2017-esm.js.map
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ "./node_modules/alpine-turbo-drive-adapter/dist/alpine-turbo-drive-adapter.esm.js":
|
||
/*!****************************************************************************************!*\
|
||
!*** ./node_modules/alpine-turbo-drive-adapter/dist/alpine-turbo-drive-adapter.esm.js ***!
|
||
\****************************************************************************************/
|
||
/***/ (() => {
|
||
|
||
function isValidVersion(required, current) {
|
||
const requiredArray = required.split('.');
|
||
const currentArray = current.split('.');
|
||
|
||
for (let i = 0; i < requiredArray.length; i++) {
|
||
if (!currentArray[i] || currentArray[i] < requiredArray[i]) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
function beforeDomReady(callback) {
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('readystatechange', () => {
|
||
if (document.readyState === 'interactive') {
|
||
callback();
|
||
}
|
||
});
|
||
} else {
|
||
callback();
|
||
}
|
||
}
|
||
|
||
class Bridge {
|
||
init() {
|
||
// Tag all cloaked elements on first page load.
|
||
document.body.querySelectorAll('[x-cloak]').forEach(el => {
|
||
el.setAttribute('data-alpine-was-cloaked', el.getAttribute('x-cloak') ?? '');
|
||
});
|
||
this.configureEventHandlers();
|
||
}
|
||
|
||
setMutationObserverState(state) {
|
||
if (!window.Alpine.version || !isValidVersion('2.4.0', window.Alpine.version)) {
|
||
throw new Error('Invalid Alpine version. Please use Alpine 2.4.0 or above');
|
||
}
|
||
|
||
window.Alpine.pauseMutationObserver = state;
|
||
}
|
||
|
||
configureEventHandlers() {
|
||
// Once Turbolinks finished is magic, we initialise Alpine on the new page
|
||
// and resume the observer
|
||
const initCallback = () => {
|
||
window.Alpine.discoverUninitializedComponents(el => {
|
||
window.Alpine.initializeComponent(el);
|
||
});
|
||
requestAnimationFrame(() => {
|
||
this.setMutationObserverState(false);
|
||
});
|
||
}; // Before swapping the body, clean up any element with x-turbolinks-cached
|
||
// which do not have any Alpine properties.
|
||
// Note, at this point all html fragments marked as data-turbolinks-permanent
|
||
// are already copied over from the previous page so they retain their listener
|
||
// and custom properties and we don't want to reset them.
|
||
|
||
|
||
const beforeRenderCallback = event => {
|
||
const newBody = event.data ? event.data.newBody : event.detail.newBody;
|
||
newBody.querySelectorAll('[data-alpine-generated-me],[x-cloak]').forEach(el => {
|
||
if (el.hasAttribute('x-cloak')) {
|
||
// When we get a new document body tag any cloaked elements so we can cloak
|
||
// them again before caching.
|
||
el.setAttribute('data-alpine-was-cloaked', el.getAttribute('x-cloak') ?? '');
|
||
}
|
||
|
||
if (el.hasAttribute('data-alpine-generated-me')) {
|
||
el.removeAttribute('data-alpine-generated-me');
|
||
|
||
if (typeof el.__x_for_key === 'undefined' && typeof el.__x_inserted_me === 'undefined') {
|
||
el.remove();
|
||
}
|
||
}
|
||
});
|
||
}; // Pause the the mutation observer to avoid data races, it will be resumed by the turbolinks:load event.
|
||
// We mark as `data-alpine-generated-m` all elements that are crated by an Alpine templating directives.
|
||
// The reason is that turbolinks caches pages using cloneNode which removes listeners and custom properties
|
||
// So we need to propagate this infomation using a HTML attribute. I know, not ideal but I could not think
|
||
// of a better option.
|
||
// Note, we can't remove any Alpine generated element as yet because if they live inside an element
|
||
// marked as data-turbolinks-permanent they need to be copied into the next page.
|
||
// The coping process happens somewhere between before-cache and before-render.
|
||
|
||
|
||
const beforeCacheCallback = () => {
|
||
this.setMutationObserverState(true);
|
||
document.body.querySelectorAll('[x-for],[x-if],[data-alpine-was-cloaked]').forEach(el => {
|
||
// Cloak any elements again that were tagged when the page was loaded
|
||
if (el.hasAttribute('data-alpine-was-cloaked')) {
|
||
el.setAttribute('x-cloak', el.getAttribute('data-alpine-was-cloaked') ?? '');
|
||
el.removeAttribute('data-alpine-was-cloaked');
|
||
}
|
||
|
||
if (el.hasAttribute('x-for')) {
|
||
let nextEl = el.nextElementSibling;
|
||
|
||
while (nextEl && typeof nextEl.__x_for_key !== 'undefined') {
|
||
const currEl = nextEl;
|
||
nextEl = nextEl.nextElementSibling;
|
||
currEl.setAttribute('data-alpine-generated-me', true);
|
||
}
|
||
} else if (el.hasAttribute('x-if')) {
|
||
const ifEl = el.nextElementSibling;
|
||
|
||
if (ifEl && typeof ifEl.__x_inserted_me !== 'undefined') {
|
||
ifEl.setAttribute('data-alpine-generated-me', true);
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
document.addEventListener('turbo:load', initCallback);
|
||
document.addEventListener('turbolinks:load', initCallback);
|
||
document.addEventListener('turbo:before-render', beforeRenderCallback);
|
||
document.addEventListener('turbolinks:before-render', beforeRenderCallback);
|
||
document.addEventListener('turbo:before-cache', beforeCacheCallback);
|
||
document.addEventListener('turbolinks:before-cache', beforeCacheCallback);
|
||
}
|
||
|
||
}
|
||
|
||
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'));
|
||
} // To better suport x-cloak, we need to init the library when the DOM
|
||
// has been downloaded but before Alpine kicks in
|
||
|
||
|
||
beforeDomReady(() => {
|
||
const bridge = new Bridge();
|
||
bridge.init();
|
||
});
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ "./node_modules/alpinejs/dist/alpine.js":
|
||
/*!**********************************************!*\
|
||
!*** ./node_modules/alpinejs/dist/alpine.js ***!
|
||
\**********************************************/
|
||
/***/ (function(module) {
|
||
|
||
(function (global, factory) {
|
||
true ? module.exports = factory() :
|
||
0;
|
||
}(this, (function () { 'use strict';
|
||
|
||
function _defineProperty(obj, key, value) {
|
||
if (key in obj) {
|
||
Object.defineProperty(obj, key, {
|
||
value: value,
|
||
enumerable: true,
|
||
configurable: true,
|
||
writable: true
|
||
});
|
||
} else {
|
||
obj[key] = value;
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
|
||
function ownKeys(object, enumerableOnly) {
|
||
var keys = Object.keys(object);
|
||
|
||
if (Object.getOwnPropertySymbols) {
|
||
var symbols = Object.getOwnPropertySymbols(object);
|
||
if (enumerableOnly) symbols = symbols.filter(function (sym) {
|
||
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
||
});
|
||
keys.push.apply(keys, symbols);
|
||
}
|
||
|
||
return keys;
|
||
}
|
||
|
||
function _objectSpread2(target) {
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
var source = arguments[i] != null ? arguments[i] : {};
|
||
|
||
if (i % 2) {
|
||
ownKeys(Object(source), true).forEach(function (key) {
|
||
_defineProperty(target, key, source[key]);
|
||
});
|
||
} else if (Object.getOwnPropertyDescriptors) {
|
||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
||
} else {
|
||
ownKeys(Object(source)).forEach(function (key) {
|
||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
||
});
|
||
}
|
||
}
|
||
|
||
return target;
|
||
}
|
||
|
||
// Thanks @stimulus:
|
||
// https://github.com/stimulusjs/stimulus/blob/master/packages/%40stimulus/core/src/application.ts
|
||
function domReady() {
|
||
return new Promise(resolve => {
|
||
if (document.readyState == "loading") {
|
||
document.addEventListener("DOMContentLoaded", resolve);
|
||
} else {
|
||
resolve();
|
||
}
|
||
});
|
||
}
|
||
function arrayUnique(array) {
|
||
return Array.from(new Set(array));
|
||
}
|
||
function isTesting() {
|
||
return navigator.userAgent.includes("Node.js") || navigator.userAgent.includes("jsdom");
|
||
}
|
||
function checkedAttrLooseCompare(valueA, valueB) {
|
||
return valueA == valueB;
|
||
}
|
||
function warnIfMalformedTemplate(el, directive) {
|
||
if (el.tagName.toLowerCase() !== 'template') {
|
||
console.warn(`Alpine: [${directive}] directive should only be added to <template> tags. See https://github.com/alpinejs/alpine#${directive}`);
|
||
} else if (el.content.childElementCount !== 1) {
|
||
console.warn(`Alpine: <template> tag with [${directive}] encountered with an unexpected number of root elements. Make sure <template> has a single root element. `);
|
||
}
|
||
}
|
||
function kebabCase(subject) {
|
||
return subject.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/[_\s]/, '-').toLowerCase();
|
||
}
|
||
function camelCase(subject) {
|
||
return subject.toLowerCase().replace(/-(\w)/g, (match, char) => char.toUpperCase());
|
||
}
|
||
function walk(el, callback) {
|
||
if (callback(el) === false) return;
|
||
let node = el.firstElementChild;
|
||
|
||
while (node) {
|
||
walk(node, callback);
|
||
node = node.nextElementSibling;
|
||
}
|
||
}
|
||
function debounce(func, wait) {
|
||
var timeout;
|
||
return function () {
|
||
var context = this,
|
||
args = arguments;
|
||
|
||
var later = function later() {
|
||
timeout = null;
|
||
func.apply(context, args);
|
||
};
|
||
|
||
clearTimeout(timeout);
|
||
timeout = setTimeout(later, wait);
|
||
};
|
||
}
|
||
|
||
const handleError = (el, expression, error) => {
|
||
console.warn(`Alpine Error: "${error}"\n\nExpression: "${expression}"\nElement:`, el);
|
||
|
||
if (!isTesting()) {
|
||
Object.assign(error, {
|
||
el,
|
||
expression
|
||
});
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
function tryCatch(cb, {
|
||
el,
|
||
expression
|
||
}) {
|
||
try {
|
||
const value = cb();
|
||
return value instanceof Promise ? value.catch(e => handleError(el, expression, e)) : value;
|
||
} catch (e) {
|
||
handleError(el, expression, e);
|
||
}
|
||
}
|
||
|
||
function saferEval(el, expression, dataContext, additionalHelperVariables = {}) {
|
||
return tryCatch(() => {
|
||
if (typeof expression === 'function') {
|
||
return expression.call(dataContext);
|
||
}
|
||
|
||
return new Function(['$data', ...Object.keys(additionalHelperVariables)], `var __alpine_result; with($data) { __alpine_result = ${expression} }; return __alpine_result`)(dataContext, ...Object.values(additionalHelperVariables));
|
||
}, {
|
||
el,
|
||
expression
|
||
});
|
||
}
|
||
function saferEvalNoReturn(el, expression, dataContext, additionalHelperVariables = {}) {
|
||
return tryCatch(() => {
|
||
if (typeof expression === 'function') {
|
||
return Promise.resolve(expression.call(dataContext, additionalHelperVariables['$event']));
|
||
}
|
||
|
||
let AsyncFunction = Function;
|
||
/* MODERN-ONLY:START */
|
||
|
||
AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
||
/* MODERN-ONLY:END */
|
||
// For the cases when users pass only a function reference to the caller: `x-on:click="foo"`
|
||
// Where "foo" is a function. Also, we'll pass the function the event instance when we call it.
|
||
|
||
if (Object.keys(dataContext).includes(expression)) {
|
||
let methodReference = new Function(['dataContext', ...Object.keys(additionalHelperVariables)], `with(dataContext) { return ${expression} }`)(dataContext, ...Object.values(additionalHelperVariables));
|
||
|
||
if (typeof methodReference === 'function') {
|
||
return Promise.resolve(methodReference.call(dataContext, additionalHelperVariables['$event']));
|
||
} else {
|
||
return Promise.resolve();
|
||
}
|
||
}
|
||
|
||
return Promise.resolve(new AsyncFunction(['dataContext', ...Object.keys(additionalHelperVariables)], `with(dataContext) { ${expression} }`)(dataContext, ...Object.values(additionalHelperVariables)));
|
||
}, {
|
||
el,
|
||
expression
|
||
});
|
||
}
|
||
const xAttrRE = /^x-(on|bind|data|text|html|model|if|for|show|cloak|transition|ref|spread)\b/;
|
||
function isXAttr(attr) {
|
||
const name = replaceAtAndColonWithStandardSyntax(attr.name);
|
||
return xAttrRE.test(name);
|
||
}
|
||
function getXAttrs(el, component, type) {
|
||
let directives = Array.from(el.attributes).filter(isXAttr).map(parseHtmlAttribute); // Get an object of directives from x-spread.
|
||
|
||
let spreadDirective = directives.filter(directive => directive.type === 'spread')[0];
|
||
|
||
if (spreadDirective) {
|
||
let spreadObject = saferEval(el, spreadDirective.expression, component.$data); // Add x-spread directives to the pile of existing directives.
|
||
|
||
directives = directives.concat(Object.entries(spreadObject).map(([name, value]) => parseHtmlAttribute({
|
||
name,
|
||
value
|
||
})));
|
||
}
|
||
|
||
if (type) return directives.filter(i => i.type === type);
|
||
return sortDirectives(directives);
|
||
}
|
||
|
||
function sortDirectives(directives) {
|
||
let directiveOrder = ['bind', 'model', 'show', 'catch-all'];
|
||
return directives.sort((a, b) => {
|
||
let typeA = directiveOrder.indexOf(a.type) === -1 ? 'catch-all' : a.type;
|
||
let typeB = directiveOrder.indexOf(b.type) === -1 ? 'catch-all' : b.type;
|
||
return directiveOrder.indexOf(typeA) - directiveOrder.indexOf(typeB);
|
||
});
|
||
}
|
||
|
||
function parseHtmlAttribute({
|
||
name,
|
||
value
|
||
}) {
|
||
const normalizedName = replaceAtAndColonWithStandardSyntax(name);
|
||
const typeMatch = normalizedName.match(xAttrRE);
|
||
const valueMatch = normalizedName.match(/:([a-zA-Z0-9\-:]+)/);
|
||
const modifiers = normalizedName.match(/\.[^.\]]+(?=[^\]]*$)/g) || [];
|
||
return {
|
||
type: typeMatch ? typeMatch[1] : null,
|
||
value: valueMatch ? valueMatch[1] : null,
|
||
modifiers: modifiers.map(i => i.replace('.', '')),
|
||
expression: value
|
||
};
|
||
}
|
||
function isBooleanAttr(attrName) {
|
||
// As per HTML spec table https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute
|
||
// Array roughly ordered by estimated usage
|
||
const booleanAttributes = ['disabled', 'checked', 'required', 'readonly', 'hidden', 'open', 'selected', 'autofocus', 'itemscope', 'multiple', 'novalidate', 'allowfullscreen', 'allowpaymentrequest', 'formnovalidate', 'autoplay', 'controls', 'loop', 'muted', 'playsinline', 'default', 'ismap', 'reversed', 'async', 'defer', 'nomodule'];
|
||
return booleanAttributes.includes(attrName);
|
||
}
|
||
function replaceAtAndColonWithStandardSyntax(name) {
|
||
if (name.startsWith('@')) {
|
||
return name.replace('@', 'x-on:');
|
||
} else if (name.startsWith(':')) {
|
||
return name.replace(':', 'x-bind:');
|
||
}
|
||
|
||
return name;
|
||
}
|
||
function convertClassStringToArray(classList, filterFn = Boolean) {
|
||
return classList.split(' ').filter(filterFn);
|
||
}
|
||
const TRANSITION_TYPE_IN = 'in';
|
||
const TRANSITION_TYPE_OUT = 'out';
|
||
const TRANSITION_CANCELLED = 'cancelled';
|
||
function transitionIn(el, show, reject, component, forceSkip = false) {
|
||
// We don't want to transition on the initial page load.
|
||
if (forceSkip) return show();
|
||
|
||
if (el.__x_transition && el.__x_transition.type === TRANSITION_TYPE_IN) {
|
||
// there is already a similar transition going on, this was probably triggered by
|
||
// a change in a different property, let's just leave the previous one doing its job
|
||
return;
|
||
}
|
||
|
||
const attrs = getXAttrs(el, component, 'transition');
|
||
const showAttr = getXAttrs(el, component, 'show')[0]; // If this is triggered by a x-show.transition.
|
||
|
||
if (showAttr && showAttr.modifiers.includes('transition')) {
|
||
let modifiers = showAttr.modifiers; // If x-show.transition.out, we'll skip the "in" transition.
|
||
|
||
if (modifiers.includes('out') && !modifiers.includes('in')) return show();
|
||
const settingBothSidesOfTransition = modifiers.includes('in') && modifiers.includes('out'); // If x-show.transition.in...out... only use "in" related modifiers for this transition.
|
||
|
||
modifiers = settingBothSidesOfTransition ? modifiers.filter((i, index) => index < modifiers.indexOf('out')) : modifiers;
|
||
transitionHelperIn(el, modifiers, show, reject); // Otherwise, we can assume x-transition:enter.
|
||
} else if (attrs.some(attr => ['enter', 'enter-start', 'enter-end'].includes(attr.value))) {
|
||
transitionClassesIn(el, component, attrs, show, reject);
|
||
} else {
|
||
// If neither, just show that damn thing.
|
||
show();
|
||
}
|
||
}
|
||
function transitionOut(el, hide, reject, component, forceSkip = false) {
|
||
// We don't want to transition on the initial page load.
|
||
if (forceSkip) return hide();
|
||
|
||
if (el.__x_transition && el.__x_transition.type === TRANSITION_TYPE_OUT) {
|
||
// there is already a similar transition going on, this was probably triggered by
|
||
// a change in a different property, let's just leave the previous one doing its job
|
||
return;
|
||
}
|
||
|
||
const attrs = getXAttrs(el, component, 'transition');
|
||
const showAttr = getXAttrs(el, component, 'show')[0];
|
||
|
||
if (showAttr && showAttr.modifiers.includes('transition')) {
|
||
let modifiers = showAttr.modifiers;
|
||
if (modifiers.includes('in') && !modifiers.includes('out')) return hide();
|
||
const settingBothSidesOfTransition = modifiers.includes('in') && modifiers.includes('out');
|
||
modifiers = settingBothSidesOfTransition ? modifiers.filter((i, index) => index > modifiers.indexOf('out')) : modifiers;
|
||
transitionHelperOut(el, modifiers, settingBothSidesOfTransition, hide, reject);
|
||
} else if (attrs.some(attr => ['leave', 'leave-start', 'leave-end'].includes(attr.value))) {
|
||
transitionClassesOut(el, component, attrs, hide, reject);
|
||
} else {
|
||
hide();
|
||
}
|
||
}
|
||
function transitionHelperIn(el, modifiers, showCallback, reject) {
|
||
// Default values inspired by: https://material.io/design/motion/speed.html#duration
|
||
const styleValues = {
|
||
duration: modifierValue(modifiers, 'duration', 150),
|
||
origin: modifierValue(modifiers, 'origin', 'center'),
|
||
first: {
|
||
opacity: 0,
|
||
scale: modifierValue(modifiers, 'scale', 95)
|
||
},
|
||
second: {
|
||
opacity: 1,
|
||
scale: 100
|
||
}
|
||
};
|
||
transitionHelper(el, modifiers, showCallback, () => {}, reject, styleValues, TRANSITION_TYPE_IN);
|
||
}
|
||
function transitionHelperOut(el, modifiers, settingBothSidesOfTransition, hideCallback, reject) {
|
||
// Make the "out" transition .5x slower than the "in". (Visually better)
|
||
// HOWEVER, if they explicitly set a duration for the "out" transition,
|
||
// use that.
|
||
const duration = settingBothSidesOfTransition ? modifierValue(modifiers, 'duration', 150) : modifierValue(modifiers, 'duration', 150) / 2;
|
||
const styleValues = {
|
||
duration: duration,
|
||
origin: modifierValue(modifiers, 'origin', 'center'),
|
||
first: {
|
||
opacity: 1,
|
||
scale: 100
|
||
},
|
||
second: {
|
||
opacity: 0,
|
||
scale: modifierValue(modifiers, 'scale', 95)
|
||
}
|
||
};
|
||
transitionHelper(el, modifiers, () => {}, hideCallback, reject, styleValues, TRANSITION_TYPE_OUT);
|
||
}
|
||
|
||
function modifierValue(modifiers, key, fallback) {
|
||
// If the modifier isn't present, use the default.
|
||
if (modifiers.indexOf(key) === -1) return fallback; // If it IS present, grab the value after it: x-show.transition.duration.500ms
|
||
|
||
const rawValue = modifiers[modifiers.indexOf(key) + 1];
|
||
if (!rawValue) return fallback;
|
||
|
||
if (key === 'scale') {
|
||
// Check if the very next value is NOT a number and return the fallback.
|
||
// If x-show.transition.scale, we'll use the default scale value.
|
||
// That is how a user opts out of the opacity transition.
|
||
if (!isNumeric(rawValue)) return fallback;
|
||
}
|
||
|
||
if (key === 'duration') {
|
||
// Support x-show.transition.duration.500ms && duration.500
|
||
let match = rawValue.match(/([0-9]+)ms/);
|
||
if (match) return match[1];
|
||
}
|
||
|
||
if (key === 'origin') {
|
||
// Support chaining origin directions: x-show.transition.top.right
|
||
if (['top', 'right', 'left', 'center', 'bottom'].includes(modifiers[modifiers.indexOf(key) + 2])) {
|
||
return [rawValue, modifiers[modifiers.indexOf(key) + 2]].join(' ');
|
||
}
|
||
}
|
||
|
||
return rawValue;
|
||
}
|
||
|
||
function transitionHelper(el, modifiers, hook1, hook2, reject, styleValues, type) {
|
||
// clear the previous transition if exists to avoid caching the wrong styles
|
||
if (el.__x_transition) {
|
||
el.__x_transition.cancel && el.__x_transition.cancel();
|
||
} // If the user set these style values, we'll put them back when we're done with them.
|
||
|
||
|
||
const opacityCache = el.style.opacity;
|
||
const transformCache = el.style.transform;
|
||
const transformOriginCache = el.style.transformOrigin; // If no modifiers are present: x-show.transition, we'll default to both opacity and scale.
|
||
|
||
const noModifiers = !modifiers.includes('opacity') && !modifiers.includes('scale');
|
||
const transitionOpacity = noModifiers || modifiers.includes('opacity');
|
||
const transitionScale = noModifiers || modifiers.includes('scale'); // These are the explicit stages of a transition (same stages for in and for out).
|
||
// This way you can get a birds eye view of the hooks, and the differences
|
||
// between them.
|
||
|
||
const stages = {
|
||
start() {
|
||
if (transitionOpacity) el.style.opacity = styleValues.first.opacity;
|
||
if (transitionScale) el.style.transform = `scale(${styleValues.first.scale / 100})`;
|
||
},
|
||
|
||
during() {
|
||
if (transitionScale) el.style.transformOrigin = styleValues.origin;
|
||
el.style.transitionProperty = [transitionOpacity ? `opacity` : ``, transitionScale ? `transform` : ``].join(' ').trim();
|
||
el.style.transitionDuration = `${styleValues.duration / 1000}s`;
|
||
el.style.transitionTimingFunction = `cubic-bezier(0.4, 0.0, 0.2, 1)`;
|
||
},
|
||
|
||
show() {
|
||
hook1();
|
||
},
|
||
|
||
end() {
|
||
if (transitionOpacity) el.style.opacity = styleValues.second.opacity;
|
||
if (transitionScale) el.style.transform = `scale(${styleValues.second.scale / 100})`;
|
||
},
|
||
|
||
hide() {
|
||
hook2();
|
||
},
|
||
|
||
cleanup() {
|
||
if (transitionOpacity) el.style.opacity = opacityCache;
|
||
if (transitionScale) el.style.transform = transformCache;
|
||
if (transitionScale) el.style.transformOrigin = transformOriginCache;
|
||
el.style.transitionProperty = null;
|
||
el.style.transitionDuration = null;
|
||
el.style.transitionTimingFunction = null;
|
||
}
|
||
|
||
};
|
||
transition(el, stages, type, reject);
|
||
}
|
||
|
||
const ensureStringExpression = (expression, el, component) => {
|
||
return typeof expression === 'function' ? component.evaluateReturnExpression(el, expression) : expression;
|
||
};
|
||
|
||
function transitionClassesIn(el, component, directives, showCallback, reject) {
|
||
const enter = convertClassStringToArray(ensureStringExpression((directives.find(i => i.value === 'enter') || {
|
||
expression: ''
|
||
}).expression, el, component));
|
||
const enterStart = convertClassStringToArray(ensureStringExpression((directives.find(i => i.value === 'enter-start') || {
|
||
expression: ''
|
||
}).expression, el, component));
|
||
const enterEnd = convertClassStringToArray(ensureStringExpression((directives.find(i => i.value === 'enter-end') || {
|
||
expression: ''
|
||
}).expression, el, component));
|
||
transitionClasses(el, enter, enterStart, enterEnd, showCallback, () => {}, TRANSITION_TYPE_IN, reject);
|
||
}
|
||
function transitionClassesOut(el, component, directives, hideCallback, reject) {
|
||
const leave = convertClassStringToArray(ensureStringExpression((directives.find(i => i.value === 'leave') || {
|
||
expression: ''
|
||
}).expression, el, component));
|
||
const leaveStart = convertClassStringToArray(ensureStringExpression((directives.find(i => i.value === 'leave-start') || {
|
||
expression: ''
|
||
}).expression, el, component));
|
||
const leaveEnd = convertClassStringToArray(ensureStringExpression((directives.find(i => i.value === 'leave-end') || {
|
||
expression: ''
|
||
}).expression, el, component));
|
||
transitionClasses(el, leave, leaveStart, leaveEnd, () => {}, hideCallback, TRANSITION_TYPE_OUT, reject);
|
||
}
|
||
function transitionClasses(el, classesDuring, classesStart, classesEnd, hook1, hook2, type, reject) {
|
||
// clear the previous transition if exists to avoid caching the wrong classes
|
||
if (el.__x_transition) {
|
||
el.__x_transition.cancel && el.__x_transition.cancel();
|
||
}
|
||
|
||
const originalClasses = el.__x_original_classes || [];
|
||
const stages = {
|
||
start() {
|
||
el.classList.add(...classesStart);
|
||
},
|
||
|
||
during() {
|
||
el.classList.add(...classesDuring);
|
||
},
|
||
|
||
show() {
|
||
hook1();
|
||
},
|
||
|
||
end() {
|
||
// Don't remove classes that were in the original class attribute.
|
||
el.classList.remove(...classesStart.filter(i => !originalClasses.includes(i)));
|
||
el.classList.add(...classesEnd);
|
||
},
|
||
|
||
hide() {
|
||
hook2();
|
||
},
|
||
|
||
cleanup() {
|
||
el.classList.remove(...classesDuring.filter(i => !originalClasses.includes(i)));
|
||
el.classList.remove(...classesEnd.filter(i => !originalClasses.includes(i)));
|
||
}
|
||
|
||
};
|
||
transition(el, stages, type, reject);
|
||
}
|
||
function transition(el, stages, type, reject) {
|
||
const finish = once(() => {
|
||
stages.hide(); // Adding an "isConnected" check, in case the callback
|
||
// removed the element from the DOM.
|
||
|
||
if (el.isConnected) {
|
||
stages.cleanup();
|
||
}
|
||
|
||
delete el.__x_transition;
|
||
});
|
||
el.__x_transition = {
|
||
// Set transition type so we can avoid clearing transition if the direction is the same
|
||
type: type,
|
||
// create a callback for the last stages of the transition so we can call it
|
||
// from different point and early terminate it. Once will ensure that function
|
||
// is only called one time.
|
||
cancel: once(() => {
|
||
reject(TRANSITION_CANCELLED);
|
||
finish();
|
||
}),
|
||
finish,
|
||
// This store the next animation frame so we can cancel it
|
||
nextFrame: null
|
||
};
|
||
stages.start();
|
||
stages.during();
|
||
el.__x_transition.nextFrame = requestAnimationFrame(() => {
|
||
// Note: Safari's transitionDuration property will list out comma separated transition durations
|
||
// for every single transition property. Let's grab the first one and call it a day.
|
||
let duration = Number(getComputedStyle(el).transitionDuration.replace(/,.*/, '').replace('s', '')) * 1000;
|
||
|
||
if (duration === 0) {
|
||
duration = Number(getComputedStyle(el).animationDuration.replace('s', '')) * 1000;
|
||
}
|
||
|
||
stages.show();
|
||
el.__x_transition.nextFrame = requestAnimationFrame(() => {
|
||
stages.end();
|
||
setTimeout(el.__x_transition.finish, duration);
|
||
});
|
||
});
|
||
}
|
||
function isNumeric(subject) {
|
||
return !Array.isArray(subject) && !isNaN(subject);
|
||
} // Thanks @vuejs
|
||
// https://github.com/vuejs/vue/blob/4de4649d9637262a9b007720b59f80ac72a5620c/src/shared/util.js
|
||
|
||
function once(callback) {
|
||
let called = false;
|
||
return function () {
|
||
if (!called) {
|
||
called = true;
|
||
callback.apply(this, arguments);
|
||
}
|
||
};
|
||
}
|
||
|
||
function handleForDirective(component, templateEl, expression, initialUpdate, extraVars) {
|
||
warnIfMalformedTemplate(templateEl, 'x-for');
|
||
let iteratorNames = typeof expression === 'function' ? parseForExpression(component.evaluateReturnExpression(templateEl, expression)) : parseForExpression(expression);
|
||
let items = evaluateItemsAndReturnEmptyIfXIfIsPresentAndFalseOnElement(component, templateEl, iteratorNames, extraVars); // As we walk the array, we'll also walk the DOM (updating/creating as we go).
|
||
|
||
let currentEl = templateEl;
|
||
items.forEach((item, index) => {
|
||
let iterationScopeVariables = getIterationScopeVariables(iteratorNames, item, index, items, extraVars());
|
||
let currentKey = generateKeyForIteration(component, templateEl, index, iterationScopeVariables);
|
||
let nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(currentEl.nextElementSibling, currentKey); // If we haven't found a matching key, insert the element at the current position.
|
||
|
||
if (!nextEl) {
|
||
nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl); // And transition it in if it's not the first page load.
|
||
|
||
transitionIn(nextEl, () => {}, () => {}, component, initialUpdate);
|
||
nextEl.__x_for = iterationScopeVariables;
|
||
component.initializeElements(nextEl, () => nextEl.__x_for); // Otherwise update the element we found.
|
||
} else {
|
||
// Temporarily remove the key indicator to allow the normal "updateElements" to work.
|
||
delete nextEl.__x_for_key;
|
||
nextEl.__x_for = iterationScopeVariables;
|
||
component.updateElements(nextEl, () => nextEl.__x_for);
|
||
}
|
||
|
||
currentEl = nextEl;
|
||
currentEl.__x_for_key = currentKey;
|
||
});
|
||
removeAnyLeftOverElementsFromPreviousUpdate(currentEl, component);
|
||
} // This was taken from VueJS 2.* core. Thanks Vue!
|
||
|
||
function parseForExpression(expression) {
|
||
let forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
|
||
let stripParensRE = /^\(|\)$/g;
|
||
let forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
|
||
let inMatch = String(expression).match(forAliasRE);
|
||
if (!inMatch) return;
|
||
let res = {};
|
||
res.items = inMatch[2].trim();
|
||
let item = inMatch[1].trim().replace(stripParensRE, '');
|
||
let iteratorMatch = item.match(forIteratorRE);
|
||
|
||
if (iteratorMatch) {
|
||
res.item = item.replace(forIteratorRE, '').trim();
|
||
res.index = iteratorMatch[1].trim();
|
||
|
||
if (iteratorMatch[2]) {
|
||
res.collection = iteratorMatch[2].trim();
|
||
}
|
||
} else {
|
||
res.item = item;
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
function getIterationScopeVariables(iteratorNames, item, index, items, extraVars) {
|
||
// We must create a new object, so each iteration has a new scope
|
||
let scopeVariables = extraVars ? _objectSpread2({}, extraVars) : {};
|
||
scopeVariables[iteratorNames.item] = item;
|
||
if (iteratorNames.index) scopeVariables[iteratorNames.index] = index;
|
||
if (iteratorNames.collection) scopeVariables[iteratorNames.collection] = items;
|
||
return scopeVariables;
|
||
}
|
||
|
||
function generateKeyForIteration(component, el, index, iterationScopeVariables) {
|
||
let bindKeyAttribute = getXAttrs(el, component, 'bind').filter(attr => attr.value === 'key')[0]; // If the dev hasn't specified a key, just return the index of the iteration.
|
||
|
||
if (!bindKeyAttribute) return index;
|
||
return component.evaluateReturnExpression(el, bindKeyAttribute.expression, () => iterationScopeVariables);
|
||
}
|
||
|
||
function evaluateItemsAndReturnEmptyIfXIfIsPresentAndFalseOnElement(component, el, iteratorNames, extraVars) {
|
||
let ifAttribute = getXAttrs(el, component, 'if')[0];
|
||
|
||
if (ifAttribute && !component.evaluateReturnExpression(el, ifAttribute.expression)) {
|
||
return [];
|
||
}
|
||
|
||
let items = component.evaluateReturnExpression(el, iteratorNames.items, extraVars); // This adds support for the `i in n` syntax.
|
||
|
||
if (isNumeric(items) && items >= 0) {
|
||
items = Array.from(Array(items).keys(), i => i + 1);
|
||
}
|
||
|
||
return items;
|
||
}
|
||
|
||
function addElementInLoopAfterCurrentEl(templateEl, currentEl) {
|
||
let clone = document.importNode(templateEl.content, true);
|
||
currentEl.parentElement.insertBefore(clone, currentEl.nextElementSibling);
|
||
return currentEl.nextElementSibling;
|
||
}
|
||
|
||
function lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey) {
|
||
if (!nextEl) return; // If we are already past the x-for generated elements, we don't need to look ahead.
|
||
|
||
if (nextEl.__x_for_key === undefined) return; // If the the key's DO match, no need to look ahead.
|
||
|
||
if (nextEl.__x_for_key === currentKey) return nextEl; // If they don't, we'll look ahead for a match.
|
||
// If we find it, we'll move it to the current position in the loop.
|
||
|
||
let tmpNextEl = nextEl;
|
||
|
||
while (tmpNextEl) {
|
||
if (tmpNextEl.__x_for_key === currentKey) {
|
||
return tmpNextEl.parentElement.insertBefore(tmpNextEl, nextEl);
|
||
}
|
||
|
||
tmpNextEl = tmpNextEl.nextElementSibling && tmpNextEl.nextElementSibling.__x_for_key !== undefined ? tmpNextEl.nextElementSibling : false;
|
||
}
|
||
}
|
||
|
||
function removeAnyLeftOverElementsFromPreviousUpdate(currentEl, component) {
|
||
var nextElementFromOldLoop = currentEl.nextElementSibling && currentEl.nextElementSibling.__x_for_key !== undefined ? currentEl.nextElementSibling : false;
|
||
|
||
while (nextElementFromOldLoop) {
|
||
let nextElementFromOldLoopImmutable = nextElementFromOldLoop;
|
||
let nextSibling = nextElementFromOldLoop.nextElementSibling;
|
||
transitionOut(nextElementFromOldLoop, () => {
|
||
nextElementFromOldLoopImmutable.remove();
|
||
}, () => {}, component);
|
||
nextElementFromOldLoop = nextSibling && nextSibling.__x_for_key !== undefined ? nextSibling : false;
|
||
}
|
||
}
|
||
|
||
function handleAttributeBindingDirective(component, el, attrName, expression, extraVars, attrType, modifiers) {
|
||
var value = component.evaluateReturnExpression(el, expression, extraVars);
|
||
|
||
if (attrName === 'value') {
|
||
if (Alpine.ignoreFocusedForValueBinding && document.activeElement.isSameNode(el)) return; // If nested model key is undefined, set the default value to empty string.
|
||
|
||
if (value === undefined && String(expression).match(/\./)) {
|
||
value = '';
|
||
}
|
||
|
||
if (el.type === 'radio') {
|
||
// Set radio value from x-bind:value, if no "value" attribute exists.
|
||
// If there are any initial state values, radio will have a correct
|
||
// "checked" value since x-bind:value is processed before x-model.
|
||
if (el.attributes.value === undefined && attrType === 'bind') {
|
||
el.value = value;
|
||
} else if (attrType !== 'bind') {
|
||
el.checked = checkedAttrLooseCompare(el.value, value);
|
||
}
|
||
} else if (el.type === 'checkbox') {
|
||
// If we are explicitly binding a string to the :value, set the string,
|
||
// If the value is a boolean, leave it alone, it will be set to "on"
|
||
// automatically.
|
||
if (typeof value !== 'boolean' && ![null, undefined].includes(value) && attrType === 'bind') {
|
||
el.value = String(value);
|
||
} else if (attrType !== 'bind') {
|
||
if (Array.isArray(value)) {
|
||
// I'm purposely not using Array.includes here because it's
|
||
// strict, and because of Numeric/String mis-casting, I
|
||
// want the "includes" to be "fuzzy".
|
||
el.checked = value.some(val => checkedAttrLooseCompare(val, el.value));
|
||
} else {
|
||
el.checked = !!value;
|
||
}
|
||
}
|
||
} else if (el.tagName === 'SELECT') {
|
||
updateSelect(el, value);
|
||
} else {
|
||
if (el.value === value) return;
|
||
el.value = value;
|
||
}
|
||
} else if (attrName === 'class') {
|
||
if (Array.isArray(value)) {
|
||
const originalClasses = el.__x_original_classes || [];
|
||
el.setAttribute('class', arrayUnique(originalClasses.concat(value)).join(' '));
|
||
} else if (typeof value === 'object') {
|
||
// Sorting the keys / class names by their boolean value will ensure that
|
||
// anything that evaluates to `false` and needs to remove classes is run first.
|
||
const keysSortedByBooleanValue = Object.keys(value).sort((a, b) => value[a] - value[b]);
|
||
keysSortedByBooleanValue.forEach(classNames => {
|
||
if (value[classNames]) {
|
||
convertClassStringToArray(classNames).forEach(className => el.classList.add(className));
|
||
} else {
|
||
convertClassStringToArray(classNames).forEach(className => el.classList.remove(className));
|
||
}
|
||
});
|
||
} else {
|
||
const originalClasses = el.__x_original_classes || [];
|
||
const newClasses = value ? convertClassStringToArray(value) : [];
|
||
el.setAttribute('class', arrayUnique(originalClasses.concat(newClasses)).join(' '));
|
||
}
|
||
} else {
|
||
attrName = modifiers.includes('camel') ? camelCase(attrName) : attrName; // If an attribute's bound value is null, undefined or false, remove the attribute
|
||
|
||
if ([null, undefined, false].includes(value)) {
|
||
el.removeAttribute(attrName);
|
||
} else {
|
||
isBooleanAttr(attrName) ? setIfChanged(el, attrName, attrName) : setIfChanged(el, attrName, value);
|
||
}
|
||
}
|
||
}
|
||
|
||
function setIfChanged(el, attrName, value) {
|
||
if (el.getAttribute(attrName) != value) {
|
||
el.setAttribute(attrName, value);
|
||
}
|
||
}
|
||
|
||
function updateSelect(el, value) {
|
||
const arrayWrappedValue = [].concat(value).map(value => {
|
||
return value + '';
|
||
});
|
||
Array.from(el.options).forEach(option => {
|
||
option.selected = arrayWrappedValue.includes(option.value || option.text);
|
||
});
|
||
}
|
||
|
||
function handleTextDirective(el, output, expression) {
|
||
// If nested model key is undefined, set the default value to empty string.
|
||
if (output === undefined && String(expression).match(/\./)) {
|
||
output = '';
|
||
}
|
||
|
||
el.textContent = output;
|
||
}
|
||
|
||
function handleHtmlDirective(component, el, expression, extraVars) {
|
||
el.innerHTML = component.evaluateReturnExpression(el, expression, extraVars);
|
||
}
|
||
|
||
function handleShowDirective(component, el, value, modifiers, initialUpdate = false) {
|
||
const hide = () => {
|
||
el.style.display = 'none';
|
||
el.__x_is_shown = false;
|
||
};
|
||
|
||
const show = () => {
|
||
if (el.style.length === 1 && el.style.display === 'none') {
|
||
el.removeAttribute('style');
|
||
} else {
|
||
el.style.removeProperty('display');
|
||
}
|
||
|
||
el.__x_is_shown = true;
|
||
};
|
||
|
||
if (initialUpdate === true) {
|
||
if (value) {
|
||
show();
|
||
} else {
|
||
hide();
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
const handle = (resolve, reject) => {
|
||
if (value) {
|
||
if (el.style.display === 'none' || el.__x_transition) {
|
||
transitionIn(el, () => {
|
||
show();
|
||
}, reject, component);
|
||
}
|
||
|
||
resolve(() => {});
|
||
} else {
|
||
if (el.style.display !== 'none') {
|
||
transitionOut(el, () => {
|
||
resolve(() => {
|
||
hide();
|
||
});
|
||
}, reject, component);
|
||
} else {
|
||
resolve(() => {});
|
||
}
|
||
}
|
||
}; // The working of x-show is a bit complex because we need to
|
||
// wait for any child transitions to finish before hiding
|
||
// some element. Also, this has to be done recursively.
|
||
// If x-show.immediate, foregoe the waiting.
|
||
|
||
|
||
if (modifiers.includes('immediate')) {
|
||
handle(finish => finish(), () => {});
|
||
return;
|
||
} // x-show is encountered during a DOM tree walk. If an element
|
||
// we encounter is NOT a child of another x-show element we
|
||
// can execute the previous x-show stack (if one exists).
|
||
|
||
|
||
if (component.showDirectiveLastElement && !component.showDirectiveLastElement.contains(el)) {
|
||
component.executeAndClearRemainingShowDirectiveStack();
|
||
}
|
||
|
||
component.showDirectiveStack.push(handle);
|
||
component.showDirectiveLastElement = el;
|
||
}
|
||
|
||
function handleIfDirective(component, el, expressionResult, initialUpdate, extraVars) {
|
||
warnIfMalformedTemplate(el, 'x-if');
|
||
const elementHasAlreadyBeenAdded = el.nextElementSibling && el.nextElementSibling.__x_inserted_me === true;
|
||
|
||
if (expressionResult && (!elementHasAlreadyBeenAdded || el.__x_transition)) {
|
||
const clone = document.importNode(el.content, true);
|
||
el.parentElement.insertBefore(clone, el.nextElementSibling);
|
||
transitionIn(el.nextElementSibling, () => {}, () => {}, component, initialUpdate);
|
||
component.initializeElements(el.nextElementSibling, extraVars);
|
||
el.nextElementSibling.__x_inserted_me = true;
|
||
} else if (!expressionResult && elementHasAlreadyBeenAdded) {
|
||
transitionOut(el.nextElementSibling, () => {
|
||
el.nextElementSibling.remove();
|
||
}, () => {}, component, initialUpdate);
|
||
}
|
||
}
|
||
|
||
function registerListener(component, el, event, modifiers, expression, extraVars = {}) {
|
||
const options = {
|
||
passive: modifiers.includes('passive')
|
||
};
|
||
|
||
if (modifiers.includes('camel')) {
|
||
event = camelCase(event);
|
||
}
|
||
|
||
let handler, listenerTarget;
|
||
|
||
if (modifiers.includes('away')) {
|
||
listenerTarget = document;
|
||
|
||
handler = e => {
|
||
// Don't do anything if the click came from the element or within it.
|
||
if (el.contains(e.target)) return; // Don't do anything if this element isn't currently visible.
|
||
|
||
if (el.offsetWidth < 1 && el.offsetHeight < 1) return; // Now that we are sure the element is visible, AND the click
|
||
// is from outside it, let's run the expression.
|
||
|
||
runListenerHandler(component, expression, e, extraVars);
|
||
|
||
if (modifiers.includes('once')) {
|
||
document.removeEventListener(event, handler, options);
|
||
}
|
||
};
|
||
} else {
|
||
listenerTarget = modifiers.includes('window') ? window : modifiers.includes('document') ? document : el;
|
||
|
||
handler = e => {
|
||
// Remove this global event handler if the element that declared it
|
||
// has been removed. It's now stale.
|
||
if (listenerTarget === window || listenerTarget === document) {
|
||
if (!document.body.contains(el)) {
|
||
listenerTarget.removeEventListener(event, handler, options);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (isKeyEvent(event)) {
|
||
if (isListeningForASpecificKeyThatHasntBeenPressed(e, modifiers)) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (modifiers.includes('prevent')) e.preventDefault();
|
||
if (modifiers.includes('stop')) e.stopPropagation(); // If the .self modifier isn't present, or if it is present and
|
||
// the target element matches the element we are registering the
|
||
// event on, run the handler
|
||
|
||
if (!modifiers.includes('self') || e.target === el) {
|
||
const returnValue = runListenerHandler(component, expression, e, extraVars);
|
||
returnValue.then(value => {
|
||
if (value === false) {
|
||
e.preventDefault();
|
||
} else {
|
||
if (modifiers.includes('once')) {
|
||
listenerTarget.removeEventListener(event, handler, options);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
};
|
||
}
|
||
|
||
if (modifiers.includes('debounce')) {
|
||
let nextModifier = modifiers[modifiers.indexOf('debounce') + 1] || 'invalid-wait';
|
||
let wait = isNumeric(nextModifier.split('ms')[0]) ? Number(nextModifier.split('ms')[0]) : 250;
|
||
handler = debounce(handler, wait);
|
||
}
|
||
|
||
listenerTarget.addEventListener(event, handler, options);
|
||
}
|
||
|
||
function runListenerHandler(component, expression, e, extraVars) {
|
||
return component.evaluateCommandExpression(e.target, expression, () => {
|
||
return _objectSpread2(_objectSpread2({}, extraVars()), {}, {
|
||
'$event': e
|
||
});
|
||
});
|
||
}
|
||
|
||
function isKeyEvent(event) {
|
||
return ['keydown', 'keyup'].includes(event);
|
||
}
|
||
|
||
function isListeningForASpecificKeyThatHasntBeenPressed(e, modifiers) {
|
||
let keyModifiers = modifiers.filter(i => {
|
||
return !['window', 'document', 'prevent', 'stop'].includes(i);
|
||
});
|
||
|
||
if (keyModifiers.includes('debounce')) {
|
||
let debounceIndex = keyModifiers.indexOf('debounce');
|
||
keyModifiers.splice(debounceIndex, isNumeric((keyModifiers[debounceIndex + 1] || 'invalid-wait').split('ms')[0]) ? 2 : 1);
|
||
} // If no modifier is specified, we'll call it a press.
|
||
|
||
|
||
if (keyModifiers.length === 0) return false; // If one is passed, AND it matches the key pressed, we'll call it a press.
|
||
|
||
if (keyModifiers.length === 1 && keyModifiers[0] === keyToModifier(e.key)) return false; // The user is listening for key combinations.
|
||
|
||
const systemKeyModifiers = ['ctrl', 'shift', 'alt', 'meta', 'cmd', 'super'];
|
||
const selectedSystemKeyModifiers = systemKeyModifiers.filter(modifier => keyModifiers.includes(modifier));
|
||
keyModifiers = keyModifiers.filter(i => !selectedSystemKeyModifiers.includes(i));
|
||
|
||
if (selectedSystemKeyModifiers.length > 0) {
|
||
const activelyPressedKeyModifiers = selectedSystemKeyModifiers.filter(modifier => {
|
||
// Alias "cmd" and "super" to "meta"
|
||
if (modifier === 'cmd' || modifier === 'super') modifier = 'meta';
|
||
return e[`${modifier}Key`];
|
||
}); // If all the modifiers selected are pressed, ...
|
||
|
||
if (activelyPressedKeyModifiers.length === selectedSystemKeyModifiers.length) {
|
||
// AND the remaining key is pressed as well. It's a press.
|
||
if (keyModifiers[0] === keyToModifier(e.key)) return false;
|
||
}
|
||
} // We'll call it NOT a valid keypress.
|
||
|
||
|
||
return true;
|
||
}
|
||
|
||
function keyToModifier(key) {
|
||
switch (key) {
|
||
case '/':
|
||
return 'slash';
|
||
|
||
case ' ':
|
||
case 'Spacebar':
|
||
return 'space';
|
||
|
||
default:
|
||
return key && kebabCase(key);
|
||
}
|
||
}
|
||
|
||
function registerModelListener(component, el, modifiers, expression, extraVars) {
|
||
// If the element we are binding to is a select, a radio, or checkbox
|
||
// we'll listen for the change event instead of the "input" event.
|
||
var event = el.tagName.toLowerCase() === 'select' || ['checkbox', 'radio'].includes(el.type) || modifiers.includes('lazy') ? 'change' : 'input';
|
||
const listenerExpression = `${expression} = rightSideOfExpression($event, ${expression})`;
|
||
registerListener(component, el, event, modifiers, listenerExpression, () => {
|
||
return _objectSpread2(_objectSpread2({}, extraVars()), {}, {
|
||
rightSideOfExpression: generateModelAssignmentFunction(el, modifiers, expression)
|
||
});
|
||
});
|
||
}
|
||
|
||
function generateModelAssignmentFunction(el, modifiers, expression) {
|
||
if (el.type === 'radio') {
|
||
// Radio buttons only work properly when they share a name attribute.
|
||
// People might assume we take care of that for them, because
|
||
// they already set a shared "x-model" attribute.
|
||
if (!el.hasAttribute('name')) el.setAttribute('name', expression);
|
||
}
|
||
|
||
return (event, currentValue) => {
|
||
// Check for event.detail due to an issue where IE11 handles other events as a CustomEvent.
|
||
if (event instanceof CustomEvent && event.detail) {
|
||
return event.detail;
|
||
} else if (el.type === 'checkbox') {
|
||
// If the data we are binding to is an array, toggle its value inside the array.
|
||
if (Array.isArray(currentValue)) {
|
||
const newValue = modifiers.includes('number') ? safeParseNumber(event.target.value) : event.target.value;
|
||
return event.target.checked ? currentValue.concat([newValue]) : currentValue.filter(el => !checkedAttrLooseCompare(el, newValue));
|
||
} else {
|
||
return event.target.checked;
|
||
}
|
||
} else if (el.tagName.toLowerCase() === 'select' && el.multiple) {
|
||
return modifiers.includes('number') ? Array.from(event.target.selectedOptions).map(option => {
|
||
const rawValue = option.value || option.text;
|
||
return safeParseNumber(rawValue);
|
||
}) : Array.from(event.target.selectedOptions).map(option => {
|
||
return option.value || option.text;
|
||
});
|
||
} else {
|
||
const rawValue = event.target.value;
|
||
return modifiers.includes('number') ? safeParseNumber(rawValue) : modifiers.includes('trim') ? rawValue.trim() : rawValue;
|
||
}
|
||
};
|
||
}
|
||
|
||
function safeParseNumber(rawValue) {
|
||
const number = rawValue ? parseFloat(rawValue) : null;
|
||
return isNumeric(number) ? number : rawValue;
|
||
}
|
||
|
||
/**
|
||
* Copyright (C) 2017 salesforce.com, inc.
|
||
*/
|
||
const { isArray } = Array;
|
||
const { getPrototypeOf, create: ObjectCreate, defineProperty: ObjectDefineProperty, defineProperties: ObjectDefineProperties, isExtensible, getOwnPropertyDescriptor, getOwnPropertyNames, getOwnPropertySymbols, preventExtensions, hasOwnProperty, } = Object;
|
||
const { push: ArrayPush, concat: ArrayConcat, map: ArrayMap, } = Array.prototype;
|
||
function isUndefined(obj) {
|
||
return obj === undefined;
|
||
}
|
||
function isFunction(obj) {
|
||
return typeof obj === 'function';
|
||
}
|
||
function isObject(obj) {
|
||
return typeof obj === 'object';
|
||
}
|
||
const proxyToValueMap = new WeakMap();
|
||
function registerProxy(proxy, value) {
|
||
proxyToValueMap.set(proxy, value);
|
||
}
|
||
const unwrap = (replicaOrAny) => proxyToValueMap.get(replicaOrAny) || replicaOrAny;
|
||
|
||
function wrapValue(membrane, value) {
|
||
return membrane.valueIsObservable(value) ? membrane.getProxy(value) : value;
|
||
}
|
||
/**
|
||
* Unwrap property descriptors will set value on original descriptor
|
||
* We only need to unwrap if value is specified
|
||
* @param descriptor external descrpitor provided to define new property on original value
|
||
*/
|
||
function unwrapDescriptor(descriptor) {
|
||
if (hasOwnProperty.call(descriptor, 'value')) {
|
||
descriptor.value = unwrap(descriptor.value);
|
||
}
|
||
return descriptor;
|
||
}
|
||
function lockShadowTarget(membrane, shadowTarget, originalTarget) {
|
||
const targetKeys = ArrayConcat.call(getOwnPropertyNames(originalTarget), getOwnPropertySymbols(originalTarget));
|
||
targetKeys.forEach((key) => {
|
||
let descriptor = getOwnPropertyDescriptor(originalTarget, key);
|
||
// We do not need to wrap the descriptor if configurable
|
||
// Because we can deal with wrapping it when user goes through
|
||
// Get own property descriptor. There is also a chance that this descriptor
|
||
// could change sometime in the future, so we can defer wrapping
|
||
// until we need to
|
||
if (!descriptor.configurable) {
|
||
descriptor = wrapDescriptor(membrane, descriptor, wrapValue);
|
||
}
|
||
ObjectDefineProperty(shadowTarget, key, descriptor);
|
||
});
|
||
preventExtensions(shadowTarget);
|
||
}
|
||
class ReactiveProxyHandler {
|
||
constructor(membrane, value) {
|
||
this.originalTarget = value;
|
||
this.membrane = membrane;
|
||
}
|
||
get(shadowTarget, key) {
|
||
const { originalTarget, membrane } = this;
|
||
const value = originalTarget[key];
|
||
const { valueObserved } = membrane;
|
||
valueObserved(originalTarget, key);
|
||
return membrane.getProxy(value);
|
||
}
|
||
set(shadowTarget, key, value) {
|
||
const { originalTarget, membrane: { valueMutated } } = this;
|
||
const oldValue = originalTarget[key];
|
||
if (oldValue !== value) {
|
||
originalTarget[key] = value;
|
||
valueMutated(originalTarget, key);
|
||
}
|
||
else if (key === 'length' && isArray(originalTarget)) {
|
||
// fix for issue #236: push will add the new index, and by the time length
|
||
// is updated, the internal length is already equal to the new length value
|
||
// therefore, the oldValue is equal to the value. This is the forking logic
|
||
// to support this use case.
|
||
valueMutated(originalTarget, key);
|
||
}
|
||
return true;
|
||
}
|
||
deleteProperty(shadowTarget, key) {
|
||
const { originalTarget, membrane: { valueMutated } } = this;
|
||
delete originalTarget[key];
|
||
valueMutated(originalTarget, key);
|
||
return true;
|
||
}
|
||
apply(shadowTarget, thisArg, argArray) {
|
||
/* No op */
|
||
}
|
||
construct(target, argArray, newTarget) {
|
||
/* No op */
|
||
}
|
||
has(shadowTarget, key) {
|
||
const { originalTarget, membrane: { valueObserved } } = this;
|
||
valueObserved(originalTarget, key);
|
||
return key in originalTarget;
|
||
}
|
||
ownKeys(shadowTarget) {
|
||
const { originalTarget } = this;
|
||
return ArrayConcat.call(getOwnPropertyNames(originalTarget), getOwnPropertySymbols(originalTarget));
|
||
}
|
||
isExtensible(shadowTarget) {
|
||
const shadowIsExtensible = isExtensible(shadowTarget);
|
||
if (!shadowIsExtensible) {
|
||
return shadowIsExtensible;
|
||
}
|
||
const { originalTarget, membrane } = this;
|
||
const targetIsExtensible = isExtensible(originalTarget);
|
||
if (!targetIsExtensible) {
|
||
lockShadowTarget(membrane, shadowTarget, originalTarget);
|
||
}
|
||
return targetIsExtensible;
|
||
}
|
||
setPrototypeOf(shadowTarget, prototype) {
|
||
}
|
||
getPrototypeOf(shadowTarget) {
|
||
const { originalTarget } = this;
|
||
return getPrototypeOf(originalTarget);
|
||
}
|
||
getOwnPropertyDescriptor(shadowTarget, key) {
|
||
const { originalTarget, membrane } = this;
|
||
const { valueObserved } = this.membrane;
|
||
// keys looked up via hasOwnProperty need to be reactive
|
||
valueObserved(originalTarget, key);
|
||
let desc = getOwnPropertyDescriptor(originalTarget, key);
|
||
if (isUndefined(desc)) {
|
||
return desc;
|
||
}
|
||
const shadowDescriptor = getOwnPropertyDescriptor(shadowTarget, key);
|
||
if (!isUndefined(shadowDescriptor)) {
|
||
return shadowDescriptor;
|
||
}
|
||
// Note: by accessing the descriptor, the key is marked as observed
|
||
// but access to the value, setter or getter (if available) cannot observe
|
||
// mutations, just like regular methods, in which case we just do nothing.
|
||
desc = wrapDescriptor(membrane, desc, wrapValue);
|
||
if (!desc.configurable) {
|
||
// If descriptor from original target is not configurable,
|
||
// We must copy the wrapped descriptor over to the shadow target.
|
||
// Otherwise, proxy will throw an invariant error.
|
||
// This is our last chance to lock the value.
|
||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/getOwnPropertyDescriptor#Invariants
|
||
ObjectDefineProperty(shadowTarget, key, desc);
|
||
}
|
||
return desc;
|
||
}
|
||
preventExtensions(shadowTarget) {
|
||
const { originalTarget, membrane } = this;
|
||
lockShadowTarget(membrane, shadowTarget, originalTarget);
|
||
preventExtensions(originalTarget);
|
||
return true;
|
||
}
|
||
defineProperty(shadowTarget, key, descriptor) {
|
||
const { originalTarget, membrane } = this;
|
||
const { valueMutated } = membrane;
|
||
const { configurable } = descriptor;
|
||
// We have to check for value in descriptor
|
||
// because Object.freeze(proxy) calls this method
|
||
// with only { configurable: false, writeable: false }
|
||
// Additionally, method will only be called with writeable:false
|
||
// if the descriptor has a value, as opposed to getter/setter
|
||
// So we can just check if writable is present and then see if
|
||
// value is present. This eliminates getter and setter descriptors
|
||
if (hasOwnProperty.call(descriptor, 'writable') && !hasOwnProperty.call(descriptor, 'value')) {
|
||
const originalDescriptor = getOwnPropertyDescriptor(originalTarget, key);
|
||
descriptor.value = originalDescriptor.value;
|
||
}
|
||
ObjectDefineProperty(originalTarget, key, unwrapDescriptor(descriptor));
|
||
if (configurable === false) {
|
||
ObjectDefineProperty(shadowTarget, key, wrapDescriptor(membrane, descriptor, wrapValue));
|
||
}
|
||
valueMutated(originalTarget, key);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
function wrapReadOnlyValue(membrane, value) {
|
||
return membrane.valueIsObservable(value) ? membrane.getReadOnlyProxy(value) : value;
|
||
}
|
||
class ReadOnlyHandler {
|
||
constructor(membrane, value) {
|
||
this.originalTarget = value;
|
||
this.membrane = membrane;
|
||
}
|
||
get(shadowTarget, key) {
|
||
const { membrane, originalTarget } = this;
|
||
const value = originalTarget[key];
|
||
const { valueObserved } = membrane;
|
||
valueObserved(originalTarget, key);
|
||
return membrane.getReadOnlyProxy(value);
|
||
}
|
||
set(shadowTarget, key, value) {
|
||
return false;
|
||
}
|
||
deleteProperty(shadowTarget, key) {
|
||
return false;
|
||
}
|
||
apply(shadowTarget, thisArg, argArray) {
|
||
/* No op */
|
||
}
|
||
construct(target, argArray, newTarget) {
|
||
/* No op */
|
||
}
|
||
has(shadowTarget, key) {
|
||
const { originalTarget, membrane: { valueObserved } } = this;
|
||
valueObserved(originalTarget, key);
|
||
return key in originalTarget;
|
||
}
|
||
ownKeys(shadowTarget) {
|
||
const { originalTarget } = this;
|
||
return ArrayConcat.call(getOwnPropertyNames(originalTarget), getOwnPropertySymbols(originalTarget));
|
||
}
|
||
setPrototypeOf(shadowTarget, prototype) {
|
||
}
|
||
getOwnPropertyDescriptor(shadowTarget, key) {
|
||
const { originalTarget, membrane } = this;
|
||
const { valueObserved } = membrane;
|
||
// keys looked up via hasOwnProperty need to be reactive
|
||
valueObserved(originalTarget, key);
|
||
let desc = getOwnPropertyDescriptor(originalTarget, key);
|
||
if (isUndefined(desc)) {
|
||
return desc;
|
||
}
|
||
const shadowDescriptor = getOwnPropertyDescriptor(shadowTarget, key);
|
||
if (!isUndefined(shadowDescriptor)) {
|
||
return shadowDescriptor;
|
||
}
|
||
// Note: by accessing the descriptor, the key is marked as observed
|
||
// but access to the value or getter (if available) cannot be observed,
|
||
// just like regular methods, in which case we just do nothing.
|
||
desc = wrapDescriptor(membrane, desc, wrapReadOnlyValue);
|
||
if (hasOwnProperty.call(desc, 'set')) {
|
||
desc.set = undefined; // readOnly membrane does not allow setters
|
||
}
|
||
if (!desc.configurable) {
|
||
// If descriptor from original target is not configurable,
|
||
// We must copy the wrapped descriptor over to the shadow target.
|
||
// Otherwise, proxy will throw an invariant error.
|
||
// This is our last chance to lock the value.
|
||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/getOwnPropertyDescriptor#Invariants
|
||
ObjectDefineProperty(shadowTarget, key, desc);
|
||
}
|
||
return desc;
|
||
}
|
||
preventExtensions(shadowTarget) {
|
||
return false;
|
||
}
|
||
defineProperty(shadowTarget, key, descriptor) {
|
||
return false;
|
||
}
|
||
}
|
||
function createShadowTarget(value) {
|
||
let shadowTarget = undefined;
|
||
if (isArray(value)) {
|
||
shadowTarget = [];
|
||
}
|
||
else if (isObject(value)) {
|
||
shadowTarget = {};
|
||
}
|
||
return shadowTarget;
|
||
}
|
||
const ObjectDotPrototype = Object.prototype;
|
||
function defaultValueIsObservable(value) {
|
||
// intentionally checking for null
|
||
if (value === null) {
|
||
return false;
|
||
}
|
||
// treat all non-object types, including undefined, as non-observable values
|
||
if (typeof value !== 'object') {
|
||
return false;
|
||
}
|
||
if (isArray(value)) {
|
||
return true;
|
||
}
|
||
const proto = getPrototypeOf(value);
|
||
return (proto === ObjectDotPrototype || proto === null || getPrototypeOf(proto) === null);
|
||
}
|
||
const defaultValueObserved = (obj, key) => {
|
||
/* do nothing */
|
||
};
|
||
const defaultValueMutated = (obj, key) => {
|
||
/* do nothing */
|
||
};
|
||
const defaultValueDistortion = (value) => value;
|
||
function wrapDescriptor(membrane, descriptor, getValue) {
|
||
const { set, get } = descriptor;
|
||
if (hasOwnProperty.call(descriptor, 'value')) {
|
||
descriptor.value = getValue(membrane, descriptor.value);
|
||
}
|
||
else {
|
||
if (!isUndefined(get)) {
|
||
descriptor.get = function () {
|
||
// invoking the original getter with the original target
|
||
return getValue(membrane, get.call(unwrap(this)));
|
||
};
|
||
}
|
||
if (!isUndefined(set)) {
|
||
descriptor.set = function (value) {
|
||
// At this point we don't have a clear indication of whether
|
||
// or not a valid mutation will occur, we don't have the key,
|
||
// and we are not sure why and how they are invoking this setter.
|
||
// Nevertheless we preserve the original semantics by invoking the
|
||
// original setter with the original target and the unwrapped value
|
||
set.call(unwrap(this), membrane.unwrapProxy(value));
|
||
};
|
||
}
|
||
}
|
||
return descriptor;
|
||
}
|
||
class ReactiveMembrane {
|
||
constructor(options) {
|
||
this.valueDistortion = defaultValueDistortion;
|
||
this.valueMutated = defaultValueMutated;
|
||
this.valueObserved = defaultValueObserved;
|
||
this.valueIsObservable = defaultValueIsObservable;
|
||
this.objectGraph = new WeakMap();
|
||
if (!isUndefined(options)) {
|
||
const { valueDistortion, valueMutated, valueObserved, valueIsObservable } = options;
|
||
this.valueDistortion = isFunction(valueDistortion) ? valueDistortion : defaultValueDistortion;
|
||
this.valueMutated = isFunction(valueMutated) ? valueMutated : defaultValueMutated;
|
||
this.valueObserved = isFunction(valueObserved) ? valueObserved : defaultValueObserved;
|
||
this.valueIsObservable = isFunction(valueIsObservable) ? valueIsObservable : defaultValueIsObservable;
|
||
}
|
||
}
|
||
getProxy(value) {
|
||
const unwrappedValue = unwrap(value);
|
||
const distorted = this.valueDistortion(unwrappedValue);
|
||
if (this.valueIsObservable(distorted)) {
|
||
const o = this.getReactiveState(unwrappedValue, distorted);
|
||
// when trying to extract the writable version of a readonly
|
||
// we return the readonly.
|
||
return o.readOnly === value ? value : o.reactive;
|
||
}
|
||
return distorted;
|
||
}
|
||
getReadOnlyProxy(value) {
|
||
value = unwrap(value);
|
||
const distorted = this.valueDistortion(value);
|
||
if (this.valueIsObservable(distorted)) {
|
||
return this.getReactiveState(value, distorted).readOnly;
|
||
}
|
||
return distorted;
|
||
}
|
||
unwrapProxy(p) {
|
||
return unwrap(p);
|
||
}
|
||
getReactiveState(value, distortedValue) {
|
||
const { objectGraph, } = this;
|
||
let reactiveState = objectGraph.get(distortedValue);
|
||
if (reactiveState) {
|
||
return reactiveState;
|
||
}
|
||
const membrane = this;
|
||
reactiveState = {
|
||
get reactive() {
|
||
const reactiveHandler = new ReactiveProxyHandler(membrane, distortedValue);
|
||
// caching the reactive proxy after the first time it is accessed
|
||
const proxy = new Proxy(createShadowTarget(distortedValue), reactiveHandler);
|
||
registerProxy(proxy, value);
|
||
ObjectDefineProperty(this, 'reactive', { value: proxy });
|
||
return proxy;
|
||
},
|
||
get readOnly() {
|
||
const readOnlyHandler = new ReadOnlyHandler(membrane, distortedValue);
|
||
// caching the readOnly proxy after the first time it is accessed
|
||
const proxy = new Proxy(createShadowTarget(distortedValue), readOnlyHandler);
|
||
registerProxy(proxy, value);
|
||
ObjectDefineProperty(this, 'readOnly', { value: proxy });
|
||
return proxy;
|
||
}
|
||
};
|
||
objectGraph.set(distortedValue, reactiveState);
|
||
return reactiveState;
|
||
}
|
||
}
|
||
/** version: 0.26.0 */
|
||
|
||
function wrap(data, mutationCallback) {
|
||
|
||
let membrane = new ReactiveMembrane({
|
||
valueMutated(target, key) {
|
||
mutationCallback(target, key);
|
||
}
|
||
|
||
});
|
||
return {
|
||
data: membrane.getProxy(data),
|
||
membrane: membrane
|
||
};
|
||
}
|
||
function unwrap$1(membrane, observable) {
|
||
let unwrappedData = membrane.unwrapProxy(observable);
|
||
let copy = {};
|
||
Object.keys(unwrappedData).forEach(key => {
|
||
if (['$el', '$refs', '$nextTick', '$watch'].includes(key)) return;
|
||
copy[key] = unwrappedData[key];
|
||
});
|
||
return copy;
|
||
}
|
||
|
||
class Component {
|
||
constructor(el, componentForClone = null) {
|
||
this.$el = el;
|
||
const dataAttr = this.$el.getAttribute('x-data');
|
||
const dataExpression = dataAttr === '' ? '{}' : dataAttr;
|
||
const initExpression = this.$el.getAttribute('x-init');
|
||
let dataExtras = {
|
||
$el: this.$el
|
||
};
|
||
let canonicalComponentElementReference = componentForClone ? componentForClone.$el : this.$el;
|
||
Object.entries(Alpine.magicProperties).forEach(([name, callback]) => {
|
||
Object.defineProperty(dataExtras, `$${name}`, {
|
||
get: function get() {
|
||
return callback(canonicalComponentElementReference);
|
||
}
|
||
});
|
||
});
|
||
this.unobservedData = componentForClone ? componentForClone.getUnobservedData() : saferEval(el, dataExpression, dataExtras);
|
||
// Construct a Proxy-based observable. This will be used to handle reactivity.
|
||
|
||
let {
|
||
membrane,
|
||
data
|
||
} = this.wrapDataInObservable(this.unobservedData);
|
||
this.$data = data;
|
||
this.membrane = membrane; // After making user-supplied data methods reactive, we can now add
|
||
// our magic properties to the original data for access.
|
||
|
||
this.unobservedData.$el = this.$el;
|
||
this.unobservedData.$refs = this.getRefsProxy();
|
||
this.nextTickStack = [];
|
||
|
||
this.unobservedData.$nextTick = callback => {
|
||
this.nextTickStack.push(callback);
|
||
};
|
||
|
||
this.watchers = {};
|
||
|
||
this.unobservedData.$watch = (property, callback) => {
|
||
if (!this.watchers[property]) this.watchers[property] = [];
|
||
this.watchers[property].push(callback);
|
||
};
|
||
/* MODERN-ONLY:START */
|
||
// We remove this piece of code from the legacy build.
|
||
// In IE11, we have already defined our helpers at this point.
|
||
// Register custom magic properties.
|
||
|
||
|
||
Object.entries(Alpine.magicProperties).forEach(([name, callback]) => {
|
||
Object.defineProperty(this.unobservedData, `$${name}`, {
|
||
get: function get() {
|
||
return callback(canonicalComponentElementReference, this.$el);
|
||
}
|
||
});
|
||
});
|
||
/* MODERN-ONLY:END */
|
||
|
||
this.showDirectiveStack = [];
|
||
this.showDirectiveLastElement;
|
||
componentForClone || Alpine.onBeforeComponentInitializeds.forEach(callback => callback(this));
|
||
var initReturnedCallback; // If x-init is present AND we aren't cloning (skip x-init on clone)
|
||
|
||
if (initExpression && !componentForClone) {
|
||
// We want to allow data manipulation, but not trigger DOM updates just yet.
|
||
// We haven't even initialized the elements with their Alpine bindings. I mean c'mon.
|
||
this.pauseReactivity = true;
|
||
initReturnedCallback = this.evaluateReturnExpression(this.$el, initExpression);
|
||
this.pauseReactivity = false;
|
||
} // Register all our listeners and set all our attribute bindings.
|
||
// If we're cloning a component, the third parameter ensures no duplicate
|
||
// event listeners are registered (the mutation observer will take care of them)
|
||
|
||
|
||
this.initializeElements(this.$el, () => {}, componentForClone); // Use mutation observer to detect new elements being added within this component at run-time.
|
||
// Alpine's just so darn flexible amirite?
|
||
|
||
this.listenForNewElementsToInitialize();
|
||
|
||
if (typeof initReturnedCallback === 'function') {
|
||
// Run the callback returned from the "x-init" hook to allow the user to do stuff after
|
||
// Alpine's got it's grubby little paws all over everything.
|
||
initReturnedCallback.call(this.$data);
|
||
}
|
||
|
||
componentForClone || setTimeout(() => {
|
||
Alpine.onComponentInitializeds.forEach(callback => callback(this));
|
||
}, 0);
|
||
}
|
||
|
||
getUnobservedData() {
|
||
return unwrap$1(this.membrane, this.$data);
|
||
}
|
||
|
||
wrapDataInObservable(data) {
|
||
var self = this;
|
||
let updateDom = debounce(function () {
|
||
self.updateElements(self.$el);
|
||
}, 0);
|
||
return wrap(data, (target, key) => {
|
||
if (self.watchers[key]) {
|
||
// If there's a watcher for this specific key, run it.
|
||
self.watchers[key].forEach(callback => callback(target[key]));
|
||
} else if (Array.isArray(target)) {
|
||
// Arrays are special cases, if any of the items change, we consider the array as mutated.
|
||
Object.keys(self.watchers).forEach(fullDotNotationKey => {
|
||
let dotNotationParts = fullDotNotationKey.split('.'); // Ignore length mutations since they would result in duplicate calls.
|
||
// For example, when calling push, we would get a mutation for the item's key
|
||
// and a second mutation for the length property.
|
||
|
||
if (key === 'length') return;
|
||
dotNotationParts.reduce((comparisonData, part) => {
|
||
if (Object.is(target, comparisonData[part])) {
|
||
self.watchers[fullDotNotationKey].forEach(callback => callback(target));
|
||
}
|
||
|
||
return comparisonData[part];
|
||
}, self.unobservedData);
|
||
});
|
||
} else {
|
||
// Let's walk through the watchers with "dot-notation" (foo.bar) and see
|
||
// if this mutation fits any of them.
|
||
Object.keys(self.watchers).filter(i => i.includes('.')).forEach(fullDotNotationKey => {
|
||
let dotNotationParts = fullDotNotationKey.split('.'); // If this dot-notation watcher's last "part" doesn't match the current
|
||
// key, then skip it early for performance reasons.
|
||
|
||
if (key !== dotNotationParts[dotNotationParts.length - 1]) return; // Now, walk through the dot-notation "parts" recursively to find
|
||
// a match, and call the watcher if one's found.
|
||
|
||
dotNotationParts.reduce((comparisonData, part) => {
|
||
if (Object.is(target, comparisonData)) {
|
||
// Run the watchers.
|
||
self.watchers[fullDotNotationKey].forEach(callback => callback(target[key]));
|
||
}
|
||
|
||
return comparisonData[part];
|
||
}, self.unobservedData);
|
||
});
|
||
} // Don't react to data changes for cases like the `x-created` hook.
|
||
|
||
|
||
if (self.pauseReactivity) return;
|
||
updateDom();
|
||
});
|
||
}
|
||
|
||
walkAndSkipNestedComponents(el, callback, initializeComponentCallback = () => {}) {
|
||
walk(el, el => {
|
||
// We've hit a component.
|
||
if (el.hasAttribute('x-data')) {
|
||
// If it's not the current one.
|
||
if (!el.isSameNode(this.$el)) {
|
||
// Initialize it if it's not.
|
||
if (!el.__x) initializeComponentCallback(el); // Now we'll let that sub-component deal with itself.
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return callback(el);
|
||
});
|
||
}
|
||
|
||
initializeElements(rootEl, extraVars = () => {}, componentForClone = false) {
|
||
this.walkAndSkipNestedComponents(rootEl, el => {
|
||
// Don't touch spawns from for loop
|
||
if (el.__x_for_key !== undefined) return false; // Don't touch spawns from if directives
|
||
|
||
if (el.__x_inserted_me !== undefined) return false;
|
||
this.initializeElement(el, extraVars, componentForClone ? false : true);
|
||
}, el => {
|
||
if (!componentForClone) el.__x = new Component(el);
|
||
});
|
||
this.executeAndClearRemainingShowDirectiveStack();
|
||
this.executeAndClearNextTickStack(rootEl);
|
||
}
|
||
|
||
initializeElement(el, extraVars, shouldRegisterListeners = true) {
|
||
// To support class attribute merging, we have to know what the element's
|
||
// original class attribute looked like for reference.
|
||
if (el.hasAttribute('class') && getXAttrs(el, this).length > 0) {
|
||
el.__x_original_classes = convertClassStringToArray(el.getAttribute('class'));
|
||
}
|
||
|
||
shouldRegisterListeners && this.registerListeners(el, extraVars);
|
||
this.resolveBoundAttributes(el, true, extraVars);
|
||
}
|
||
|
||
updateElements(rootEl, extraVars = () => {}) {
|
||
this.walkAndSkipNestedComponents(rootEl, el => {
|
||
// Don't touch spawns from for loop (and check if the root is actually a for loop in a parent, don't skip it.)
|
||
if (el.__x_for_key !== undefined && !el.isSameNode(this.$el)) return false;
|
||
this.updateElement(el, extraVars);
|
||
}, el => {
|
||
el.__x = new Component(el);
|
||
});
|
||
this.executeAndClearRemainingShowDirectiveStack();
|
||
this.executeAndClearNextTickStack(rootEl);
|
||
}
|
||
|
||
executeAndClearNextTickStack(el) {
|
||
// Skip spawns from alpine directives
|
||
if (el === this.$el && this.nextTickStack.length > 0) {
|
||
// We run the tick stack after the next frame to allow any
|
||
// running transitions to pass the initial show stage.
|
||
requestAnimationFrame(() => {
|
||
while (this.nextTickStack.length > 0) {
|
||
this.nextTickStack.shift()();
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
executeAndClearRemainingShowDirectiveStack() {
|
||
// The goal here is to start all the x-show transitions
|
||
// and build a nested promise chain so that elements
|
||
// only hide when the children are finished hiding.
|
||
this.showDirectiveStack.reverse().map(handler => {
|
||
return new Promise((resolve, reject) => {
|
||
handler(resolve, reject);
|
||
});
|
||
}).reduce((promiseChain, promise) => {
|
||
return promiseChain.then(() => {
|
||
return promise.then(finishElement => {
|
||
finishElement();
|
||
});
|
||
});
|
||
}, Promise.resolve(() => {})).catch(e => {
|
||
if (e !== TRANSITION_CANCELLED) throw e;
|
||
}); // We've processed the handler stack. let's clear it.
|
||
|
||
this.showDirectiveStack = [];
|
||
this.showDirectiveLastElement = undefined;
|
||
}
|
||
|
||
updateElement(el, extraVars) {
|
||
this.resolveBoundAttributes(el, false, extraVars);
|
||
}
|
||
|
||
registerListeners(el, extraVars) {
|
||
getXAttrs(el, this).forEach(({
|
||
type,
|
||
value,
|
||
modifiers,
|
||
expression
|
||
}) => {
|
||
switch (type) {
|
||
case 'on':
|
||
registerListener(this, el, value, modifiers, expression, extraVars);
|
||
break;
|
||
|
||
case 'model':
|
||
registerModelListener(this, el, modifiers, expression, extraVars);
|
||
break;
|
||
}
|
||
});
|
||
}
|
||
|
||
resolveBoundAttributes(el, initialUpdate = false, extraVars) {
|
||
let attrs = getXAttrs(el, this);
|
||
attrs.forEach(({
|
||
type,
|
||
value,
|
||
modifiers,
|
||
expression
|
||
}) => {
|
||
switch (type) {
|
||
case 'model':
|
||
handleAttributeBindingDirective(this, el, 'value', expression, extraVars, type, modifiers);
|
||
break;
|
||
|
||
case 'bind':
|
||
// The :key binding on an x-for is special, ignore it.
|
||
if (el.tagName.toLowerCase() === 'template' && value === 'key') return;
|
||
handleAttributeBindingDirective(this, el, value, expression, extraVars, type, modifiers);
|
||
break;
|
||
|
||
case 'text':
|
||
var output = this.evaluateReturnExpression(el, expression, extraVars);
|
||
handleTextDirective(el, output, expression);
|
||
break;
|
||
|
||
case 'html':
|
||
handleHtmlDirective(this, el, expression, extraVars);
|
||
break;
|
||
|
||
case 'show':
|
||
var output = this.evaluateReturnExpression(el, expression, extraVars);
|
||
handleShowDirective(this, el, output, modifiers, initialUpdate);
|
||
break;
|
||
|
||
case 'if':
|
||
// If this element also has x-for on it, don't process x-if.
|
||
// We will let the "x-for" directive handle the "if"ing.
|
||
if (attrs.some(i => i.type === 'for')) return;
|
||
var output = this.evaluateReturnExpression(el, expression, extraVars);
|
||
handleIfDirective(this, el, output, initialUpdate, extraVars);
|
||
break;
|
||
|
||
case 'for':
|
||
handleForDirective(this, el, expression, initialUpdate, extraVars);
|
||
break;
|
||
|
||
case 'cloak':
|
||
el.removeAttribute('x-cloak');
|
||
break;
|
||
}
|
||
});
|
||
}
|
||
|
||
evaluateReturnExpression(el, expression, extraVars = () => {}) {
|
||
return saferEval(el, expression, this.$data, _objectSpread2(_objectSpread2({}, extraVars()), {}, {
|
||
$dispatch: this.getDispatchFunction(el)
|
||
}));
|
||
}
|
||
|
||
evaluateCommandExpression(el, expression, extraVars = () => {}) {
|
||
return saferEvalNoReturn(el, expression, this.$data, _objectSpread2(_objectSpread2({}, extraVars()), {}, {
|
||
$dispatch: this.getDispatchFunction(el)
|
||
}));
|
||
}
|
||
|
||
getDispatchFunction(el) {
|
||
return (event, detail = {}) => {
|
||
el.dispatchEvent(new CustomEvent(event, {
|
||
detail,
|
||
bubbles: true
|
||
}));
|
||
};
|
||
}
|
||
|
||
listenForNewElementsToInitialize() {
|
||
const targetNode = this.$el;
|
||
const observerOptions = {
|
||
childList: true,
|
||
attributes: true,
|
||
subtree: true
|
||
};
|
||
const observer = new MutationObserver(mutations => {
|
||
for (let i = 0; i < mutations.length; i++) {
|
||
// Filter out mutations triggered from child components.
|
||
const closestParentComponent = mutations[i].target.closest('[x-data]');
|
||
if (!(closestParentComponent && closestParentComponent.isSameNode(this.$el))) continue;
|
||
|
||
if (mutations[i].type === 'attributes' && mutations[i].attributeName === 'x-data') {
|
||
const xAttr = mutations[i].target.getAttribute('x-data') || '{}';
|
||
const rawData = saferEval(this.$el, xAttr, {
|
||
$el: this.$el
|
||
});
|
||
Object.keys(rawData).forEach(key => {
|
||
if (this.$data[key] !== rawData[key]) {
|
||
this.$data[key] = rawData[key];
|
||
}
|
||
});
|
||
}
|
||
|
||
if (mutations[i].addedNodes.length > 0) {
|
||
mutations[i].addedNodes.forEach(node => {
|
||
if (node.nodeType !== 1 || node.__x_inserted_me) return;
|
||
|
||
if (node.matches('[x-data]') && !node.__x) {
|
||
node.__x = new Component(node);
|
||
return;
|
||
}
|
||
|
||
this.initializeElements(node);
|
||
});
|
||
}
|
||
}
|
||
});
|
||
observer.observe(targetNode, observerOptions);
|
||
}
|
||
|
||
getRefsProxy() {
|
||
var self = this;
|
||
var refObj = {};
|
||
// One of the goals of this is to not hold elements in memory, but rather re-evaluate
|
||
// the DOM when the system needs something from it. This way, the framework is flexible and
|
||
// friendly to outside DOM changes from libraries like Vue/Livewire.
|
||
// For this reason, I'm using an "on-demand" proxy to fake a "$refs" object.
|
||
|
||
return new Proxy(refObj, {
|
||
get(object, property) {
|
||
if (property === '$isAlpineProxy') return true;
|
||
var ref; // We can't just query the DOM because it's hard to filter out refs in
|
||
// nested components.
|
||
|
||
self.walkAndSkipNestedComponents(self.$el, el => {
|
||
if (el.hasAttribute('x-ref') && el.getAttribute('x-ref') === property) {
|
||
ref = el;
|
||
}
|
||
});
|
||
return ref;
|
||
}
|
||
|
||
});
|
||
}
|
||
|
||
}
|
||
|
||
const Alpine = {
|
||
version: "2.8.2",
|
||
pauseMutationObserver: false,
|
||
magicProperties: {},
|
||
onComponentInitializeds: [],
|
||
onBeforeComponentInitializeds: [],
|
||
ignoreFocusedForValueBinding: false,
|
||
start: async function start() {
|
||
if (!isTesting()) {
|
||
await domReady();
|
||
}
|
||
|
||
this.discoverComponents(el => {
|
||
this.initializeComponent(el);
|
||
}); // It's easier and more performant to just support Turbolinks than listen
|
||
// to MutationObserver mutations at the document level.
|
||
|
||
document.addEventListener("turbolinks:load", () => {
|
||
this.discoverUninitializedComponents(el => {
|
||
this.initializeComponent(el);
|
||
});
|
||
});
|
||
this.listenForNewUninitializedComponentsAtRunTime();
|
||
},
|
||
discoverComponents: function discoverComponents(callback) {
|
||
const rootEls = document.querySelectorAll('[x-data]');
|
||
rootEls.forEach(rootEl => {
|
||
callback(rootEl);
|
||
});
|
||
},
|
||
discoverUninitializedComponents: function discoverUninitializedComponents(callback, el = null) {
|
||
const rootEls = (el || document).querySelectorAll('[x-data]');
|
||
Array.from(rootEls).filter(el => el.__x === undefined).forEach(rootEl => {
|
||
callback(rootEl);
|
||
});
|
||
},
|
||
listenForNewUninitializedComponentsAtRunTime: function listenForNewUninitializedComponentsAtRunTime() {
|
||
const targetNode = document.querySelector('body');
|
||
const observerOptions = {
|
||
childList: true,
|
||
attributes: true,
|
||
subtree: true
|
||
};
|
||
const observer = new MutationObserver(mutations => {
|
||
if (this.pauseMutationObserver) return;
|
||
|
||
for (let i = 0; i < mutations.length; i++) {
|
||
if (mutations[i].addedNodes.length > 0) {
|
||
mutations[i].addedNodes.forEach(node => {
|
||
// Discard non-element nodes (like line-breaks)
|
||
if (node.nodeType !== 1) return; // Discard any changes happening within an existing component.
|
||
// They will take care of themselves.
|
||
|
||
if (node.parentElement && node.parentElement.closest('[x-data]')) return;
|
||
this.discoverUninitializedComponents(el => {
|
||
this.initializeComponent(el);
|
||
}, node.parentElement);
|
||
});
|
||
}
|
||
}
|
||
});
|
||
observer.observe(targetNode, observerOptions);
|
||
},
|
||
initializeComponent: function initializeComponent(el) {
|
||
if (!el.__x) {
|
||
// Wrap in a try/catch so that we don't prevent other components
|
||
// from initializing when one component contains an error.
|
||
try {
|
||
el.__x = new Component(el);
|
||
} catch (error) {
|
||
setTimeout(() => {
|
||
throw error;
|
||
}, 0);
|
||
}
|
||
}
|
||
},
|
||
clone: function clone(component, newEl) {
|
||
if (!newEl.__x) {
|
||
newEl.__x = new Component(newEl, component);
|
||
}
|
||
},
|
||
addMagicProperty: function addMagicProperty(name, callback) {
|
||
this.magicProperties[name] = callback;
|
||
},
|
||
onComponentInitialized: function onComponentInitialized(callback) {
|
||
this.onComponentInitializeds.push(callback);
|
||
},
|
||
onBeforeComponentInitialized: function onBeforeComponentInitialized(callback) {
|
||
this.onBeforeComponentInitializeds.push(callback);
|
||
}
|
||
};
|
||
|
||
if (!isTesting()) {
|
||
window.Alpine = Alpine;
|
||
|
||
if (window.deferLoadingAlpine) {
|
||
window.deferLoadingAlpine(function () {
|
||
window.Alpine.start();
|
||
});
|
||
} else {
|
||
window.Alpine.start();
|
||
}
|
||
}
|
||
|
||
return Alpine;
|
||
|
||
})));
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ "./resources/js/app.js":
|
||
/*!*****************************!*\
|
||
!*** ./resources/js/app.js ***!
|
||
\*****************************/
|
||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||
|
||
"use strict";
|
||
__webpack_require__.r(__webpack_exports__);
|
||
/* harmony import */ var _hotwired_turbo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @hotwired/turbo */ "./node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js");
|
||
/* harmony import */ var alpine_turbo_drive_adapter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! alpine-turbo-drive-adapter */ "./node_modules/alpine-turbo-drive-adapter/dist/alpine-turbo-drive-adapter.esm.js");
|
||
/* harmony import */ var alpine_turbo_drive_adapter__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(alpine_turbo_drive_adapter__WEBPACK_IMPORTED_MODULE_1__);
|
||
/* harmony import */ var alpinejs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! alpinejs */ "./node_modules/alpinejs/dist/alpine.js");
|
||
/* harmony import */ var alpinejs__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(alpinejs__WEBPACK_IMPORTED_MODULE_2__);
|
||
|
||
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ "./resources/css/app.css":
|
||
/*!*******************************!*\
|
||
!*** ./resources/css/app.css ***!
|
||
\*******************************/
|
||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||
|
||
"use strict";
|
||
__webpack_require__.r(__webpack_exports__);
|
||
// extracted by mini-css-extract-plugin
|
||
|
||
|
||
/***/ })
|
||
|
||
/******/ });
|
||
/************************************************************************/
|
||
/******/ // The module cache
|
||
/******/ var __webpack_module_cache__ = {};
|
||
/******/
|
||
/******/ // The require function
|
||
/******/ function __webpack_require__(moduleId) {
|
||
/******/ // Check if module is in cache
|
||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||
/******/ if (cachedModule !== undefined) {
|
||
/******/ return cachedModule.exports;
|
||
/******/ }
|
||
/******/ // Create a new module (and put it into the cache)
|
||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||
/******/ // no module.id needed
|
||
/******/ // no module.loaded needed
|
||
/******/ exports: {}
|
||
/******/ };
|
||
/******/
|
||
/******/ // Execute the module function
|
||
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||
/******/
|
||
/******/ // Return the exports of the module
|
||
/******/ return module.exports;
|
||
/******/ }
|
||
/******/
|
||
/******/ // expose the modules object (__webpack_modules__)
|
||
/******/ __webpack_require__.m = __webpack_modules__;
|
||
/******/
|
||
/************************************************************************/
|
||
/******/ /* webpack/runtime/chunk loaded */
|
||
/******/ (() => {
|
||
/******/ var deferred = [];
|
||
/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
|
||
/******/ if(chunkIds) {
|
||
/******/ priority = priority || 0;
|
||
/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
|
||
/******/ deferred[i] = [chunkIds, fn, priority];
|
||
/******/ return;
|
||
/******/ }
|
||
/******/ var notFulfilled = Infinity;
|
||
/******/ for (var i = 0; i < deferred.length; i++) {
|
||
/******/ var [chunkIds, fn, priority] = deferred[i];
|
||
/******/ var fulfilled = true;
|
||
/******/ for (var j = 0; j < chunkIds.length; j++) {
|
||
/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
|
||
/******/ chunkIds.splice(j--, 1);
|
||
/******/ } else {
|
||
/******/ fulfilled = false;
|
||
/******/ if(priority < notFulfilled) notFulfilled = priority;
|
||
/******/ }
|
||
/******/ }
|
||
/******/ if(fulfilled) {
|
||
/******/ deferred.splice(i--, 1)
|
||
/******/ result = fn();
|
||
/******/ }
|
||
/******/ }
|
||
/******/ return result;
|
||
/******/ };
|
||
/******/ })();
|
||
/******/
|
||
/******/ /* webpack/runtime/compat get default export */
|
||
/******/ (() => {
|
||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||
/******/ __webpack_require__.n = (module) => {
|
||
/******/ var getter = module && module.__esModule ?
|
||
/******/ () => (module['default']) :
|
||
/******/ () => (module);
|
||
/******/ __webpack_require__.d(getter, { a: getter });
|
||
/******/ return getter;
|
||
/******/ };
|
||
/******/ })();
|
||
/******/
|
||
/******/ /* webpack/runtime/define property getters */
|
||
/******/ (() => {
|
||
/******/ // define getter functions for harmony exports
|
||
/******/ __webpack_require__.d = (exports, definition) => {
|
||
/******/ for(var key in definition) {
|
||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||
/******/ }
|
||
/******/ }
|
||
/******/ };
|
||
/******/ })();
|
||
/******/
|
||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||
/******/ (() => {
|
||
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||
/******/ })();
|
||
/******/
|
||
/******/ /* webpack/runtime/make namespace object */
|
||
/******/ (() => {
|
||
/******/ // define __esModule on exports
|
||
/******/ __webpack_require__.r = (exports) => {
|
||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||
/******/ }
|
||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||
/******/ };
|
||
/******/ })();
|
||
/******/
|
||
/******/ /* webpack/runtime/jsonp chunk loading */
|
||
/******/ (() => {
|
||
/******/ // no baseURI
|
||
/******/
|
||
/******/ // object to store loaded and loading chunks
|
||
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
|
||
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
|
||
/******/ var installedChunks = {
|
||
/******/ "/js/app": 0,
|
||
/******/ "css/app": 0
|
||
/******/ };
|
||
/******/
|
||
/******/ // no chunk on demand loading
|
||
/******/
|
||
/******/ // no prefetching
|
||
/******/
|
||
/******/ // no preloaded
|
||
/******/
|
||
/******/ // no HMR
|
||
/******/
|
||
/******/ // no HMR manifest
|
||
/******/
|
||
/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
|
||
/******/
|
||
/******/ // install a JSONP callback for chunk loading
|
||
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
|
||
/******/ var [chunkIds, moreModules, runtime] = data;
|
||
/******/ // add "moreModules" to the modules object,
|
||
/******/ // then flag all "chunkIds" as loaded and fire callback
|
||
/******/ var moduleId, chunkId, i = 0;
|
||
/******/ for(moduleId in moreModules) {
|
||
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
|
||
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
|
||
/******/ }
|
||
/******/ }
|
||
/******/ if(runtime) runtime(__webpack_require__);
|
||
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
|
||
/******/ for(;i < chunkIds.length; i++) {
|
||
/******/ chunkId = chunkIds[i];
|
||
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
|
||
/******/ installedChunks[chunkId][0]();
|
||
/******/ }
|
||
/******/ installedChunks[chunkIds[i]] = 0;
|
||
/******/ }
|
||
/******/ __webpack_require__.O();
|
||
/******/ }
|
||
/******/
|
||
/******/ var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
|
||
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
|
||
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
|
||
/******/ })();
|
||
/******/
|
||
/************************************************************************/
|
||
/******/
|
||
/******/ // startup
|
||
/******/ // Load entry module and return exports
|
||
/******/ // This entry module depends on other loaded chunks and execution need to be delayed
|
||
/******/ __webpack_require__.O(undefined, ["css/app"], () => (__webpack_require__("./resources/js/app.js")))
|
||
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["css/app"], () => (__webpack_require__("./resources/css/app.css")))
|
||
/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
|
||
/******/
|
||
/******/ })()
|
||
; |