var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { EventEmitter } from "events";
import { addClass, removeClass, getAsValue } from "@matdata/yasgui-utils";
import TabSettingsModal from "./TabSettingsModal";
import { default as Yasqe } from "@matdata/yasqe";
import { default as Yasr } from "@matdata/yasr";
import { mapValues, eq, mergeWith, words, deburr, invert } from "lodash-es";
import * as shareLink from "./linkUtils";
import EndpointSelect from "./endpointSelect";
import "./tab.scss";
import { getRandomId, default as Yasgui } from "./";
import * as OAuth2Utils from "./OAuth2Utils";
import { hashQueryText } from "./queryManagement/textHash";
import SaveManagedQueryModal from "./queryManagement/SaveManagedQueryModal";
import { saveManagedQuery } from "./queryManagement/saveManagedQuery";
import { getWorkspaceBackend } from "./queryManagement/backends/getWorkspaceBackend";
import { asWorkspaceBackendError } from "./queryManagement/backends/errors";
import { normalizeQueryFilename } from "./queryManagement/normalizeQueryFilename";
export class Tab extends EventEmitter {
    constructor(yasgui, conf) {
        super();
        this.endpointButtonConfigs = [];
        this.handleKeyDown = (event) => {
            var _a, _b, _c, _d, _e, _f, _g, _h, _j;
            if (event.defaultPrevented)
                return;
            const saveModalOpen = !!document.querySelector(".saveManagedQueryModalOverlay.open");
            if (!saveModalOpen) {
                const isSaveShortcut = (event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey && event.key.toLowerCase() === "s";
                if (isSaveShortcut) {
                    event.preventDefault();
                    void this.saveManagedQueryOrSaveAsManagedQuery();
                    return;
                }
            }
            if (event.key === "F11") {
                event.preventDefault();
                if (this.yasqe) {
                    this.yasqe.toggleFullscreen();
                    if ((_a = this.yasr) === null || _a === void 0 ? void 0 : _a.getIsFullscreen()) {
                        this.yasr.toggleFullscreen();
                    }
                }
            }
            else if (event.key === "F10") {
                event.preventDefault();
                if (this.yasr) {
                    this.yasr.toggleFullscreen();
                    if ((_b = this.yasqe) === null || _b === void 0 ? void 0 : _b.getIsFullscreen()) {
                        this.yasqe.toggleFullscreen();
                    }
                }
            }
            else if (event.key === "F9") {
                event.preventDefault();
                const yasqeFullscreen = (_c = this.yasqe) === null || _c === void 0 ? void 0 : _c.getIsFullscreen();
                const yasrFullscreen = (_d = this.yasr) === null || _d === void 0 ? void 0 : _d.getIsFullscreen();
                if (yasqeFullscreen) {
                    (_e = this.yasqe) === null || _e === void 0 ? void 0 : _e.toggleFullscreen();
                    (_f = this.yasr) === null || _f === void 0 ? void 0 : _f.toggleFullscreen();
                }
                else if (yasrFullscreen) {
                    (_g = this.yasr) === null || _g === void 0 ? void 0 : _g.toggleFullscreen();
                    (_h = this.yasqe) === null || _h === void 0 ? void 0 : _h.toggleFullscreen();
                }
                else {
                    (_j = this.yasqe) === null || _j === void 0 ? void 0 : _j.toggleFullscreen();
                }
            }
        };
        this.handleYasqeBlur = (yasqe) => {
            var _a;
            this.persistentJson.yasqe.value = yasqe.getValue();
            (_a = this.settingsModal) === null || _a === void 0 ? void 0 : _a.capturePrefixesFromQuery();
            this.emit("change", this, this.persistentJson);
        };
        this.handleYasqeQuery = (yasqe) => {
            if (yasqe.getValue() !== this.persistentJson.yasqe.value) {
                this.persistentJson.yasqe.value = yasqe.getValue();
                this.emit("change", this, this.persistentJson);
            }
            this.emit("query", this);
        };
        this.handleYasqeQueryAbort = () => {
            this.emit("queryAbort", this);
            if (this.yasr) {
                this.yasr.hideLoading();
            }
        };
        this.handleYasqeQueryBefore = () => {
            this.emit("queryBefore", this);
            if (this.yasr) {
                this.yasr.showLoading();
            }
        };
        this.handleYasqeResize = (_yasqe, newSize) => {
            this.persistentJson.yasqe.editorHeight = newSize;
            this.emit("change", this, this.persistentJson);
        };
        this.handleAutocompletionShown = (_yasqe, widget) => {
            this.emit("autocompletionShown", this, widget);
        };
        this.handleAutocompletionClose = (_yasqe) => {
            this.emit("autocompletionClose", this);
        };
        this.handleQueryResponse = (_yasqe, response, duration) => {
            this.emit("queryResponse", this);
            if (!this.yasr)
                throw new Error("Resultset visualizer not initialized. Cannot draw results");
            this.yasr.setResponse(response, duration);
            if (!this.yasr.results)
                return;
            if (!this.yasr.results.hasError()) {
                this.persistentJson.yasr.response = this.yasr.results.getAsStoreObject(this.yasgui.config.yasr.maxPersistentResponseSize);
            }
            else {
                this.persistentJson.yasr.response = undefined;
            }
            this.emit("change", this, this.persistentJson);
        };
        this.handleYasqeMouseDown = (event) => {
            if (!event.ctrlKey || !this.yasqe)
                return;
            const target = event.target;
            if (!target.closest(".CodeMirror"))
                return;
            const pos = this.yasqe.coordsChar({ left: event.clientX, top: event.clientY });
            const token = this.yasqe.getTokenAt(pos);
            const tokenString = token.string.trim();
            if (tokenString.startsWith("?") || tokenString.startsWith("$"))
                return;
            const isFullUri = tokenString.startsWith("<") && tokenString.endsWith(">");
            const isPrefixedName = /^[\w-]+:[\w-]+/.test(tokenString);
            if (!isFullUri && !isPrefixedName)
                return;
            event.preventDefault();
            event.stopPropagation();
            let uri = tokenString;
            if (isFullUri) {
                uri = tokenString.slice(1, -1);
            }
            else if (isPrefixedName) {
                const prefixes = this.yasqe.getPrefixesFromQuery();
                const [prefix, localName] = tokenString.split(":");
                const prefixUri = prefixes[prefix];
                if (prefixUri) {
                    uri = prefixUri + localName;
                }
            }
            const constructQuery = `CONSTRUCT {   
  ?s_left ?p_left ?target .
  ?target ?p_right ?o_right .
}
WHERE {
  BIND(<${uri}> as ?target)
  {
    ?s_left ?p_left ?target .
  }
  UNION
  {
    ?target ?p_right ?o_right .
  }  
} LIMIT 1000`;
            void this.executeBackgroundQuery(constructQuery);
        };
        this.initVerticalDrag = () => {
            document.documentElement.addEventListener("mousemove", this.doVerticalDrag, false);
            document.documentElement.addEventListener("mouseup", this.stopVerticalDrag, false);
        };
        this.doVerticalDrag = (event) => {
            if (!this.editorWrapperEl || !this.rootEl)
                return;
            const offset = this.calculateVerticalDragOffset(event);
            const totalWidth = this.rootEl.offsetWidth;
            const minWidth = 200;
            const maxWidth = totalWidth - minWidth - 10;
            const newWidth = Math.max(minWidth, Math.min(maxWidth, offset));
            this.editorWrapperEl.style.width = newWidth + "px";
            this.editorWrapperEl.style.flex = "0 0 " + newWidth + "px";
        };
        this.stopVerticalDrag = () => {
            document.documentElement.removeEventListener("mousemove", this.doVerticalDrag, false);
            document.documentElement.removeEventListener("mouseup", this.stopVerticalDrag, false);
            if (this.yasqe) {
                this.yasqe.refresh();
                this.yasqe.refreshSnippetsBar();
            }
            if (this.yasr) {
                this.yasr.refresh();
            }
        };
        this.resetVerticalSplit = () => {
            if (!this.editorWrapperEl)
                return;
            this.editorWrapperEl.style.width = "";
            this.editorWrapperEl.style.flex = "1 1 50%";
            if (this.yasqe) {
                this.yasqe.refresh();
            }
            if (this.yasr) {
                this.yasr.refresh();
            }
        };
        if (!conf || conf.id === undefined)
            throw new Error("Expected a valid configuration to initialize tab with");
        this.yasgui = yasgui;
        this.persistentJson = conf;
        this.currentOrientation = this.yasgui.config.orientation || "vertical";
    }
    name() {
        return this.persistentJson.name;
    }
    getPersistedJson() {
        return this.persistentJson;
    }
    getId() {
        return this.persistentJson.id;
    }
    getManagedQueryMetadata() {
        return this.persistentJson.managedQuery;
    }
    setManagedQueryMetadata(metadata) {
        if (metadata) {
            this.persistentJson.managedQuery = metadata;
        }
        else {
            delete this.persistentJson.managedQuery;
        }
        this.emit("change", this, this.persistentJson);
    }
    isManagedQueryTab() {
        return !!this.persistentJson.managedQuery;
    }
    hasUnsavedManagedChanges() {
        const meta = this.getManagedQueryMetadata();
        if (!meta)
            return false;
        if (!meta.lastSavedTextHash)
            return false;
        try {
            const current = this.yasqe ? this.yasqe.getValue() : this.persistentJson.yasqe.value;
            const currentHash = hashQueryText(current);
            return currentHash !== meta.lastSavedTextHash;
        }
        catch (_a) {
            return false;
        }
    }
    getDefaultSaveModalValues() {
        var _a;
        const meta = this.getManagedQueryMetadata();
        if (!meta)
            return { name: this.name() };
        if (meta.backendType !== "git")
            return { workspaceId: meta.workspaceId };
        const path = (_a = meta.queryRef) === null || _a === void 0 ? void 0 : _a.path;
        if (!path)
            return { workspaceId: meta.workspaceId };
        const parts = path.split("/");
        const filename = parts.pop();
        const folderPath = parts.join("/");
        return {
            workspaceId: meta.workspaceId,
            folderPath,
            filename,
            name: this.name(),
        };
    }
    getManagedQueryIdFromMetadata(meta) {
        var _a, _b;
        if (meta.backendType === "git")
            return (_a = meta.queryRef) === null || _a === void 0 ? void 0 : _a.path;
        return (_b = meta.queryRef) === null || _b === void 0 ? void 0 : _b.managedQueryIri;
    }
    versionRefFromVersionTag(backendType, versionTag) {
        if (!versionTag)
            return undefined;
        if (backendType === "git")
            return { commitSha: versionTag };
        return { managedQueryVersionIri: versionTag };
    }
    getQueryTextForSave() {
        try {
            if (this.yasqe)
                return this.yasqe.getValue();
        }
        catch (_a) {
        }
        return this.persistentJson.yasqe.value;
    }
    saveManagedQueryOrSaveAsManagedQuery() {
        return __awaiter(this, void 0, void 0, function* () {
            const meta = this.getManagedQueryMetadata();
            if (!meta) {
                yield this.saveAsManagedQuery();
                return;
            }
            const queryId = this.getManagedQueryIdFromMetadata(meta);
            if (!queryId) {
                yield this.saveAsManagedQuery();
                return;
            }
            const workspace = this.yasgui.persistentConfig.getWorkspace(meta.workspaceId);
            if (!workspace) {
                window.alert("Selected workspace no longer exists");
                return;
            }
            const backend = getWorkspaceBackend(workspace, { persistentConfig: this.yasgui.persistentConfig });
            const expectedVersionTag = (() => {
                var _a, _b;
                if (!(meta === null || meta === void 0 ? void 0 : meta.lastSavedVersionRef))
                    return undefined;
                if (meta.backendType === "git")
                    return (_a = meta.lastSavedVersionRef) === null || _a === void 0 ? void 0 : _a.commitSha;
                return (_b = meta.lastSavedVersionRef) === null || _b === void 0 ? void 0 : _b.managedQueryVersionIri;
            })();
            try {
                yield backend.writeQuery(queryId, this.getQueryTextForSave(), { expectedVersionTag });
            }
            catch (e) {
                const err = asWorkspaceBackendError(e);
                if (err.code === "CONFLICT") {
                    if (meta.backendType === "git") {
                        try {
                            const latest = yield backend.readQuery(queryId);
                            const latestHash = hashQueryText(latest.queryText);
                            if (meta.lastSavedTextHash && meta.lastSavedTextHash === latestHash && latest.versionTag) {
                                yield backend.writeQuery(queryId, this.getQueryTextForSave(), { expectedVersionTag: latest.versionTag });
                            }
                            else {
                                window.alert("Save conflict. Resolve the conflict externally (e.g., pull/rebase/merge) and then try saving again.");
                                return;
                            }
                        }
                        catch (_a) {
                            window.alert("Save conflict. Resolve the conflict externally (e.g., pull/rebase/merge) and then try saving again.");
                            return;
                        }
                    }
                    else {
                        window.alert("Save conflict. Refresh the query and try again.");
                        return;
                    }
                }
                window.alert(err.message);
                return;
            }
            const read = yield backend.readQuery(queryId);
            const lastSavedTextHash = hashQueryText(read.queryText);
            const lastSavedVersionRef = this.versionRefFromVersionTag(meta.backendType, read.versionTag);
            this.setManagedQueryMetadata(Object.assign(Object.assign({}, meta), { lastSavedTextHash,
                lastSavedVersionRef }));
            this.yasgui.queryBrowser.invalidateAndRefresh(meta.workspaceId);
        });
    }
    saveAsManagedQuery() {
        return __awaiter(this, void 0, void 0, function* () {
            const modal = new SaveManagedQueryModal(this.yasgui);
            const defaults = this.getDefaultSaveModalValues();
            let result;
            try {
                const modalDefaults = {
                    workspaceId: defaults.workspaceId,
                    folderPath: defaults.folderPath || "",
                    name: defaults.name || this.name(),
                };
                if (defaults.filename)
                    modalDefaults.filename = defaults.filename;
                result = yield modal.show(modalDefaults);
            }
            catch (_a) {
                return;
            }
            const workspace = this.yasgui.persistentConfig.getWorkspace(result.workspaceId);
            if (!workspace) {
                window.alert("Selected workspace no longer exists");
                return;
            }
            const backend = getWorkspaceBackend(workspace, { persistentConfig: this.yasgui.persistentConfig });
            const meta = this.getManagedQueryMetadata();
            const expectedVersionTag = (() => {
                var _a, _b;
                if (!(meta === null || meta === void 0 ? void 0 : meta.lastSavedVersionRef))
                    return undefined;
                if (meta.backendType === "git")
                    return (_a = meta.lastSavedVersionRef) === null || _a === void 0 ? void 0 : _a.commitSha;
                return (_b = meta.lastSavedVersionRef) === null || _b === void 0 ? void 0 : _b.managedQueryVersionIri;
            })();
            try {
                modal.notifySaveInProgress();
                const { managedMetadata } = yield saveManagedQuery({
                    backend,
                    backendType: workspace.type,
                    workspaceId: workspace.id,
                    workspaceIri: workspace.type === "sparql" ? workspace.workspaceIri : undefined,
                    folderPath: result.folderPath,
                    name: result.name,
                    filename: result.filename,
                    queryText: this.getQueryTextForSave(),
                    associatedEndpoint: workspace.type === "sparql" ? this.getEndpoint() : undefined,
                    message: result.message,
                    expectedVersionTag,
                });
                modal.notifySaveComplete();
                this.setManagedQueryMetadata(managedMetadata);
                if (result.name && result.name.trim()) {
                    this.setName(result.name.trim());
                }
                this.yasgui.queryBrowser.invalidateAndRefresh(workspace.id);
            }
            catch (e) {
                modal.notifySaveComplete();
                const err = asWorkspaceBackendError(e);
                window.alert(err.message);
            }
        });
    }
    draw() {
        if (this.rootEl)
            return;
        this.rootEl = document.createElement("div");
        this.rootEl.className = "tabPanel";
        this.rootEl.id = this.persistentJson.id;
        this.rootEl.setAttribute("role", "tabpanel");
        this.rootEl.setAttribute("aria-labelledby", "tab-" + this.persistentJson.id);
        addClass(this.rootEl, `orientation-${this.currentOrientation}`);
        const editorWrapper = document.createElement("div");
        editorWrapper.className = "editorwrapper";
        this.editorWrapperEl = editorWrapper;
        const controlbarAndYasqeDiv = document.createElement("div");
        this.controlBarEl = document.createElement("div");
        this.controlBarEl.className = "controlbar";
        controlbarAndYasqeDiv.appendChild(this.controlBarEl);
        this.yasqeWrapperEl = document.createElement("div");
        controlbarAndYasqeDiv.appendChild(this.yasqeWrapperEl);
        editorWrapper.appendChild(controlbarAndYasqeDiv);
        this.yasrWrapperEl = document.createElement("div");
        this.yasrWrapperEl.className = "yasrWrapperEl";
        this.initTabSettingsMenu();
        this.rootEl.appendChild(editorWrapper);
        this.drawVerticalResizer();
        this.rootEl.appendChild(this.yasrWrapperEl);
        this.initControlbar();
        this.initYasqe();
        this.initYasr();
        this.yasgui._setPanel(this.persistentJson.id, this.rootEl);
    }
    hide() {
        removeClass(this.rootEl, "active");
        this.detachKeyboardListeners();
    }
    show() {
        this.draw();
        addClass(this.rootEl, "active");
        this.yasgui.tabElements.selectTab(this.persistentJson.id);
        if (this.yasqe) {
            this.yasqe.refresh();
            if (this.yasgui.config.autofocus)
                this.yasqe.focus();
        }
        if (this.yasr) {
            this.yasr.refresh();
        }
        this.setEndpoint(this.getEndpoint(), this.yasgui.persistentConfig.getEndpointHistory());
        this.attachKeyboardListeners();
    }
    attachKeyboardListeners() {
        if (!this.rootEl)
            return;
        document.addEventListener("keydown", this.handleKeyDown);
    }
    detachKeyboardListeners() {
        document.removeEventListener("keydown", this.handleKeyDown);
    }
    select() {
        this.yasgui.selectTabId(this.persistentJson.id);
    }
    close() {
        if (this.isManagedQueryTab() && this.hasUnsavedManagedChanges()) {
            const wantsSave = window.confirm("This managed query has unsaved changes. Save before closing?");
            if (wantsSave) {
                void this.saveManagedQueryOrSaveAsManagedQuery().then(() => {
                    if (!this.hasUnsavedManagedChanges()) {
                        this.closeNow();
                    }
                });
                return;
            }
            const discard = window.confirm("Discard changes and close the tab?");
            if (!discard)
                return;
        }
        this.closeNow();
    }
    closeNow() {
        this.detachKeyboardListeners();
        if (this.yasqe)
            this.yasqe.abortQuery();
        if (this.yasgui.getTab() === this) {
            const tabs = this.yasgui.persistentConfig.getTabs();
            const i = tabs.indexOf(this.persistentJson.id);
            if (i > -1) {
                this.yasgui.selectTabId(tabs[i === tabs.length - 1 ? i - 1 : i + 1]);
            }
        }
        this.yasgui._removePanel(this.rootEl);
        this.yasgui.persistentConfig.deleteTab(this.persistentJson.id);
        this.yasgui.emit("tabClose", this.yasgui, this);
        this.emit("close", this);
        this.yasgui.tabElements.get(this.persistentJson.id).delete();
        delete this.yasgui._tabs[this.persistentJson.id];
    }
    getQuery() {
        var _a;
        if (!this.yasqe) {
            throw new Error("Cannot get value from uninitialized editor");
        }
        return (_a = this.yasqe) === null || _a === void 0 ? void 0 : _a.getValue();
    }
    setQuery(query) {
        if (!this.yasqe) {
            throw new Error("Cannot set value for uninitialized editor");
        }
        this.yasqe.setValue(query);
        this.persistentJson.yasqe.value = query;
        this.emit("change", this, this.persistentJson);
        return this;
    }
    getRequestConfig() {
        return this.persistentJson.requestConfig;
    }
    initControlbar() {
        this.initOrientationToggle();
        this.initEndpointSelectField();
        this.initEndpointButtons();
        if (this.yasgui.config.endpointInfo && this.controlBarEl) {
            this.controlBarEl.appendChild(this.yasgui.config.endpointInfo());
        }
    }
    initOrientationToggle() {
        if (!this.controlBarEl)
            return;
        this.orientationToggleButton = document.createElement("button");
        this.orientationToggleButton.className = "tabContextButton orientationToggle";
        this.orientationToggleButton.setAttribute("aria-label", "Toggle layout orientation");
        this.orientationToggleButton.title = "Toggle layout orientation";
        this.updateOrientationToggleIcon();
        this.orientationToggleButton.addEventListener("click", () => {
            this.toggleOrientation();
        });
        this.controlBarEl.appendChild(this.orientationToggleButton);
    }
    updateOrientationToggleIcon() {
        if (!this.orientationToggleButton)
            return;
        this.orientationToggleButton.innerHTML =
            this.currentOrientation === "vertical"
                ? '<i class="fas fa-grip-lines-vertical"></i>'
                : '<i class="fas fa-grip-lines"></i>';
        this.orientationToggleButton.title =
            this.currentOrientation === "vertical" ? "Switch to horizontal layout" : "Switch to vertical layout";
    }
    toggleOrientation() {
        if (!this.rootEl)
            return;
        const newOrientation = this.currentOrientation === "vertical" ? "horizontal" : "vertical";
        this.yasgui.config.orientation = newOrientation;
        for (const tabId in this.yasgui._tabs) {
            const tab = this.yasgui._tabs[tabId];
            if (tab && tab.rootEl) {
                removeClass(tab.rootEl, `orientation-${tab.currentOrientation}`);
                tab.currentOrientation = newOrientation;
                addClass(tab.rootEl, `orientation-${newOrientation}`);
                if (tab.orientationToggleButton) {
                    tab.updateOrientationToggleIcon();
                }
                if (tab.editorWrapperEl) {
                    tab.editorWrapperEl.style.width = "";
                    tab.editorWrapperEl.style.flex = "";
                }
                if (tab.yasqe) {
                    tab.yasqe.refresh();
                    tab.yasqe.refreshSnippetsBar();
                }
                if (tab.yasr) {
                    tab.yasr.refresh();
                }
            }
        }
    }
    getYasqe() {
        return this.yasqe;
    }
    getYasr() {
        return this.yasr;
    }
    initTabSettingsMenu() {
        if (!this.controlBarEl)
            throw new Error("Need to initialize wrapper elements before drawing tab settings");
        this.settingsModal = new TabSettingsModal(this, this.controlBarEl);
    }
    initEndpointSelectField() {
        if (!this.controlBarEl)
            throw new Error("Need to initialize wrapper elements before drawing endpoint field");
        this.endpointSelect = new EndpointSelect(this.getEndpoint(), this.controlBarEl, this.yasgui.config.endpointCatalogueOptions, this.yasgui.persistentConfig.getEndpointHistory());
        this.endpointSelect.on("select", (endpoint, endpointHistory) => {
            this.setEndpoint(endpoint, endpointHistory);
        });
        this.endpointSelect.on("remove", (endpoint, endpointHistory) => {
            this.setEndpoint(endpoint, endpointHistory);
        });
    }
    initEndpointButtons() {
        if (!this.controlBarEl)
            throw new Error("Need to initialize wrapper elements before drawing endpoint buttons");
        if (!this.endpointButtonsContainer) {
            this.endpointButtonsContainer = document.createElement("div");
            addClass(this.endpointButtonsContainer, "endpointButtonsContainer");
            this.controlBarEl.appendChild(this.endpointButtonsContainer);
        }
        this.refreshEndpointButtons();
        this.initEndpointButtonsResizeObserver();
    }
    initEndpointButtonsResizeObserver() {
        if (!this.controlBarEl || !this.endpointButtonsContainer)
            return;
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }
        this.resizeObserver = new ResizeObserver(() => {
            this.updateEndpointButtonsOverflow();
        });
        this.resizeObserver.observe(this.controlBarEl);
    }
    updateEndpointButtonsOverflow() {
        if (!this.endpointButtonsContainer || !this.controlBarEl)
            return;
        const buttons = Array.from(this.endpointButtonsContainer.querySelectorAll(".endpointButton:not(.endpointOverflowBtn)"));
        if (buttons.length === 0) {
            this.hideOverflowButton();
            return;
        }
        const containerRect = this.controlBarEl.getBoundingClientRect();
        const containerWidth = containerRect.width;
        const endpointButtonsRect = this.endpointButtonsContainer.getBoundingClientRect();
        const buttonsContainerLeft = endpointButtonsRect.left - containerRect.left;
        const overflowButtonWidth = 40;
        const availableWidth = containerWidth - buttonsContainerLeft - overflowButtonWidth - 20;
        buttons.forEach((btn) => btn.classList.remove("endpointButtonHidden"));
        let totalWidth = 0;
        let overflowIndex = -1;
        for (let i = 0; i < buttons.length; i++) {
            const btn = buttons[i];
            const btnWidth = btn.offsetWidth + 4;
            totalWidth += btnWidth;
            if (totalWidth > availableWidth && overflowIndex === -1) {
                overflowIndex = i;
            }
        }
        if (overflowIndex === -1) {
            this.hideOverflowButton();
            buttons.forEach((btn) => btn.classList.remove("endpointButtonHidden"));
        }
        else {
            buttons.forEach((btn, index) => {
                if (index >= overflowIndex) {
                    btn.classList.add("endpointButtonHidden");
                }
                else {
                    btn.classList.remove("endpointButtonHidden");
                }
            });
            this.showOverflowButton(overflowIndex);
        }
    }
    showOverflowButton(overflowStartIndex) {
        if (!this.endpointButtonsContainer)
            return;
        if (!this.endpointOverflowButton) {
            this.endpointOverflowButton = document.createElement("button");
            addClass(this.endpointOverflowButton, "endpointOverflowBtn");
            this.endpointOverflowButton.innerHTML = '<i class="fas fa-ellipsis-vertical"></i>';
            this.endpointOverflowButton.title = "More endpoints";
            this.endpointOverflowButton.setAttribute("aria-label", "More endpoint options");
            this.endpointOverflowButton.setAttribute("aria-haspopup", "true");
            this.endpointOverflowButton.setAttribute("aria-expanded", "false");
            this.endpointOverflowButton.addEventListener("click", (e) => {
                e.stopPropagation();
                this.toggleOverflowDropdown();
            });
            this.endpointButtonsContainer.appendChild(this.endpointOverflowButton);
        }
        this.endpointOverflowButton.dataset.overflowStart = String(overflowStartIndex);
        this.endpointOverflowButton.style.display = "flex";
    }
    hideOverflowButton() {
        if (this.endpointOverflowButton) {
            this.endpointOverflowButton.style.display = "none";
        }
        this.closeOverflowDropdown();
    }
    toggleOverflowDropdown() {
        if (this.endpointOverflowDropdown && this.endpointOverflowDropdown.style.display !== "none") {
            this.closeOverflowDropdown();
        }
        else {
            this.openOverflowDropdown();
        }
    }
    openOverflowDropdown() {
        if (!this.endpointOverflowButton || !this.endpointButtonsContainer)
            return;
        const overflowStartIndex = parseInt(this.endpointOverflowButton.dataset.overflowStart || "0", 10);
        const overflowButtons = this.endpointButtonConfigs.slice(overflowStartIndex);
        if (overflowButtons.length === 0)
            return;
        if (!this.endpointOverflowDropdown) {
            this.endpointOverflowDropdown = document.createElement("div");
            addClass(this.endpointOverflowDropdown, "endpointOverflowDropdown");
            this.endpointButtonsContainer.appendChild(this.endpointOverflowDropdown);
        }
        this.endpointOverflowDropdown.innerHTML = "";
        overflowButtons.forEach((buttonConfig) => {
            const item = document.createElement("button");
            addClass(item, "endpointOverflowItem");
            item.textContent = buttonConfig.label;
            item.title = `Set endpoint to ${buttonConfig.endpoint}`;
            item.setAttribute("aria-label", `Set endpoint to ${buttonConfig.endpoint}`);
            item.addEventListener("click", () => {
                this.setEndpoint(buttonConfig.endpoint);
                this.closeOverflowDropdown();
            });
            this.endpointOverflowDropdown.appendChild(item);
        });
        this.endpointOverflowDropdown.style.display = "block";
        this.endpointOverflowButton.setAttribute("aria-expanded", "true");
        const closeHandler = (e) => {
            if (this.endpointOverflowDropdown &&
                !this.endpointOverflowDropdown.contains(e.target) &&
                e.target !== this.endpointOverflowButton) {
                this.closeOverflowDropdown();
                document.removeEventListener("click", closeHandler);
            }
        };
        setTimeout(() => {
            document.addEventListener("click", closeHandler);
        }, 0);
    }
    closeOverflowDropdown() {
        if (this.endpointOverflowDropdown) {
            this.endpointOverflowDropdown.style.display = "none";
        }
        if (this.endpointOverflowButton) {
            this.endpointOverflowButton.setAttribute("aria-expanded", "false");
        }
    }
    refreshEndpointButtons() {
        if (!this.endpointButtonsContainer)
            return;
        this.endpointButtonsContainer.innerHTML = "";
        this.endpointOverflowButton = undefined;
        this.endpointOverflowDropdown = undefined;
        const disabledButtons = this.yasgui.persistentConfig.getDisabledDevButtons();
        const configButtons = (this.yasgui.config.endpointButtons || []).filter((button) => !disabledButtons.includes(button.endpoint));
        const endpointConfigs = this.yasgui.persistentConfig.getEndpointConfigs();
        const endpointButtons = endpointConfigs
            .filter((config) => config.showAsButton && config.label)
            .map((config) => ({ endpoint: config.endpoint, label: config.label }));
        const customButtons = this.yasgui.persistentConfig.getCustomEndpointButtons();
        const allButtons = [...configButtons, ...endpointButtons, ...customButtons];
        this.endpointButtonConfigs = allButtons;
        if (allButtons.length === 0) {
            this.endpointButtonsContainer.style.display = "none";
            return;
        }
        this.endpointButtonsContainer.style.display = "flex";
        allButtons.forEach((buttonConfig) => {
            const button = document.createElement("button");
            addClass(button, "endpointButton");
            button.textContent = buttonConfig.label;
            button.title = `Set endpoint to ${buttonConfig.endpoint}`;
            button.setAttribute("aria-label", `Set endpoint to ${buttonConfig.endpoint}`);
            button.addEventListener("click", () => {
                this.setEndpoint(buttonConfig.endpoint);
            });
            this.endpointButtonsContainer.appendChild(button);
        });
        requestAnimationFrame(() => {
            this.updateEndpointButtonsOverflow();
        });
    }
    setEndpoint(endpoint, endpointHistory) {
        if (endpoint)
            endpoint = endpoint.trim();
        if (endpointHistory && !eq(endpointHistory, this.yasgui.persistentConfig.getEndpointHistory())) {
            this.yasgui.emit("endpointHistoryChange", this.yasgui, endpointHistory);
        }
        if (this.persistentJson.requestConfig.endpoint !== endpoint) {
            this.persistentJson.requestConfig.endpoint = endpoint;
            this.emit("change", this, this.persistentJson);
            if (endpoint && !this.yasgui.persistentConfig.getEndpointConfig(endpoint)) {
                this.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {});
            }
            this.emit("endpointChange", this, endpoint);
        }
        if (this.endpointSelect instanceof EndpointSelect) {
            this.endpointSelect.setEndpoint(endpoint, endpointHistory);
        }
        return this;
    }
    getEndpoint() {
        return getAsValue(this.persistentJson.requestConfig.endpoint, this.yasgui);
    }
    updateContextMenu() {
        this.getTabListEl().redrawContextMenu();
    }
    getShareableLink(baseURL) {
        return shareLink.createShareLink(baseURL || window.location.href, this);
    }
    getShareObject() {
        return shareLink.createShareConfig(this);
    }
    getTabListEl() {
        return this.yasgui.tabElements.get(this.persistentJson.id);
    }
    setName(newName) {
        this.getTabListEl().rename(newName);
        this.persistentJson.name = newName;
        this.emit("change", this, this.persistentJson);
        return this;
    }
    suggestManagedFilenameFromName(name) {
        const trimmed = name.trim();
        const safe = trimmed.replace(/[\\/]/g, "-");
        return normalizeQueryFilename(safe);
    }
    renameTab(newName) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const nextName = newName.trim();
            if (!nextName)
                return;
            if (nextName === this.name())
                return;
            const meta = this.getManagedQueryMetadata();
            if (!meta) {
                this.setName(nextName);
                return;
            }
            const workspace = this.yasgui.persistentConfig.getWorkspace(meta.workspaceId);
            if (!workspace) {
                window.alert("Selected workspace no longer exists");
                return;
            }
            const backend = getWorkspaceBackend(workspace, { persistentConfig: this.yasgui.persistentConfig });
            if (meta.backendType === "sparql") {
                const queryId = this.getManagedQueryIdFromMetadata(meta);
                if (!queryId)
                    return;
                if (!backend.renameQuery) {
                    window.alert("This workspace does not support renaming queries");
                    return;
                }
                try {
                    this.getTabListEl().setAsRenaming(true);
                    yield backend.renameQuery(queryId, nextName);
                    this.setName(nextName);
                    this.yasgui.queryBrowser.invalidateAndRefresh(meta.workspaceId);
                }
                catch (e) {
                    const err = asWorkspaceBackendError(e);
                    window.alert(err.message);
                }
                finally {
                    this.getTabListEl().setAsRenaming(false);
                }
                return;
            }
            const oldPath = (_a = meta.queryRef) === null || _a === void 0 ? void 0 : _a.path;
            if (!oldPath) {
                this.setName(nextName);
                return;
            }
            const parts = oldPath.split("/").filter(Boolean);
            const oldFilename = parts.pop() || oldPath;
            const folderPrefix = parts.join("/");
            const newFilename = this.suggestManagedFilenameFromName(nextName);
            const newPath = folderPrefix ? `${folderPrefix}/${newFilename}` : newFilename;
            if (newPath === oldPath) {
                this.setName(nextName);
                return;
            }
            try {
                this.getTabListEl().setAsRenaming(true);
                yield backend.writeQuery(newPath, this.getQueryTextForSave(), {
                    message: `Rename ${oldFilename} to ${newFilename}`,
                });
                if (!backend.deleteQuery) {
                    window.alert("This workspace does not support deleting queries, so the old file could not be removed.");
                }
                else {
                    yield backend.deleteQuery(oldPath);
                }
                const read = yield backend.readQuery(newPath);
                const lastSavedTextHash = hashQueryText(read.queryText);
                const lastSavedVersionRef = this.versionRefFromVersionTag("git", read.versionTag);
                this.setManagedQueryMetadata(Object.assign(Object.assign({}, meta), { queryRef: Object.assign(Object.assign({}, meta.queryRef), { path: newPath }), lastSavedTextHash,
                    lastSavedVersionRef }));
                this.setName(nextName);
                this.yasgui.queryBrowser.invalidateAndRefresh(meta.workspaceId);
            }
            catch (e) {
                const err = asWorkspaceBackendError(e);
                window.alert(err.message);
            }
            finally {
                this.getTabListEl().setAsRenaming(false);
            }
        });
    }
    hasResults() {
        var _a;
        return !!((_a = this.yasr) === null || _a === void 0 ? void 0 : _a.results);
    }
    getName() {
        return this.persistentJson.name;
    }
    query() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.yasqe)
                return Promise.reject(new Error("No yasqe editor initialized"));
            const tokenValid = yield this.ensureOAuth2TokenValid();
            if (!tokenValid) {
                return Promise.reject(new Error("OAuth 2.0 authentication failed"));
            }
            return this.yasqe.query();
        });
    }
    setRequestConfig(requestConfig) {
        this.persistentJson.requestConfig = Object.assign(Object.assign({}, this.persistentJson.requestConfig), requestConfig);
        this.emit("change", this, this.persistentJson);
    }
    getAuthForCurrentEndpoint() {
        const endpoint = this.getEndpoint();
        if (!endpoint)
            return undefined;
        const endpointConfig = this.yasgui.persistentConfig.getEndpointConfig(endpoint);
        if (!endpointConfig || !endpointConfig.authentication)
            return undefined;
        const auth = endpointConfig.authentication;
        if (auth.type === "basic") {
            return {
                type: "basic",
                config: {
                    username: auth.username,
                    password: auth.password,
                },
            };
        }
        else if (auth.type === "bearer") {
            return {
                type: "bearer",
                config: {
                    token: auth.token,
                },
            };
        }
        else if (auth.type === "apiKey") {
            return {
                type: "apiKey",
                config: {
                    headerName: auth.headerName,
                    apiKey: auth.apiKey,
                },
            };
        }
        else if (auth.type === "oauth2") {
            if (auth.accessToken) {
                return {
                    type: "oauth2",
                    config: {
                        accessToken: auth.accessToken,
                        idToken: auth.idToken,
                    },
                };
            }
        }
        return undefined;
    }
    ensureOAuth2TokenValid() {
        return __awaiter(this, void 0, void 0, function* () {
            const endpoint = this.getEndpoint();
            if (!endpoint)
                return true;
            const endpointConfig = this.yasgui.persistentConfig.getEndpointConfig(endpoint);
            if (!endpointConfig || !endpointConfig.authentication)
                return true;
            const auth = endpointConfig.authentication;
            if (auth.type !== "oauth2")
                return true;
            if (OAuth2Utils.isTokenExpired(auth.tokenExpiry)) {
                if (auth.refreshToken) {
                    try {
                        const tokenResponse = yield OAuth2Utils.refreshOAuth2Token({
                            clientId: auth.clientId,
                            tokenEndpoint: auth.tokenEndpoint,
                        }, auth.refreshToken);
                        const tokenExpiry = OAuth2Utils.calculateTokenExpiry(tokenResponse.expires_in);
                        this.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
                            authentication: Object.assign(Object.assign({}, auth), { accessToken: tokenResponse.access_token, idToken: tokenResponse.id_token, refreshToken: tokenResponse.refresh_token || auth.refreshToken, tokenExpiry }),
                        });
                        return true;
                    }
                    catch (error) {
                        console.error("Failed to refresh OAuth 2.0 token:", error);
                        alert("Your OAuth 2.0 session has expired and could not be refreshed. Please re-authenticate by clicking the Settings button (gear icon) and selecting the SPARQL Endpoints tab.");
                        return false;
                    }
                }
                else {
                    alert("Your OAuth 2.0 session has expired. Please re-authenticate by clicking the Settings button (gear icon) and selecting the SPARQL Endpoints tab.");
                    return false;
                }
            }
            return true;
        });
    }
    getStaticRequestConfig() {
        const config = {};
        let key;
        for (key in this.yasgui.config.requestConfig) {
            if (key === "adjustQueryBeforeRequest")
                continue;
            const val = this.yasgui.config.requestConfig[key];
            if (typeof val === "function") {
                config[key] = val(this.yasgui);
            }
        }
        return config;
    }
    initYasqe() {
        const currentTheme = this.yasgui.getTheme();
        const cmTheme = currentTheme === "dark" ? "material-palenight" : "default";
        const yasqeConf = Object.assign(Object.assign({}, this.yasgui.config.yasqe), { theme: cmTheme, value: this.persistentJson.yasqe.value, editorHeight: this.persistentJson.yasqe.editorHeight ? this.persistentJson.yasqe.editorHeight : undefined, persistenceId: null, consumeShareLink: null, createShareableLink: () => this.getShareableLink(), showSnippetsBar: this.yasgui.config.showSnippetsBar !== false, requestConfig: () => {
                const processedReqConfig = Object.assign(Object.assign({ acceptHeaderGraph: "text/turtle", acceptHeaderSelect: "application/sparql-results+json" }, mergeWith({}, this.persistentJson.requestConfig, this.getStaticRequestConfig(), function customizer(objValue, srcValue) {
                    if (Array.isArray(objValue) || Array.isArray(srcValue)) {
                        return [...(objValue || []), ...(srcValue || [])];
                    }
                })), { adjustQueryBeforeRequest: this.yasgui.config.requestConfig.adjustQueryBeforeRequest });
                const endpointAuth = this.getAuthForCurrentEndpoint();
                if (endpointAuth) {
                    if (endpointAuth.type === "basic" && typeof processedReqConfig.basicAuth === "undefined") {
                        processedReqConfig.basicAuth = endpointAuth.config;
                    }
                    else if (endpointAuth.type === "bearer" && typeof processedReqConfig.bearerAuth === "undefined") {
                        processedReqConfig.bearerAuth = endpointAuth.config;
                    }
                    else if (endpointAuth.type === "apiKey" && typeof processedReqConfig.apiKeyAuth === "undefined") {
                        processedReqConfig.apiKeyAuth = endpointAuth.config;
                    }
                    else if (endpointAuth.type === "oauth2" && typeof processedReqConfig.oauth2Auth === "undefined") {
                        processedReqConfig.oauth2Auth = endpointAuth.config;
                    }
                }
                return processedReqConfig;
            } });
        const existingExtraKeys = yasqeConf.extraKeys;
        const mergedExtraKeys = existingExtraKeys && typeof existingExtraKeys === "object" ? Object.assign({}, existingExtraKeys) : {};
        mergedExtraKeys["Ctrl-S"] = () => {
            const saveModalOpen = !!document.querySelector(".saveManagedQueryModalOverlay.open");
            if (saveModalOpen)
                return;
            void this.saveManagedQueryOrSaveAsManagedQuery();
        };
        mergedExtraKeys["Cmd-S"] = mergedExtraKeys["Ctrl-S"];
        yasqeConf.extraKeys = mergedExtraKeys;
        if (!yasqeConf.hintConfig) {
            yasqeConf.hintConfig = {};
        }
        if (!yasqeConf.hintConfig.container) {
            yasqeConf.hintConfig.container = this.yasgui.rootEl;
        }
        if (!this.yasqeWrapperEl) {
            throw new Error("Expected a wrapper element before instantiating yasqe");
        }
        this.yasqe = new Yasqe(this.yasqeWrapperEl, yasqeConf);
        this.yasqe.on("saveManagedQuery", () => {
            void this.saveManagedQueryOrSaveAsManagedQuery();
        });
        this.updateSaveButtonVisibility();
        this.yasqe.on("blur", this.handleYasqeBlur);
        this.yasqe.on("query", this.handleYasqeQuery);
        this.yasqe.on("queryBefore", this.handleYasqeQueryBefore);
        this.yasqe.on("queryAbort", this.handleYasqeQueryAbort);
        this.yasqe.on("resize", this.handleYasqeResize);
        this.yasqe.on("autocompletionShown", this.handleAutocompletionShown);
        this.yasqe.on("autocompletionClose", this.handleAutocompletionClose);
        this.yasqe.on("queryResponse", this.handleQueryResponse);
        this.attachYasqeMouseHandler();
    }
    updateSaveButtonVisibility() {
        if (!this.yasqe)
            return;
        const workspaces = this.yasgui.persistentConfig.getWorkspaces();
        const hasWorkspaces = workspaces && workspaces.length > 0;
        this.yasqe.setSaveButtonVisible(hasWorkspaces);
    }
    initSaveManagedQueryIcon() {
        if (!this.yasqe)
            return;
        const wrapper = this.yasqe.getWrapperElement();
        const buttons = wrapper === null || wrapper === void 0 ? void 0 : wrapper.querySelector(".yasqe_buttons");
        if (!buttons)
            return;
        if (buttons.querySelector(".yasqe_saveManagedQueryButton"))
            return;
        const queryBtn = buttons.querySelector(".yasqe_queryButton");
        if (!queryBtn)
            return;
        const saveBtn = document.createElement("button");
        saveBtn.type = "button";
        saveBtn.className = "yasqe_saveManagedQueryButton";
        saveBtn.title = "Save managed query";
        saveBtn.setAttribute("aria-label", "Save managed query");
        saveBtn.innerHTML = '<i class="fas fa-save" aria-hidden="true"></i>';
        saveBtn.addEventListener("click", (e) => {
            e.preventDefault();
            e.stopPropagation();
            void this.saveManagedQueryOrSaveAsManagedQuery();
        });
        buttons.insertBefore(saveBtn, queryBtn);
    }
    destroyYasqe() {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j;
        (_a = this.yasqe) === null || _a === void 0 ? void 0 : _a.off("blur", this.handleYasqeBlur);
        (_b = this.yasqe) === null || _b === void 0 ? void 0 : _b.off("query", this.handleYasqeQuery);
        (_c = this.yasqe) === null || _c === void 0 ? void 0 : _c.off("queryAbort", this.handleYasqeQueryAbort);
        (_d = this.yasqe) === null || _d === void 0 ? void 0 : _d.off("resize", this.handleYasqeResize);
        (_e = this.yasqe) === null || _e === void 0 ? void 0 : _e.off("autocompletionShown", this.handleAutocompletionShown);
        (_f = this.yasqe) === null || _f === void 0 ? void 0 : _f.off("autocompletionClose", this.handleAutocompletionClose);
        (_g = this.yasqe) === null || _g === void 0 ? void 0 : _g.off("queryBefore", this.handleYasqeQueryBefore);
        (_h = this.yasqe) === null || _h === void 0 ? void 0 : _h.off("queryResponse", this.handleQueryResponse);
        this.detachYasqeMouseHandler();
        (_j = this.yasqe) === null || _j === void 0 ? void 0 : _j.destroy();
        this.yasqe = undefined;
    }
    executeBackgroundQuery(query) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.yasqe || !this.yasr)
                return;
            try {
                this.yasr.showLoading();
                this.emit("queryBefore", this);
                const startTime = Date.now();
                const queryResponse = yield Yasqe.Sparql.executeQuery(this.yasqe, undefined, {
                    customQuery: query,
                    customAccept: "text/turtle",
                });
                const duration = Date.now() - startTime;
                this.yasr.setResponse(queryResponse, duration);
                if (this.yasr.plugins["Graph"]) {
                    this.yasr.selectPlugin("Graph");
                }
                this.yasr.hideLoading();
                this.emit("queryResponse", this);
            }
            catch (error) {
                console.error("Background query failed:", error);
                if (this.yasr) {
                    this.yasr.hideLoading();
                    const errorObj = error;
                    let errorText = error instanceof Error ? error.message : String(error);
                    this.yasr.setResponse({
                        error: {
                            status: errorObj.status,
                            statusText: errorObj.statusText || (error instanceof Error ? error.name : undefined),
                            text: errorText,
                        },
                    }, 0);
                }
            }
        });
    }
    attachYasqeMouseHandler() {
        if (!this.yasqe)
            return;
        const wrapper = this.yasqe.getWrapperElement();
        if (wrapper) {
            wrapper.addEventListener("mousedown", this.handleYasqeMouseDown);
        }
    }
    detachYasqeMouseHandler() {
        if (!this.yasqe)
            return;
        const wrapper = this.yasqe.getWrapperElement();
        if (wrapper) {
            wrapper.removeEventListener("mousedown", this.handleYasqeMouseDown);
        }
    }
    initYasr() {
        if (!this.yasrWrapperEl)
            throw new Error("Wrapper for yasr does not exist");
        const yasrConf = {
            persistenceId: null,
            prefixes: (yasr) => {
                var _a;
                const prefixesFromYasrConf = typeof this.yasgui.config.yasr.prefixes === "function"
                    ? this.yasgui.config.yasr.prefixes(yasr)
                    : this.yasgui.config.yasr.prefixes;
                const prefixesFromYasqe = (_a = this.yasqe) === null || _a === void 0 ? void 0 : _a.getPrefixesFromQuery();
                return invert(invert(Object.assign(Object.assign({}, prefixesFromYasrConf), prefixesFromYasqe)));
            },
            defaultPlugin: this.persistentJson.yasr.settings.selectedPlugin,
            getPlainQueryLinkToEndpoint: () => {
                if (this.yasqe) {
                    return shareLink.appendArgsToUrl(this.getEndpoint(), Yasqe.Sparql.getUrlArguments(this.yasqe, this.persistentJson.requestConfig));
                }
            },
            plugins: mapValues(this.persistentJson.yasr.settings.pluginsConfig, (conf) => ({
                dynamicConfig: conf,
            })),
            errorRenderers: [
                getCorsErrorRenderer(this),
                ...(Yasr.defaults.errorRenderers || []),
            ],
        };
        if (yasrConf.getDownloadFileName === undefined) {
            yasrConf.getDownloadFileName = () => words(deburr(this.getName())).join("-");
        }
        this.yasr = new Yasr(this.yasrWrapperEl, yasrConf, this.persistentJson.yasr.response);
        this.persistentJson.yasr.settings = this.yasr.getPersistentConfig();
        this.yasr.on("change", () => {
            if (this.yasr) {
                this.persistentJson.yasr.settings = this.yasr.getPersistentConfig();
            }
            this.emit("change", this, this.persistentJson);
        });
    }
    drawVerticalResizer() {
        if (this.verticalResizerEl || !this.rootEl)
            return;
        this.verticalResizerEl = document.createElement("div");
        addClass(this.verticalResizerEl, "verticalResizeWrapper");
        const chip = document.createElement("div");
        addClass(chip, "verticalResizeChip");
        this.verticalResizerEl.appendChild(chip);
        this.verticalResizerEl.addEventListener("mousedown", this.initVerticalDrag, false);
        this.verticalResizerEl.addEventListener("dblclick", this.resetVerticalSplit, false);
        this.rootEl.appendChild(this.verticalResizerEl);
    }
    calculateVerticalDragOffset(event) {
        if (!this.rootEl)
            return 0;
        let parentOffset = 0;
        if (this.rootEl.offsetParent) {
            parentOffset = this.rootEl.offsetParent.offsetLeft;
        }
        let scrollOffset = 0;
        let parentElement = this.rootEl.parentElement;
        while (parentElement) {
            scrollOffset += parentElement.scrollLeft;
            parentElement = parentElement.parentElement;
        }
        return event.clientX - parentOffset - this.rootEl.offsetLeft + scrollOffset;
    }
    destroy() {
        var _a, _b, _c;
        if (this.verticalResizerEl) {
            this.verticalResizerEl.removeEventListener("mousedown", this.initVerticalDrag, false);
            this.verticalResizerEl.removeEventListener("dblclick", this.resetVerticalSplit, false);
        }
        document.documentElement.removeEventListener("mousemove", this.doVerticalDrag, false);
        document.documentElement.removeEventListener("mouseup", this.stopVerticalDrag, false);
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
            this.resizeObserver = undefined;
        }
        this.removeAllListeners();
        (_a = this.settingsModal) === null || _a === void 0 ? void 0 : _a.destroy();
        (_b = this.endpointSelect) === null || _b === void 0 ? void 0 : _b.destroy();
        this.endpointSelect = undefined;
        (_c = this.yasr) === null || _c === void 0 ? void 0 : _c.destroy();
        this.yasr = undefined;
        this.destroyYasqe();
    }
    static getDefaults(yasgui) {
        return {
            yasqe: {
                value: yasgui ? yasgui.config.yasqe.value : Yasgui.defaults.yasqe.value,
            },
            yasr: {
                response: undefined,
                settings: {
                    selectedPlugin: yasgui ? yasgui.config.yasr.defaultPlugin : "table",
                    pluginsConfig: {},
                },
            },
            requestConfig: yasgui ? yasgui.config.requestConfig : Object.assign({}, Yasgui.defaults.requestConfig),
            id: getRandomId(),
            name: yasgui ? yasgui.createTabName() : Yasgui.defaults.tabName,
        };
    }
}
export default Tab;
const safeEndpoint = (endpoint) => {
    const url = new URL(endpoint);
    return encodeURI(url.href);
};
function getCorsErrorRenderer(tab) {
    return (error) => __awaiter(this, void 0, void 0, function* () {
        if (!error.status) {
            const shouldReferToHttp = new URL(tab.getEndpoint()).protocol === "http:" && window.location.protocol === "https:";
            const isNetworkError = !error.text ||
                error.text.indexOf("Request has been terminated") >= 0 ||
                error.text.indexOf("Failed to fetch") >= 0 ||
                error.text.indexOf("NetworkError") >= 0 ||
                error.text.indexOf("Network request failed") >= 0;
            if (shouldReferToHttp && isNetworkError) {
                const errorEl = document.createElement("div");
                const errorSpan = document.createElement("p");
                errorSpan.innerHTML = `You are trying to query an HTTP endpoint (<a href="${safeEndpoint(tab.getEndpoint())}" target="_blank" rel="noopener noreferrer">${safeEndpoint(tab.getEndpoint())}</a>) from an HTTP<strong>S</strong> website (<a href="${safeEndpoint(window.location.href)}">${safeEndpoint(window.location.href)}</a>).<br>This can be blocked in modern browsers, see <a target="_blank" rel="noopener noreferrer" href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy">https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy</a>. See also <a href="https://yasgui-doc.matdata.eu/docs/user-guide#querying-local-endpoints">the YasGUI documentation</a> for possible workarounds.`;
                errorEl.appendChild(errorSpan);
                return errorEl;
            }
        }
    });
}
//# sourceMappingURL=Tab.js.map