diff --git a/src/scrpt.min.js b/src/scrpt.min.js index 2c9919e..655b393 100644 --- a/src/scrpt.min.js +++ b/src/scrpt.min.js @@ -1 +1 @@ -const xPositions = ["left", "right"], yPositions = ["top", "bottom"], nm = "scrpt", chatWidth = "400px", domain = "http://164.90.239.9:8000"; class Scrpt { loadInterval; constructor({ position: t = "bottom-right", appName: e = "" } = {}) { if (this.position = this.getPosition(t), this.open = !1, this.inputText = "", this.appName = e, !t.includes("-")) throw new Error("position must include - symbol. for example bottom-right"); if (!yPositions.includes(t.split("-")[0])) throw new Error("y position must be top or bottom"); if (!xPositions.includes(t.split("-")[1])) throw new Error("x position must be left or right"); if ("" === e) throw new Error("invalid app name"); this.getChatInitialData(e).then((t => { this.initialize() })), this.createStyles() } detectMob() { return [/Android/i, /webOS/i, /iPhone/i, /iPad/i, /iPod/i, /BlackBerry/i, /Windows Phone/i].some((t => navigator.userAgent.match(t))) } getPosition(t) { const [e, n] = t.split("-"); return { [e]: "40px", [n]: "40px" } } initialize() { const t = document.createElement("div"); t.style.position = "fixed", t.style.zIndex = "9999", Object.keys(this.position).forEach((e => t.style[e] = this.position[e])), document.body.appendChild(t); const e = document.createElement("div"); e.classList.add(`${nm}-button-container`); const n = document.createElement("span"); n.innerHTML = '\n \n \n ', n.classList.add(`${nm}-icon`), this.chatIcon = n; const i = document.createElement("span"); i.innerHTML = '\n \n ', i.classList.add(`${nm}-icon`, `${nm}-hidden`), this.closeIcon = i, this.chatContainer = document.createElement("div"), this.chatContainer.classList.add(`${nm}-hidden`, `${nm}-chat-container`), this.chatContainer.style.width = this.detectMob() ? window.innerWidth - 5 + "px" : "400px", this.chatContainer.style.bottom = this.detectMob() ? "0px" : "75px", this.createChatContainerContent(), this.chatContent.style.height = this.detectMob() ? window.innerHeight - 230 + "px" : "500px", e.appendChild(this.chatIcon), e.appendChild(this.closeIcon), e.addEventListener("click", this.toggleOpen.bind(this)), t.appendChild(this.chatContainer), t.appendChild(e), this.chatContent.innerHTML += this.chatStripe(!0, this.welcomeMessage, "") } createStyles() { const t = document.createElement("style"); document.head.appendChild(t), t.innerHTML = `\n .${nm}-clearfix::after {content: "";clear: both;display: table;}.${nm}-icon {cursor: pointer;width: 100%;position: absolute;top: 11px;left: 13px;transition: transform .3s ease;color: white;}.${nm}-hidden {transform: scale(0);}.${nm}-button-container {background: linear-gradient(to bottom right, #4294e3, #8f12fd);width: 70px;height: 70px;border-radius: 50%;}.${nm}-chat-container {box-shadow: 0 0 18px 8px rgba(0,0,0, 0.1);right: -25px;bottom: 75px;position: absolute;transition: max-height .2s ease;background-color: white;border-radius: 10px;}.${nm}-chat-container.hidden {max-height: 0px;}.${nm}-scrpt-header {display: inline-block;width: 100%;margin: 0;padding: 10px;color: white;background: linear-gradient(to bottom right, #4294e3, #8f12fd);border-top-left-radius: 10px;border-top-right-radius: 10px;}.${nm}-chat-container form input {padding: 20px;display: inline-block;width: calc(100% - 50px);border: 0px;background-color: #f7f7f7;}.${nm}-chat-container form input:focus {outline: none;}.${nm}-chat-container form button {cursor: pointer;color: #8f12fd;background-color: #f7f7f7;border: 0;border-radius: 4px;padding: 20px 10px;}.${nm}-scrpt-chat-bottom-menu {padding-top: 20px;list-style-type: none;text-align: center;padding-left: 0px;margin-left: 0px;}.${nm}-scrpt-chat-bottom-menu li {display: inline-block;padding-left: 30px;padding-right: 30px;cursor: pointer;}.${nm}-bottom-menu-icon {padding-bottom: 5px;display: inline-block;}.${nm}-chat-content {display: block;width: 100%;padding: 10px;overflow-y: scroll;position: relative;box-shadow: 0 4px 2px -2px rgba(0,0,0, 0.1);}.${nm}-close-button, .${nm}-fullscreen-button {border: 0px;background-color: white;border-radius: 100%;padding-bottom: 3px;float: right;margin-left: 4px;}.${nm}-msg-box {display: inline-block;width:80%;}.${nm}-msg-box p {padding: 7px;}.${nm}-income {float: left;}.${nm}-outcome {float: right;}.${nm}-bubble-outcome {background-color: gray;color: white;border-top-left-radius: 10px;border-top-right-radius: 10px;border-bottom-left-radius: 10px;}.${nm}-bubble-income {background-color: #f7f7f7;color: #424242;border-top-left-radius: 10px;border-top-right-radius: 10px;border-bottom-right-radius: 10px;}\n ` } createChatContainerContent() { const t = document.createElement("span"); t.classList.add(`${nm}-clearfix`), this.chatContainer.innerHTML = ""; const e = document.createElement("div"); e.classList.add(`${nm}-scrpt-header`); const n = document.createElement("button"); n.innerHTML = '\n \n ', n.classList.add(`${nm}-close-button`), n.addEventListener("click", (() => this.closeChat())), e.appendChild(n), this.fullScreenButton = document.createElement("button"), this.fullScreenButton.innerHTML = '\n \n ', this.fullScreenButton.classList.add(`${nm}-fullscreen-button`), this.fullScreenButton.addEventListener("click", (() => this.fullscreenchat())), e.appendChild(this.fullScreenButton); const i = document.createElement("form"); i.classList.add(`${nm}-content`); const o = document.createElement("input"); o.requered = !0, o.id = `${nm}-text`, o.type = "text", o.placeholder = this.inputText, this.btn = document.createElement("button"), this.btn.innerHTML = '\n \n ', this.chatContent = document.createElement("div"), this.chatContent.classList.add(`${nm}-chat-content`), i.appendChild(this.chatContent), i.appendChild(t), i.appendChild(o), i.appendChild(this.btn), i.addEventListener("submit", this.submit.bind(this)); const a = document.createElement("ul"); a.classList.add(`${nm}-scrpt-chat-bottom-menu`);[{ icon: '\n \n \n ', text: "Home", click: function () { alert(this.text) } }, { icon: '\n \n \n \n ', text: "Chat", click: function () { alert(this.text) } }, { icon: '\n \n \n \n ', text: "Help", click: function () { alert(this.text) } }].forEach((t => { let e = document.createElement("li"), n = document.createElement("span"); n.classList.add(`${nm}-bottom-menu-icon`), n.innerHTML = t.icon, e.appendChild(n); let i = document.createElement("br"); e.appendChild(i); let o = document.createElement("span"); o.innerHTML = t.text, e.appendChild(o), a.appendChild(e) })), this.chatContainer.appendChild(e), this.chatContainer.appendChild(i), this.chatContainer.appendChild(t), this.chatContainer.appendChild(a) } async submit(t) { t.preventDefault(); let e = this.generateUniqueId(), n = document.getElementById(`${nm}-text`), i = n.value; if ("" === i.trim()) return; this.chatContent.innerHTML += this.chatStripe(!1, i, ""), n.disabled = !0, n.value = "", this.btn.disabled = !0; let o = await this.makeRequest("POST", `${domain}/answer?name=${this.appName}`, { question: i }); o = JSON.parse(o), this.chatContent.innerHTML += this.chatStripe(!0, " ", e); const a = document.getElementById(e); this.typeText(a, o.answer) } toggleOpen() { this.open = !this.open, this.open ? this.openChat() : this.closeChat() } fullscreenchat() { "400px" === this.chatContainer.style.width ? (this.chatContainer.style.width = window.innerWidth - 30 + "px", this.chatContainer.style.height = window.innerHeight - 125 + "px") : (this.chatContainer.style.width = this.detectMob() ? window.innerWidth - 17 + "px" : "400px", this.chatContainer.style.bottom = this.detectMob() ? "0px" : "75px", this.chatContainer.style.height = "auto") } closeChat() { this.open = !1, this.chatIcon.classList.remove(`${nm}-hidden`), this.closeIcon.classList.add(`${nm}-hidden`), this.chatContainer.classList.add(`${nm}-hidden`) } openChat() { this.chatIcon.classList.add(`${nm}-hidden`), this.closeIcon.classList.remove(`${nm}-hidden`), this.chatContainer.classList.remove(`${nm}-hidden`) } typeText(t, e) { let n = 0, i = setInterval((() => { if (n < e.length) t.innerHTML += e.charAt(n), n++, this.chatContent.scrollTop = this.chatContent.scrollHeight; else { clearInterval(i), document.getElementById(`${nm}-text`).disabled = !1, this.btn.disabled = !1 } }), 20) } uuidv4() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (t => (t ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> t / 4).toString(16))) } generateUniqueId() { return this.uuidv4() } chatStripe(t, e, n) { return `\n
\n

${e}

\n
\n ` } async getChatInitialData(t) { let e = await this.makeRequest("GET", `${domain}/api/project/${t}/init`), n = JSON.parse(e); this.welcomeMessage = n.data.welcome_message, this.inputText = n.data.input_text } makeRequest(t, e, n = {}) { return new Promise((function (i, o) { let a = new XMLHttpRequest; a.open(t, e), a.setRequestHeader("Content-type", "application/json"), a.onload = function () { this.status >= 200 && this.status < 300 ? i(a.response) : o({ status: this.status, statusText: a.statusText }) }, a.onerror = function () { o({ status: this.status, statusText: a.statusText }) }, 0 !== Object.keys(n).length ? a.send(JSON.stringify(n)) : a.send() })) } } \ No newline at end of file +const xPositions = ["left", "right"], yPositions = ["top", "bottom"], nm = "scrpt", chatWidth = "400px", domain = "http://164.90.239.9:8000"; class Scrpt { loadInterval; constructor({ position: t = "bottom-right", appName: e = "" } = {}) { if (this.position = this.getPosition(t), this.open = !1, this.inputText = "", this.appName = e, !t.includes("-")) throw new Error("position must include - symbol. for example bottom-right"); if (!yPositions.includes(t.split("-")[0])) throw new Error("y position must be top or bottom"); if (!xPositions.includes(t.split("-")[1])) throw new Error("x position must be left or right"); if ("" === e) throw new Error("invalid app name"); this.getChatInitialData(e).then((t => { this.initialize() })), this.createStyles() } detectMob() { return [/Android/i, /webOS/i, /iPhone/i, /iPad/i, /iPod/i, /BlackBerry/i, /Windows Phone/i].some((t => navigator.userAgent.match(t))) } getPosition(t) { const [e, i] = t.split("-"); return { [e]: "40px", [i]: "40px" } } initialize() { const t = this.dce("div"); t.style.position = "fixed", t.style.zIndex = "9999", Object.keys(this.position).forEach((e => t.style[e] = this.position[e])), document.body.appendChild(t); const e = this.dce("div"); e.classList.add(`${nm}-button-container`); const i = this.dce("img"); i.src = "https://icons.getbootstrap.com/assets/icons/chat-dots.svg", i.classList.add(`${nm}-icon`), this.chatIcon = i; const n = this.dce("img"); n.src = "https://icons.getbootstrap.com/assets/icons/x.svg", n.classList.add(`${nm}-icon`, `${nm}-hidden`), this.closeIcon = n, this.chatContainer = this.dce("div"), this.chatContainer.classList.add(`${nm}-hidden`, `${nm}-chat-container`), this.chatContainer.style.width = this.detectMob() ? window.innerWidth - 5 + "px" : "400px", this.chatContainer.style.bottom = this.detectMob() ? "0px" : "75px", this.createChatContainerContent(), this.chatContent.style.height = this.detectMob() ? window.innerHeight - 230 + "px" : "500px", e.appendChild(this.chatIcon), e.appendChild(this.closeIcon), e.addEventListener("click", this.toggleOpen.bind(this)), t.appendChild(this.chatContainer), t.appendChild(e), this.chatContent.innerHTML += this.chatStripe(!0, this.welcomeMessage, "") } createStyles() { const t = this.dce("style"); document.head.appendChild(t), t.innerHTML = `\n .${nm}-clearfix::after {content: "";clear: both;display: table;}.${nm}-icon {cursor: pointer;width: 65%;position: absolute;top: 11px;left: 13px;transition: transform .3s ease;filter: invert(1);}.${nm}-hidden {transform: scale(0);}.${nm}-button-container {background: linear-gradient(to bottom right, #4294e3, #8f12fd);width: 70px;height: 70px;border-radius: 50%;}.${nm}-chat-container {box-shadow: 0 0 18px 8px rgba(0,0,0, 0.1);right: -25px;bottom: 75px;position: absolute;transition: max-height .2s ease;background-color: white;border-radius: 10px;}.${nm}-chat-container.hidden {max-height: 0px;}.${nm}-scrpt-header {display: inline-block;width: 100%;margin: 0;padding: 10px;color: white;background: linear-gradient(to bottom right, #4294e3, #8f12fd);border-top-left-radius: 10px;border-top-right-radius: 10px;}.${nm}-chat-container form input {padding: 20px;display: inline-block;width: calc(100% - 50px);border: 0px;background-color: #f7f7f7;}.${nm}-chat-container form input:focus {outline: none;}.${nm}-chat-send {cursor: pointer;display: inline-block;padding: 20px 14px;background-color: #f7f7f7;}.${nm}-scrpt-chat-bottom-menu {padding-top: 20px;list-style-type: none;text-align: center;padding-left: 0px;margin-left: 0px;}.${nm}-scrpt-chat-bottom-menu li {display: inline-block;padding-left: 30px;padding-right: 30px;cursor: pointer;}.${nm}-bottom-menu-icon {padding-bottom: 8px;display: inline-block; width: 20px;}.${nm}-chat-content {display: block;width: 100%;padding: 10px;overflow-y: scroll;position: relative;box-shadow: 0 4px 2px -2px rgba(0,0,0, 0.1);}.${nm}-close-button, .${nm}-fullscreen-button {border: 0px;background-color: white;border-radius: 100%;padding-bottom: 3px;float: right;margin-left: 4px;}.${nm}-msg-box {display: inline-block;width:80%;}.${nm}-msg-box p {padding: 7px;}.${nm}-income {float: left;}.${nm}-outcome {float: right;}.${nm}-bubble-outcome {background-color: gray;color: white;border-top-left-radius: 10px;border-top-right-radius: 10px;border-bottom-left-radius: 10px;}.${nm}-bubble-income {background-color: #f7f7f7;color: #424242;border-top-left-radius: 10px;border-top-right-radius: 10px;border-bottom-right-radius: 10px;}\n ` } createChatContainerContent() { const t = this.dce("span"); t.classList.add(`${nm}-clearfix`), this.chatContainer.innerHTML = ""; const e = this.dce("div"); e.classList.add(`${nm}-scrpt-header`); const i = this.dce("button"); let n = this.dce("img"); n.src = this.closeIcon.src, i.appendChild(n), i.classList.add(`${nm}-close-button`), i.addEventListener("click", (() => this.closeChat())), e.appendChild(i), this.fullScreenButton = this.dce("button"); let s = this.dce("img"); s.src = "https://icons.getbootstrap.com/assets/icons/arrows-angle-expand.svg", this.fullScreenButton.appendChild(s), this.fullScreenButton.classList.add(`${nm}-fullscreen-button`), this.fullScreenButton.addEventListener("click", (() => this.fullscreenchat())), e.appendChild(this.fullScreenButton); const o = this.dce("form"); o.classList.add(`${nm}-content`); const a = this.dce("input"); a.requered = !0, a.id = `${nm}-text`, a.type = "text", a.placeholder = this.inputText; let c = this.dce("div"); this.btn = this.dce("img"), this.btn.src = "https://icons.getbootstrap.com/assets/icons/send.svg", c.classList.add(`${nm}-chat-send`), this.btn.style.width = "20px", c.appendChild(this.btn), this.chatContent = this.dce("div"), this.chatContent.classList.add(`${nm}-chat-content`), o.appendChild(this.chatContent), o.appendChild(t), o.appendChild(a), o.appendChild(c), o.addEventListener("submit", this.submit.bind(this)); const d = this.dce("ul"); d.classList.add(`${nm}-scrpt-chat-bottom-menu`);[{ icon: "https://icons.getbootstrap.com/assets/icons/house.svg", text: "Home", click: function () { alert(this.text) } }, { icon: this.chatIcon.src, text: "Chat", click: function () { alert(this.text) } }, { icon: "https://icons.getbootstrap.com/assets/icons/question-circle.svg", text: "Help", click: function () { alert(this.text) } }].forEach((t => { let e = this.dce("li"), i = this.dce("img"); i.classList.add(`${nm}-bottom-menu-icon`), i.src = t.icon, e.appendChild(i); let n = this.dce("br"); e.appendChild(n); let s = this.dce("span"); s.innerHTML = t.text, e.appendChild(s), d.appendChild(e) })), this.chatContainer.appendChild(e), this.chatContainer.appendChild(o), this.chatContainer.appendChild(t), this.chatContainer.appendChild(d) } async submit(t) { t.preventDefault(); let e = this.generateUniqueId(), i = document.getElementById(`${nm}-text`), n = i.value; if ("" === n.trim()) return; this.chatContent.innerHTML += this.chatStripe(!1, n, ""), i.disabled = !0, i.value = "", this.btn.disabled = !0; let s = await this.makeRequest("POST", `${domain}/answer?name=${this.appName}`, { question: n }); s = JSON.parse(s), this.chatContent.innerHTML += this.chatStripe(!0, " ", e); const o = document.getElementById(e); this.typeText(o, s.answer) } toggleOpen() { this.open = !this.open, this.open ? this.openChat() : this.closeChat() } fullscreenchat() { "400px" === this.chatContainer.style.width ? (this.chatContainer.style.width = window.innerWidth - 30 + "px", this.chatContainer.style.height = window.innerHeight - 125 + "px") : (this.chatContainer.style.width = this.detectMob() ? window.innerWidth - 17 + "px" : "400px", this.chatContainer.style.bottom = this.detectMob() ? "0px" : "75px", this.chatContainer.style.height = "auto") } closeChat() { this.open = !1, this.chatIcon.classList.remove(`${nm}-hidden`), this.closeIcon.classList.add(`${nm}-hidden`), this.chatContainer.classList.add(`${nm}-hidden`) } openChat() { this.chatIcon.classList.add(`${nm}-hidden`), this.closeIcon.classList.remove(`${nm}-hidden`), this.chatContainer.classList.remove(`${nm}-hidden`) } typeText(t, e) { let i = 0, n = setInterval((() => { if (i < e.length) t.innerHTML += e.charAt(i), i++, this.chatContent.scrollTop = this.chatContent.scrollHeight; else { clearInterval(n), document.getElementById(`${nm}-text`).disabled = !1, this.btn.disabled = !1 } }), 20) } uuidv4() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (t => (t ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> t / 4).toString(16))) } generateUniqueId() { return this.uuidv4() } chatStripe(t, e, i) { return `\n
\n

${e}

\n
\n ` } async getChatInitialData(t) { let e = await this.makeRequest("GET", `${domain}/api/project/${t}/init`), i = JSON.parse(e); this.welcomeMessage = i.data.welcome_message, this.inputText = i.data.input_text } dce(t) { return document.createElement([t]) } makeRequest(t, e, i = {}) { return new Promise((function (n, s) { let o = new XMLHttpRequest; o.open(t, e), o.setRequestHeader("Content-type", "application/json"), o.onload = function () { this.status >= 200 && this.status < 300 ? n(o.response) : s({ status: this.status, statusText: o.statusText }) }, o.onerror = function () { s({ status: this.status, statusText: o.statusText }) }, 0 !== Object.keys(i).length ? o.send(JSON.stringify(i)) : o.send() })) } } \ No newline at end of file