PageSourceSearch

https://rominaeva.com/js/show_toast.js

js rominaeva.com collected 2026-09-29 01:36:45 UTC 8,650 bytes, 177 lines download raw bytes

1/**
2 * Author and copyright: Stefan Haack (https://shaack.com)
3 * Repository: https://github.com/shaack/bootstrap-show-toast
4 * License: MIT, see file 'LICENSE'
5 */
6; (function (bootstrap) {
7    "use strict"
8
9    function createElement(html) {
10        const template = document.createElement('template')
11        template.innerHTML = html.trim()
12        return template.content.firstChild
13    }
14
15    function Toast(props) {
16        // see https://getbootstrap.com/docs/5.2/components/toasts/
17        this.props = {
18            header: "", // the header text
19            headerSmall: "", // additional text in the header, aligns right
20            body: "", // the body text of the toast
21            closeButton: true, // show a close button
22            closeButtonLabel: "close", // the label of the close button
23            closeButtonClass: "", // set to "btn-close-white" for dark backgrounds
24            toastClass: "", // the appearance
25            animation: true, // apply a CSS fade transition to the toast
26            delay: 5000, //	delay in milliseconds before hiding the toast, set delay to `Infinity` to make it sticky
27            position: "top-0 end-0", // top right
28            topOffset: "", // override top position with an explicit CSS value (e.g. "80px") — omit top-0 from position when using this
29            rightOffset: "", // override right padding with a CSS value (e.g. "16px") or "container" to auto-align with the Bootstrap .container right edge
30            direction: "append", // or "prepend", the stack direction
31            zIndex: 1100, // the z-index of the container
32            ariaLive: "assertive",
33            type: "info", // "info", "success", "warning", "error"
34            width: "", // override toast width with an explicit CSS value (e.g. "250px")
35        }
36        this.containerId = "bootstrap-show-toast-container-" + this.props.position.replace(" ", "_")
37        for (let prop in props) {
38            // noinspection JSUnfilteredForInLoop
39            this.props[prop] = props[prop]
40        }
41        const cssClass = ("toast " + this.props.toastClass).trim()
42        let toastHeader = ""
43        const showHeader = this.props.header || this.props.headerSmall
44        let colors = {
45            info: "primary",
46            success: "success",
47            warning: "warning",
48            error: "danger"
49        }
50        if (showHeader) {
51            toastHeader = `<div class="toast-header bg-white border-0 border-start border-5 border-${colors[this.props.type]} rounded">
52                            <div class="mb-0 me-auto">${this.props.header}</div>
53                            ${this.props.headerSmall ? `<small>${this.props.headerSmall}</small>` : ""}
54                            ${this.props.closeButton ? `<button type="button" class="btn-close ${this.props.closeButtonClass}" data-bs-dismiss="toast" aria-label="${this.props.closeButtonLabel}"></button>` : ""}
55                          </div>`
56        }
57        this.template =
58            `<div class="${cssClass} border-0 shadow-lg" role="alert" aria-live="${this.props.ariaLive}" aria-atomic="true">
59              ${toastHeader}
60            </div>`
61        //   <div class="d-flex bg-white">
62        //       <div class="toast-body">
63        //         ${this.props.body}
64        //       </div>
65        //       ${(!showHeader && this.props.closeButton) ? `<button type="button" class="btn-close me-2 mx-auto ${this.props.closeButtonClass}" style="margin-top: 0.69rem" data-bs-dismiss="toast" aria-label="${this.props.closeButtonLabel}"></button>` : ""}
66        //   </div>
67        this.container = document.getElementById(this.containerId)
68        if (!this.container) {
69            this.container = document.createElement("div")
70            this.container.id = this.containerId
71            this.container.setAttribute("class", "toast-container position-fixed p-3 " + this.props.position)
72            this.container.style.zIndex = "" + this.props.zIndex
73            this.container.style.transition = "margin-top 0.3s ease"
74            if (this.props.topOffset) {
75                const applyTopMargin = (container, topOffsetProp) => {
76                    if (topOffsetProp === 'navbar') {
77                        const navbarEl = document.querySelector('nav.navbar')
78                        if (!navbarEl) {
79                            container.style.setProperty('margin-top', '0px', 'important')
80                            return
81                        }
82                        const isNavbarVisible = !navbarEl.classList.contains('navbar--hidden')
83                        if (isNavbarVisible) {
84                            const topMargin = (navbarEl.getBoundingClientRect().bottom - 10) + 'px'
85                            container.style.setProperty('margin-top', topMargin, 'important')
86                        } else {
87                            container.style.setProperty('margin-top', '0px', 'important')
88                        }
89                        return
90                    }
91                    container.style.setProperty('margin-top', topOffsetProp, 'important')
92                }
93
94                applyTopMargin(this.container, this.props.topOffset)
95
96                if (this.props.topOffset === 'navbar') {
97                    // Re-apply on resize
98                    window.addEventListener('resize', () => {
99                        applyTopMargin(this.container, this.props.topOffset)
100                    })
101
102                    // Re-apply on scroll to track navbar show/hide
103                    window.addEventListener('scroll', () => {
104                        applyTopMargin(this.container, this.props.topOffset)
105                    }, { passive: true })
106
107                    // Also observe class changes on the navbar for immediate reaction
108                    const navbarEl = document.querySelector('nav.navbar')
109                    if (navbarEl) {
110                        const observer = new MutationObserver(() => {
111                            applyTopMargin(this.container, this.props.topOffset)
112                        })
113                        observer.observe(navbarEl, { attributes: true, attributeFilter: ['class'] })
114                    }
115                }
116            }
117            if (this.props.rightOffset) {
118                const applyRightPadding = (container, rightOffsetProp) => {
119                    if (rightOffsetProp === 'container') {
120                        // Look for the specific page container: catalogue or product detail
121                        const targetEl = document.querySelector('.catalogue-container')
122                            || document.querySelector('.top-area')
123                        if (!targetEl) {
124                            container.style.setProperty('padding-right', '0px', 'important')
125                            return
126                        }
127                        const targetRect = targetEl.getBoundingClientRect()
128                        const rightGap = window.innerWidth - targetRect.right
129                        container.style.setProperty('padding-right', Math.max(rightGap, 0) + 'px', 'important')
130                        return
131                    }
132                    container.style.setProperty('padding-right', rightOffsetProp, 'important')
133                }
134
135                applyRightPadding(this.container, this.props.rightOffset)
136
137                if (this.props.rightOffset === 'container') {
138                    window.addEventListener('resize', () => {
139                        applyRightPadding(this.container, this.props.rightOffset)
140                    })
141                }
142            }
143            document.body.appendChild(this.container)
144        }
145        this.element = createElement(this.template)
146        if (this.props.width) {
147            this.element.style.width = this.props.width
148        }
149        this.toast = this.showToast(this.element)
150    }
151
152    Toast.prototype.showToast = function (toastElement) {
153        if (this.props.direction === "prepend") {
154            this.container.prepend(toastElement)
155        } else {
156            this.container.append(toastElement)
157        }
158        this.toast = new bootstrap.Toast(toastElement, {
159            animation: this.props.animation,
160            autohide: this.props.delay > 0 && this.props.delay !== Infinity, // TODO remove 0 for infinity 2022-09-02
161            delay: this.props.delay
162
163        })
164        this.toast.show()
165
166        return toastElement
167    }
168
169    bootstrap.showToast = function (props) {
170        return new Toast(props)
171    }
172
173}(bootstrap))
174
175window.addEventListener("showToast", function (event) {
176    bootstrap.showToast(event.detail)
177})

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.