PageSourceSearch

https://imacademy.cz/js/dynamic-modal.js

js imacademy.cz collected 2026-10-10 00:28:40 UTC 7,384 bytes, 208 lines download raw bytes

1import Form from "./form.js";
2import GlobalListeners from "./global-listeners.js";
3import Utils from "./utils.js";
4class DynamicModal {
5    static instance;
6    $modalContainer;
7    $modalHeader;
8    $modalBody;
9    $loading;
10    isShown = false;
11    modalsInQueue = [];
12    constructor() {
13        this.$modalContainer = $("#dynamic-modal");
14        this.$modalHeader = this.$modalContainer.find('.modal-content .modal-header');
15        this.$modalBody = this.$modalContainer.find('.modal-content .modal-body');
16        this.$loading = this.$modalContainer.find('.loading');
17        this.$modalContainer
18            .on('show.bs.modal', () => this.showModalHandler())
19            .on('hide.bs.modal', () => this.hideModalHandler())
20            .on('hidden.bs.modal', () => this.hiddenModalHandler());
21    }
22    static getInstance() {
23        if (!DynamicModal.instance) {
24            DynamicModal.instance = new DynamicModal();
25        }
26        return DynamicModal.instance;
27    }
28    async LoadAndShow(param) {
29        if (param == undefined) {
30            console.error("DynamicModal.LoadAndShow: invalid parameters");
31            return;
32        }
33        if (typeof param === "string") {
34            var props = new DynamicModalProps();
35            props.contentSource = param;
36            await this.LoadAndShow(props);
37            return;
38        }
39        var props = param;
40        this.$loading.show();
41        if (!props.closeButton) {
42            this.$modalHeader.addClass("hidden");
43        }
44        else {
45            this.$modalHeader.removeClass("hidden");
46        }
47        if (props.staticBackdrop === false) {
48            this.$modalContainer.on('hidePrevented.bs.modal', function () {
49                $(this).modal('hide');
50            });
51        }
52        $(this.$modalContainer).find(".modal-dialog").removeClass("modal-xl modal-lg modal-md modal-sm").addClass(`modal-${props.size}`);
53        if (!this.isShown) {
54            this.$modalContainer.modal('show');
55        }
56        var content = await this.getContent(props.contentSource);
57        this.replaceWithContent(content);
58        this.$loading.hide();
59    }
60    async Hide() {
61        if (this.isShown) {
62            this.$modalContainer.modal('hide');
63        }
64    }
65    AddToQueue(props) {
66        this.modalsInQueue.push(props);
67    }
68    handleBackButton() {
69        // look in content for div with class "back-url" and take it's data-content into a variable
70        var $modalBackButton = this.$modalHeader.find(".modal-back");
71        var backUrl = this.$modalBody.find(".back-url").first().data("content");
72        if (!backUrl) {
73            $modalBackButton.css("display", "none");
74            return;
75        }
76        $modalBackButton.attr("data-content", backUrl);
77        $modalBackButton.css("display", "flex");
78        $modalBackButton.off("click");
79        $modalBackButton.on("click", () => {
80            this.LoadAndShow(backUrl);
81        });
82    }
83    replaceWithContent(content) {
84        // check if content starts with <div class="modal-body">
85        this.$modalBody.remove();
86        if (content.trimStart().startsWith('<div class="modal-body')) {
87            this.$modalBody = $(content);
88        }
89        else {
90            this.$modalBody = $('<div class="modal-body"></div>');
91            this.$modalBody.html(content);
92        }
93        this.$modalContainer.find('.modal-content').append(this.$modalBody);
94        var context = this;
95        this.$modalContainer.find("form").each(function () {
96            if ($(this).hasClass("cancel-modal-form-hook"))
97                return;
98            new Form($(this), context.$loading, (data) => context.handleSuccess(data));
99        });
100        this.handleBackButton();
101        GlobalListeners.Initialize(this.$modalContainer);
102    }
103    async handleSuccess(response) {
104        var data = await response.text();
105        if (data.startsWith("success")) {
106            var dataArr = data.split(";");
107            if (dataArr.length == 1) {
108                // no redirect
109                location.reload();
110                return;
111            }
112            var redirectUrl = dataArr[1];
113            location.href = redirectUrl;
114        }
115        else {
116            this.replaceWithContent(data);
117            this.$loading.hide();
118        }
119    }
120    async getContent(contentSource) {
121        if (contentSource == null || contentSource == "")
122            return Promise.resolve(null);
123        return new Promise((resolve, reject) => {
124            if (contentSource.startsWith('/')) {
125                // load content from url
126                $.get(contentSource, (data) => {
127                    resolve(data);
128                }).fail((jqXHR, textStatus, error) => {
129                    console.debug(jqXHR);
130                    var displayedError = jqXHR.responseText.length > 300
131                        ? error
132                        : jqXHR.responseText;
133                    toastr.error(displayedError);
134                });
135            }
136            else if (contentSource.startsWith('#')) {
137                // load content from element
138                const content = $(contentSource).html();
139                if (content) {
140                    resolve(content);
141                }
142                else {
143                    reject(new Error(`Failed to load content from element: ${contentSource}`));
144                }
145            }
146            else {
147                resolve(contentSource);
148            }
149        });
150    }
151    showModalHandler() {
152        Utils.PauseAllVideos();
153        this.isShown = true;
154    }
155    hideModalHandler() {
156        Utils.PauseAllVideos();
157        this.isShown = false;
158        this.$modalContainer.off('hidePrevented.bs.modal');
159    }
160    hiddenModalHandler() {
161        GlobalListeners.Dispose(this.$modalBody);
162        this.$modalBody.html("");
163        // reset classes to default
164        this.$modalHeader.removeClass("hidden");
165        // reattach event handlers
166        // to get rid of all other attached handlers from specific modals
167        this.$modalContainer.off();
168        this.$modalContainer
169            .on('show.bs.modal', () => this.showModalHandler())
170            .on('hide.bs.modal', () => this.hideModalHandler())
171            .on('hidden.bs.modal', () => this.hiddenModalHandler());
172        // load next modal from queue
173        if (this.modalsInQueue.length > 0) {
174            var props = this.modalsInQueue.shift();
175            this.LoadAndShow(props);
176        }
177    }
178}
179export function InitializeDynamicModalTrigger($trigger) {
180    var props = new DynamicModalProps;
181    {
182        props.contentSource = $trigger.data("content");
183        props.closeButton = $trigger.dataBool("close-button");
184        props.size = $trigger.data("size");
185        props.staticBackdrop = $trigger.dataBool("static-backdrop");
186    }
187    var autoShow = $trigger.dataBool("auto-show");
188    if (autoShow) {
189        if (!dynamicModal.isShown) {
190            dynamicModal.LoadAndShow(props);
191        }
192        else {
193            dynamicModal.AddToQueue(props);
194        }
195        return;
196    }
197    $trigger.on("click", function () {
198        dynamicModal.LoadAndShow(props);
199    });
200}
201export class DynamicModalProps {
202    contentSource;
203    closeButton = true;
204    size = "md";
205    staticBackdrop = true;
206}
207export const dynamicModal = DynamicModal.getInstance();
208//# sourceMappingURL=dynamic-modal.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.