@alan-ai/alan-sdk-web 1.8.32 → 1.8.35

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.
@@ -6,4 +6,6 @@ export interface AlanButton {
6
6
  activate: () => Promise<void>;
7
7
  deactivate: () => void;
8
8
  isActive: () => boolean;
9
+ remove: () => void;
10
+ sendText: (text: string) => void;
9
11
  }
package/dist/alan_lib.js CHANGED
@@ -208,7 +208,7 @@
208
208
 
209
209
  function ConnectionWrapper() {
210
210
  var _this = this;
211
- this._worker = new Worker(window.URL.createObjectURL(new Blob(["(function(ns) {\n 'use strict';\n\n var SENT_TS = 1;\n var REMOTE_TS = 2;\n var TIMESTAMP = 3;\n var AUDIO_DATA = 4;\n var JSON_DATA = 5;\n\n AlanFrame.fields = [\n propUint64(SENT_TS, 'sentTs'),\n propUint64(REMOTE_TS, 'remoteTs'),\n propUint64(TIMESTAMP, 'timestamp'),\n propBytes(AUDIO_DATA, 'audioData'),\n propJson(JSON_DATA, 'jsonData'),\n ];\n\n function AlanFrameProp(type, name, sizeF, readF, writeF) {\n this.type = type;\n this.name = name;\n this.sizeF = sizeF;\n this.writeF = writeF;\n this.readF = readF;\n }\n\n function fixedSize(size) {\n return function() {\n return size;\n }\n }\n\n function bufferSize(buffer) {\n return 4 + byteLength(buffer);\n }\n\n function writeUIntN(uint8array, value, nBytes, offset) {\n for (var i = 0; i < nBytes; i++ ) {\n uint8array[offset + i] = 0xFF & value;\n value /= 256;\n }\n }\n\n function readUIntN(uint8array, nBytes, offset) {\n var r = 0;\n for (var i = nBytes - 1; i >= 0; i-- ) {\n r *= 256;\n r += 0xFF & uint8array[offset + i];\n }\n return r;\n }\n\n function writeUInt64(uint8array, value, offset) {\n writeUIntN(uint8array, value, 8, offset);\n }\n\n function readUInt64(uint8array, offset) {\n return readUIntN(uint8array, 8, offset);\n }\n\n function writeUInt32(uint8array, value, offset) {\n writeUIntN(uint8array, value, 4, offset);\n }\n\n function readUInt32(uint8array, offset) {\n return readUIntN(uint8array, 4, offset);\n }\n\n function writeBuffer(uint8array, buffer, offset) {\n buffer = toUint8(buffer);\n writeUInt32(uint8array, buffer.length, offset);\n for (var i = 0; i < buffer.length; i++ ) {\n uint8array[offset + 4 + i] = buffer[i];\n }\n }\n\n function readBuffer(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('buffer too big');\n }\n return uint8array.subarray(offset + 4, offset + 4 + size);\n }\n\n function readUTF8(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('string too big');\n }\n return String.fromCharCode.apply(null, uint8array.slice(offset + 4, offset + 4 + size));\n }\n\n function writeUTF8(uint8array, string, offset) {\n writeUInt32(uint8array, string.length, offset);\n for (var i = 0; i < string.length; i++ ) {\n uint8array[offset + 4 + i] = string.charCodeAt(i);\n }\n }\n\n function sizeUTF8(string) {\n return 4 + string.length;\n }\n\n function propUint32(type, name) {\n return new AlanFrameProp(type, name, fixedSize(4), readUInt32, writeUInt32);\n }\n\n function propUint64(type, name) {\n return new AlanFrameProp(type, name, fixedSize(8), readUInt64, writeUInt64);\n }\n\n function propBytes(type, name) {\n return new AlanFrameProp(type, name, bufferSize, readBuffer, writeBuffer);\n }\n\n function propJson(type, name) {\n return new AlanFrameProp(type, name, sizeUTF8, readUTF8, writeUTF8);\n }\n\n AlanFrame.fieldByType = function(type) {\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var frame = AlanFrame.fields[i];\n if (frame.type === type) {\n return frame;\n }\n }\n throw new Error('invalid field: ' + type);\n };\n\n function AlanFrame() {\n this.version = 1;\n }\n\n AlanFrame.prototype.write = function() {\n var result = new Uint8Array(this.writeSize());\n var offset = 1;\n result[0] = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n result[offset++] = field.type;\n field.writeF(result, value, offset);\n offset += field.sizeF(value);\n }\n }\n return result.buffer;\n };\n\n /**\n * @returns UInt8Array\n */\n AlanFrame.prototype.writeSize = function() {\n var size = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n size += 1 + field.sizeF(value);\n }\n }\n return size;\n };\n\n AlanFrame.prototype.toString = function() {\n var first = true, str = '';\n for (var k in this) {\n if (this.hasOwnProperty(k)) {\n if (first) {\n str += k + ' = ';\n first = false;\n } else {\n str += ', ' + k + ' = ';\n }\n var v = this[k];\n if (typeof(v) === 'object') {\n str += 'bytes[' + byteLength(v) + ']';\n } else {\n str += v;\n }\n }\n }\n return str;\n };\n\n function byteLength(b) {\n if (b instanceof Uint8Array) {\n return b.length;\n }\n if (b instanceof ArrayBuffer) {\n return b.byteLength;\n }\n }\n\n function toArrayBuffer(buffer) {\n if (buffer instanceof ArrayBuffer) {\n return buffer;\n }\n return buffer.buffer;\n }\n\n function toUint8(buffer) {\n if (buffer instanceof Uint8Array) {\n return buffer;\n }\n if (buffer instanceof ArrayBuffer) {\n return new Uint8Array(buffer);\n }\n throw new Error('invalid buffer type');\n }\n\n function parse(uint8array) {\n uint8array = toUint8(uint8array);\n var r = new AlanFrame();\n var offset = 0;\n r.version = uint8array[offset++];\n while (offset < uint8array.length) {\n var frame = AlanFrame.fieldByType(uint8array[offset++]);\n r[frame.name] = frame.readF(uint8array, offset);\n offset += frame.sizeF(r[frame.name]);\n }\n return r;\n }\n\n ns.create = function() {\n return new AlanFrame();\n };\n\n ns.parse = parse;\n\n})(typeof(window) !== 'undefined' ? (function() {window.alanFrame = {}; return window.alanFrame; })() :\n typeof(WorkerGlobalScope) !== 'undefined' ? (function() {alanFrame = {}; return alanFrame; })() :\n exports);\n\n\n'use strict';\n\nvar ALAN_OFF = 'off';\nvar ALAN_SPEAKING = 'speaking';\nvar ALAN_LISTENING = 'listening';\n\nfunction ConnectionImpl(config, auth, mode) {\n var _this = this;\n this._config = config;\n this._auth = auth;\n this._mode = mode;\n this._projectId = config.projectId;\n this._url = config.url;\n this._connected = false;\n this._authorized = false;\n this._dialogId = null;\n this._callId = 1;\n this._callSent = {};\n this._callWait = [];\n this._failed = false;\n this._closed = false;\n this._reconnectTimeout = 100;\n this._cleanups = [];\n this._format = null;\n this._formatSent = false;\n this._frameQueue = [];\n this._remoteSentTs = 0;\n this._remoteRecvTs = 0;\n this._rtt = 25;\n this._rttAlpha = 1./16;\n this._alanState = ALAN_OFF;\n this._sendTimer = setInterval(_this._flushQueue.bind(_this), 50);\n this._visualState = {};\n this._addCleanup(function() {clearInterval(_this._sendTimer);});\n this._connect();\n console.log('Alan: connection created');\n}\n\nConnectionImpl.prototype._addCleanup = function(f) {\n this._cleanups.push(f);\n};\n\nConnectionImpl.prototype._onConnectStatus = function(s) {\n console.log('Alan: connection status - ' + s);\n this._fire('connectStatus', s);\n};\n\nConnectionImpl.prototype._fire = function(event, object) {\n if (event === 'options') {\n if (object.versions) {\n object.versions['alanbase:web'] = this._config.version;\n }\n }\n postMessage(['fireEvent', event, object]);\n};\n\nConnectionImpl.prototype._connect = function() {\n var _this = this;\n if (this._socket) {\n console.error('socket is already connected');\n return;\n }\n console.log('Alan: connecting - ' + getConnectionDetails(this._url));\n this._socket = new WebSocket(this._url);\n this._socket.binaryType = 'arraybuffer';\n this._socket.onopen = function(e) {\n console.info('Alan: connected');\n _this._connected = true;\n _this._reconnectTimeout = 100;\n _this._fire('connection', {status: 'connected'});\n if (_this._auth) {\n _this._fire('connection', {status: 'authorizing'});\n _this._callAuth();\n } else {\n _this._callWait.forEach(function(c) { _this._sendCall(c); });\n _this._callWait = [];\n }\n };\n this._socket.onmessage = function(msg) {\n if (msg.data instanceof ArrayBuffer) {\n var f = alanFrame.parse(msg.data);\n if (f.sentTs > 0) {\n _this._remoteSentTs = f.sentTs;\n _this._remoteRecvTs = Date.now();\n } else {\n _this._remoteSentTs = null;\n _this._remoteRecvTs = null;\n }\n var rtt = 0;\n if (f.remoteTs) {\n rtt = Date.now() - f.remoteTs;\n }\n _this._rtt = _this._rttAlpha * rtt + (1 - _this._rttAlpha) * _this._rtt;\n var uint8 = new Uint8Array(f.audioData);\n var frame = [];\n var batch = 10000;\n for (var offset = 0; offset < uint8.byteLength; offset += batch) {\n var b = uint8.subarray(offset, Math.min(uint8.byteLength, offset + batch));\n let a = String.fromCharCode.apply(null, b);\n frame.push(a);\n }\n frame = frame.join('');\n postMessage(['alanAudio', 'playFrame', frame]);\n } else if (typeof(msg.data) === 'string') {\n msg = JSON.parse(msg.data);\n if (msg.i) {\n var c = _this._callSent[msg.i];\n delete _this._callSent[msg.i];\n if (c && c.callback) {\n c.callback(msg.e, msg.r);\n }\n } else if (msg.e) {\n if (msg.e === 'text') {\n postMessage(['alanAudio', 'playText', msg.p]);\n } else if (msg.e === 'showPopup') {\n postMessage(['alanAudio', 'showPopup', msg.p]);\n } else if (msg.e === 'command') {\n postMessage(['alanAudio', 'playCommand', msg.p]);\n } else if (msg.e === 'inactivity') {\n postMessage(['alanAudio', 'stop']);\n } else {\n _this._fire(msg.e, msg.p);\n }\n }\n } else {\n console.error('invalid message type');\n }\n };\n this._socket.onerror = function(evt) {\n console.error('Alan: connection closed due to error: ', evt);\n };\n this._socket.onclose = function(evt) {\n console.info('Alan: connection closed');\n _this._connected = false;\n _this._authorized = false;\n _this._socket = null;\n _this._onConnectStatus('disconnected');\n if (!_this._failed && _this._reconnectTimeout && !_this._closed) {\n console.log('Alan: reconnecting in %s ms.', _this._reconnectTimeout);\n _this._reConnect = setTimeout(_this._connect.bind(_this), _this._reconnectTimeout);\n if (_this._reconnectTimeout < 3000) {\n _this._reconnectTimeout *= 2;\n } else {\n _this._reconnectTimeout += 500;\n }\n _this._reconnectTimeout = Math.min(7000, _this._reconnectTimeout);\n }\n };\n this._addCleanup(function() {\n if (this._socket) {\n this._socket.close();\n this._socket = null;\n }\n });\n};\n\nConnectionImpl.prototype._callAuth = function() {\n var _this = this;\n var callback = function(err, r) {\n if (!err && r.status === 'authorized') {\n _this._authorized = true;\n _this._formatSent = false;\n if (r.dialogId) {\n postMessage(['setDialogId', r.dialogId]);\n _this._dialogId = r.dialogId;\n }\n _this._onAuthorized();\n _this._onConnectStatus('authorized');\n } else if (err === 'auth-failed') {\n _this._onConnectStatus('auth-failed');\n if (_this._socket) {\n _this._socket.close();\n _this._socket = null;\n _this._failed = true;\n }\n } else {\n _this._onConnectStatus('invalid-auth-response');\n console.log('Alan: invalid auth response', err, r);\n }\n };\n var authParam = this._auth;\n authParam.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (this._dialogId) {\n authParam.dialogId = this._dialogId;\n }\n authParam.mode = this._mode;\n this._sendCall({cid: this._callId++, method: '_auth_', callback: callback, param: authParam});\n return this;\n};\n\nConnectionImpl.prototype._sendCall = function(call) {\n this._sendFormatIfNeeded(false);\n this._socket.send(JSON.stringify({i: call.cid, m: call.method, p: call.param}));\n if (call.callback) {\n this._callSent[call.cid] = call;\n }\n};\n\nConnectionImpl.prototype._onAuthorized = function() {\n var _this = this;\n this._callWait.forEach(function(c) {\n _this._sendCall(c);\n });\n this._callWait = [];\n};\n\nConnectionImpl.prototype.close = function() {\n for (var i = 0; i < this._cleanups.length; i++ ) {\n this._cleanups[i]();\n }\n this._cleanups = [];\n this._closed = true;\n \n if (this._socket && (this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)) {\n this._socket.close();\n this._socket = null;\n }\n console.log('Alan: closed connection to: ' + getConnectionDetails(this._url));\n //close(); TODO: delete it!\n};\n\nConnectionImpl.prototype.call = function(cid, method, param) {\n var call = {cid: cid, method: method, param: param, callback: function(err, obj) {\n if (cid) {\n postMessage(['callback', cid, err, obj]);\n }\n }};\n if (this._authorized || this._connected && !this._auth) {\n this._sendCall(call);\n } else {\n this._callWait.push(call);\n }\n};\n\nConnectionImpl.prototype.setVisual = function(state) {\n this._visualState = state;\n this.call(null, '_visual_', state);\n};\n\nConnectionImpl.prototype._sendFrame = function(frame) {\n if (!this._socket) {\n console.error('sendFrame to closed socket');\n return;\n }\n frame.sentTs = Date.now();\n if (this._remoteSentTs > 0 && this._remoteRecvTs > 0) {\n frame.remoteTs = this._remoteSentTs + Date.now() - this._remoteRecvTs;\n }\n this._socket.send(frame.write());\n};\n\nConnectionImpl.prototype._listen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'listen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_LISTENING;\n};\n\nConnectionImpl.prototype._stopListen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'stopListen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_OFF;\n};\n\nConnectionImpl.prototype._onAudioFormat = function(format) {\n this._formatSent = false;\n this._format = format;\n};\n\nConnectionImpl.prototype._onMicFrame = function(sampleRate, frame) {\n if (this._alanState === ALAN_SPEAKING) {\n return;\n }\n if (this._alanState === ALAN_OFF) {\n this._listen();\n }\n if (this._alanState !== ALAN_LISTENING) {\n console.error('invalid alan state: ' + this._alanState);\n return;\n }\n this._sendFormatIfNeeded(true);\n var f = alanFrame.create();\n f.audioData = frame;\n this._frameQueue.push(f);\n};\n\nConnectionImpl.prototype._sendFormatIfNeeded = function(inQueue) {\n if (!this._format || this._formatSent) {\n return;\n }\n this._formatSent = true;\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({format: this._format});\n if (inQueue) {\n this._frameQueue.push(f);\n } else {\n this._sendFrame(f);\n }\n};\n\nConnectionImpl.prototype._flushQueue = function() {\n if (!this._socket || !this._connected) {\n var d = 0;\n while (this._frameQueue.length > 100 && !this._frameQueue[0].jsonData) {\n this._frameQueue.shift();\n d++;\n }\n if (d > 0) {\n console.error('dropped: %s, frames', d);\n }\n return;\n }\n while (this._frameQueue.length > 0 && this._socket && this._socket.bufferedAmount < 64 * 1024) {\n this._sendFrame(this._frameQueue.shift());\n }\n};\n\nfunction getConnectionDetails(url){\n var urlParts = url.split('/');\n var projectId = urlParts[4];\n var environment = urlParts[5];\n var host = urlParts[2];\n\n if (projectId && environment && host) {\n return ' (ProjectID: ' + projectId + ', environment: ' + environment + ', host: ' + host + ')';\n }\n\n return url;\n}\n\nfunction connectProject(config, auth, mode) {\n var c = new ConnectionImpl(config, auth, mode);\n c.onAudioEvent = function(event, arg1, arg2) {\n if (event === 'format') {\n c._onAudioFormat(arg1);\n } else if (event === 'frame') {\n c._onMicFrame(arg1, arg2);\n } else if (event === 'micStop' || event === 'playStart') {\n c._stopListen();\n } else {\n console.error('unknown audio event: ' + event, arg1, arg2);\n }\n };\n return c;\n}\n\nvar factories = {\n connectProject: connectProject,\n};\n\nvar currentConnect = null;\n\nonmessage = function(e) {\n var name = e.data[0];\n try {\n if (!currentConnect) {\n currentConnect = factories[name].apply(null, e.data.slice(1, e.data.length));\n } else {\n currentConnect[name].apply(currentConnect, e.data.slice(1, e.data.length));\n }\n } catch(e) {\n console.error('error calling: ' + name, e);\n }\n};\n"]),{type: 'text/javascript'}));
211
+ this._worker = new Worker(window.URL.createObjectURL(new Blob(["(function(ns) {\n 'use strict';\n\n var SENT_TS = 1;\n var REMOTE_TS = 2;\n var TIMESTAMP = 3;\n var AUDIO_DATA = 4;\n var JSON_DATA = 5;\n\n AlanFrame.fields = [\n propUint64(SENT_TS, 'sentTs'),\n propUint64(REMOTE_TS, 'remoteTs'),\n propUint64(TIMESTAMP, 'timestamp'),\n propBytes(AUDIO_DATA, 'audioData'),\n propJson(JSON_DATA, 'jsonData'),\n ];\n\n function AlanFrameProp(type, name, sizeF, readF, writeF) {\n this.type = type;\n this.name = name;\n this.sizeF = sizeF;\n this.writeF = writeF;\n this.readF = readF;\n }\n\n function fixedSize(size) {\n return function() {\n return size;\n }\n }\n\n function bufferSize(buffer) {\n return 4 + byteLength(buffer);\n }\n\n function writeUIntN(uint8array, value, nBytes, offset) {\n for (var i = 0; i < nBytes; i++ ) {\n uint8array[offset + i] = 0xFF & value;\n value /= 256;\n }\n }\n\n function readUIntN(uint8array, nBytes, offset) {\n var r = 0;\n for (var i = nBytes - 1; i >= 0; i-- ) {\n r *= 256;\n r += 0xFF & uint8array[offset + i];\n }\n return r;\n }\n\n function writeUInt64(uint8array, value, offset) {\n writeUIntN(uint8array, value, 8, offset);\n }\n\n function readUInt64(uint8array, offset) {\n return readUIntN(uint8array, 8, offset);\n }\n\n function writeUInt32(uint8array, value, offset) {\n writeUIntN(uint8array, value, 4, offset);\n }\n\n function readUInt32(uint8array, offset) {\n return readUIntN(uint8array, 4, offset);\n }\n\n function writeBuffer(uint8array, buffer, offset) {\n buffer = toUint8(buffer);\n writeUInt32(uint8array, buffer.length, offset);\n for (var i = 0; i < buffer.length; i++ ) {\n uint8array[offset + 4 + i] = buffer[i];\n }\n }\n\n function readBuffer(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('buffer too big');\n }\n return uint8array.subarray(offset + 4, offset + 4 + size);\n }\n\n function readUTF8(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('string too big');\n }\n return String.fromCharCode.apply(null, uint8array.slice(offset + 4, offset + 4 + size));\n }\n\n function writeUTF8(uint8array, string, offset) {\n writeUInt32(uint8array, string.length, offset);\n for (var i = 0; i < string.length; i++ ) {\n uint8array[offset + 4 + i] = string.charCodeAt(i);\n }\n }\n\n function sizeUTF8(string) {\n return 4 + string.length;\n }\n\n function propUint32(type, name) {\n return new AlanFrameProp(type, name, fixedSize(4), readUInt32, writeUInt32);\n }\n\n function propUint64(type, name) {\n return new AlanFrameProp(type, name, fixedSize(8), readUInt64, writeUInt64);\n }\n\n function propBytes(type, name) {\n return new AlanFrameProp(type, name, bufferSize, readBuffer, writeBuffer);\n }\n\n function propJson(type, name) {\n return new AlanFrameProp(type, name, sizeUTF8, readUTF8, writeUTF8);\n }\n\n AlanFrame.fieldByType = function(type) {\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var frame = AlanFrame.fields[i];\n if (frame.type === type) {\n return frame;\n }\n }\n throw new Error('invalid field: ' + type);\n };\n\n function AlanFrame() {\n this.version = 1;\n }\n\n AlanFrame.prototype.write = function() {\n var result = new Uint8Array(this.writeSize());\n var offset = 1;\n result[0] = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n result[offset++] = field.type;\n field.writeF(result, value, offset);\n offset += field.sizeF(value);\n }\n }\n return result.buffer;\n };\n\n /**\n * @returns UInt8Array\n */\n AlanFrame.prototype.writeSize = function() {\n var size = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n size += 1 + field.sizeF(value);\n }\n }\n return size;\n };\n\n AlanFrame.prototype.toString = function() {\n var first = true, str = '';\n for (var k in this) {\n if (this.hasOwnProperty(k)) {\n if (first) {\n str += k + ' = ';\n first = false;\n } else {\n str += ', ' + k + ' = ';\n }\n var v = this[k];\n if (typeof(v) === 'object') {\n str += 'bytes[' + byteLength(v) + ']';\n } else {\n str += v;\n }\n }\n }\n return str;\n };\n\n function byteLength(b) {\n if (b instanceof Uint8Array) {\n return b.length;\n }\n if (b instanceof ArrayBuffer) {\n return b.byteLength;\n }\n }\n\n function toArrayBuffer(buffer) {\n if (buffer instanceof ArrayBuffer) {\n return buffer;\n }\n return buffer.buffer;\n }\n\n function toUint8(buffer) {\n if (buffer instanceof Uint8Array) {\n return buffer;\n }\n if (buffer instanceof ArrayBuffer) {\n return new Uint8Array(buffer);\n }\n throw new Error('invalid buffer type');\n }\n\n function parse(uint8array) {\n uint8array = toUint8(uint8array);\n var r = new AlanFrame();\n var offset = 0;\n r.version = uint8array[offset++];\n while (offset < uint8array.length) {\n var frame = AlanFrame.fieldByType(uint8array[offset++]);\n r[frame.name] = frame.readF(uint8array, offset);\n offset += frame.sizeF(r[frame.name]);\n }\n return r;\n }\n\n ns.create = function() {\n return new AlanFrame();\n };\n\n ns.parse = parse;\n\n})(typeof(window) !== 'undefined' ? (function() {window.alanFrame = {}; return window.alanFrame; })() :\n typeof(WorkerGlobalScope) !== 'undefined' ? (function() {alanFrame = {}; return alanFrame; })() :\n exports);\n\n\n'use strict';\n\n\n\nvar ALAN_OFF = 'off';\nvar ALAN_SPEAKING = 'speaking';\nvar ALAN_LISTENING = 'listening';\n\nfunction ConnectionImpl(config, auth, mode) {\n var _this = this;\n this._config = config;\n this._auth = auth;\n this._mode = mode;\n this._projectId = config.projectId;\n this._url = config.url;\n this._connected = false;\n this._authorized = false;\n this._dialogId = null;\n this._callId = 1;\n this._callSent = {};\n this._callWait = [];\n this._failed = false;\n this._closed = false;\n this._reconnectTimeout = 100;\n this._cleanups = [];\n this._format = null;\n this._formatSent = false;\n this._frameQueue = [];\n this._remoteSentTs = 0;\n this._remoteRecvTs = 0;\n this._rtt = 25;\n this._rttAlpha = 1./16;\n this._alanState = ALAN_OFF;\n this._sendTimer = setInterval(_this._flushQueue.bind(_this), 50);\n this._visualState = {};\n this._addCleanup(function() {clearInterval(_this._sendTimer);});\n this._connect();\n console.log('Alan: connection created');\n}\n\nConnectionImpl.prototype._addCleanup = function(f) {\n this._cleanups.push(f);\n};\n\nConnectionImpl.prototype._onConnectStatus = function(s) {\n console.log('Alan: connection status - ' + s);\n this._fire('connectStatus', s);\n};\n\nConnectionImpl.prototype._fire = function(event, object) {\n if (event === 'options') {\n if (object.versions) {\n object.versions['alanbase:web'] = this._config.version;\n }\n }\n postMessage(['fireEvent', event, object]);\n};\n\nConnectionImpl.prototype._connect = function() {\n var _this = this;\n if (this._socket) {\n console.error('socket is already connected');\n return;\n }\n console.log('Alan: connecting - ' + getConnectionDetails(this._url));\n this._socket = new WebSocket(this._url);\n this._socket.binaryType = 'arraybuffer';\n this._socket.onopen = function(e) {\n console.info('Alan: connected');\n _this._connected = true;\n _this._reconnectTimeout = 100;\n _this._fire('connection', {status: 'connected'});\n if (_this._auth) {\n _this._fire('connection', {status: 'authorizing'});\n _this._callAuth();\n } else {\n _this._callWait.forEach(function(c) { _this._sendCall(c); });\n _this._callWait = [];\n }\n };\n this._socket.onmessage = function(msg) {\n if (msg.data instanceof ArrayBuffer) {\n var f = alanFrame.parse(msg.data);\n if (f.sentTs > 0) {\n _this._remoteSentTs = f.sentTs;\n _this._remoteRecvTs = Date.now();\n } else {\n _this._remoteSentTs = null;\n _this._remoteRecvTs = null;\n }\n var rtt = 0;\n if (f.remoteTs) {\n rtt = Date.now() - f.remoteTs;\n }\n _this._rtt = _this._rttAlpha * rtt + (1 - _this._rttAlpha) * _this._rtt;\n var uint8 = new Uint8Array(f.audioData);\n var frame = [];\n var batch = 10000;\n for (var offset = 0; offset < uint8.byteLength; offset += batch) {\n var b = uint8.subarray(offset, Math.min(uint8.byteLength, offset + batch));\n let a = String.fromCharCode.apply(null, b);\n frame.push(a);\n }\n frame = frame.join('');\n postMessage(['alanAudio', 'playFrame', frame]);\n } else if (typeof(msg.data) === 'string') {\n msg = JSON.parse(msg.data);\n if (msg.i) {\n var c = _this._callSent[msg.i];\n delete _this._callSent[msg.i];\n if (c && c.callback) {\n c.callback(msg.e, msg.r);\n }\n } else if (msg.e) {\n if (msg.e === 'text') {\n postMessage(['alanAudio', 'playText', msg.p]);\n } else if (msg.e === 'showPopup') {\n postMessage(['alanAudio', 'showPopup', msg.p]);\n } else if (msg.e === 'command') {\n postMessage(['alanAudio', 'playCommand', msg.p]);\n } else if (msg.e === 'inactivity') {\n postMessage(['alanAudio', 'stop']);\n } else {\n _this._fire(msg.e, msg.p);\n }\n }\n } else {\n console.error('invalid message type');\n }\n };\n this._socket.onerror = function(evt) {\n console.error('Alan: connection closed due to error: ', evt);\n };\n this._socket.onclose = function(evt) {\n console.info('Alan: connection closed');\n _this._connected = false;\n _this._authorized = false;\n _this._socket = null;\n _this._onConnectStatus('disconnected');\n if (!_this._failed && _this._reconnectTimeout && !_this._closed) {\n console.log('Alan: reconnecting in %s ms.', _this._reconnectTimeout);\n _this._reConnect = setTimeout(_this._connect.bind(_this), _this._reconnectTimeout);\n if (_this._reconnectTimeout < 3000) {\n _this._reconnectTimeout *= 2;\n } else {\n _this._reconnectTimeout += 500;\n }\n _this._reconnectTimeout = Math.min(7000, _this._reconnectTimeout);\n }\n };\n this._addCleanup(function() {\n if (this._socket) {\n this._socket.close();\n this._socket = null;\n }\n });\n};\n\nConnectionImpl.prototype._callAuth = function() {\n var _this = this;\n var callback = function(err, r) {\n if (!err && r.status === 'authorized') {\n _this._authorized = true;\n _this._formatSent = false;\n if (r.dialogId) {\n postMessage(['setDialogId', r.dialogId]);\n _this._dialogId = r.dialogId;\n }\n _this._onAuthorized();\n _this._onConnectStatus('authorized');\n } else if (err === 'auth-failed') {\n _this._onConnectStatus('auth-failed');\n if (_this._socket) {\n _this._socket.close();\n _this._socket = null;\n _this._failed = true;\n }\n } else {\n _this._onConnectStatus('invalid-auth-response');\n console.log('Alan: invalid auth response', err, r);\n }\n };\n var authParam = this._auth;\n authParam.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (this._dialogId) {\n authParam.dialogId = this._dialogId;\n }\n authParam.mode = this._mode;\n this._sendCall({cid: this._callId++, method: '_auth_', callback: callback, param: authParam});\n return this;\n};\n\nConnectionImpl.prototype._sendCall = function(call) {\n this._sendFormatIfNeeded(false);\n this._socket.send(JSON.stringify({i: call.cid, m: call.method, p: call.param}));\n if (call.callback) {\n this._callSent[call.cid] = call;\n }\n};\n\nConnectionImpl.prototype._onAuthorized = function() {\n var _this = this;\n this._callWait.forEach(function(c) {\n _this._sendCall(c);\n });\n this._callWait = [];\n};\n\nConnectionImpl.prototype.close = function() {\n for (var i = 0; i < this._cleanups.length; i++ ) {\n this._cleanups[i]();\n }\n this._cleanups = [];\n this._closed = true;\n \n if (this._socket && (this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)) {\n this._socket.close();\n this._socket = null;\n }\n console.log('Alan: closed connection to: ' + getConnectionDetails(this._url));\n //close(); TODO: delete it!\n};\n\nConnectionImpl.prototype.call = function(cid, method, param) {\n var call = {cid: cid, method: method, param: param, callback: function(err, obj) {\n if (cid) {\n postMessage(['callback', cid, err, obj]);\n }\n }};\n if (this._authorized || this._connected && !this._auth) {\n this._sendCall(call);\n } else {\n this._callWait.push(call);\n }\n};\n\nConnectionImpl.prototype.setVisual = function(state) {\n this._visualState = state;\n this.call(null, '_visual_', state);\n};\n\nConnectionImpl.prototype._sendFrame = function(frame) {\n if (!this._socket) {\n console.error('sendFrame to closed socket');\n return;\n }\n frame.sentTs = Date.now();\n if (this._remoteSentTs > 0 && this._remoteRecvTs > 0) {\n frame.remoteTs = this._remoteSentTs + Date.now() - this._remoteRecvTs;\n }\n this._socket.send(frame.write());\n};\n\nConnectionImpl.prototype._listen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'listen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_LISTENING;\n};\n\nConnectionImpl.prototype._stopListen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'stopListen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_OFF;\n};\n\nConnectionImpl.prototype._onAudioFormat = function(format) {\n this._formatSent = false;\n this._format = format;\n};\n\nConnectionImpl.prototype._onMicFrame = function(sampleRate, frame) {\n if (this._alanState === ALAN_SPEAKING) {\n return;\n }\n if (this._alanState === ALAN_OFF) {\n this._listen();\n }\n if (this._alanState !== ALAN_LISTENING) {\n console.error('invalid alan state: ' + this._alanState);\n return;\n }\n this._sendFormatIfNeeded(true);\n var f = alanFrame.create();\n f.audioData = frame;\n this._frameQueue.push(f);\n};\n\nConnectionImpl.prototype._sendFormatIfNeeded = function(inQueue) {\n if (!this._format || this._formatSent) {\n return;\n }\n this._formatSent = true;\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({format: this._format});\n if (inQueue) {\n this._frameQueue.push(f);\n } else {\n this._sendFrame(f);\n }\n};\n\nConnectionImpl.prototype._flushQueue = function() {\n if (!this._socket || !this._connected) {\n var d = 0;\n while (this._frameQueue.length > 100 && !this._frameQueue[0].jsonData) {\n this._frameQueue.shift();\n d++;\n }\n if (d > 0) {\n console.error('dropped: %s, frames', d);\n }\n return;\n }\n while (this._frameQueue.length > 0 && this._socket && this._socket.bufferedAmount < 64 * 1024) {\n this._sendFrame(this._frameQueue.shift());\n }\n};\n\nfunction getConnectionDetails(url){\n var urlParts = url.split('/');\n var projectId = urlParts[4];\n var environment = urlParts[5];\n var host = urlParts[2];\n\n if (projectId && environment && host) {\n return ' (ProjectID: ' + projectId + ', environment: ' + environment + ', host: ' + host + ')';\n }\n\n return url;\n}\n\nfunction connectProject(config, auth, mode) {\n var c = new ConnectionImpl(config, auth, mode);\n c.onAudioEvent = function(event, arg1, arg2) {\n if (event === 'format') {\n c._onAudioFormat(arg1);\n } else if (event === 'frame') {\n c._onMicFrame(arg1, arg2);\n } else if (event === 'micStop' || event === 'playStart') {\n c._stopListen();\n } else {\n console.error('unknown audio event: ' + event, arg1, arg2);\n }\n };\n return c;\n}\n\nvar factories = {\n connectProject: connectProject,\n};\n\nvar currentConnect = null;\n\nonmessage = function(e) {\n var name = e.data[0];\n try {\n if (!currentConnect) {\n currentConnect = factories[name].apply(null, e.data.slice(1, e.data.length));\n } else {\n currentConnect[name].apply(currentConnect, e.data.slice(1, e.data.length));\n }\n } catch(e) {\n console.error('error calling: ' + name, e);\n }\n};\n"]),{type: 'text/javascript'}));
212
212
  this._worker.onmessage = function(e) {
213
213
  if (e.data[0] === 'fireEvent') {
214
214
  _this._fire(e.data[1], e.data[2]);
@@ -780,7 +780,7 @@
780
780
 
781
781
  /// <reference types="../global" />
782
782
  (function (ns) {
783
- var alanButtonVersion = '1.8.32';
783
+ var alanButtonVersion = '1.8.35';
784
784
  if (window.alanBtn) {
785
785
  console.warn('Alan: the Alan Button source code has already added (v.' + alanButtonVersion + ')');
786
786
  }
@@ -788,6 +788,7 @@
788
788
  var currentProjectId = null;
789
789
  var deviceId;
790
790
  var firstClick = null;
791
+ var btnInstance;
791
792
  // Define base properties for disable/enable button functionality
792
793
  var isLocalStorageAvailable = false;
793
794
  try {
@@ -833,6 +834,11 @@
833
834
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
834
835
  s4() + '-' + s4() + s4() + s4();
835
836
  }
837
+ var AlanButtonTextMessageType;
838
+ (function (AlanButtonTextMessageType) {
839
+ AlanButtonTextMessageType["Request"] = "request";
840
+ AlanButtonTextMessageType["Response"] = "response";
841
+ })(AlanButtonTextMessageType || (AlanButtonTextMessageType = {}));
836
842
  function alanBtn(options) {
837
843
  options = options || {};
838
844
  var btnDisabled = false;
@@ -842,6 +848,7 @@
842
848
  var absolutePosition = false;
843
849
  var micWasStoppedByTimeout = false;
844
850
  var keepButtonPositionAfterDnD = false;
851
+ var dragAndDropEnabled = true;
845
852
  // Btn modes
846
853
  var mode;
847
854
  if (options.mode === 'tutor') {
@@ -855,10 +862,13 @@
855
862
  mode = 'component';
856
863
  }
857
864
  console.log('Alan: v.' + alanButtonVersion);
858
- if (window.tutorProject && !isTutorMode()) {
859
- throw new Error('The Alan Button instance has already been created. There cannot be two Alan Button instances created at the same time');
865
+ if (window.tutorProject && !isTutorMode() && btnInstance) {
866
+ if (currentProjectId === options.key) {
867
+ return btnInstance;
868
+ }
869
+ throw new Error('The Alan Button instance has already been created. There cannot be two Alan Button instances created at the same time connected to the different projects.');
860
870
  }
861
- var btnInstance = {
871
+ btnInstance = {
862
872
  // Common public API
863
873
  version: alanButtonVersion,
864
874
  setVisualState: function (visualStateData) {
@@ -916,6 +926,9 @@
916
926
  isActive: function () {
917
927
  return isAlanActive;
918
928
  },
929
+ sendText: function (text) {
930
+ window.tutorProject.call('text', { text: text });
931
+ },
919
932
  //deprecated
920
933
  callClientApi: function (method, data, callback) {
921
934
  console.error('The "callClientApi" method is deprecated. Please use the "callProjectApi: instead.\n\nSee more info here: https://alan.app/docs/client-api/methods/common-api/?highlight=callprojectapi#callprojectapi');
@@ -949,7 +962,10 @@
949
962
  remove: function () {
950
963
  alanAudio.stop();
951
964
  window.tutorProject.close();
952
- rootEl.remove();
965
+ window.tutorProject.off('scripts', onScriptsCb);
966
+ window.tutorProject.off('text', onTextCbInMicBtn);
967
+ rootEl.innerHTML = '';
968
+ btnInstance = null;
953
969
  if (!isTutorMode()) {
954
970
  window.tutorProject = null;
955
971
  }
@@ -1316,7 +1332,7 @@
1316
1332
  }
1317
1333
  if (absolutePosition) {
1318
1334
  el.style.position = 'absolute';
1319
- el.classList.add('absolute-positioned');
1335
+ el.classList.add('alan-btn-lib__absolute-positioned');
1320
1336
  }
1321
1337
  if (topPos) {
1322
1338
  el.style.bottom = '';
@@ -1329,14 +1345,14 @@
1329
1345
  if (isLeftAligned) {
1330
1346
  btn.style.left = '0';
1331
1347
  btn.style.right = '';
1332
- recognisedTextHolder.classList.remove('left-side');
1333
- recognisedTextHolder.classList.add('right-side');
1348
+ recognisedTextHolder.classList.remove('alan-btn-lib__left-side');
1349
+ recognisedTextHolder.classList.add('alan-btn-lib__right-side');
1334
1350
  }
1335
1351
  else {
1336
1352
  btn.style.right = '0';
1337
1353
  btn.style.left = '';
1338
- recognisedTextHolder.classList.remove('right-side');
1339
- recognisedTextHolder.classList.add('left-side');
1354
+ recognisedTextHolder.classList.remove('alan-btn-lib__right-side');
1355
+ recognisedTextHolder.classList.add('alan-btn-lib__left-side');
1340
1356
  }
1341
1357
  }
1342
1358
  function applyBtnSizeOptions(size) {
@@ -1698,8 +1714,8 @@
1698
1714
  keyFrames += getStyleSheetMarker() + '.alanBtn{transform: scale(1);' + transitionCss + ';} .alanBtn' + hoverSelector + '{transform: scale(1.11111);transition:' + transitionCss + ';}.alanBtn:focus {transform: scale(1);' + transitionCss + '; border: solid 3px #50e3c2; outline: none; }';
1699
1715
  }
1700
1716
  keyFrames += getStyleSheetMarker() + '.alanBtn-recognised-text-holder { position:fixed; transform: translateY(' + (isTopAligned ? '-' : '') + '50%); max-width:236px; font-family: Helvetica, Arial, sans-serif; font-size: 14px; line-height: 18px; min-height: 40px; color: #000; font-weight: normal; background-color: #fff; border-radius:10px; box-shadow: 0px 1px 14px rgba(0, 0, 0, 0.35); display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack: activate;-ms-flex-pack: start;justify-content: start;}';
1701
- keyFrames += getStyleSheetMarker() + ' .alanBtn-recognised-text-holder.with-text.left-side { text-align: left;}';
1702
- keyFrames += getStyleSheetMarker() + ' .alanBtn-recognised-text-holder.with-text.right-side { text-align: right;}';
1717
+ keyFrames += getStyleSheetMarker() + ' .alanBtn-recognised-text-holder.alan-btn-lib__with-text.alan-btn-lib__left-side { text-align: left;}';
1718
+ keyFrames += getStyleSheetMarker() + ' .alanBtn-recognised-text-holder.alan-btn-lib__with-text.alan-btn-lib__right-side { text-align: right;}';
1703
1719
  keyFrames += getStyleSheetMarker() + ' .alanBtn-recognised-text-holder .alanBtn-recognised-text-content:not(:empty) {padding: 10px;}';
1704
1720
  keyFrames += getStyleSheetMarker(true) + '.alanBtn-recognised-text-holder-long { font-size: 12px!important;line-height: 1.4!important;} ';
1705
1721
  keyFrames += getStyleSheetMarker(true) + '.alanBtn-recognised-text-holder-super-long { font-size: 11px!important;line-height: 1.4!important;} ';
@@ -1723,11 +1739,11 @@
1723
1739
  keyFrames += getStyleSheetMarker() + '.alan-alert-popup {border-radius:10px; box-shadow: 0px 5px 14px rgba(3, 3, 3, 0.25);padding:12px;padding-right:24px;text-align: center;width: 220px;background: rgb(255 255 255);position: fixed;left: 50%;transform: translateX(-50%);top: 10%; color: #000;font-size: 14px;line-height: 18px;}';
1724
1740
  keyFrames += getStyleSheetMarker() + '.alan-alert-popup__close-btn {background:url("' + popupCloseIconImgBase64 + '") no-repeat center;cursor:pointer; background-size:100% 100%;position: absolute;top: 12px;right: 12px;width: 14px;height: 14px;}';
1725
1741
  keyFrames += getStyleSheetMarker() + '.alan-overlay {position: fixed;top: 0;left: 0;right: 0;bottom: 0;z-index: 99;background: rgba(0, 0, 0, 0.57);opacity: 0;-webkit-animation: alan-fade-in 0.5s 0.2s forwards;-moz-animation: alan-fade-in 0.5s 0.2s forwards;-o-animation: alan-fade-in 0.5s 0.2s forwards;animation: alan-fade-in 0.5s 0.2s forwards;}';
1726
- keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.default-popup {border-radius:10px; box-shadow: 0px 5px 14px rgba(3, 3, 3, 0.25);padding:6px 30px 6px 12px;text-align: left;width: 220px;background: rgb(255 255 255);}';
1727
- keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.top.right {border-top-right-radius: 0!important;}';
1728
- keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.top.left {border-top-left-radius: 0!important;}';
1729
- keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.bottom.left {border-bottom-left-radius: 0!important;}';
1730
- keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.bottom.right {border-bottom-right-radius: 0!important;}';
1742
+ keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.alan-btn-lib__default-popup {border-radius:10px; box-shadow: 0px 5px 14px rgba(3, 3, 3, 0.25);padding:6px 30px 6px 12px;text-align: left;width: 220px;background: rgb(255 255 255);}';
1743
+ keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.alan-btn-lib__top.alan-btn-lib__right {border-top-right-radius: 0!important;}';
1744
+ keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.alan-btn-lib__top.alan-btn-lib__left {border-top-left-radius: 0!important;}';
1745
+ keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.alan-btn-lib__bottom.alan-btn-lib__left {border-bottom-left-radius: 0!important;}';
1746
+ keyFrames += getStyleSheetMarker() + '.alan-overlay-popup.alan-btn-lib__bottom.alan-btn-lib__right {border-bottom-right-radius: 0!important;}';
1731
1747
  keyFrames += getStyleSheetMarker() + '.alan-overlay-popup {position: fixed;opacity: 0;-webkit-animation: alan-fade-in 0.5s 0.2s forwards;-moz-animation: alan-fade-in 0.5s 0.2s forwards;-o-animation: alan-fade-in 0.5s 0.2s forwards;animation: alan-fade-in 0.5s 0.2s forwards;}';
1732
1748
  keyFrames += getStyleSheetMarker() + '.alan-overlay-popup__body {position:relative;color: #0D1940;font-size: 16px;line-height: 20px;}';
1733
1749
  keyFrames += getStyleSheetMarker() + '.alan-overlay-popup__ok {background:url("' + popupCloseIconImgBase64 + '") no-repeat center; background-size:100% 100%;min-height:14px;height:14px;max-height:14px;min-width:14px;width:14px;max-width:14px;opacity:0;transition:opacity 300ms ease-in-out;position:absolute;top:8px;right:8px;cursor: pointer;pointer-events: auto!important;}';
@@ -1867,6 +1883,8 @@
1867
1883
  });
1868
1884
  window.tutorProject.on('connectStatus', onConnectStatusChange);
1869
1885
  window.tutorProject.on('options', onOptionsReceived);
1886
+ window.tutorProject.on('scripts', onScriptsCb);
1887
+ window.tutorProject.on('text', onTextCbInMicBtn);
1870
1888
  //window.tutorProject.on('popup', onPopup);
1871
1889
  // console.info('BTN: tutorProject', options.key);
1872
1890
  }
@@ -2065,6 +2083,9 @@
2065
2083
  if (isMobile() || isTutorMode()) {
2066
2084
  return;
2067
2085
  }
2086
+ if (options.onEvent) {
2087
+ options.onEvent(Object.assign(p, { name: 'popup' }));
2088
+ }
2068
2089
  if (p) {
2069
2090
  showPopup(p.popup ? p.popup : p);
2070
2091
  }
@@ -2109,7 +2130,7 @@
2109
2130
  document.getElementsByTagName('head')[0].appendChild(popupStyle);
2110
2131
  }
2111
2132
  }
2112
- popup.classList.add(isLeftAligned ? 'left' : 'right');
2133
+ popup.classList.add(isLeftAligned ? 'alan-btn-lib__left' : 'alan-btn-lib__right');
2113
2134
  if (!absolutePosition) {
2114
2135
  if (!isLeftAligned) {
2115
2136
  popup.style.right = initRightPos + (-buttonMarginInPopup || 0) + 'px';
@@ -2118,12 +2139,12 @@
2118
2139
  popup.style.left = rootElClientRect.x + (-buttonMarginInPopup || 0) + 'px';
2119
2140
  }
2120
2141
  if (rootElClientRect.top > 80) {
2121
- popup.classList.add('bottom');
2142
+ popup.classList.add('alan-btn-lib__bottom');
2122
2143
  popup.style.top = rootElClientRect.top + (buttonMarginInPopup ? (_btnSize + buttonMarginInPopup) : (-popup2BtnMargin)) + 'px';
2123
2144
  popup.style.setProperty('transform', 'translateY(-100%)', 'important');
2124
2145
  }
2125
2146
  else {
2126
- popup.classList.add('top');
2147
+ popup.classList.add('alan-btn-lib__top');
2127
2148
  popup.style.top = rootElClientRect.top + (buttonMarginInPopup ? (-buttonMarginInPopup) : (_btnSize + popup2BtnMargin)) + 'px';
2128
2149
  }
2129
2150
  }
@@ -2131,11 +2152,11 @@
2131
2152
  popup.style.position = 'absolute';
2132
2153
  popup.style[isLeftAligned ? 'left' : 'right'] = (-buttonMarginInPopup || 0) + 'px';
2133
2154
  popup.style[isTopAligned ? 'top' : 'bottom'] = (buttonMarginInPopup ? -buttonMarginInPopup : (_btnSize + popup2BtnMargin)) + 'px';
2134
- popup.classList.add(isTopAligned ? 'top' : 'bottom');
2155
+ popup.classList.add(isTopAligned ? 'alan-btn-lib__top' : 'alan-btn-lib__bottom');
2135
2156
  }
2136
2157
  if (!popupOptions.html) {
2137
2158
  if (message) {
2138
- popup.classList.add('default-popup');
2159
+ popup.classList.add('alan-btn-lib__default-popup');
2139
2160
  popup.innerHTML = '<div class="alan-overlay-popup__body">' + message + '</div>';
2140
2161
  }
2141
2162
  }
@@ -2259,7 +2280,7 @@
2259
2280
  if (!options.hideRecognizedText) {
2260
2281
  if (recognisedTextHolder.classList.value.indexOf('alanBtn-text-appearing') === -1) {
2261
2282
  recognisedTextHolder.style.opacity = '1';
2262
- recognisedTextHolder.classList.add('with-text');
2283
+ recognisedTextHolder.classList.add('alan-btn-lib__with-text');
2263
2284
  recognisedTextHolder.classList.add('alanBtn-text-appearing');
2264
2285
  recognisedTextHolder.classList.remove('alanBtn-text-disappearing');
2265
2286
  }
@@ -2270,7 +2291,7 @@
2270
2291
  }
2271
2292
  recognisedTextContent.innerHTML = recognisedText;
2272
2293
  }
2273
- if (recognisedTextHolder.classList.contains('absolute-positioned')) {
2294
+ if (recognisedTextHolder.classList.contains('alan-btn-lib__absolute-positioned')) {
2274
2295
  if (recognisedText.length < 33) {
2275
2296
  recognisedTextHolder.style.whiteSpace = 'nowrap';
2276
2297
  recognisedTextHolder.style.minWidth = 'auto';
@@ -2318,28 +2339,32 @@
2318
2339
  recognisedTextContent.innerHTML = '';
2319
2340
  recognisedTextHolder.classList.remove('alanBtn-recognised-text-holder-long');
2320
2341
  recognisedTextHolder.classList.remove('alanBtn-recognised-text-holder-super-long');
2321
- recognisedTextHolder.classList.remove('with-text');
2342
+ recognisedTextHolder.classList.remove('alan-btn-lib__with-text');
2322
2343
  }, delay || 810);
2323
2344
  }
2324
2345
  }
2325
2346
  function onOptionsReceived(data) {
2347
+ var _a, _b, _c;
2326
2348
  if (data && data.web) {
2327
- keepButtonPositionAfterDnD = data.web.keepButtonPositionAfterDnD;
2349
+ keepButtonPositionAfterDnD = ((_a = data.web.alanButtonDragAndDrop) === null || _a === void 0 ? void 0 : _a.keepButtonPositionAfterDnD) || data.web.keepButtonPositionAfterDnD;
2328
2350
  if (!keepButtonPositionAfterDnD) {
2329
2351
  clearSavedBtnPosition();
2330
2352
  }
2331
- setButtonPosition(data.web.keepButtonPositionAfterDnD);
2353
+ setButtonPosition(keepButtonPositionAfterDnD);
2332
2354
  }
2333
2355
  else {
2334
2356
  setButtonPosition();
2335
2357
  }
2358
+ if (data && data.web) {
2359
+ dragAndDropEnabled = (_b = data.web.alanButtonDragAndDrop) === null || _b === void 0 ? void 0 : _b.dragAndDropEnabled;
2360
+ }
2336
2361
  if (data && data.web && data.web.hideS2TPanel === true) {
2337
2362
  hideSpeach2TextPanel();
2338
2363
  }
2339
2364
  else {
2340
2365
  showSpeach2TextPanel();
2341
2366
  }
2342
- if (data && data.web && data.web.popupEnabled === true) {
2367
+ if (data && data.web && (((_c = data.web.alanButtonPopup) === null || _c === void 0 ? void 0 : _c.popupEnabled) === true || data.web.popupEnabled === true)) {
2343
2368
  popupEnabled = true;
2344
2369
  }
2345
2370
  else {
@@ -2409,7 +2434,6 @@
2409
2434
  playSoundNext();
2410
2435
  isAlanActive = true;
2411
2436
  if (window.tutorProject) {
2412
- window.tutorProject.on('text', onTextCbInMicBtn);
2413
2437
  window.tutorProject.on('parsed', onParsedCbInMicBtn);
2414
2438
  window.tutorProject.on('recognized', onRecognizedCbInMicBtn);
2415
2439
  window.tutorProject.on('connectStatus', onConnectStatusChange);
@@ -2433,7 +2457,6 @@
2433
2457
  switchState(DEFAULT);
2434
2458
  isAlanActive = false;
2435
2459
  if (window.tutorProject) {
2436
- window.tutorProject.off('text', onTextCbInMicBtn);
2437
2460
  window.tutorProject.off('parsed', onParsedCbInMicBtn);
2438
2461
  window.tutorProject.off('recognized', onRecognizedCbInMicBtn);
2439
2462
  window.tutorProject.off('connectStatus', onConnectStatusChange);
@@ -2525,7 +2548,7 @@
2525
2548
  function onTextCbInMicBtn(e) {
2526
2549
  // console.info('BTN: onTextCb', e, new Date());
2527
2550
  if (options.onEvent) {
2528
- options.onEvent(Object.assign(e, { name: 'text' }));
2551
+ options.onEvent(Object.assign(e, { name: 'text', type: AlanButtonTextMessageType.Response }));
2529
2552
  }
2530
2553
  turnOffVoiceFn();
2531
2554
  }
@@ -2561,6 +2584,11 @@
2561
2584
  }
2562
2585
  turnOffVoiceFn();
2563
2586
  }
2587
+ function onScriptsCb(e) {
2588
+ if (options.onEvent) {
2589
+ options.onEvent(Object.assign(e, { name: 'scripts' }));
2590
+ }
2591
+ }
2564
2592
  function playSoundOn() {
2565
2593
  if (!soundOnAudioDoesNotExist) {
2566
2594
  soundOnAudio.currentTime = 0;
@@ -3110,6 +3138,8 @@
3110
3138
  var newLeftPos, newTopPos;
3111
3139
  if (!posInfo)
3112
3140
  return;
3141
+ if (!dragAndDropEnabled)
3142
+ return;
3113
3143
  if (dndIsDown) {
3114
3144
  togglePopupVisibility(false);
3115
3145
  hideRecognisedText(0, true);