@seamly/web-ui 19.1.4 → 19.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +634 -0
- package/build/dist/lib/index.debug.js +4 -4
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.js +41 -42
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/standalone.js +41 -42
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/style-guide.js +39 -39
- package/build/dist/lib/style-guide.min.js +1 -1
- package/package.json +1 -1
- package/src/javascripts/domains/store/index.js +10 -9
- package/src/javascripts/domains/translations/middleware.js +6 -5
- package/src/javascripts/ui/utils/seamly-utils.js +3 -3
- package/src/.DS_Store +0 -0
|
@@ -79,7 +79,7 @@ eval("/**\n * marked - a markdown parser\n * Copyright (c) 2011-2021, Christophe
|
|
|
79
79
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
80
80
|
|
|
81
81
|
"use strict";
|
|
82
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Channel\": () => (/* binding */ Channel),\n/* harmony export */ \"LongPoll\": () => (/* binding */ LongPoll),\n/* harmony export */ \"Presence\": () => (/* binding */ Presence),\n/* harmony export */ \"Serializer\": () => (/* binding */ serializer_default),\n/* harmony export */ \"Socket\": () => (/* binding */ Socket)\n/* harmony export */ });\n// js/phoenix/utils.js\nvar closure = value => {\n if (typeof value === \"function\") {\n return value;\n } else {\n let closure2 = function () {\n return value;\n };\n\n return closure2;\n }\n}; // js/phoenix/constants.js\n\n\nvar globalSelf = typeof self !== \"undefined\" ? self : null;\nvar phxWindow = typeof window !== \"undefined\" ? window : null;\nvar global = globalSelf || phxWindow || void 0;\nvar DEFAULT_VSN = \"2.0.0\";\nvar SOCKET_STATES = {\n connecting: 0,\n open: 1,\n closing: 2,\n closed: 3\n};\nvar DEFAULT_TIMEOUT = 1e4;\nvar WS_CLOSE_NORMAL = 1e3;\nvar CHANNEL_STATES = {\n closed: \"closed\",\n errored: \"errored\",\n joined: \"joined\",\n joining: \"joining\",\n leaving: \"leaving\"\n};\nvar CHANNEL_EVENTS = {\n close: \"phx_close\",\n error: \"phx_error\",\n join: \"phx_join\",\n reply: \"phx_reply\",\n leave: \"phx_leave\"\n};\nvar TRANSPORTS = {\n longpoll: \"longpoll\",\n websocket: \"websocket\"\n};\nvar XHR_STATES = {\n complete: 4\n}; // js/phoenix/push.js\n\nvar Push = class {\n constructor(channel, event, payload, timeout) {\n this.channel = channel;\n this.event = event;\n\n this.payload = payload || function () {\n return {};\n };\n\n this.receivedResp = null;\n this.timeout = timeout;\n this.timeoutTimer = null;\n this.recHooks = [];\n this.sent = false;\n }\n\n resend(timeout) {\n this.timeout = timeout;\n this.reset();\n this.send();\n }\n\n send() {\n if (this.hasReceived(\"timeout\")) {\n return;\n }\n\n this.startTimeout();\n this.sent = true;\n this.channel.socket.push({\n topic: this.channel.topic,\n event: this.event,\n payload: this.payload(),\n ref: this.ref,\n join_ref: this.channel.joinRef()\n });\n }\n\n receive(status, callback) {\n if (this.hasReceived(status)) {\n callback(this.receivedResp.response);\n }\n\n this.recHooks.push({\n status,\n callback\n });\n return this;\n }\n\n reset() {\n this.cancelRefEvent();\n this.ref = null;\n this.refEvent = null;\n this.receivedResp = null;\n this.sent = false;\n }\n\n matchReceive({\n status,\n response,\n _ref\n }) {\n this.recHooks.filter(h => h.status === status).forEach(h => h.callback(response));\n }\n\n cancelRefEvent() {\n if (!this.refEvent) {\n return;\n }\n\n this.channel.off(this.refEvent);\n }\n\n cancelTimeout() {\n clearTimeout(this.timeoutTimer);\n this.timeoutTimer = null;\n }\n\n startTimeout() {\n if (this.timeoutTimer) {\n this.cancelTimeout();\n }\n\n this.ref = this.channel.socket.makeRef();\n this.refEvent = this.channel.replyEventName(this.ref);\n this.channel.on(this.refEvent, payload => {\n this.cancelRefEvent();\n this.cancelTimeout();\n this.receivedResp = payload;\n this.matchReceive(payload);\n });\n this.timeoutTimer = setTimeout(() => {\n this.trigger(\"timeout\", {});\n }, this.timeout);\n }\n\n hasReceived(status) {\n return this.receivedResp && this.receivedResp.status === status;\n }\n\n trigger(status, response) {\n this.channel.trigger(this.refEvent, {\n status,\n response\n });\n }\n\n}; // js/phoenix/timer.js\n\nvar Timer = class {\n constructor(callback, timerCalc) {\n this.callback = callback;\n this.timerCalc = timerCalc;\n this.timer = null;\n this.tries = 0;\n }\n\n reset() {\n this.tries = 0;\n clearTimeout(this.timer);\n }\n\n scheduleTimeout() {\n clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.tries = this.tries + 1;\n this.callback();\n }, this.timerCalc(this.tries + 1));\n }\n\n}; // js/phoenix/channel.js\n\nvar Channel = class {\n constructor(topic, params, socket) {\n this.state = CHANNEL_STATES.closed;\n this.topic = topic;\n this.params = closure(params || {});\n this.socket = socket;\n this.bindings = [];\n this.bindingRef = 0;\n this.timeout = this.socket.timeout;\n this.joinedOnce = false;\n this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout);\n this.pushBuffer = [];\n this.stateChangeRefs = [];\n this.rejoinTimer = new Timer(() => {\n if (this.socket.isConnected()) {\n this.rejoin();\n }\n }, this.socket.rejoinAfterMs);\n this.stateChangeRefs.push(this.socket.onError(() => this.rejoinTimer.reset()));\n this.stateChangeRefs.push(this.socket.onOpen(() => {\n this.rejoinTimer.reset();\n\n if (this.isErrored()) {\n this.rejoin();\n }\n }));\n this.joinPush.receive(\"ok\", () => {\n this.state = CHANNEL_STATES.joined;\n this.rejoinTimer.reset();\n this.pushBuffer.forEach(pushEvent => pushEvent.send());\n this.pushBuffer = [];\n });\n this.joinPush.receive(\"error\", () => {\n this.state = CHANNEL_STATES.errored;\n\n if (this.socket.isConnected()) {\n this.rejoinTimer.scheduleTimeout();\n }\n });\n this.onClose(() => {\n this.rejoinTimer.reset();\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `close ${this.topic} ${this.joinRef()}`);\n this.state = CHANNEL_STATES.closed;\n this.socket.remove(this);\n });\n this.onError(reason => {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `error ${this.topic}`, reason);\n\n if (this.isJoining()) {\n this.joinPush.reset();\n }\n\n this.state = CHANNEL_STATES.errored;\n\n if (this.socket.isConnected()) {\n this.rejoinTimer.scheduleTimeout();\n }\n });\n this.joinPush.receive(\"timeout\", () => {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `timeout ${this.topic} (${this.joinRef()})`, this.joinPush.timeout);\n let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), this.timeout);\n leavePush.send();\n this.state = CHANNEL_STATES.errored;\n this.joinPush.reset();\n\n if (this.socket.isConnected()) {\n this.rejoinTimer.scheduleTimeout();\n }\n });\n this.on(CHANNEL_EVENTS.reply, (payload, ref) => {\n this.trigger(this.replyEventName(ref), payload);\n });\n }\n\n join(timeout = this.timeout) {\n if (this.joinedOnce) {\n throw new Error(\"tried to join multiple times. 'join' can only be called a single time per channel instance\");\n } else {\n this.timeout = timeout;\n this.joinedOnce = true;\n this.rejoin();\n return this.joinPush;\n }\n }\n\n onClose(callback) {\n this.on(CHANNEL_EVENTS.close, callback);\n }\n\n onError(callback) {\n return this.on(CHANNEL_EVENTS.error, reason => callback(reason));\n }\n\n on(event, callback) {\n let ref = this.bindingRef++;\n this.bindings.push({\n event,\n ref,\n callback\n });\n return ref;\n }\n\n off(event, ref) {\n this.bindings = this.bindings.filter(bind => {\n return !(bind.event === event && (typeof ref === \"undefined\" || ref === bind.ref));\n });\n }\n\n canPush() {\n return this.socket.isConnected() && this.isJoined();\n }\n\n push(event, payload, timeout = this.timeout) {\n payload = payload || {};\n\n if (!this.joinedOnce) {\n throw new Error(`tried to push '${event}' to '${this.topic}' before joining. Use channel.join() before pushing events`);\n }\n\n let pushEvent = new Push(this, event, function () {\n return payload;\n }, timeout);\n\n if (this.canPush()) {\n pushEvent.send();\n } else {\n pushEvent.startTimeout();\n this.pushBuffer.push(pushEvent);\n }\n\n return pushEvent;\n }\n\n leave(timeout = this.timeout) {\n this.rejoinTimer.reset();\n this.joinPush.cancelTimeout();\n this.state = CHANNEL_STATES.leaving;\n\n let onClose = () => {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `leave ${this.topic}`);\n this.trigger(CHANNEL_EVENTS.close, \"leave\");\n };\n\n let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), timeout);\n leavePush.receive(\"ok\", () => onClose()).receive(\"timeout\", () => onClose());\n leavePush.send();\n\n if (!this.canPush()) {\n leavePush.trigger(\"ok\", {});\n }\n\n return leavePush;\n }\n\n onMessage(_event, payload, _ref) {\n return payload;\n }\n\n isMember(topic, event, payload, joinRef) {\n if (this.topic !== topic) {\n return false;\n }\n\n if (joinRef && joinRef !== this.joinRef()) {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", \"dropping outdated message\", {\n topic,\n event,\n payload,\n joinRef\n });\n return false;\n } else {\n return true;\n }\n }\n\n joinRef() {\n return this.joinPush.ref;\n }\n\n rejoin(timeout = this.timeout) {\n if (this.isLeaving()) {\n return;\n }\n\n this.socket.leaveOpenTopic(this.topic);\n this.state = CHANNEL_STATES.joining;\n this.joinPush.resend(timeout);\n }\n\n trigger(event, payload, ref, joinRef) {\n let handledPayload = this.onMessage(event, payload, ref, joinRef);\n\n if (payload && !handledPayload) {\n throw new Error(\"channel onMessage callbacks must return the payload, modified or unmodified\");\n }\n\n let eventBindings = this.bindings.filter(bind => bind.event === event);\n\n for (let i = 0; i < eventBindings.length; i++) {\n let bind = eventBindings[i];\n bind.callback(handledPayload, ref, joinRef || this.joinRef());\n }\n }\n\n replyEventName(ref) {\n return `chan_reply_${ref}`;\n }\n\n isClosed() {\n return this.state === CHANNEL_STATES.closed;\n }\n\n isErrored() {\n return this.state === CHANNEL_STATES.errored;\n }\n\n isJoined() {\n return this.state === CHANNEL_STATES.joined;\n }\n\n isJoining() {\n return this.state === CHANNEL_STATES.joining;\n }\n\n isLeaving() {\n return this.state === CHANNEL_STATES.leaving;\n }\n\n}; // js/phoenix/ajax.js\n\nvar Ajax = class {\n static request(method, endPoint, accept, body, timeout, ontimeout, callback) {\n if (global.XDomainRequest) {\n let req = new global.XDomainRequest();\n this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback);\n } else {\n let req = new global.XMLHttpRequest();\n this.xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback);\n }\n }\n\n static xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) {\n req.timeout = timeout;\n req.open(method, endPoint);\n\n req.onload = () => {\n let response = this.parseJSON(req.responseText);\n callback && callback(response);\n };\n\n if (ontimeout) {\n req.ontimeout = ontimeout;\n }\n\n req.onprogress = () => {};\n\n req.send(body);\n }\n\n static xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback) {\n req.open(method, endPoint, true);\n req.timeout = timeout;\n req.setRequestHeader(\"Content-Type\", accept);\n\n req.onerror = () => {\n callback && callback(null);\n };\n\n req.onreadystatechange = () => {\n if (req.readyState === XHR_STATES.complete && callback) {\n let response = this.parseJSON(req.responseText);\n callback(response);\n }\n };\n\n if (ontimeout) {\n req.ontimeout = ontimeout;\n }\n\n req.send(body);\n }\n\n static parseJSON(resp) {\n if (!resp || resp === \"\") {\n return null;\n }\n\n try {\n return JSON.parse(resp);\n } catch (e) {\n console && console.log(\"failed to parse JSON response\", resp);\n return null;\n }\n }\n\n static serialize(obj, parentKey) {\n let queryStr = [];\n\n for (var key in obj) {\n if (!Object.prototype.hasOwnProperty.call(obj, key)) {\n continue;\n }\n\n let paramKey = parentKey ? `${parentKey}[${key}]` : key;\n let paramVal = obj[key];\n\n if (typeof paramVal === \"object\") {\n queryStr.push(this.serialize(paramVal, paramKey));\n } else {\n queryStr.push(encodeURIComponent(paramKey) + \"=\" + encodeURIComponent(paramVal));\n }\n }\n\n return queryStr.join(\"&\");\n }\n\n static appendParams(url, params) {\n if (Object.keys(params).length === 0) {\n return url;\n }\n\n let prefix = url.match(/\\?/) ? \"&\" : \"?\";\n return `${url}${prefix}${this.serialize(params)}`;\n }\n\n}; // js/phoenix/longpoll.js\n\nvar LongPoll = class {\n constructor(endPoint) {\n this.endPoint = null;\n this.token = null;\n this.skipHeartbeat = true;\n\n this.onopen = function () {};\n\n this.onerror = function () {};\n\n this.onmessage = function () {};\n\n this.onclose = function () {};\n\n this.pollEndpoint = this.normalizeEndpoint(endPoint);\n this.readyState = SOCKET_STATES.connecting;\n this.poll();\n }\n\n normalizeEndpoint(endPoint) {\n return endPoint.replace(\"ws://\", \"http://\").replace(\"wss://\", \"https://\").replace(new RegExp(\"(.*)/\" + TRANSPORTS.websocket), \"$1/\" + TRANSPORTS.longpoll);\n }\n\n endpointURL() {\n return Ajax.appendParams(this.pollEndpoint, {\n token: this.token\n });\n }\n\n closeAndRetry() {\n this.close();\n this.readyState = SOCKET_STATES.connecting;\n }\n\n ontimeout() {\n this.onerror(\"timeout\");\n this.closeAndRetry();\n }\n\n poll() {\n if (!(this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting)) {\n return;\n }\n\n Ajax.request(\"GET\", this.endpointURL(), \"application/json\", null, this.timeout, this.ontimeout.bind(this), resp => {\n if (resp) {\n var {\n status,\n token,\n messages\n } = resp;\n this.token = token;\n } else {\n status = 0;\n }\n\n switch (status) {\n case 200:\n messages.forEach(msg => {\n setTimeout(() => {\n this.onmessage({\n data: msg\n });\n }, 0);\n });\n this.poll();\n break;\n\n case 204:\n this.poll();\n break;\n\n case 410:\n this.readyState = SOCKET_STATES.open;\n this.onopen();\n this.poll();\n break;\n\n case 403:\n this.onerror();\n this.close();\n break;\n\n case 0:\n case 500:\n this.onerror();\n this.closeAndRetry();\n break;\n\n default:\n throw new Error(`unhandled poll status ${status}`);\n }\n });\n }\n\n send(body) {\n Ajax.request(\"POST\", this.endpointURL(), \"application/json\", body, this.timeout, this.onerror.bind(this, \"timeout\"), resp => {\n if (!resp || resp.status !== 200) {\n this.onerror(resp && resp.status);\n this.closeAndRetry();\n }\n });\n }\n\n close(_code, _reason) {\n this.readyState = SOCKET_STATES.closed;\n this.onclose();\n }\n\n}; // js/phoenix/presence.js\n\nvar Presence = class {\n constructor(channel, opts = {}) {\n let events = opts.events || {\n state: \"presence_state\",\n diff: \"presence_diff\"\n };\n this.state = {};\n this.pendingDiffs = [];\n this.channel = channel;\n this.joinRef = null;\n this.caller = {\n onJoin: function () {},\n onLeave: function () {},\n onSync: function () {}\n };\n this.channel.on(events.state, newState => {\n let {\n onJoin,\n onLeave,\n onSync\n } = this.caller;\n this.joinRef = this.channel.joinRef();\n this.state = Presence.syncState(this.state, newState, onJoin, onLeave);\n this.pendingDiffs.forEach(diff => {\n this.state = Presence.syncDiff(this.state, diff, onJoin, onLeave);\n });\n this.pendingDiffs = [];\n onSync();\n });\n this.channel.on(events.diff, diff => {\n let {\n onJoin,\n onLeave,\n onSync\n } = this.caller;\n\n if (this.inPendingSyncState()) {\n this.pendingDiffs.push(diff);\n } else {\n this.state = Presence.syncDiff(this.state, diff, onJoin, onLeave);\n onSync();\n }\n });\n }\n\n onJoin(callback) {\n this.caller.onJoin = callback;\n }\n\n onLeave(callback) {\n this.caller.onLeave = callback;\n }\n\n onSync(callback) {\n this.caller.onSync = callback;\n }\n\n list(by) {\n return Presence.list(this.state, by);\n }\n\n inPendingSyncState() {\n return !this.joinRef || this.joinRef !== this.channel.joinRef();\n }\n\n static syncState(currentState, newState, onJoin, onLeave) {\n let state = this.clone(currentState);\n let joins = {};\n let leaves = {};\n this.map(state, (key, presence) => {\n if (!newState[key]) {\n leaves[key] = presence;\n }\n });\n this.map(newState, (key, newPresence) => {\n let currentPresence = state[key];\n\n if (currentPresence) {\n let newRefs = newPresence.metas.map(m => m.phx_ref);\n let curRefs = currentPresence.metas.map(m => m.phx_ref);\n let joinedMetas = newPresence.metas.filter(m => curRefs.indexOf(m.phx_ref) < 0);\n let leftMetas = currentPresence.metas.filter(m => newRefs.indexOf(m.phx_ref) < 0);\n\n if (joinedMetas.length > 0) {\n joins[key] = newPresence;\n joins[key].metas = joinedMetas;\n }\n\n if (leftMetas.length > 0) {\n leaves[key] = this.clone(currentPresence);\n leaves[key].metas = leftMetas;\n }\n } else {\n joins[key] = newPresence;\n }\n });\n return this.syncDiff(state, {\n joins,\n leaves\n }, onJoin, onLeave);\n }\n\n static syncDiff(state, diff, onJoin, onLeave) {\n let {\n joins,\n leaves\n } = this.clone(diff);\n\n if (!onJoin) {\n onJoin = function () {};\n }\n\n if (!onLeave) {\n onLeave = function () {};\n }\n\n this.map(joins, (key, newPresence) => {\n let currentPresence = state[key];\n state[key] = this.clone(newPresence);\n\n if (currentPresence) {\n let joinedRefs = state[key].metas.map(m => m.phx_ref);\n let curMetas = currentPresence.metas.filter(m => joinedRefs.indexOf(m.phx_ref) < 0);\n state[key].metas.unshift(...curMetas);\n }\n\n onJoin(key, currentPresence, newPresence);\n });\n this.map(leaves, (key, leftPresence) => {\n let currentPresence = state[key];\n\n if (!currentPresence) {\n return;\n }\n\n let refsToRemove = leftPresence.metas.map(m => m.phx_ref);\n currentPresence.metas = currentPresence.metas.filter(p => {\n return refsToRemove.indexOf(p.phx_ref) < 0;\n });\n onLeave(key, currentPresence, leftPresence);\n\n if (currentPresence.metas.length === 0) {\n delete state[key];\n }\n });\n return state;\n }\n\n static list(presences, chooser) {\n if (!chooser) {\n chooser = function (key, pres) {\n return pres;\n };\n }\n\n return this.map(presences, (key, presence) => {\n return chooser(key, presence);\n });\n }\n\n static map(obj, func) {\n return Object.getOwnPropertyNames(obj).map(key => func(key, obj[key]));\n }\n\n static clone(obj) {\n return JSON.parse(JSON.stringify(obj));\n }\n\n}; // js/phoenix/serializer.js\n\nvar serializer_default = {\n HEADER_LENGTH: 1,\n META_LENGTH: 4,\n KINDS: {\n push: 0,\n reply: 1,\n broadcast: 2\n },\n\n encode(msg, callback) {\n if (msg.payload.constructor === ArrayBuffer) {\n return callback(this.binaryEncode(msg));\n } else {\n let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload];\n return callback(JSON.stringify(payload));\n }\n },\n\n decode(rawPayload, callback) {\n if (rawPayload.constructor === ArrayBuffer) {\n return callback(this.binaryDecode(rawPayload));\n } else {\n let [join_ref, ref, topic, event, payload] = JSON.parse(rawPayload);\n return callback({\n join_ref,\n ref,\n topic,\n event,\n payload\n });\n }\n },\n\n binaryEncode(message) {\n let {\n join_ref,\n ref,\n event,\n topic,\n payload\n } = message;\n let metaLength = this.META_LENGTH + join_ref.length + ref.length + topic.length + event.length;\n let header = new ArrayBuffer(this.HEADER_LENGTH + metaLength);\n let view = new DataView(header);\n let offset = 0;\n view.setUint8(offset++, this.KINDS.push);\n view.setUint8(offset++, join_ref.length);\n view.setUint8(offset++, ref.length);\n view.setUint8(offset++, topic.length);\n view.setUint8(offset++, event.length);\n Array.from(join_ref, char => view.setUint8(offset++, char.charCodeAt(0)));\n Array.from(ref, char => view.setUint8(offset++, char.charCodeAt(0)));\n Array.from(topic, char => view.setUint8(offset++, char.charCodeAt(0)));\n Array.from(event, char => view.setUint8(offset++, char.charCodeAt(0)));\n var combined = new Uint8Array(header.byteLength + payload.byteLength);\n combined.set(new Uint8Array(header), 0);\n combined.set(new Uint8Array(payload), header.byteLength);\n return combined.buffer;\n },\n\n binaryDecode(buffer) {\n let view = new DataView(buffer);\n let kind = view.getUint8(0);\n let decoder = new TextDecoder();\n\n switch (kind) {\n case this.KINDS.push:\n return this.decodePush(buffer, view, decoder);\n\n case this.KINDS.reply:\n return this.decodeReply(buffer, view, decoder);\n\n case this.KINDS.broadcast:\n return this.decodeBroadcast(buffer, view, decoder);\n }\n },\n\n decodePush(buffer, view, decoder) {\n let joinRefSize = view.getUint8(1);\n let topicSize = view.getUint8(2);\n let eventSize = view.getUint8(3);\n let offset = this.HEADER_LENGTH + this.META_LENGTH - 1;\n let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));\n offset = offset + joinRefSize;\n let topic = decoder.decode(buffer.slice(offset, offset + topicSize));\n offset = offset + topicSize;\n let event = decoder.decode(buffer.slice(offset, offset + eventSize));\n offset = offset + eventSize;\n let data = buffer.slice(offset, buffer.byteLength);\n return {\n join_ref: joinRef,\n ref: null,\n topic,\n event,\n payload: data\n };\n },\n\n decodeReply(buffer, view, decoder) {\n let joinRefSize = view.getUint8(1);\n let refSize = view.getUint8(2);\n let topicSize = view.getUint8(3);\n let eventSize = view.getUint8(4);\n let offset = this.HEADER_LENGTH + this.META_LENGTH;\n let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));\n offset = offset + joinRefSize;\n let ref = decoder.decode(buffer.slice(offset, offset + refSize));\n offset = offset + refSize;\n let topic = decoder.decode(buffer.slice(offset, offset + topicSize));\n offset = offset + topicSize;\n let event = decoder.decode(buffer.slice(offset, offset + eventSize));\n offset = offset + eventSize;\n let data = buffer.slice(offset, buffer.byteLength);\n let payload = {\n status: event,\n response: data\n };\n return {\n join_ref: joinRef,\n ref,\n topic,\n event: CHANNEL_EVENTS.reply,\n payload\n };\n },\n\n decodeBroadcast(buffer, view, decoder) {\n let topicSize = view.getUint8(1);\n let eventSize = view.getUint8(2);\n let offset = this.HEADER_LENGTH + 2;\n let topic = decoder.decode(buffer.slice(offset, offset + topicSize));\n offset = offset + topicSize;\n let event = decoder.decode(buffer.slice(offset, offset + eventSize));\n offset = offset + eventSize;\n let data = buffer.slice(offset, buffer.byteLength);\n return {\n join_ref: null,\n ref: null,\n topic,\n event,\n payload: data\n };\n }\n\n}; // js/phoenix/socket.js\n\nvar Socket = class {\n constructor(endPoint, opts = {}) {\n this.stateChangeCallbacks = {\n open: [],\n close: [],\n error: [],\n message: []\n };\n this.channels = [];\n this.sendBuffer = [];\n this.ref = 0;\n this.timeout = opts.timeout || DEFAULT_TIMEOUT;\n this.transport = opts.transport || global.WebSocket || LongPoll;\n this.establishedConnections = 0;\n this.defaultEncoder = serializer_default.encode.bind(serializer_default);\n this.defaultDecoder = serializer_default.decode.bind(serializer_default);\n this.closeWasClean = false;\n this.binaryType = opts.binaryType || \"arraybuffer\";\n this.connectClock = 1;\n\n if (this.transport !== LongPoll) {\n this.encode = opts.encode || this.defaultEncoder;\n this.decode = opts.decode || this.defaultDecoder;\n } else {\n this.encode = this.defaultEncoder;\n this.decode = this.defaultDecoder;\n }\n\n let awaitingConnectionOnPageShow = null;\n\n if (phxWindow && phxWindow.addEventListener) {\n phxWindow.addEventListener(\"pagehide\", _e => {\n if (this.conn) {\n this.disconnect();\n awaitingConnectionOnPageShow = this.connectClock;\n }\n });\n phxWindow.addEventListener(\"pageshow\", _e => {\n if (awaitingConnectionOnPageShow === this.connectClock) {\n awaitingConnectionOnPageShow = null;\n this.connect();\n }\n });\n }\n\n this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 3e4;\n\n this.rejoinAfterMs = tries => {\n if (opts.rejoinAfterMs) {\n return opts.rejoinAfterMs(tries);\n } else {\n return [1e3, 2e3, 5e3][tries - 1] || 1e4;\n }\n };\n\n this.reconnectAfterMs = tries => {\n if (opts.reconnectAfterMs) {\n return opts.reconnectAfterMs(tries);\n } else {\n return [10, 50, 100, 150, 200, 250, 500, 1e3, 2e3][tries - 1] || 5e3;\n }\n };\n\n this.logger = opts.logger || null;\n this.longpollerTimeout = opts.longpollerTimeout || 2e4;\n this.params = closure(opts.params || {});\n this.endPoint = `${endPoint}/${TRANSPORTS.websocket}`;\n this.vsn = opts.vsn || DEFAULT_VSN;\n this.heartbeatTimer = null;\n this.pendingHeartbeatRef = null;\n this.reconnectTimer = new Timer(() => {\n this.teardown(() => this.connect());\n }, this.reconnectAfterMs);\n }\n\n replaceTransport(newTransport) {\n this.disconnect();\n this.transport = newTransport;\n }\n\n protocol() {\n return location.protocol.match(/^https/) ? \"wss\" : \"ws\";\n }\n\n endPointURL() {\n let uri = Ajax.appendParams(Ajax.appendParams(this.endPoint, this.params()), {\n vsn: this.vsn\n });\n\n if (uri.charAt(0) !== \"/\") {\n return uri;\n }\n\n if (uri.charAt(1) === \"/\") {\n return `${this.protocol()}:${uri}`;\n }\n\n return `${this.protocol()}://${location.host}${uri}`;\n }\n\n disconnect(callback, code, reason) {\n this.connectClock++;\n this.closeWasClean = true;\n this.reconnectTimer.reset();\n this.teardown(callback, code, reason);\n }\n\n connect(params) {\n this.connectClock++;\n\n if (params) {\n console && console.log(\"passing params to connect is deprecated. Instead pass :params to the Socket constructor\");\n this.params = closure(params);\n }\n\n if (this.conn) {\n return;\n }\n\n this.closeWasClean = false;\n this.conn = new this.transport(this.endPointURL());\n this.conn.binaryType = this.binaryType;\n this.conn.timeout = this.longpollerTimeout;\n\n this.conn.onopen = () => this.onConnOpen();\n\n this.conn.onerror = error => this.onConnError(error);\n\n this.conn.onmessage = event => this.onConnMessage(event);\n\n this.conn.onclose = event => this.onConnClose(event);\n }\n\n log(kind, msg, data) {\n this.logger(kind, msg, data);\n }\n\n hasLogger() {\n return this.logger !== null;\n }\n\n onOpen(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.open.push([ref, callback]);\n return ref;\n }\n\n onClose(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.close.push([ref, callback]);\n return ref;\n }\n\n onError(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.error.push([ref, callback]);\n return ref;\n }\n\n onMessage(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.message.push([ref, callback]);\n return ref;\n }\n\n onConnOpen() {\n if (this.hasLogger()) this.log(\"transport\", `connected to ${this.endPointURL()}`);\n this.closeWasClean = false;\n this.establishedConnections++;\n this.flushSendBuffer();\n this.reconnectTimer.reset();\n this.resetHeartbeat();\n this.stateChangeCallbacks.open.forEach(([, callback]) => callback());\n }\n\n heartbeatTimeout() {\n if (this.pendingHeartbeatRef) {\n this.pendingHeartbeatRef = null;\n\n if (this.hasLogger()) {\n this.log(\"transport\", \"heartbeat timeout. Attempting to re-establish connection\");\n }\n\n this.abnormalClose(\"heartbeat timeout\");\n }\n }\n\n resetHeartbeat() {\n if (this.conn && this.conn.skipHeartbeat) {\n return;\n }\n\n this.pendingHeartbeatRef = null;\n clearTimeout(this.heartbeatTimer);\n setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);\n }\n\n teardown(callback, code, reason) {\n if (!this.conn) {\n return callback && callback();\n }\n\n this.waitForBufferDone(() => {\n if (this.conn) {\n if (code) {\n this.conn.close(code, reason || \"\");\n } else {\n this.conn.close();\n }\n }\n\n this.waitForSocketClosed(() => {\n if (this.conn) {\n this.conn.onclose = function () {};\n\n this.conn = null;\n }\n\n callback && callback();\n });\n });\n }\n\n waitForBufferDone(callback, tries = 1) {\n if (tries === 5 || !this.conn || !this.conn.bufferedAmount) {\n callback();\n return;\n }\n\n setTimeout(() => {\n this.waitForBufferDone(callback, tries + 1);\n }, 150 * tries);\n }\n\n waitForSocketClosed(callback, tries = 1) {\n if (tries === 5 || !this.conn || this.conn.readyState === SOCKET_STATES.closed) {\n callback();\n return;\n }\n\n setTimeout(() => {\n this.waitForSocketClosed(callback, tries + 1);\n }, 150 * tries);\n }\n\n onConnClose(event) {\n let closeCode = event && event.code;\n if (this.hasLogger()) this.log(\"transport\", \"close\", event);\n this.triggerChanError();\n clearTimeout(this.heartbeatTimer);\n\n if (!this.closeWasClean && closeCode !== 1e3) {\n this.reconnectTimer.scheduleTimeout();\n }\n\n this.stateChangeCallbacks.close.forEach(([, callback]) => callback(event));\n }\n\n onConnError(error) {\n if (this.hasLogger()) this.log(\"transport\", error);\n let transportBefore = this.transport;\n let establishedBefore = this.establishedConnections;\n this.stateChangeCallbacks.error.forEach(([, callback]) => {\n callback(error, transportBefore, establishedBefore);\n });\n\n if (transportBefore === this.transport || establishedBefore > 0) {\n this.triggerChanError();\n }\n }\n\n triggerChanError() {\n this.channels.forEach(channel => {\n if (!(channel.isErrored() || channel.isLeaving() || channel.isClosed())) {\n channel.trigger(CHANNEL_EVENTS.error);\n }\n });\n }\n\n connectionState() {\n switch (this.conn && this.conn.readyState) {\n case SOCKET_STATES.connecting:\n return \"connecting\";\n\n case SOCKET_STATES.open:\n return \"open\";\n\n case SOCKET_STATES.closing:\n return \"closing\";\n\n default:\n return \"closed\";\n }\n }\n\n isConnected() {\n return this.connectionState() === \"open\";\n }\n\n remove(channel) {\n this.off(channel.stateChangeRefs);\n this.channels = this.channels.filter(c => c.joinRef() !== channel.joinRef());\n }\n\n off(refs) {\n for (let key in this.stateChangeCallbacks) {\n this.stateChangeCallbacks[key] = this.stateChangeCallbacks[key].filter(([ref]) => {\n return refs.indexOf(ref) === -1;\n });\n }\n }\n\n channel(topic, chanParams = {}) {\n let chan = new Channel(topic, chanParams, this);\n this.channels.push(chan);\n return chan;\n }\n\n push(data) {\n if (this.hasLogger()) {\n let {\n topic,\n event,\n payload,\n ref,\n join_ref\n } = data;\n this.log(\"push\", `${topic} ${event} (${join_ref}, ${ref})`, payload);\n }\n\n if (this.isConnected()) {\n this.encode(data, result => this.conn.send(result));\n } else {\n this.sendBuffer.push(() => this.encode(data, result => this.conn.send(result)));\n }\n }\n\n makeRef() {\n let newRef = this.ref + 1;\n\n if (newRef === this.ref) {\n this.ref = 0;\n } else {\n this.ref = newRef;\n }\n\n return this.ref.toString();\n }\n\n sendHeartbeat() {\n if (this.pendingHeartbeatRef && !this.isConnected()) {\n return;\n }\n\n this.pendingHeartbeatRef = this.makeRef();\n this.push({\n topic: \"phoenix\",\n event: \"heartbeat\",\n payload: {},\n ref: this.pendingHeartbeatRef\n });\n this.heartbeatTimer = setTimeout(() => this.heartbeatTimeout(), this.heartbeatIntervalMs);\n }\n\n abnormalClose(reason) {\n this.closeWasClean = false;\n\n if (this.isConnected()) {\n this.conn.close(WS_CLOSE_NORMAL, reason);\n }\n }\n\n flushSendBuffer() {\n if (this.isConnected() && this.sendBuffer.length > 0) {\n this.sendBuffer.forEach(callback => callback());\n this.sendBuffer = [];\n }\n }\n\n onConnMessage(rawMessage) {\n this.decode(rawMessage.data, msg => {\n let {\n topic,\n event,\n payload,\n ref,\n join_ref\n } = msg;\n\n if (ref && ref === this.pendingHeartbeatRef) {\n clearTimeout(this.heartbeatTimer);\n this.pendingHeartbeatRef = null;\n setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);\n }\n\n if (this.hasLogger()) this.log(\"receive\", `${payload.status || \"\"} ${topic} ${event} ${ref && \"(\" + ref + \")\" || \"\"}`, payload);\n\n for (let i = 0; i < this.channels.length; i++) {\n const channel = this.channels[i];\n\n if (!channel.isMember(topic, event, payload, join_ref)) {\n continue;\n }\n\n channel.trigger(event, payload, ref, join_ref);\n }\n\n for (let i = 0; i < this.stateChangeCallbacks.message.length; i++) {\n let [, callback] = this.stateChangeCallbacks.message[i];\n callback(msg);\n }\n });\n }\n\n leaveOpenTopic(topic) {\n let dupChannel = this.channels.find(c => c.topic === topic && (c.isJoined() || c.isJoining()));\n\n if (dupChannel) {\n if (this.hasLogger()) this.log(\"transport\", `leaving duplicate topic \"${topic}\"`);\n dupChannel.leave();\n }\n }\n\n};\n\n\n//# sourceURL=webpack://@seamly/web-ui/./node_modules/phoenix/priv/static/phoenix.esm.js?");
|
|
82
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Channel\": () => (/* binding */ Channel),\n/* harmony export */ \"LongPoll\": () => (/* binding */ LongPoll),\n/* harmony export */ \"Presence\": () => (/* binding */ Presence),\n/* harmony export */ \"Serializer\": () => (/* binding */ serializer_default),\n/* harmony export */ \"Socket\": () => (/* binding */ Socket)\n/* harmony export */ });\n// js/phoenix/utils.js\nvar closure = value => {\n if (typeof value === \"function\") {\n return value;\n } else {\n let closure2 = function () {\n return value;\n };\n\n return closure2;\n }\n}; // js/phoenix/constants.js\n\n\nvar globalSelf = typeof self !== \"undefined\" ? self : null;\nvar phxWindow = typeof window !== \"undefined\" ? window : null;\nvar global = globalSelf || phxWindow || void 0;\nvar DEFAULT_VSN = \"2.0.0\";\nvar SOCKET_STATES = {\n connecting: 0,\n open: 1,\n closing: 2,\n closed: 3\n};\nvar DEFAULT_TIMEOUT = 1e4;\nvar WS_CLOSE_NORMAL = 1e3;\nvar CHANNEL_STATES = {\n closed: \"closed\",\n errored: \"errored\",\n joined: \"joined\",\n joining: \"joining\",\n leaving: \"leaving\"\n};\nvar CHANNEL_EVENTS = {\n close: \"phx_close\",\n error: \"phx_error\",\n join: \"phx_join\",\n reply: \"phx_reply\",\n leave: \"phx_leave\"\n};\nvar TRANSPORTS = {\n longpoll: \"longpoll\",\n websocket: \"websocket\"\n};\nvar XHR_STATES = {\n complete: 4\n}; // js/phoenix/push.js\n\nvar Push = class {\n constructor(channel, event, payload, timeout) {\n this.channel = channel;\n this.event = event;\n\n this.payload = payload || function () {\n return {};\n };\n\n this.receivedResp = null;\n this.timeout = timeout;\n this.timeoutTimer = null;\n this.recHooks = [];\n this.sent = false;\n }\n\n resend(timeout) {\n this.timeout = timeout;\n this.reset();\n this.send();\n }\n\n send() {\n if (this.hasReceived(\"timeout\")) {\n return;\n }\n\n this.startTimeout();\n this.sent = true;\n this.channel.socket.push({\n topic: this.channel.topic,\n event: this.event,\n payload: this.payload(),\n ref: this.ref,\n join_ref: this.channel.joinRef()\n });\n }\n\n receive(status, callback) {\n if (this.hasReceived(status)) {\n callback(this.receivedResp.response);\n }\n\n this.recHooks.push({\n status,\n callback\n });\n return this;\n }\n\n reset() {\n this.cancelRefEvent();\n this.ref = null;\n this.refEvent = null;\n this.receivedResp = null;\n this.sent = false;\n }\n\n matchReceive({\n status,\n response,\n _ref\n }) {\n this.recHooks.filter(h => h.status === status).forEach(h => h.callback(response));\n }\n\n cancelRefEvent() {\n if (!this.refEvent) {\n return;\n }\n\n this.channel.off(this.refEvent);\n }\n\n cancelTimeout() {\n clearTimeout(this.timeoutTimer);\n this.timeoutTimer = null;\n }\n\n startTimeout() {\n if (this.timeoutTimer) {\n this.cancelTimeout();\n }\n\n this.ref = this.channel.socket.makeRef();\n this.refEvent = this.channel.replyEventName(this.ref);\n this.channel.on(this.refEvent, payload => {\n this.cancelRefEvent();\n this.cancelTimeout();\n this.receivedResp = payload;\n this.matchReceive(payload);\n });\n this.timeoutTimer = setTimeout(() => {\n this.trigger(\"timeout\", {});\n }, this.timeout);\n }\n\n hasReceived(status) {\n return this.receivedResp && this.receivedResp.status === status;\n }\n\n trigger(status, response) {\n this.channel.trigger(this.refEvent, {\n status,\n response\n });\n }\n\n}; // js/phoenix/timer.js\n\nvar Timer = class {\n constructor(callback, timerCalc) {\n this.callback = callback;\n this.timerCalc = timerCalc;\n this.timer = null;\n this.tries = 0;\n }\n\n reset() {\n this.tries = 0;\n clearTimeout(this.timer);\n }\n\n scheduleTimeout() {\n clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.tries = this.tries + 1;\n this.callback();\n }, this.timerCalc(this.tries + 1));\n }\n\n}; // js/phoenix/channel.js\n\nvar Channel = class {\n constructor(topic, params, socket) {\n this.state = CHANNEL_STATES.closed;\n this.topic = topic;\n this.params = closure(params || {});\n this.socket = socket;\n this.bindings = [];\n this.bindingRef = 0;\n this.timeout = this.socket.timeout;\n this.joinedOnce = false;\n this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout);\n this.pushBuffer = [];\n this.stateChangeRefs = [];\n this.rejoinTimer = new Timer(() => {\n if (this.socket.isConnected()) {\n this.rejoin();\n }\n }, this.socket.rejoinAfterMs);\n this.stateChangeRefs.push(this.socket.onError(() => this.rejoinTimer.reset()));\n this.stateChangeRefs.push(this.socket.onOpen(() => {\n this.rejoinTimer.reset();\n\n if (this.isErrored()) {\n this.rejoin();\n }\n }));\n this.joinPush.receive(\"ok\", () => {\n this.state = CHANNEL_STATES.joined;\n this.rejoinTimer.reset();\n this.pushBuffer.forEach(pushEvent => pushEvent.send());\n this.pushBuffer = [];\n });\n this.joinPush.receive(\"error\", () => {\n this.state = CHANNEL_STATES.errored;\n\n if (this.socket.isConnected()) {\n this.rejoinTimer.scheduleTimeout();\n }\n });\n this.onClose(() => {\n this.rejoinTimer.reset();\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `close ${this.topic} ${this.joinRef()}`);\n this.state = CHANNEL_STATES.closed;\n this.socket.remove(this);\n });\n this.onError(reason => {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `error ${this.topic}`, reason);\n\n if (this.isJoining()) {\n this.joinPush.reset();\n }\n\n this.state = CHANNEL_STATES.errored;\n\n if (this.socket.isConnected()) {\n this.rejoinTimer.scheduleTimeout();\n }\n });\n this.joinPush.receive(\"timeout\", () => {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `timeout ${this.topic} (${this.joinRef()})`, this.joinPush.timeout);\n let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), this.timeout);\n leavePush.send();\n this.state = CHANNEL_STATES.errored;\n this.joinPush.reset();\n\n if (this.socket.isConnected()) {\n this.rejoinTimer.scheduleTimeout();\n }\n });\n this.on(CHANNEL_EVENTS.reply, (payload, ref) => {\n this.trigger(this.replyEventName(ref), payload);\n });\n }\n\n join(timeout = this.timeout) {\n if (this.joinedOnce) {\n throw new Error(\"tried to join multiple times. 'join' can only be called a single time per channel instance\");\n } else {\n this.timeout = timeout;\n this.joinedOnce = true;\n this.rejoin();\n return this.joinPush;\n }\n }\n\n onClose(callback) {\n this.on(CHANNEL_EVENTS.close, callback);\n }\n\n onError(callback) {\n return this.on(CHANNEL_EVENTS.error, reason => callback(reason));\n }\n\n on(event, callback) {\n let ref = this.bindingRef++;\n this.bindings.push({\n event,\n ref,\n callback\n });\n return ref;\n }\n\n off(event, ref) {\n this.bindings = this.bindings.filter(bind => {\n return !(bind.event === event && (typeof ref === \"undefined\" || ref === bind.ref));\n });\n }\n\n canPush() {\n return this.socket.isConnected() && this.isJoined();\n }\n\n push(event, payload, timeout = this.timeout) {\n payload = payload || {};\n\n if (!this.joinedOnce) {\n throw new Error(`tried to push '${event}' to '${this.topic}' before joining. Use channel.join() before pushing events`);\n }\n\n let pushEvent = new Push(this, event, function () {\n return payload;\n }, timeout);\n\n if (this.canPush()) {\n pushEvent.send();\n } else {\n pushEvent.startTimeout();\n this.pushBuffer.push(pushEvent);\n }\n\n return pushEvent;\n }\n\n leave(timeout = this.timeout) {\n this.rejoinTimer.reset();\n this.joinPush.cancelTimeout();\n this.state = CHANNEL_STATES.leaving;\n\n let onClose = () => {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", `leave ${this.topic}`);\n this.trigger(CHANNEL_EVENTS.close, \"leave\");\n };\n\n let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), timeout);\n leavePush.receive(\"ok\", () => onClose()).receive(\"timeout\", () => onClose());\n leavePush.send();\n\n if (!this.canPush()) {\n leavePush.trigger(\"ok\", {});\n }\n\n return leavePush;\n }\n\n onMessage(_event, payload, _ref) {\n return payload;\n }\n\n isMember(topic, event, payload, joinRef) {\n if (this.topic !== topic) {\n return false;\n }\n\n if (joinRef && joinRef !== this.joinRef()) {\n if (this.socket.hasLogger()) this.socket.log(\"channel\", \"dropping outdated message\", {\n topic,\n event,\n payload,\n joinRef\n });\n return false;\n } else {\n return true;\n }\n }\n\n joinRef() {\n return this.joinPush.ref;\n }\n\n rejoin(timeout = this.timeout) {\n if (this.isLeaving()) {\n return;\n }\n\n this.socket.leaveOpenTopic(this.topic);\n this.state = CHANNEL_STATES.joining;\n this.joinPush.resend(timeout);\n }\n\n trigger(event, payload, ref, joinRef) {\n let handledPayload = this.onMessage(event, payload, ref, joinRef);\n\n if (payload && !handledPayload) {\n throw new Error(\"channel onMessage callbacks must return the payload, modified or unmodified\");\n }\n\n let eventBindings = this.bindings.filter(bind => bind.event === event);\n\n for (let i = 0; i < eventBindings.length; i++) {\n let bind = eventBindings[i];\n bind.callback(handledPayload, ref, joinRef || this.joinRef());\n }\n }\n\n replyEventName(ref) {\n return `chan_reply_${ref}`;\n }\n\n isClosed() {\n return this.state === CHANNEL_STATES.closed;\n }\n\n isErrored() {\n return this.state === CHANNEL_STATES.errored;\n }\n\n isJoined() {\n return this.state === CHANNEL_STATES.joined;\n }\n\n isJoining() {\n return this.state === CHANNEL_STATES.joining;\n }\n\n isLeaving() {\n return this.state === CHANNEL_STATES.leaving;\n }\n\n}; // js/phoenix/ajax.js\n\nvar Ajax = class {\n static request(method, endPoint, accept, body, timeout, ontimeout, callback) {\n if (global.XDomainRequest) {\n let req = new global.XDomainRequest();\n this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback);\n } else {\n let req = new global.XMLHttpRequest();\n this.xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback);\n }\n }\n\n static xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) {\n req.timeout = timeout;\n req.open(method, endPoint);\n\n req.onload = () => {\n let response = this.parseJSON(req.responseText);\n callback && callback(response);\n };\n\n if (ontimeout) {\n req.ontimeout = ontimeout;\n }\n\n req.onprogress = () => {};\n\n req.send(body);\n }\n\n static xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback) {\n req.open(method, endPoint, true);\n req.timeout = timeout;\n req.setRequestHeader(\"Content-Type\", accept);\n\n req.onerror = () => {\n callback && callback(null);\n };\n\n req.onreadystatechange = () => {\n if (req.readyState === XHR_STATES.complete && callback) {\n let response = this.parseJSON(req.responseText);\n callback(response);\n }\n };\n\n if (ontimeout) {\n req.ontimeout = ontimeout;\n }\n\n req.send(body);\n }\n\n static parseJSON(resp) {\n if (!resp || resp === \"\") {\n return null;\n }\n\n try {\n return JSON.parse(resp);\n } catch (e) {\n console && console.log(\"failed to parse JSON response\", resp);\n return null;\n }\n }\n\n static serialize(obj, parentKey) {\n let queryStr = [];\n\n for (var key in obj) {\n if (!Object.prototype.hasOwnProperty.call(obj, key)) {\n continue;\n }\n\n let paramKey = parentKey ? `${parentKey}[${key}]` : key;\n let paramVal = obj[key];\n\n if (typeof paramVal === \"object\") {\n queryStr.push(this.serialize(paramVal, paramKey));\n } else {\n queryStr.push(encodeURIComponent(paramKey) + \"=\" + encodeURIComponent(paramVal));\n }\n }\n\n return queryStr.join(\"&\");\n }\n\n static appendParams(url, params) {\n if (Object.keys(params).length === 0) {\n return url;\n }\n\n let prefix = url.match(/\\?/) ? \"&\" : \"?\";\n return `${url}${prefix}${this.serialize(params)}`;\n }\n\n}; // js/phoenix/longpoll.js\n\nvar LongPoll = class {\n constructor(endPoint) {\n this.endPoint = null;\n this.token = null;\n this.skipHeartbeat = true;\n\n this.onopen = function () {};\n\n this.onerror = function () {};\n\n this.onmessage = function () {};\n\n this.onclose = function () {};\n\n this.pollEndpoint = this.normalizeEndpoint(endPoint);\n this.readyState = SOCKET_STATES.connecting;\n this.poll();\n }\n\n normalizeEndpoint(endPoint) {\n return endPoint.replace(\"ws://\", \"http://\").replace(\"wss://\", \"https://\").replace(new RegExp(\"(.*)/\" + TRANSPORTS.websocket), \"$1/\" + TRANSPORTS.longpoll);\n }\n\n endpointURL() {\n return Ajax.appendParams(this.pollEndpoint, {\n token: this.token\n });\n }\n\n closeAndRetry() {\n this.close();\n this.readyState = SOCKET_STATES.connecting;\n }\n\n ontimeout() {\n this.onerror(\"timeout\");\n this.closeAndRetry();\n }\n\n poll() {\n if (!(this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting)) {\n return;\n }\n\n Ajax.request(\"GET\", this.endpointURL(), \"application/json\", null, this.timeout, this.ontimeout.bind(this), resp => {\n if (resp) {\n var {\n status,\n token,\n messages\n } = resp;\n this.token = token;\n } else {\n status = 0;\n }\n\n switch (status) {\n case 200:\n messages.forEach(msg => {\n setTimeout(() => {\n this.onmessage({\n data: msg\n });\n }, 0);\n });\n this.poll();\n break;\n\n case 204:\n this.poll();\n break;\n\n case 410:\n this.readyState = SOCKET_STATES.open;\n this.onopen();\n this.poll();\n break;\n\n case 403:\n this.onerror();\n this.close();\n break;\n\n case 0:\n case 500:\n this.onerror();\n this.closeAndRetry();\n break;\n\n default:\n throw new Error(`unhandled poll status ${status}`);\n }\n });\n }\n\n send(body) {\n Ajax.request(\"POST\", this.endpointURL(), \"application/json\", body, this.timeout, this.onerror.bind(this, \"timeout\"), resp => {\n if (!resp || resp.status !== 200) {\n this.onerror(resp && resp.status);\n this.closeAndRetry();\n }\n });\n }\n\n close(_code, _reason) {\n this.readyState = SOCKET_STATES.closed;\n this.onclose();\n }\n\n}; // js/phoenix/presence.js\n\nvar Presence = class {\n constructor(channel, opts = {}) {\n let events = opts.events || {\n state: \"presence_state\",\n diff: \"presence_diff\"\n };\n this.state = {};\n this.pendingDiffs = [];\n this.channel = channel;\n this.joinRef = null;\n this.caller = {\n onJoin: function () {},\n onLeave: function () {},\n onSync: function () {}\n };\n this.channel.on(events.state, newState => {\n let {\n onJoin,\n onLeave,\n onSync\n } = this.caller;\n this.joinRef = this.channel.joinRef();\n this.state = Presence.syncState(this.state, newState, onJoin, onLeave);\n this.pendingDiffs.forEach(diff => {\n this.state = Presence.syncDiff(this.state, diff, onJoin, onLeave);\n });\n this.pendingDiffs = [];\n onSync();\n });\n this.channel.on(events.diff, diff => {\n let {\n onJoin,\n onLeave,\n onSync\n } = this.caller;\n\n if (this.inPendingSyncState()) {\n this.pendingDiffs.push(diff);\n } else {\n this.state = Presence.syncDiff(this.state, diff, onJoin, onLeave);\n onSync();\n }\n });\n }\n\n onJoin(callback) {\n this.caller.onJoin = callback;\n }\n\n onLeave(callback) {\n this.caller.onLeave = callback;\n }\n\n onSync(callback) {\n this.caller.onSync = callback;\n }\n\n list(by) {\n return Presence.list(this.state, by);\n }\n\n inPendingSyncState() {\n return !this.joinRef || this.joinRef !== this.channel.joinRef();\n }\n\n static syncState(currentState, newState, onJoin, onLeave) {\n let state = this.clone(currentState);\n let joins = {};\n let leaves = {};\n this.map(state, (key, presence) => {\n if (!newState[key]) {\n leaves[key] = presence;\n }\n });\n this.map(newState, (key, newPresence) => {\n let currentPresence = state[key];\n\n if (currentPresence) {\n let newRefs = newPresence.metas.map(m => m.phx_ref);\n let curRefs = currentPresence.metas.map(m => m.phx_ref);\n let joinedMetas = newPresence.metas.filter(m => curRefs.indexOf(m.phx_ref) < 0);\n let leftMetas = currentPresence.metas.filter(m => newRefs.indexOf(m.phx_ref) < 0);\n\n if (joinedMetas.length > 0) {\n joins[key] = newPresence;\n joins[key].metas = joinedMetas;\n }\n\n if (leftMetas.length > 0) {\n leaves[key] = this.clone(currentPresence);\n leaves[key].metas = leftMetas;\n }\n } else {\n joins[key] = newPresence;\n }\n });\n return this.syncDiff(state, {\n joins,\n leaves\n }, onJoin, onLeave);\n }\n\n static syncDiff(state, diff, onJoin, onLeave) {\n let {\n joins,\n leaves\n } = this.clone(diff);\n\n if (!onJoin) {\n onJoin = function () {};\n }\n\n if (!onLeave) {\n onLeave = function () {};\n }\n\n this.map(joins, (key, newPresence) => {\n let currentPresence = state[key];\n state[key] = this.clone(newPresence);\n\n if (currentPresence) {\n let joinedRefs = state[key].metas.map(m => m.phx_ref);\n let curMetas = currentPresence.metas.filter(m => joinedRefs.indexOf(m.phx_ref) < 0);\n state[key].metas.unshift(...curMetas);\n }\n\n onJoin(key, currentPresence, newPresence);\n });\n this.map(leaves, (key, leftPresence) => {\n let currentPresence = state[key];\n\n if (!currentPresence) {\n return;\n }\n\n let refsToRemove = leftPresence.metas.map(m => m.phx_ref);\n currentPresence.metas = currentPresence.metas.filter(p => {\n return refsToRemove.indexOf(p.phx_ref) < 0;\n });\n onLeave(key, currentPresence, leftPresence);\n\n if (currentPresence.metas.length === 0) {\n delete state[key];\n }\n });\n return state;\n }\n\n static list(presences, chooser) {\n if (!chooser) {\n chooser = function (key, pres) {\n return pres;\n };\n }\n\n return this.map(presences, (key, presence) => {\n return chooser(key, presence);\n });\n }\n\n static map(obj, func) {\n return Object.getOwnPropertyNames(obj).map(key => func(key, obj[key]));\n }\n\n static clone(obj) {\n return JSON.parse(JSON.stringify(obj));\n }\n\n}; // js/phoenix/serializer.js\n\nvar serializer_default = {\n HEADER_LENGTH: 1,\n META_LENGTH: 4,\n KINDS: {\n push: 0,\n reply: 1,\n broadcast: 2\n },\n\n encode(msg, callback) {\n if (msg.payload.constructor === ArrayBuffer) {\n return callback(this.binaryEncode(msg));\n } else {\n let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload];\n return callback(JSON.stringify(payload));\n }\n },\n\n decode(rawPayload, callback) {\n if (rawPayload.constructor === ArrayBuffer) {\n return callback(this.binaryDecode(rawPayload));\n } else {\n let [join_ref, ref, topic, event, payload] = JSON.parse(rawPayload);\n return callback({\n join_ref,\n ref,\n topic,\n event,\n payload\n });\n }\n },\n\n binaryEncode(message) {\n let {\n join_ref,\n ref,\n event,\n topic,\n payload\n } = message;\n let metaLength = this.META_LENGTH + join_ref.length + ref.length + topic.length + event.length;\n let header = new ArrayBuffer(this.HEADER_LENGTH + metaLength);\n let view = new DataView(header);\n let offset = 0;\n view.setUint8(offset++, this.KINDS.push);\n view.setUint8(offset++, join_ref.length);\n view.setUint8(offset++, ref.length);\n view.setUint8(offset++, topic.length);\n view.setUint8(offset++, event.length);\n Array.from(join_ref, char => view.setUint8(offset++, char.charCodeAt(0)));\n Array.from(ref, char => view.setUint8(offset++, char.charCodeAt(0)));\n Array.from(topic, char => view.setUint8(offset++, char.charCodeAt(0)));\n Array.from(event, char => view.setUint8(offset++, char.charCodeAt(0)));\n var combined = new Uint8Array(header.byteLength + payload.byteLength);\n combined.set(new Uint8Array(header), 0);\n combined.set(new Uint8Array(payload), header.byteLength);\n return combined.buffer;\n },\n\n binaryDecode(buffer) {\n let view = new DataView(buffer);\n let kind = view.getUint8(0);\n let decoder = new TextDecoder();\n\n switch (kind) {\n case this.KINDS.push:\n return this.decodePush(buffer, view, decoder);\n\n case this.KINDS.reply:\n return this.decodeReply(buffer, view, decoder);\n\n case this.KINDS.broadcast:\n return this.decodeBroadcast(buffer, view, decoder);\n }\n },\n\n decodePush(buffer, view, decoder) {\n let joinRefSize = view.getUint8(1);\n let topicSize = view.getUint8(2);\n let eventSize = view.getUint8(3);\n let offset = this.HEADER_LENGTH + this.META_LENGTH - 1;\n let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));\n offset = offset + joinRefSize;\n let topic = decoder.decode(buffer.slice(offset, offset + topicSize));\n offset = offset + topicSize;\n let event = decoder.decode(buffer.slice(offset, offset + eventSize));\n offset = offset + eventSize;\n let data = buffer.slice(offset, buffer.byteLength);\n return {\n join_ref: joinRef,\n ref: null,\n topic,\n event,\n payload: data\n };\n },\n\n decodeReply(buffer, view, decoder) {\n let joinRefSize = view.getUint8(1);\n let refSize = view.getUint8(2);\n let topicSize = view.getUint8(3);\n let eventSize = view.getUint8(4);\n let offset = this.HEADER_LENGTH + this.META_LENGTH;\n let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));\n offset = offset + joinRefSize;\n let ref = decoder.decode(buffer.slice(offset, offset + refSize));\n offset = offset + refSize;\n let topic = decoder.decode(buffer.slice(offset, offset + topicSize));\n offset = offset + topicSize;\n let event = decoder.decode(buffer.slice(offset, offset + eventSize));\n offset = offset + eventSize;\n let data = buffer.slice(offset, buffer.byteLength);\n let payload = {\n status: event,\n response: data\n };\n return {\n join_ref: joinRef,\n ref,\n topic,\n event: CHANNEL_EVENTS.reply,\n payload\n };\n },\n\n decodeBroadcast(buffer, view, decoder) {\n let topicSize = view.getUint8(1);\n let eventSize = view.getUint8(2);\n let offset = this.HEADER_LENGTH + 2;\n let topic = decoder.decode(buffer.slice(offset, offset + topicSize));\n offset = offset + topicSize;\n let event = decoder.decode(buffer.slice(offset, offset + eventSize));\n offset = offset + eventSize;\n let data = buffer.slice(offset, buffer.byteLength);\n return {\n join_ref: null,\n ref: null,\n topic,\n event,\n payload: data\n };\n }\n\n}; // js/phoenix/socket.js\n\nvar Socket = class {\n constructor(endPoint, opts = {}) {\n this.stateChangeCallbacks = {\n open: [],\n close: [],\n error: [],\n message: []\n };\n this.channels = [];\n this.sendBuffer = [];\n this.ref = 0;\n this.timeout = opts.timeout || DEFAULT_TIMEOUT;\n this.transport = opts.transport || global.WebSocket || LongPoll;\n this.establishedConnections = 0;\n this.defaultEncoder = serializer_default.encode.bind(serializer_default);\n this.defaultDecoder = serializer_default.decode.bind(serializer_default);\n this.closeWasClean = false;\n this.binaryType = opts.binaryType || \"arraybuffer\";\n this.connectClock = 1;\n\n if (this.transport !== LongPoll) {\n this.encode = opts.encode || this.defaultEncoder;\n this.decode = opts.decode || this.defaultDecoder;\n } else {\n this.encode = this.defaultEncoder;\n this.decode = this.defaultDecoder;\n }\n\n let awaitingConnectionOnPageShow = null;\n\n if (phxWindow && phxWindow.addEventListener) {\n phxWindow.addEventListener(\"pagehide\", _e => {\n if (this.conn) {\n this.disconnect();\n awaitingConnectionOnPageShow = this.connectClock;\n }\n });\n phxWindow.addEventListener(\"pageshow\", _e => {\n if (awaitingConnectionOnPageShow === this.connectClock) {\n awaitingConnectionOnPageShow = null;\n this.connect();\n }\n });\n }\n\n this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 3e4;\n\n this.rejoinAfterMs = tries => {\n if (opts.rejoinAfterMs) {\n return opts.rejoinAfterMs(tries);\n } else {\n return [1e3, 2e3, 5e3][tries - 1] || 1e4;\n }\n };\n\n this.reconnectAfterMs = tries => {\n if (opts.reconnectAfterMs) {\n return opts.reconnectAfterMs(tries);\n } else {\n return [10, 50, 100, 150, 200, 250, 500, 1e3, 2e3][tries - 1] || 5e3;\n }\n };\n\n this.logger = opts.logger || null;\n this.longpollerTimeout = opts.longpollerTimeout || 2e4;\n this.params = closure(opts.params || {});\n this.endPoint = `${endPoint}/${TRANSPORTS.websocket}`;\n this.vsn = opts.vsn || DEFAULT_VSN;\n this.heartbeatTimer = null;\n this.pendingHeartbeatRef = null;\n this.reconnectTimer = new Timer(() => {\n this.teardown(() => this.connect());\n }, this.reconnectAfterMs);\n }\n\n replaceTransport(newTransport) {\n this.disconnect();\n this.transport = newTransport;\n }\n\n protocol() {\n return location.protocol.match(/^https/) ? \"wss\" : \"ws\";\n }\n\n endPointURL() {\n let uri = Ajax.appendParams(Ajax.appendParams(this.endPoint, this.params()), {\n vsn: this.vsn\n });\n\n if (uri.charAt(0) !== \"/\") {\n return uri;\n }\n\n if (uri.charAt(1) === \"/\") {\n return `${this.protocol()}:${uri}`;\n }\n\n return `${this.protocol()}://${location.host}${uri}`;\n }\n\n disconnect(callback, code, reason) {\n this.connectClock++;\n this.closeWasClean = true;\n this.reconnectTimer.reset();\n this.teardown(callback, code, reason);\n }\n\n connect(params) {\n this.connectClock++;\n\n if (params) {\n console && console.log(\"passing params to connect is deprecated. Instead pass :params to the Socket constructor\");\n this.params = closure(params);\n }\n\n if (this.conn) {\n return;\n }\n\n this.closeWasClean = false;\n this.conn = new this.transport(this.endPointURL());\n this.conn.binaryType = this.binaryType;\n this.conn.timeout = this.longpollerTimeout;\n\n this.conn.onopen = () => this.onConnOpen();\n\n this.conn.onerror = error => this.onConnError(error);\n\n this.conn.onmessage = event => this.onConnMessage(event);\n\n this.conn.onclose = event => this.onConnClose(event);\n }\n\n log(kind, msg, data) {\n this.logger(kind, msg, data);\n }\n\n hasLogger() {\n return this.logger !== null;\n }\n\n onOpen(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.open.push([ref, callback]);\n return ref;\n }\n\n onClose(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.close.push([ref, callback]);\n return ref;\n }\n\n onError(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.error.push([ref, callback]);\n return ref;\n }\n\n onMessage(callback) {\n let ref = this.makeRef();\n this.stateChangeCallbacks.message.push([ref, callback]);\n return ref;\n }\n\n onConnOpen() {\n if (this.hasLogger()) this.log(\"transport\", `connected to ${this.endPointURL()}`);\n this.closeWasClean = false;\n this.establishedConnections++;\n this.flushSendBuffer();\n this.reconnectTimer.reset();\n this.resetHeartbeat();\n this.stateChangeCallbacks.open.forEach(([, callback]) => callback());\n }\n\n heartbeatTimeout() {\n if (this.pendingHeartbeatRef) {\n this.pendingHeartbeatRef = null;\n\n if (this.hasLogger()) {\n this.log(\"transport\", \"heartbeat timeout. Attempting to re-establish connection\");\n }\n\n this.abnormalClose(\"heartbeat timeout\");\n }\n }\n\n resetHeartbeat() {\n if (this.conn && this.conn.skipHeartbeat) {\n return;\n }\n\n this.pendingHeartbeatRef = null;\n clearTimeout(this.heartbeatTimer);\n setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);\n }\n\n teardown(callback, code, reason) {\n if (!this.conn) {\n return callback && callback();\n }\n\n this.waitForBufferDone(() => {\n if (this.conn) {\n if (code) {\n this.conn.close(code, reason || \"\");\n } else {\n this.conn.close();\n }\n }\n\n this.waitForSocketClosed(() => {\n if (this.conn) {\n this.conn.onclose = function () {};\n\n this.conn = null;\n }\n\n callback && callback();\n });\n });\n }\n\n waitForBufferDone(callback, tries = 1) {\n if (tries === 5 || !this.conn || !this.conn.bufferedAmount) {\n callback();\n return;\n }\n\n setTimeout(() => {\n this.waitForBufferDone(callback, tries + 1);\n }, 150 * tries);\n }\n\n waitForSocketClosed(callback, tries = 1) {\n if (tries === 5 || !this.conn || this.conn.readyState === SOCKET_STATES.closed) {\n callback();\n return;\n }\n\n setTimeout(() => {\n this.waitForSocketClosed(callback, tries + 1);\n }, 150 * tries);\n }\n\n onConnClose(event) {\n if (this.hasLogger()) this.log(\"transport\", \"close\", event);\n this.triggerChanError();\n clearTimeout(this.heartbeatTimer);\n\n if (!this.closeWasClean) {\n this.reconnectTimer.scheduleTimeout();\n }\n\n this.stateChangeCallbacks.close.forEach(([, callback]) => callback(event));\n }\n\n onConnError(error) {\n if (this.hasLogger()) this.log(\"transport\", error);\n let transportBefore = this.transport;\n let establishedBefore = this.establishedConnections;\n this.stateChangeCallbacks.error.forEach(([, callback]) => {\n callback(error, transportBefore, establishedBefore);\n });\n\n if (transportBefore === this.transport || establishedBefore > 0) {\n this.triggerChanError();\n }\n }\n\n triggerChanError() {\n this.channels.forEach(channel => {\n if (!(channel.isErrored() || channel.isLeaving() || channel.isClosed())) {\n channel.trigger(CHANNEL_EVENTS.error);\n }\n });\n }\n\n connectionState() {\n switch (this.conn && this.conn.readyState) {\n case SOCKET_STATES.connecting:\n return \"connecting\";\n\n case SOCKET_STATES.open:\n return \"open\";\n\n case SOCKET_STATES.closing:\n return \"closing\";\n\n default:\n return \"closed\";\n }\n }\n\n isConnected() {\n return this.connectionState() === \"open\";\n }\n\n remove(channel) {\n this.off(channel.stateChangeRefs);\n this.channels = this.channels.filter(c => c.joinRef() !== channel.joinRef());\n }\n\n off(refs) {\n for (let key in this.stateChangeCallbacks) {\n this.stateChangeCallbacks[key] = this.stateChangeCallbacks[key].filter(([ref]) => {\n return refs.indexOf(ref) === -1;\n });\n }\n }\n\n channel(topic, chanParams = {}) {\n let chan = new Channel(topic, chanParams, this);\n this.channels.push(chan);\n return chan;\n }\n\n push(data) {\n if (this.hasLogger()) {\n let {\n topic,\n event,\n payload,\n ref,\n join_ref\n } = data;\n this.log(\"push\", `${topic} ${event} (${join_ref}, ${ref})`, payload);\n }\n\n if (this.isConnected()) {\n this.encode(data, result => this.conn.send(result));\n } else {\n this.sendBuffer.push(() => this.encode(data, result => this.conn.send(result)));\n }\n }\n\n makeRef() {\n let newRef = this.ref + 1;\n\n if (newRef === this.ref) {\n this.ref = 0;\n } else {\n this.ref = newRef;\n }\n\n return this.ref.toString();\n }\n\n sendHeartbeat() {\n if (this.pendingHeartbeatRef && !this.isConnected()) {\n return;\n }\n\n this.pendingHeartbeatRef = this.makeRef();\n this.push({\n topic: \"phoenix\",\n event: \"heartbeat\",\n payload: {},\n ref: this.pendingHeartbeatRef\n });\n this.heartbeatTimer = setTimeout(() => this.heartbeatTimeout(), this.heartbeatIntervalMs);\n }\n\n abnormalClose(reason) {\n this.closeWasClean = false;\n\n if (this.isConnected()) {\n this.conn.close(WS_CLOSE_NORMAL, reason);\n }\n }\n\n flushSendBuffer() {\n if (this.isConnected() && this.sendBuffer.length > 0) {\n this.sendBuffer.forEach(callback => callback());\n this.sendBuffer = [];\n }\n }\n\n onConnMessage(rawMessage) {\n this.decode(rawMessage.data, msg => {\n let {\n topic,\n event,\n payload,\n ref,\n join_ref\n } = msg;\n\n if (ref && ref === this.pendingHeartbeatRef) {\n clearTimeout(this.heartbeatTimer);\n this.pendingHeartbeatRef = null;\n setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);\n }\n\n if (this.hasLogger()) this.log(\"receive\", `${payload.status || \"\"} ${topic} ${event} ${ref && \"(\" + ref + \")\" || \"\"}`, payload);\n\n for (let i = 0; i < this.channels.length; i++) {\n const channel = this.channels[i];\n\n if (!channel.isMember(topic, event, payload, join_ref)) {\n continue;\n }\n\n channel.trigger(event, payload, ref, join_ref);\n }\n\n for (let i = 0; i < this.stateChangeCallbacks.message.length; i++) {\n let [, callback] = this.stateChangeCallbacks.message[i];\n callback(msg);\n }\n });\n }\n\n leaveOpenTopic(topic) {\n let dupChannel = this.channels.find(c => c.topic === topic && (c.isJoined() || c.isJoining()));\n\n if (dupChannel) {\n if (this.hasLogger()) this.log(\"transport\", `leaving duplicate topic \"${topic}\"`);\n dupChannel.leave();\n }\n }\n\n};\n\n\n//# sourceURL=webpack://@seamly/web-ui/./node_modules/phoenix/priv/static/phoenix.esm.js?");
|
|
83
83
|
|
|
84
84
|
/***/ }),
|
|
85
85
|
|
|
@@ -750,7 +750,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
750
750
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
751
751
|
|
|
752
752
|
"use strict";
|
|
753
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"createStore\": () => (/* binding */ createStore)\n/* harmony export */ });\n/* harmony import */ var redux_thunk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! redux-thunk */ \"./node_modules/redux-thunk/es/index.js\");\n/* harmony import */ var
|
|
753
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"createStore\": () => (/* binding */ createStore)\n/* harmony export */ });\n/* harmony import */ var redux_thunk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! redux-thunk */ \"./node_modules/redux-thunk/es/index.js\");\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../app */ \"./src/javascripts/domains/app/index.js\");\n/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config */ \"./src/javascripts/domains/config/index.js\");\n/* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../errors */ \"./src/javascripts/domains/errors/index.js\");\n/* harmony import */ var _forms__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../forms */ \"./src/javascripts/domains/forms/index.js\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../i18n */ \"./src/javascripts/domains/i18n/index.js\");\n/* harmony import */ var _interrupt__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../interrupt */ \"./src/javascripts/domains/interrupt/index.js\");\n/* harmony import */ var _options__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../options */ \"./src/javascripts/domains/options/index.js\");\n/* harmony import */ var _redux__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../redux */ \"./src/javascripts/domains/redux/index.js\");\n/* harmony import */ var _translations__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../translations */ \"./src/javascripts/domains/translations/index.js\");\n/* harmony import */ var _visibility__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../visibility */ \"./src/javascripts/domains/visibility/index.js\");\n/* harmony import */ var _state_reducer__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./state-reducer */ \"./src/javascripts/domains/store/state-reducer.js\");\n\n\n\n\n\n\n\n\n\n\n\n\nfunction createStore({\n initialState,\n api,\n eventBus\n} = {}) {\n const store = (0,_redux__WEBPACK_IMPORTED_MODULE_8__.createReduxStore)({\n reducers: {\n state: _state_reducer__WEBPACK_IMPORTED_MODULE_11__[\"default\"],\n [String(_app__WEBPACK_IMPORTED_MODULE_1__.Reducer)]: _app__WEBPACK_IMPORTED_MODULE_1__.Reducer,\n [String(_config__WEBPACK_IMPORTED_MODULE_2__.Reducer)]: _config__WEBPACK_IMPORTED_MODULE_2__.Reducer,\n [String(_forms__WEBPACK_IMPORTED_MODULE_4__.Reducer)]: _forms__WEBPACK_IMPORTED_MODULE_4__.Reducer,\n [String(_translations__WEBPACK_IMPORTED_MODULE_9__.Reducer)]: _translations__WEBPACK_IMPORTED_MODULE_9__.Reducer,\n [String(_i18n__WEBPACK_IMPORTED_MODULE_5__.Reducer)]: _i18n__WEBPACK_IMPORTED_MODULE_5__.Reducer,\n [String(_interrupt__WEBPACK_IMPORTED_MODULE_6__.Reducer)]: _interrupt__WEBPACK_IMPORTED_MODULE_6__.Reducer,\n [String(_visibility__WEBPACK_IMPORTED_MODULE_10__.Reducer)]: _visibility__WEBPACK_IMPORTED_MODULE_10__.Reducer\n },\n initialState,\n middlewares: [(0,_errors__WEBPACK_IMPORTED_MODULE_3__.createMiddleware)({\n api\n }), redux_thunk__WEBPACK_IMPORTED_MODULE_0__[\"default\"].withExtraArgument({\n api,\n eventBus\n }), (0,_config__WEBPACK_IMPORTED_MODULE_2__.createMiddleware)(), (0,_interrupt__WEBPACK_IMPORTED_MODULE_6__.createMiddleware)({\n api\n }), (0,_options__WEBPACK_IMPORTED_MODULE_7__.createMiddleware)({\n api\n }), _translations__WEBPACK_IMPORTED_MODULE_9__.createMiddleware]\n });\n return store;\n}\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/domains/store/index.js?");
|
|
754
754
|
|
|
755
755
|
/***/ }),
|
|
756
756
|
|
|
@@ -849,7 +849,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
849
849
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
850
850
|
|
|
851
851
|
"use strict";
|
|
852
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ createMiddleware)\n/* harmony export */ });\n/* harmony import */ var
|
|
852
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ createMiddleware)\n/* harmony export */ });\n/* harmony import */ var _ui_utils_seamly_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../ui/utils/seamly-utils */ \"./src/javascripts/ui/utils/seamly-utils.js\");\n/* harmony import */ var _i18n__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../i18n */ \"./src/javascripts/domains/i18n/index.js\");\n/* harmony import */ var _actions__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./actions */ \"./src/javascripts/domains/translations/actions.js\");\n\n\n\nfunction createMiddleware({\n dispatch,\n getState\n}) {\n return next => {\n return action => {\n var _action$history, _action$history$trans, _action$initialState, _action$initialState$, _action$event, _action$event$payload, _action$event$payload2;\n\n const result = next(action);\n\n switch (action.type) {\n case String(_ui_utils_seamly_utils__WEBPACK_IMPORTED_MODULE_0__.seamlyActions.SET_HISTORY):\n if ((_action$history = action.history) !== null && _action$history !== void 0 && (_action$history$trans = _action$history.translation) !== null && _action$history$trans !== void 0 && _action$history$trans.enabled) {\n dispatch(_actions__WEBPACK_IMPORTED_MODULE_2__.enable(action.history.translation.locale));\n dispatch(_i18n__WEBPACK_IMPORTED_MODULE_1__.Actions.setLocale(action.history.translation.locale));\n }\n\n break;\n\n case String(_ui_utils_seamly_utils__WEBPACK_IMPORTED_MODULE_0__.seamlyActions.SET_INITIAL_STATE):\n if ((_action$initialState = action.initialState) !== null && _action$initialState !== void 0 && (_action$initialState$ = _action$initialState.translation) !== null && _action$initialState$ !== void 0 && _action$initialState$.enabled) {\n dispatch(_actions__WEBPACK_IMPORTED_MODULE_2__.enable(action.initialState.translation.locale));\n dispatch(_i18n__WEBPACK_IMPORTED_MODULE_1__.Actions.setLocale(action.locale));\n }\n\n break;\n\n case String(_ui_utils_seamly_utils__WEBPACK_IMPORTED_MODULE_0__.seamlyActions.ADD_EVENT):\n if (action.event.type === 'info' && ((_action$event = action.event) === null || _action$event === void 0 ? void 0 : (_action$event$payload = _action$event.payload) === null || _action$event$payload === void 0 ? void 0 : (_action$event$payload2 = _action$event$payload.body) === null || _action$event$payload2 === void 0 ? void 0 : _action$event$payload2.subtype) === 'new_translation' && action.event.payload.body.translationEnabled) {\n dispatch(_i18n__WEBPACK_IMPORTED_MODULE_1__.Actions.setLocale(action.event.payload.body.translationLocale));\n }\n\n break;\n\n case String(_actions__WEBPACK_IMPORTED_MODULE_2__.disable):\n const initialLocale = _i18n__WEBPACK_IMPORTED_MODULE_1__.Selectors.selectInitialLocale(getState());\n dispatch(_i18n__WEBPACK_IMPORTED_MODULE_1__.Actions.setLocale(initialLocale));\n break;\n }\n\n return result;\n };\n };\n}\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/domains/translations/middleware.js?");
|
|
853
853
|
|
|
854
854
|
/***/ }),
|
|
855
855
|
|
|
@@ -2310,7 +2310,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
2310
2310
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
2311
2311
|
|
|
2312
2312
|
"use strict";
|
|
2313
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"eventTypes\": () => (/* binding */ eventTypes),\n/* harmony export */ \"payloadTypes\": () => (/* binding */ payloadTypes),\n/* harmony export */ \"entryTypes\": () => (/* binding */ entryTypes),\n/* harmony export */ \"readStates\": () => (/* binding */ readStates),\n/* harmony export */ \"actionTypes\": () => (/* binding */ actionTypes),\n/* harmony export */ \"dismissTypes\": () => (/* binding */ dismissTypes),\n/* harmony export */ \"ariaLiveLevels\": () => (/* binding */ ariaLiveLevels),\n/* harmony export */ \"dividerKeys\": () => (/* binding */ dividerKeys),\n/* harmony export */ \"featureKeys\": () => (/* binding */ featureKeys),\n/* harmony export */ \"seamlyActions\": () => (/* binding */ seamlyActions),\n/* harmony export */ \"cardTypes\": () => (/* binding */ cardTypes),\n/* harmony export */ \"isUnreadMessage\": () => (/* binding */ isUnreadMessage),\n/* harmony export */ \"mergeHistory\": () => (/* binding */ mergeHistory),\n/* harmony export */ \"seamlyStateReducer\": () => (/* binding */ seamlyStateReducer)\n/* harmony export */ });\n/* harmony import */ var _general_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./general-utils */ \"./src/javascripts/ui/utils/general-utils.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\nconst eventTypes = {\n info: 'info',\n message: 'message',\n participant: 'participant',\n system: 'system'\n};\nconst payloadTypes = {\n choicePrompt: 'choice_prompt',\n text: 'text',\n image: 'image',\n video: 'video',\n participant: 'participant',\n divider: 'divider',\n translation: 'translation',\n message: 'message',\n countdown: 'countdown',\n upload: 'upload',\n cta: 'cta'\n};\nconst entryTypes = {\n text: 'text',\n upload: 'upload'\n};\nconst readStates = {\n received: 'received',\n read: 'read'\n};\nconst actionTypes = {\n pickChoice: 'pick_choice',\n navigate: 'navigate',\n custom: 'custom',\n typing: 'typing',\n read: 'read',\n detachService: 'detach_service',\n interactivityUpdate: 'interactivity_update',\n dismiss: 'dismiss',\n sendTranscript: 'send_transcript',\n setTranslation: 'set_translation',\n clickCta: 'click_cta',\n clickCard: 'click_card'\n};\nconst dismissTypes = {\n resumeConversationPrompt: 'resume_conversation_prompt'\n};\nconst ariaLiveLevels = {\n assertive: 'assertive',\n polite: 'polite'\n};\nconst dividerKeys = {\n new_topic: 'newTopic',\n new_translation: 'newTranslation'\n};\nconst featureKeys = {\n cobrowsing: 'cobrowsing',\n sendTranscript: 'sendTranscript',\n typingPeekahead: 'typingPeekahead',\n uploads: 'uploads'\n};\nconst seamlyActions = {\n ADD_EVENT: 'ADD_EVENT',\n CLEAR_EVENTS: 'CLEAR_EVENTS',\n SET_HISTORY: 'SET_HISTORY',\n SET_EVENTS_READ: 'SET_EVENTS_READ',\n ACK_EVENT: 'ACK_EVENT',\n SET_IS_LOADING: 'SET_IS_LOADING',\n CLEAR_PARTICIPANTS: 'CLEAR_PARTICIPANTS',\n SET_PARTICIPANT: 'SET_PARTICIPANT',\n SET_HEADER_TITLE: 'SET_HEADER_TITLE',\n SET_HEADER_SUB_TITLE: 'SET_HEADER_SUB_TITLE',\n RESET_HISTORY_LOADED_FLAG: 'RESET_HISTORY_LOADED_FLAG',\n SET_ACTIVE_SERVICE: 'SET_ACTIVE_SERVICE',\n INIT_IDLE_DETACH_COUNTDOWN: 'INIT_IDLE_DETACH_COUNTDOWN',\n DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER: 'DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER',\n STOP_IDLE_DETACH_COUNTDOWN_COUNTER: 'STOP_IDLE_DETACH_COUNTDOWN_COUNTER',\n CLEAR_IDLE_DETACH_COUNTDOWN: 'CLEAR_IDLE_DETACH_COUNTDOWN',\n INIT_RESUME_CONVERSATION_PROMPT: 'INIT_RESUME_CONVERSATION_PROMPT',\n CLEAR_RESUME_CONVERSATION_PROMPT: 'CLEAR_RESUME_CONVERSATION_PROMPT',\n SET_SERVICE_DATA_ITEM: 'SET_SERVICE_DATA_ITEM',\n SET_FEATURES: 'SET_FEATURES',\n SET_FEATURE_ENABLED_STATE: 'SET_FEATURE_ENABLED_STATE',\n CLEAR_FEATURES: 'CLEAR_FEATURES',\n SET_INITIAL_STATE: 'SET_INITIAL_STATE',\n SET_USER_SELECTED_OPTIONS: 'SET_USER_SELECTED_OPTIONS',\n SET_USER_SELECTED_OPTION: 'SET_USER_SELECTED_OPTION',\n SHOW_OPTION: 'SHOW_OPTION',\n HIDE_OPTION: 'HIDE_OPTION',\n SET_SERVICE_ENTRY_METADATA: 'SET_SERVICE_ENTRY_METADATA',\n SET_BLOCK_AUTO_ENTRY_SWITCH: 'SET_BLOCK_AUTO_ENTRY_SWITCH',\n SET_ACTIVE_ENTRY_TYPE: 'SET_ACTIVE_ENTRY_TYPE',\n SET_USER_ENTRY_TYPE: 'SET_USER_ENTRY_TYPE',\n REGISTER_UPLOAD: 'REGISTER_UPLOAD',\n SET_UPLOAD_PROGRESS: 'SET_UPLOAD_PROGRESS',\n SET_UPLOAD_COMPLETE: 'SET_UPLOAD_COMPLETE',\n SET_UPLOAD_ERROR: 'SET_UPLOAD_ERROR',\n CLEAR_UPLOAD: 'CLEAR_UPLOAD',\n CLEAR_ALL_UPLOADS: 'CLEAR_ALL_UPLOADS',\n SET_SEAMLY_CONTAINER_ELEMENT: 'SET_SEAMLY_CONTAINER_ELEMENT'\n};\nconst cardTypes = {\n ask: 'ask',\n navigate: 'navigate',\n topic: 'topic'\n};\nconst {\n ADD_EVENT,\n CLEAR_EVENTS,\n SET_HISTORY,\n SET_EVENTS_READ,\n ACK_EVENT,\n SET_IS_LOADING,\n CLEAR_PARTICIPANTS,\n SET_PARTICIPANT,\n SET_HEADER_TITLE,\n SET_HEADER_SUB_TITLE,\n RESET_HISTORY_LOADED_FLAG,\n SET_ACTIVE_SERVICE,\n INIT_IDLE_DETACH_COUNTDOWN,\n DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER,\n STOP_IDLE_DETACH_COUNTDOWN_COUNTER,\n CLEAR_IDLE_DETACH_COUNTDOWN,\n INIT_RESUME_CONVERSATION_PROMPT,\n CLEAR_RESUME_CONVERSATION_PROMPT,\n SET_SERVICE_DATA_ITEM,\n SET_FEATURES,\n SET_FEATURE_ENABLED_STATE,\n CLEAR_FEATURES,\n SET_INITIAL_STATE,\n SET_USER_SELECTED_OPTION,\n SET_USER_SELECTED_OPTIONS,\n SHOW_OPTION,\n HIDE_OPTION,\n SET_BLOCK_AUTO_ENTRY_SWITCH,\n SET_USER_ENTRY_TYPE,\n SET_ACTIVE_ENTRY_TYPE,\n SET_SERVICE_ENTRY_METADATA,\n REGISTER_UPLOAD,\n SET_UPLOAD_PROGRESS,\n SET_UPLOAD_COMPLETE,\n SET_UPLOAD_ERROR,\n CLEAR_UPLOAD,\n CLEAR_ALL_UPLOADS,\n SET_SEAMLY_CONTAINER_ELEMENT\n} = seamlyActions;\nconst isUnreadMessage = ({\n type,\n payload\n}) => type === eventTypes.message && !payload.fromClient || type === eventTypes.info && payload.type === payloadTypes.text;\n\nconst orderHistory = events => {\n return events.sort(({\n payload: {\n occurredAt: occurredAtA\n }\n }, {\n payload: {\n occurredAt: occurredAtB\n }\n }) => occurredAtA - occurredAtB);\n};\n\nconst mergeHistory = (stateEvents, historyEvents) => {\n const newHistoryEvents = historyEvents.filter(historyEvent => // Deduplicate the event streams\n !stateEvents.find(stateEvent => stateEvent.payload.id === historyEvent.payload.id) && // Remove all non displayable participant messages\n !(historyEvent.type === 'participant' && !historyEvent.payload.participant.introduction)) // Reverse is done here because the server sends the history in the order\n // newest to oldest. In the case of exactly the same occurredAt timestamps\n // these messages will be shown in the wrong order if not reversed. For\n // the normal merging logic there is no added effect.\n .reverse();\n return orderHistory([...newHistoryEvents, ...stateEvents]);\n};\n\nconst participantReducer = (state, action) => {\n switch (action.type) {\n case CLEAR_PARTICIPANTS:\n return {\n participants: {},\n currentAgent: ''\n };\n\n case SET_PARTICIPANT:\n const {\n participants\n } = state;\n const {\n id,\n avatar,\n name,\n introduction\n } = action.participant;\n const oldParticipant = participants[id];\n\n const newParticipants = _objectSpread(_objectSpread({}, participants), {}, {\n [id]: oldParticipant ? _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, oldParticipant), avatar ? {\n avatar\n } : {}), name ? {\n name\n } : {}), introduction ? {\n introduction\n } : {}) : action.participant\n });\n\n return _objectSpread(_objectSpread({}, state), {}, {\n participants: newParticipants,\n currentAgent: state.currentAgent !== id && !action.fromClient ? id : state.currentAgent\n });\n\n default:\n return state;\n }\n};\n\nconst headerTitlesReducer = (state, action) => {\n switch (action.type) {\n case SET_HEADER_TITLE:\n return _objectSpread(_objectSpread({}, state), {}, {\n title: action.title\n });\n\n case SET_HEADER_SUB_TITLE:\n return _objectSpread(_objectSpread({}, state), {}, {\n subTitle: action.title\n });\n\n default:\n return state;\n }\n};\n\nconst calculateNewEntryMeta = (entryMeta, payload) => {\n const {\n entry\n } = payload;\n const {\n blockAutoEntrySwitch\n } = entryMeta;\n\n if (!entry) {\n return _objectSpread(_objectSpread({}, entryMeta), {}, {\n optionsOverride: {}\n });\n }\n\n const {\n type,\n options\n } = entry;\n let newActive = entryMeta.active;\n\n if (!blockAutoEntrySwitch && type !== entryMeta.userSelected) {\n newActive = type;\n }\n\n return _objectSpread(_objectSpread({}, entryMeta), {}, {\n active: newActive,\n optionsOverride: _objectSpread(_objectSpread({}, entryMeta.optionsOverride), {}, {\n [type]: options || {}\n })\n });\n};\n\nconst seamlyStateReducer = (state, action) => {\n switch (action.type) {\n case ADD_EVENT:\n const {\n type: eventType,\n payload\n } = action.event;\n const accountHasUploads = state.options.features.hasOwnProperty(featureKeys.uploads);\n const newEntryMeta = calculateNewEntryMeta(state.entryMeta, payload);\n\n let newOptions = _objectSpread({}, state.options); // This enabled override of the service enabled value for uploads.\n // If a message is sent with entry of type upload it will temporarily\n // override service value and enable uploads.\n\n\n if (accountHasUploads && (eventType === eventTypes.message || eventType === eventTypes.participant) && !payload.fromClient) {\n const {\n type: entryType\n } = payload.entry || {};\n newOptions = _objectSpread(_objectSpread({}, newOptions), {}, {\n features: _objectSpread(_objectSpread({}, newOptions.features), {}, {\n uploads: _objectSpread(_objectSpread({}, newOptions.features.uploads), {}, {\n enabledFromEntry: entryType === entryTypes.upload\n })\n })\n });\n }\n\n const incrementUnread = isUnreadMessage(action.event); // We check for duplicated and ignore them as in some error of the websocket\n // a duplicate join can be active for a while until the server connection\n // times out.\n\n const eventExists = state.events.find(e => e.payload.id === payload.id);\n\n if (eventExists) {\n return state;\n }\n\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: !accountHasUploads && newEntryMeta.active === entryTypes.upload ? _objectSpread({}, state.entryMeta) : newEntryMeta,\n options: newOptions,\n unreadEvents: incrementUnread ? state.unreadEvents + 1 : state.unreadEvents,\n events: [...state.events, _objectSpread(_objectSpread({}, action.event), {}, {\n // The payload spread should be done after adding the message\n // status to enable overriding the status when setting\n // event optimistically.\n payload: _objectSpread(_objectSpread({}, incrementUnread && {\n messageStatus: payload.fromClient ? readStates.read : readStates.received\n }), payload)\n })]\n });\n\n case ACK_EVENT:\n // If any ACKs are sent without transactionID the conversation crashes.\n // Ensure that this edge case is handled gracefully.\n if (!action.event.payload.transactionId) {\n console.warn('ACK received without transaction ID.');\n return state;\n }\n\n const matchedEvent = state.events.find(m => m.payload.transactionId === action.event.payload.transactionId);\n const {\n id,\n occurredAt\n } = action.event.payload;\n return matchedEvent ? _objectSpread(_objectSpread({}, state), {}, {\n events: orderHistory(state.events.map(m => m.payload.id === matchedEvent.payload.id ? _objectSpread(_objectSpread({}, m), {}, {\n payload: _objectSpread(_objectSpread({}, m.payload), {}, {\n id,\n occurredAt\n })\n }) : m))\n }) : state;\n\n case CLEAR_EVENTS:\n return _objectSpread(_objectSpread({}, state), {}, {\n unreadEvents: 0,\n events: []\n });\n\n case SET_EVENTS_READ:\n return _objectSpread(_objectSpread({}, state), {}, {\n unreadEvents: 0,\n events: state.events.map(event => {\n if (action.ids.indexOf(event.payload.id) !== -1) {\n return _objectSpread(_objectSpread({}, event), {}, {\n payload: _objectSpread(_objectSpread({}, event.payload), event.payload.messageStatus === readStates.received && {\n messageStatus: readStates.read\n })\n });\n }\n\n return event;\n })\n });\n\n case SET_HISTORY:\n const {\n events: history,\n participants,\n activeServiceSessionId,\n activeServiceSettings = {},\n serviceData,\n resumeConversationPrompt\n } = action.history;\n const events = mergeHistory(state.events, history);\n\n const mergedParticipants = _objectSpread(_objectSpread({}, state.participantInfo.participants), participants);\n\n const lastParticipantEvent = events.slice().reverse().find(m => (m.type === 'message' || m.type === 'participant') && !m.payload.fromClient);\n let lastParticipantId = null;\n\n if (lastParticipantEvent) {\n if (lastParticipantEvent.type === 'message') {\n lastParticipantId = lastParticipantEvent.payload.participant;\n }\n\n if (lastParticipantEvent.type === 'participant') {\n lastParticipantId = lastParticipantEvent.payload.participant.id;\n }\n }\n\n const {\n cobrowsing,\n entry,\n uploads\n } = activeServiceSettings;\n const historyNewEntryMeta = calculateNewEntryMeta(_objectSpread(_objectSpread(_objectSpread({}, state.entryMeta), entry), {}, {\n active: entry.default || payloadTypes.text,\n options: _objectSpread({}, entry && entry.options ? entry.options : {})\n }), events[events.length - 1].payload);\n\n let newFeatures = _objectSpread({}, state.options.features); // Only set cobrowsing if it was initialised by the account config.\n\n\n if (newFeatures.hasOwnProperty(featureKeys.cobrowsing)) {\n newFeatures = _objectSpread(_objectSpread({}, newFeatures), {}, {\n cobrowsing: {\n enabled: !!(cobrowsing && cobrowsing.enabled)\n }\n });\n }\n\n const newFeaturesHasUpload = newFeatures.hasOwnProperty(featureKeys.uploads); // Only set uploads if it was initialised by the account config.\n\n if (newFeaturesHasUpload) {\n const {\n payload: lastParticipantEventPayload\n } = lastParticipantEvent;\n const {\n type: entryType\n } = lastParticipantEventPayload.entry || {};\n newFeatures = _objectSpread(_objectSpread({}, newFeatures), {}, {\n uploads: {\n enabled: !!(uploads && uploads.enabled),\n enabledFromEntry: entryType === entryTypes.upload\n }\n });\n }\n\n const returnState = _objectSpread(_objectSpread({}, state), {}, {\n unreadEvents: events.filter(event => event.type === 'message' && event.payload.messageStatus === readStates.received).length,\n events: events.filter(e => e.type !== 'participant' || !!e.payload.participant.introduction),\n participantInfo: _objectSpread(_objectSpread(_objectSpread({}, state.participantInfo), lastParticipantId ? participantReducer(state.participantInfo, {\n type: SET_PARTICIPANT,\n participant: mergedParticipants[lastParticipantId]\n }) : {}), {}, {\n participants: mergedParticipants\n }),\n historyLoaded: true,\n serviceInfo: _objectSpread(_objectSpread({}, state.serviceInfo), {}, {\n activeServiceSessionId\n }),\n serviceData: serviceData || {},\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: newFeatures\n }),\n entryMeta: !newFeaturesHasUpload && historyNewEntryMeta.active === entryTypes.upload ? _objectSpread({}, state.entryMeta) : historyNewEntryMeta,\n resumeConversationPrompt: resumeConversationPrompt || false\n });\n\n if (lastParticipantId) {\n returnState.headerTitles = headerTitlesReducer(state.headerTitles, {\n type: SET_HEADER_SUB_TITLE,\n title: mergedParticipants[lastParticipantId].name\n });\n }\n\n return returnState;\n\n case RESET_HISTORY_LOADED_FLAG:\n return _objectSpread(_objectSpread({}, state), {}, {\n historyLoaded: false\n });\n\n case SET_IS_LOADING:\n return _objectSpread(_objectSpread({}, state), {}, {\n isLoading: action.isLoading\n });\n\n case INIT_IDLE_DETACH_COUNTDOWN:\n const {\n delaySeconds,\n delayTime\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: {\n hasCountdown: true,\n isActive: true,\n wasStopped: false,\n count: delaySeconds,\n remaining: delaySeconds,\n timer: delayTime\n }\n });\n\n case DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER:\n const {\n idleDetachCountdown\n } = state;\n const {\n remaining: prevRemaining\n } = idleDetachCountdown;\n const remaining = prevRemaining - 1;\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: _objectSpread(_objectSpread({}, state.idleDetachCountdown), {}, {\n remaining,\n timer: (0,_general_utils__WEBPACK_IMPORTED_MODULE_0__.getTimeFromSeconds)(remaining)\n })\n });\n\n case STOP_IDLE_DETACH_COUNTDOWN_COUNTER:\n {\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: _objectSpread(_objectSpread({}, state.idleDetachCountdown), {}, {\n isActive: false,\n wasStopped: true\n })\n });\n }\n\n case CLEAR_IDLE_DETACH_COUNTDOWN:\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: {\n hasCountdown: false,\n isActive: false\n }\n });\n\n case INIT_RESUME_CONVERSATION_PROMPT:\n return _objectSpread(_objectSpread({}, state), {}, {\n resumeConversationPrompt: true\n });\n\n case CLEAR_RESUME_CONVERSATION_PROMPT:\n return _objectSpread(_objectSpread({}, state), {}, {\n resumeConversationPrompt: false\n });\n\n case SET_PARTICIPANT:\n case CLEAR_PARTICIPANTS:\n return _objectSpread(_objectSpread({}, state), {}, {\n participantInfo: participantReducer(state.participantInfo, action)\n });\n\n case SET_ACTIVE_SERVICE:\n if (state.serviceInfo.activeServiceSessionId !== action.activeServiceSessionId) {\n return _objectSpread(_objectSpread({}, state), {}, {\n serviceInfo: _objectSpread(_objectSpread({}, state.serviceInfo), {}, {\n activeServiceSessionId: action.activeServiceSessionId\n })\n });\n }\n\n return state;\n\n case SET_HEADER_TITLE:\n case SET_HEADER_SUB_TITLE:\n return _objectSpread(_objectSpread({}, state), {}, {\n headerTitles: headerTitlesReducer(state.headerTitles, action)\n });\n\n case SET_INITIAL_STATE:\n return _objectSpread(_objectSpread({}, state), {}, {\n initialState: action.initialState\n });\n\n case SET_SERVICE_DATA_ITEM:\n return _objectSpread(_objectSpread({}, state), {}, {\n serviceData: _objectSpread(_objectSpread({}, state.serviceData), {}, {\n [action.payload.type]: action.payload\n })\n });\n\n case SET_FEATURES:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: action.features\n })\n });\n\n case SET_FEATURE_ENABLED_STATE:\n // Only set cobrowsing if it already exists in the object.\n // Otherwise we may set if for accounts not allowing it at all.\n return state.options.features.hasOwnProperty(action.key) ? _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: _objectSpread(_objectSpread({}, state.options.features), {}, {\n [action.key]: _objectSpread(_objectSpread({}, state.options.features[action.key] || {}), {}, {\n enabled: action.enabled\n })\n })\n })\n }) : state;\n\n case CLEAR_FEATURES:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: {}\n })\n });\n\n case SHOW_OPTION:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n panelActive: true,\n optionActive: action.optionName\n })\n });\n\n case HIDE_OPTION:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n panelActive: false,\n optionActive: ''\n })\n });\n\n case SET_USER_SELECTED_OPTIONS:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n userSelectedOptions: action.options\n })\n });\n\n case SET_USER_SELECTED_OPTION:\n const {\n option,\n value\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n userSelectedOptions: _objectSpread(_objectSpread({}, state.options.userSelectedOptions), {}, {\n [option]: value\n })\n })\n });\n\n case SET_BLOCK_AUTO_ENTRY_SWITCH:\n const {\n value: blockAutoEntrySwitch\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread({}, state.entryMeta), {}, {\n blockAutoEntrySwitch\n })\n });\n\n case SET_SERVICE_ENTRY_METADATA:\n const {\n entryMeta\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread(_objectSpread({}, state.entryMeta), entryMeta), {}, {\n active: entryMeta.default,\n options: _objectSpread({}, entryMeta.options || {}),\n overrideOptions: {}\n })\n });\n\n case SET_ACTIVE_ENTRY_TYPE:\n const {\n entryType: active\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread({}, state.entryMeta), {}, {\n active\n })\n });\n\n case SET_USER_ENTRY_TYPE:\n const {\n entryType: userSelected\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread({}, state.entryMeta), {}, {\n userSelected\n })\n });\n\n case REGISTER_UPLOAD:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: [...state.currentUploads, {\n id: action.fileId,\n name: action.fileName,\n progress: 1,\n uploading: true,\n complete: false,\n error: '',\n uploadHandle: action.uploadHandle\n }]\n });\n\n case SET_UPLOAD_PROGRESS:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.map(fileUpload => {\n if (fileUpload.id === action.fileId) {\n return _objectSpread(_objectSpread({}, fileUpload), {}, {\n progress: action.progress,\n uploading: action.progress !== 100,\n uploadHandle: action.progress === 100 ? null : fileUpload.uploadHandle\n });\n }\n\n return fileUpload;\n })\n });\n\n case SET_UPLOAD_ERROR:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.map(fileUpload => {\n if (fileUpload.id === action.fileId) {\n return _objectSpread(_objectSpread({}, fileUpload), {}, {\n error: action.errorText,\n progress: 0,\n uploading: false,\n uploadHandle: null\n });\n }\n\n return fileUpload;\n })\n });\n\n case SET_UPLOAD_COMPLETE:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.map(fileUpload => {\n if (fileUpload.id === action.fileId) {\n return _objectSpread(_objectSpread({}, fileUpload), {}, {\n complete: true\n });\n }\n\n return fileUpload;\n })\n });\n\n case CLEAR_UPLOAD:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.filter(fileUpload => fileUpload.id !== action.fileId)\n });\n\n case CLEAR_ALL_UPLOADS:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: []\n });\n\n case SET_SEAMLY_CONTAINER_ELEMENT:\n {\n return _objectSpread(_objectSpread({}, state), {}, {\n seamlyContainerElement: action.element\n });\n }\n\n default:\n return state;\n }\n};\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/ui/utils/seamly-utils.js?");
|
|
2313
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"eventTypes\": () => (/* binding */ eventTypes),\n/* harmony export */ \"payloadTypes\": () => (/* binding */ payloadTypes),\n/* harmony export */ \"entryTypes\": () => (/* binding */ entryTypes),\n/* harmony export */ \"readStates\": () => (/* binding */ readStates),\n/* harmony export */ \"actionTypes\": () => (/* binding */ actionTypes),\n/* harmony export */ \"dismissTypes\": () => (/* binding */ dismissTypes),\n/* harmony export */ \"ariaLiveLevels\": () => (/* binding */ ariaLiveLevels),\n/* harmony export */ \"dividerKeys\": () => (/* binding */ dividerKeys),\n/* harmony export */ \"featureKeys\": () => (/* binding */ featureKeys),\n/* harmony export */ \"seamlyActions\": () => (/* binding */ seamlyActions),\n/* harmony export */ \"cardTypes\": () => (/* binding */ cardTypes),\n/* harmony export */ \"isUnreadMessage\": () => (/* binding */ isUnreadMessage),\n/* harmony export */ \"mergeHistory\": () => (/* binding */ mergeHistory),\n/* harmony export */ \"seamlyStateReducer\": () => (/* binding */ seamlyStateReducer)\n/* harmony export */ });\n/* harmony import */ var _general_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./general-utils */ \"./src/javascripts/ui/utils/general-utils.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\nconst eventTypes = {\n info: 'info',\n message: 'message',\n participant: 'participant',\n system: 'system'\n};\nconst payloadTypes = {\n choicePrompt: 'choice_prompt',\n text: 'text',\n image: 'image',\n video: 'video',\n participant: 'participant',\n divider: 'divider',\n translation: 'translation',\n message: 'message',\n countdown: 'countdown',\n upload: 'upload',\n cta: 'cta'\n};\nconst entryTypes = {\n text: 'text',\n upload: 'upload'\n};\nconst readStates = {\n received: 'received',\n read: 'read'\n};\nconst actionTypes = {\n pickChoice: 'pick_choice',\n navigate: 'navigate',\n custom: 'custom',\n typing: 'typing',\n read: 'read',\n detachService: 'detach_service',\n interactivityUpdate: 'interactivity_update',\n dismiss: 'dismiss',\n sendTranscript: 'send_transcript',\n setTranslation: 'set_translation',\n clickCta: 'click_cta',\n clickCard: 'click_card'\n};\nconst dismissTypes = {\n resumeConversationPrompt: 'resume_conversation_prompt'\n};\nconst ariaLiveLevels = {\n assertive: 'assertive',\n polite: 'polite'\n};\nconst dividerKeys = {\n new_topic: 'newTopic',\n new_translation: 'newTranslation'\n};\nconst featureKeys = {\n cobrowsing: 'cobrowsing',\n sendTranscript: 'sendTranscript',\n typingPeekahead: 'typingPeekahead',\n uploads: 'uploads'\n};\nconst seamlyActions = {\n ADD_EVENT: 'ADD_EVENT',\n CLEAR_EVENTS: 'CLEAR_EVENTS',\n SET_HISTORY: 'SET_HISTORY',\n SET_EVENTS_READ: 'SET_EVENTS_READ',\n ACK_EVENT: 'ACK_EVENT',\n SET_IS_LOADING: 'SET_IS_LOADING',\n CLEAR_PARTICIPANTS: 'CLEAR_PARTICIPANTS',\n SET_PARTICIPANT: 'SET_PARTICIPANT',\n SET_HEADER_TITLE: 'SET_HEADER_TITLE',\n SET_HEADER_SUB_TITLE: 'SET_HEADER_SUB_TITLE',\n RESET_HISTORY_LOADED_FLAG: 'RESET_HISTORY_LOADED_FLAG',\n SET_ACTIVE_SERVICE: 'SET_ACTIVE_SERVICE',\n INIT_IDLE_DETACH_COUNTDOWN: 'INIT_IDLE_DETACH_COUNTDOWN',\n DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER: 'DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER',\n STOP_IDLE_DETACH_COUNTDOWN_COUNTER: 'STOP_IDLE_DETACH_COUNTDOWN_COUNTER',\n CLEAR_IDLE_DETACH_COUNTDOWN: 'CLEAR_IDLE_DETACH_COUNTDOWN',\n INIT_RESUME_CONVERSATION_PROMPT: 'INIT_RESUME_CONVERSATION_PROMPT',\n CLEAR_RESUME_CONVERSATION_PROMPT: 'CLEAR_RESUME_CONVERSATION_PROMPT',\n SET_SERVICE_DATA_ITEM: 'SET_SERVICE_DATA_ITEM',\n SET_FEATURES: 'SET_FEATURES',\n SET_FEATURE_ENABLED_STATE: 'SET_FEATURE_ENABLED_STATE',\n CLEAR_FEATURES: 'CLEAR_FEATURES',\n SET_INITIAL_STATE: 'SET_INITIAL_STATE',\n SET_USER_SELECTED_OPTIONS: 'SET_USER_SELECTED_OPTIONS',\n SET_USER_SELECTED_OPTION: 'SET_USER_SELECTED_OPTION',\n SHOW_OPTION: 'SHOW_OPTION',\n HIDE_OPTION: 'HIDE_OPTION',\n SET_SERVICE_ENTRY_METADATA: 'SET_SERVICE_ENTRY_METADATA',\n SET_BLOCK_AUTO_ENTRY_SWITCH: 'SET_BLOCK_AUTO_ENTRY_SWITCH',\n SET_ACTIVE_ENTRY_TYPE: 'SET_ACTIVE_ENTRY_TYPE',\n SET_USER_ENTRY_TYPE: 'SET_USER_ENTRY_TYPE',\n REGISTER_UPLOAD: 'REGISTER_UPLOAD',\n SET_UPLOAD_PROGRESS: 'SET_UPLOAD_PROGRESS',\n SET_UPLOAD_COMPLETE: 'SET_UPLOAD_COMPLETE',\n SET_UPLOAD_ERROR: 'SET_UPLOAD_ERROR',\n CLEAR_UPLOAD: 'CLEAR_UPLOAD',\n CLEAR_ALL_UPLOADS: 'CLEAR_ALL_UPLOADS',\n SET_SEAMLY_CONTAINER_ELEMENT: 'SET_SEAMLY_CONTAINER_ELEMENT'\n};\nconst cardTypes = {\n ask: 'ask',\n navigate: 'navigate',\n topic: 'topic'\n};\nconst {\n ADD_EVENT,\n CLEAR_EVENTS,\n SET_HISTORY,\n SET_EVENTS_READ,\n ACK_EVENT,\n SET_IS_LOADING,\n CLEAR_PARTICIPANTS,\n SET_PARTICIPANT,\n SET_HEADER_TITLE,\n SET_HEADER_SUB_TITLE,\n RESET_HISTORY_LOADED_FLAG,\n SET_ACTIVE_SERVICE,\n INIT_IDLE_DETACH_COUNTDOWN,\n DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER,\n STOP_IDLE_DETACH_COUNTDOWN_COUNTER,\n CLEAR_IDLE_DETACH_COUNTDOWN,\n INIT_RESUME_CONVERSATION_PROMPT,\n CLEAR_RESUME_CONVERSATION_PROMPT,\n SET_SERVICE_DATA_ITEM,\n SET_FEATURES,\n SET_FEATURE_ENABLED_STATE,\n CLEAR_FEATURES,\n SET_INITIAL_STATE,\n SET_USER_SELECTED_OPTION,\n SET_USER_SELECTED_OPTIONS,\n SHOW_OPTION,\n HIDE_OPTION,\n SET_BLOCK_AUTO_ENTRY_SWITCH,\n SET_USER_ENTRY_TYPE,\n SET_ACTIVE_ENTRY_TYPE,\n SET_SERVICE_ENTRY_METADATA,\n REGISTER_UPLOAD,\n SET_UPLOAD_PROGRESS,\n SET_UPLOAD_COMPLETE,\n SET_UPLOAD_ERROR,\n CLEAR_UPLOAD,\n CLEAR_ALL_UPLOADS,\n SET_SEAMLY_CONTAINER_ELEMENT\n} = seamlyActions;\nconst isUnreadMessage = ({\n type,\n payload\n}) => type === eventTypes.message && !payload.fromClient || type === eventTypes.info && payload.type === payloadTypes.text;\n\nconst orderHistory = events => {\n return events.sort(({\n payload: {\n occurredAt: occurredAtA\n }\n }, {\n payload: {\n occurredAt: occurredAtB\n }\n }) => occurredAtA - occurredAtB);\n};\n\nconst mergeHistory = (stateEvents, historyEvents) => {\n const newHistoryEvents = historyEvents.filter(historyEvent => // Deduplicate the event streams\n !stateEvents.find(stateEvent => stateEvent.payload.id === historyEvent.payload.id) && // Remove all non displayable participant messages\n !(historyEvent.type === 'participant' && !historyEvent.payload.participant.introduction)) // Reverse is done here because the server sends the history in the order\n // newest to oldest. In the case of exactly the same occurredAt timestamps\n // these messages will be shown in the wrong order if not reversed. For\n // the normal merging logic there is no added effect.\n .reverse();\n return orderHistory([...newHistoryEvents, ...stateEvents]);\n};\n\nconst participantReducer = (state, action) => {\n switch (action.type) {\n case CLEAR_PARTICIPANTS:\n return {\n participants: {},\n currentAgent: ''\n };\n\n case SET_PARTICIPANT:\n const {\n participants\n } = state;\n const {\n id,\n avatar,\n name,\n introduction\n } = action.participant;\n const oldParticipant = participants[id];\n\n const newParticipants = _objectSpread(_objectSpread({}, participants), {}, {\n [id]: oldParticipant ? _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, oldParticipant), avatar ? {\n avatar\n } : {}), name ? {\n name\n } : {}), introduction ? {\n introduction\n } : {}) : action.participant\n });\n\n return _objectSpread(_objectSpread({}, state), {}, {\n participants: newParticipants,\n currentAgent: state.currentAgent !== id && !action.fromClient ? id : state.currentAgent\n });\n\n default:\n return state;\n }\n};\n\nconst headerTitlesReducer = (state, action) => {\n switch (action.type) {\n case SET_HEADER_TITLE:\n return _objectSpread(_objectSpread({}, state), {}, {\n title: action.title\n });\n\n case SET_HEADER_SUB_TITLE:\n return _objectSpread(_objectSpread({}, state), {}, {\n subTitle: action.title\n });\n\n default:\n return state;\n }\n};\n\nconst calculateNewEntryMeta = (entryMeta, payload) => {\n const {\n entry\n } = payload;\n const {\n blockAutoEntrySwitch\n } = entryMeta;\n\n if (!entry) {\n return _objectSpread(_objectSpread({}, entryMeta), {}, {\n optionsOverride: {}\n });\n }\n\n const {\n type,\n options\n } = entry;\n let newActive = entryMeta.active;\n\n if (!blockAutoEntrySwitch && type !== entryMeta.userSelected) {\n newActive = type;\n }\n\n return _objectSpread(_objectSpread({}, entryMeta), {}, {\n active: newActive,\n optionsOverride: _objectSpread(_objectSpread({}, entryMeta.optionsOverride), {}, {\n [type]: options || {}\n })\n });\n};\n\nconst seamlyStateReducer = (state, action) => {\n switch (action.type) {\n case ADD_EVENT:\n const {\n type: eventType,\n payload\n } = action.event;\n const accountHasUploads = state.options.features.hasOwnProperty(featureKeys.uploads);\n const newEntryMeta = calculateNewEntryMeta(state.entryMeta, payload);\n\n let newOptions = _objectSpread({}, state.options); // This enabled override of the service enabled value for uploads.\n // If a message is sent with entry of type upload it will temporarily\n // override service value and enable uploads.\n\n\n if (accountHasUploads && (eventType === eventTypes.message || eventType === eventTypes.participant) && !payload.fromClient) {\n var _payload$entry;\n\n const entryType = payload === null || payload === void 0 ? void 0 : (_payload$entry = payload.entry) === null || _payload$entry === void 0 ? void 0 : _payload$entry.type;\n newOptions = _objectSpread(_objectSpread({}, newOptions), {}, {\n features: _objectSpread(_objectSpread({}, newOptions.features), {}, {\n uploads: _objectSpread(_objectSpread({}, newOptions.features.uploads), {}, {\n enabledFromEntry: entryType === entryTypes.upload\n })\n })\n });\n }\n\n const incrementUnread = isUnreadMessage(action.event); // We check for duplicated and ignore them as in some error of the websocket\n // a duplicate join can be active for a while until the server connection\n // times out.\n\n const eventExists = state.events.find(e => e.payload.id === payload.id);\n\n if (eventExists) {\n return state;\n }\n\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: !accountHasUploads && newEntryMeta.active === entryTypes.upload ? _objectSpread({}, state.entryMeta) : newEntryMeta,\n options: newOptions,\n unreadEvents: incrementUnread ? state.unreadEvents + 1 : state.unreadEvents,\n events: [...state.events, _objectSpread(_objectSpread({}, action.event), {}, {\n // The payload spread should be done after adding the message\n // status to enable overriding the status when setting\n // event optimistically.\n payload: _objectSpread(_objectSpread({}, incrementUnread && {\n messageStatus: payload.fromClient ? readStates.read : readStates.received\n }), payload)\n })]\n });\n\n case ACK_EVENT:\n // If any ACKs are sent without transactionID the conversation crashes.\n // Ensure that this edge case is handled gracefully.\n if (!action.event.payload.transactionId) {\n console.warn('ACK received without transaction ID.');\n return state;\n }\n\n const matchedEvent = state.events.find(m => m.payload.transactionId === action.event.payload.transactionId);\n const {\n id,\n occurredAt\n } = action.event.payload;\n return matchedEvent ? _objectSpread(_objectSpread({}, state), {}, {\n events: orderHistory(state.events.map(m => m.payload.id === matchedEvent.payload.id ? _objectSpread(_objectSpread({}, m), {}, {\n payload: _objectSpread(_objectSpread({}, m.payload), {}, {\n id,\n occurredAt\n })\n }) : m))\n }) : state;\n\n case CLEAR_EVENTS:\n return _objectSpread(_objectSpread({}, state), {}, {\n unreadEvents: 0,\n events: []\n });\n\n case SET_EVENTS_READ:\n return _objectSpread(_objectSpread({}, state), {}, {\n unreadEvents: 0,\n events: state.events.map(event => {\n if (action.ids.indexOf(event.payload.id) !== -1) {\n return _objectSpread(_objectSpread({}, event), {}, {\n payload: _objectSpread(_objectSpread({}, event.payload), event.payload.messageStatus === readStates.received && {\n messageStatus: readStates.read\n })\n });\n }\n\n return event;\n })\n });\n\n case SET_HISTORY:\n const {\n events: history,\n participants,\n activeServiceSessionId,\n activeServiceSettings = {},\n serviceData,\n resumeConversationPrompt\n } = action.history;\n const events = mergeHistory(state.events, history);\n\n const mergedParticipants = _objectSpread(_objectSpread({}, state.participantInfo.participants), participants);\n\n const lastParticipantEvent = events.slice().reverse().find(m => (m.type === 'message' || m.type === 'participant') && !m.payload.fromClient);\n let lastParticipantId = null;\n\n if (lastParticipantEvent) {\n if (lastParticipantEvent.type === 'message') {\n lastParticipantId = lastParticipantEvent.payload.participant;\n }\n\n if (lastParticipantEvent.type === 'participant') {\n lastParticipantId = lastParticipantEvent.payload.participant.id;\n }\n }\n\n const {\n cobrowsing,\n entry,\n uploads\n } = activeServiceSettings;\n const historyNewEntryMeta = calculateNewEntryMeta(_objectSpread(_objectSpread(_objectSpread({}, state.entryMeta), entry), {}, {\n active: entry.default || payloadTypes.text,\n options: _objectSpread({}, entry && entry.options ? entry.options : {})\n }), events[events.length - 1].payload);\n\n let newFeatures = _objectSpread({}, state.options.features); // Only set cobrowsing if it was initialised by the account config.\n\n\n if (newFeatures.hasOwnProperty(featureKeys.cobrowsing)) {\n newFeatures = _objectSpread(_objectSpread({}, newFeatures), {}, {\n cobrowsing: {\n enabled: !!(cobrowsing && cobrowsing.enabled)\n }\n });\n }\n\n const newFeaturesHasUpload = newFeatures.hasOwnProperty(featureKeys.uploads); // Only set uploads if it was initialised by the account config.\n\n if (newFeaturesHasUpload) {\n var _lastParticipantEvent, _lastParticipantEvent2;\n\n const entryType = lastParticipantEvent === null || lastParticipantEvent === void 0 ? void 0 : (_lastParticipantEvent = lastParticipantEvent.payload) === null || _lastParticipantEvent === void 0 ? void 0 : (_lastParticipantEvent2 = _lastParticipantEvent.entry) === null || _lastParticipantEvent2 === void 0 ? void 0 : _lastParticipantEvent2.type;\n newFeatures = _objectSpread(_objectSpread({}, newFeatures), {}, {\n uploads: {\n enabled: !!(uploads && uploads.enabled),\n enabledFromEntry: entryType === entryTypes.upload\n }\n });\n }\n\n const returnState = _objectSpread(_objectSpread({}, state), {}, {\n unreadEvents: events.filter(event => event.type === 'message' && event.payload.messageStatus === readStates.received).length,\n events: events.filter(e => e.type !== 'participant' || !!e.payload.participant.introduction),\n participantInfo: _objectSpread(_objectSpread(_objectSpread({}, state.participantInfo), lastParticipantId ? participantReducer(state.participantInfo, {\n type: SET_PARTICIPANT,\n participant: mergedParticipants[lastParticipantId]\n }) : {}), {}, {\n participants: mergedParticipants\n }),\n historyLoaded: true,\n serviceInfo: _objectSpread(_objectSpread({}, state.serviceInfo), {}, {\n activeServiceSessionId\n }),\n serviceData: serviceData || {},\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: newFeatures\n }),\n entryMeta: !newFeaturesHasUpload && historyNewEntryMeta.active === entryTypes.upload ? _objectSpread({}, state.entryMeta) : historyNewEntryMeta,\n resumeConversationPrompt: resumeConversationPrompt || false\n });\n\n if (lastParticipantId) {\n returnState.headerTitles = headerTitlesReducer(state.headerTitles, {\n type: SET_HEADER_SUB_TITLE,\n title: mergedParticipants[lastParticipantId].name\n });\n }\n\n return returnState;\n\n case RESET_HISTORY_LOADED_FLAG:\n return _objectSpread(_objectSpread({}, state), {}, {\n historyLoaded: false\n });\n\n case SET_IS_LOADING:\n return _objectSpread(_objectSpread({}, state), {}, {\n isLoading: action.isLoading\n });\n\n case INIT_IDLE_DETACH_COUNTDOWN:\n const {\n delaySeconds,\n delayTime\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: {\n hasCountdown: true,\n isActive: true,\n wasStopped: false,\n count: delaySeconds,\n remaining: delaySeconds,\n timer: delayTime\n }\n });\n\n case DECREMENT_IDLE_DETACH_COUNTDOWN_COUNTER:\n const {\n idleDetachCountdown\n } = state;\n const {\n remaining: prevRemaining\n } = idleDetachCountdown;\n const remaining = prevRemaining - 1;\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: _objectSpread(_objectSpread({}, state.idleDetachCountdown), {}, {\n remaining,\n timer: (0,_general_utils__WEBPACK_IMPORTED_MODULE_0__.getTimeFromSeconds)(remaining)\n })\n });\n\n case STOP_IDLE_DETACH_COUNTDOWN_COUNTER:\n {\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: _objectSpread(_objectSpread({}, state.idleDetachCountdown), {}, {\n isActive: false,\n wasStopped: true\n })\n });\n }\n\n case CLEAR_IDLE_DETACH_COUNTDOWN:\n return _objectSpread(_objectSpread({}, state), {}, {\n idleDetachCountdown: {\n hasCountdown: false,\n isActive: false\n }\n });\n\n case INIT_RESUME_CONVERSATION_PROMPT:\n return _objectSpread(_objectSpread({}, state), {}, {\n resumeConversationPrompt: true\n });\n\n case CLEAR_RESUME_CONVERSATION_PROMPT:\n return _objectSpread(_objectSpread({}, state), {}, {\n resumeConversationPrompt: false\n });\n\n case SET_PARTICIPANT:\n case CLEAR_PARTICIPANTS:\n return _objectSpread(_objectSpread({}, state), {}, {\n participantInfo: participantReducer(state.participantInfo, action)\n });\n\n case SET_ACTIVE_SERVICE:\n if (state.serviceInfo.activeServiceSessionId !== action.activeServiceSessionId) {\n return _objectSpread(_objectSpread({}, state), {}, {\n serviceInfo: _objectSpread(_objectSpread({}, state.serviceInfo), {}, {\n activeServiceSessionId: action.activeServiceSessionId\n })\n });\n }\n\n return state;\n\n case SET_HEADER_TITLE:\n case SET_HEADER_SUB_TITLE:\n return _objectSpread(_objectSpread({}, state), {}, {\n headerTitles: headerTitlesReducer(state.headerTitles, action)\n });\n\n case SET_INITIAL_STATE:\n return _objectSpread(_objectSpread({}, state), {}, {\n initialState: action.initialState\n });\n\n case SET_SERVICE_DATA_ITEM:\n return _objectSpread(_objectSpread({}, state), {}, {\n serviceData: _objectSpread(_objectSpread({}, state.serviceData), {}, {\n [action.payload.type]: action.payload\n })\n });\n\n case SET_FEATURES:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: action.features\n })\n });\n\n case SET_FEATURE_ENABLED_STATE:\n // Only set cobrowsing if it already exists in the object.\n // Otherwise we may set if for accounts not allowing it at all.\n return state.options.features.hasOwnProperty(action.key) ? _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: _objectSpread(_objectSpread({}, state.options.features), {}, {\n [action.key]: _objectSpread(_objectSpread({}, state.options.features[action.key] || {}), {}, {\n enabled: action.enabled\n })\n })\n })\n }) : state;\n\n case CLEAR_FEATURES:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n features: {}\n })\n });\n\n case SHOW_OPTION:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n panelActive: true,\n optionActive: action.optionName\n })\n });\n\n case HIDE_OPTION:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n panelActive: false,\n optionActive: ''\n })\n });\n\n case SET_USER_SELECTED_OPTIONS:\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n userSelectedOptions: action.options\n })\n });\n\n case SET_USER_SELECTED_OPTION:\n const {\n option,\n value\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n options: _objectSpread(_objectSpread({}, state.options), {}, {\n userSelectedOptions: _objectSpread(_objectSpread({}, state.options.userSelectedOptions), {}, {\n [option]: value\n })\n })\n });\n\n case SET_BLOCK_AUTO_ENTRY_SWITCH:\n const {\n value: blockAutoEntrySwitch\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread({}, state.entryMeta), {}, {\n blockAutoEntrySwitch\n })\n });\n\n case SET_SERVICE_ENTRY_METADATA:\n const {\n entryMeta\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread(_objectSpread({}, state.entryMeta), entryMeta), {}, {\n active: entryMeta.default,\n options: _objectSpread({}, entryMeta.options || {}),\n overrideOptions: {}\n })\n });\n\n case SET_ACTIVE_ENTRY_TYPE:\n const {\n entryType: active\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread({}, state.entryMeta), {}, {\n active\n })\n });\n\n case SET_USER_ENTRY_TYPE:\n const {\n entryType: userSelected\n } = action;\n return _objectSpread(_objectSpread({}, state), {}, {\n entryMeta: _objectSpread(_objectSpread({}, state.entryMeta), {}, {\n userSelected\n })\n });\n\n case REGISTER_UPLOAD:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: [...state.currentUploads, {\n id: action.fileId,\n name: action.fileName,\n progress: 1,\n uploading: true,\n complete: false,\n error: '',\n uploadHandle: action.uploadHandle\n }]\n });\n\n case SET_UPLOAD_PROGRESS:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.map(fileUpload => {\n if (fileUpload.id === action.fileId) {\n return _objectSpread(_objectSpread({}, fileUpload), {}, {\n progress: action.progress,\n uploading: action.progress !== 100,\n uploadHandle: action.progress === 100 ? null : fileUpload.uploadHandle\n });\n }\n\n return fileUpload;\n })\n });\n\n case SET_UPLOAD_ERROR:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.map(fileUpload => {\n if (fileUpload.id === action.fileId) {\n return _objectSpread(_objectSpread({}, fileUpload), {}, {\n error: action.errorText,\n progress: 0,\n uploading: false,\n uploadHandle: null\n });\n }\n\n return fileUpload;\n })\n });\n\n case SET_UPLOAD_COMPLETE:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.map(fileUpload => {\n if (fileUpload.id === action.fileId) {\n return _objectSpread(_objectSpread({}, fileUpload), {}, {\n complete: true\n });\n }\n\n return fileUpload;\n })\n });\n\n case CLEAR_UPLOAD:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: state.currentUploads.filter(fileUpload => fileUpload.id !== action.fileId)\n });\n\n case CLEAR_ALL_UPLOADS:\n return _objectSpread(_objectSpread({}, state), {}, {\n currentUploads: []\n });\n\n case SET_SEAMLY_CONTAINER_ELEMENT:\n {\n return _objectSpread(_objectSpread({}, state), {}, {\n seamlyContainerElement: action.element\n });\n }\n\n default:\n return state;\n }\n};\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/ui/utils/seamly-utils.js?");
|
|
2314
2314
|
|
|
2315
2315
|
/***/ }),
|
|
2316
2316
|
|