/*******************************************************************************
* Copyright (c) by Nguyen Thanh Phat.
* Author: Nguyen Thanh Phat
* Email: phat.nguyenthanh@meai.vn
******************************************************************************/
Chat3liUtils = {
widgetId: "chat3li-widget-id-0307098",
backgroundId: "background-radial",
commands: ["COMMANDS.SHOW_WIDGET", "COMMANDS.HIDE_WIDGET"],
ready: false,
triggerHook: (type, data) => {
if (!window.chat3liSettings || !window.chat3liSettings.hooks || !window.chat3liSettings.hooks[type]) {
return;
}
try {
window.chat3liSettings.hooks[type](data);
} catch (e) {
console.error(e);
}
},
_checkAndBindTOElement: () => {
if (!window.chat3liSettings || !window.chat3liSettings.custom_launcher_selector) {
return;
}
if (document && document.body) {
checkingAndBind();
} else {
window.onload = () => {
checkingAndBind();
}
}
const checkingAndBind = () => {
if (window.addEventListener) {
document.body.addEventListener('click', clickHandler, true);
} else {
document.body.attachEvent('onclick', clickHandler, true);
}
}
const clickHandler = (e) => {
let target = e.target;
while (target != null) {
const isMatch = target.matches(window.chat3liSettings.custom_launcher_selector);
if (isMatch) {
chat3liApp.command("COMMANDS.SHOW_WIDGET", {});
return;
}
target = target.parentElement;
}
}
},
extractWidgetDomain: () => {
const scriptElem = document.getElementById('chat3li-chat-widget-bootstrap');
const url = scriptElem.getAttribute('src');
const regexp = /((https?:\/\/)[^/]+)/;
const matchResult = regexp.exec(url);
return matchResult && matchResult[1];
},
_keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
delayLoad(fn, timeout) {
if (document.readyState === 'complete') {
setTimeout(fn, timeout);
} else {
window.onload = function () {
setTimeout(fn, timeout);
};
}
},
lazyLoad: ['6825ebb93887558d30d26b5c85731307', 'c71db54c0e752bf9cd8952003693213d', '0517d09289e39f36d8567d78eee0fca1'],
encode(input) {
let output = '';
let chr1;
let chr2;
let chr3;
let enc1;
let enc2;
let enc3;
let enc4;
let i = 0;
input = this._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output
+ this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2)
+ this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
_utf8_encode: (string) => {
string = string.replace(/\r\n/g, '\n');
let utftext = '';
for (let n = 0; n < string.length; n++) {
const c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
};
Chat3liApp = {
ID_WIDGET: "chat3li-widget",
state: {},
reset() {
const currentWidget = document.getElementById(this.ID_WIDGET);
if (currentWidget) {
currentWidget.remove();
}
},
init(config, context) {
this.reset();
const initTime = context && context.initTime ? context.initTime : new Date().getTime();
if (this.initTime && initTime < this.initTime) {
return;
}
this.initTime = initTime;
let oldHash;
const _hashHandler = () => {
oldHash = window.location.href;
const detect = function () {
if (oldHash !== window.location.href) {
return;
}
this.sendUrl();
oldHash = window.location.href;
}
this.state.invervalJob = setInterval(() => {
detect;
_checkFocus();
}, 100);
}
_hashHandler();
Chat3liUtils._checkAndBindTOElement();
config = config || {};
const domain = Chat3liUtils.extractWidgetDomain();
// const openerDomain = domain === 'http://3lichat' ? 'http://3lichat' : '*';
// if (!domain) {
// return;
// }
let widgetContainers;
window.addEventListener('message', _handleMsg, false);
window.addEventListener('resize', () => {
_calculateWidgetContainerMaxHeight();
});
_processWidget(config, {initTime});
function sendUrl() {
_sendMessage({
title: window.document.title,
url: window.location.href,
referrer: window.document.referrer,
search: window.location.search,
type: 'change-url',
});
}
function _calculateWidgetContainerMaxHeight() {
if (!widgetContainers) {
return;
}
const clientRect = widgetContainers.getBoundingClientRect();
widgetContainers.style.maxHeight = `${clientRect.bottom}px`;
_sendMessage({method: 'chat3li-iframe-max-height', maxHeight: clientRect.bottom});
}
function _sendMessage(data) {
const iframe = document.getElementById(Chat3liUtils.widgetId);
if (!iframe) {
return;
}
iframe.contentWindow.postMessage(data, '*');
}
function _extractPath(object, path) {
if (!path) {
return object;
}
// normalization to array
if (typeof path === 'string' || typeof path === 'number') {
path = [path];
}
let idx = 0;
let result = object;
while (path[idx] && result) {
const pathPart = path[idx];
idx++;
// 'attribute' type abbreviation
if (typeof pathPart === 'string' || typeof pathPart === 'number') {
result = result[pathPart];
continue;
}
if (pathPart.type === 'attribute') {
result = result[pathPart.name];
continue;
}
if (pathPart.type === 'function') {
if (!result[pathPart.name] || typeof result[pathPart.name] !== 'function') {
result = null;
continue;
}
let args = pathPart.args || [];
args = args.map(_mapArg);
result = result[pathPart.name].apply(result, args);
}
}
return result;
}
function _mapArg(arg) {
if (!arg.type) {
return arg;
}
if (arg.type === 'object') {
return arg.value;
}
if (arg.type == 'path') {
const target = _getTargetElement(arg);
return _extractPath(target, arg.path);
}
return null;
}
function _getTargetElement(eventConfig) {
if (eventConfig.targetType === 'window') {
return window;
}
if (eventConfig.targetType === 'document') {
return document;
}
if (eventConfig.targetType === 'xpath') {
return document.evaluate(eventConfig.targetPath, document).iterateNext();
}
return null;
}
function _getExtractTarget(event, pathConfig) {
if (pathConfig.targetType) {
return _getTargetElement(pathConfig);
}
return event;
}
function _handleWidgetRequest(request) {
const payload = request.payload;
let target;
let result;
try {
target = _getTargetElement(payload);
result = _extractPath(target, payload.path);
} catch (ex) {
let errorMessage = ex && ex.message;
errorMessage = typeof errorMessage === 'string' ? errorMessage : 'unknown_error';
_sendMessage({
method: 'chat3li-query-response',
response: {
requestId: request.requestId,
status: 'failure',
error: errorMessage,
},
});
return;
}
_sendMessage({
method: 'chat3li-query-response',
response: {
result,
status: 'success',
requestId: request.requestId,
},
});
}
function _setupEventListener(listenerId, eventConfig) {
let element;
try {
element = _getTargetElement(eventConfig);
} catch (ex) {
return;
}
if (!element) {
return;
}
element.addEventListener(eventConfig.eventType, (e) => {
// TODO: error handling
const payload = {...eventConfig.baseData || {}};
if (eventConfig.paths) {
eventConfig.paths.forEach((pathConfig) => {
const extractTarget = _getExtractTarget(e, pathConfig);
payload[pathConfig.key] = _extractPath(extractTarget, pathConfig.path);
});
}
_sendMessage({
method: 'chat3li-listen-event-triggered',
payload,
listenerId,
});
});
}
function _handleMsg(e) {
if (!widgetContainers || !widgetContainers.classList) {
return;
}
switch (e.data.method) {
case 'chat3li-init-listen-event':
_setupEventListener(e.data.listenerId, e.data.eventConfig);
break;
case 'chat3li-query':
_handleWidgetRequest(e.data.request);
break;
case 'chat3li-boxchat-change-height':
const newClass = `chat3li-widget-${e.data.value}`;
const oldClass = newClass === 'chat3li-widget-show' ? 'chat3li-widget-hide' : 'chat3li-widget-show';
widgetContainers.classList.remove(oldClass);
widgetContainers.classList.add(newClass);
widgetContainers.style.height = null;
widgetContainers.classList.remove('chat3li-widget-notif-new-message');
widgetContainers.classList.remove('chat3li-widget-resize');
if (e.data.value === 'show') {
if (e.data.contextData && e.data.contextData.widgetSize) {
widgetContainers.classList.add(`size-${e.data.contextData.widgetSize}`);
}
_calculateWidgetContainerMaxHeight();
if (window.innerWidth < 450) {
document.body.style.overflow = 'hidden';
}
Chat3liUtils.triggerHook('onShow');
updateBg(1);
} else {
if (e.data.contextData && e.data.contextData.widgetSize) {
widgetContainers.classList.remove(`size-${e.data.contextData.widgetSize}`);
}
document.body.style.overflow = '';
Chat3liUtils.triggerHook('onHide');
updateBg(0);
}
break;
case 'chat3li-boxchat-toggle-reading-size':
if (e.data.className === 'oc-expand') {
widgetContainers.classList.add('oc-widget-resize');
} else if (e.data.className === 'oc-shrink') {
setTimeout(() => {
widgetContainers.classList.remove('oc-widget-resize');
}, 300);
}
break;
case 'chat3li-hidden-widget':
widgetContainers.classList.add('hidden-widget');
updateBg(0);
break;
// TODO: Seem not used
case 'chat3li-remove-hidden-boxchat':
widgetContainers.classList.remove('hidden-widget');
break;
case 'oc-chat-widget-notif-new-message':
if (e.data.show) {
widgetContainers.classList.add('oc-widget-notif-new-message');
widgetContainers.style.height = e.data.height; // height to notice height
updateBg(1);
} else {
widgetContainers.classList.remove('oc-widget-notif-new-message');
widgetContainers.style.height = ''; // reset height
updateBg(0);
}
_calculateWidgetContainerMaxHeight();
break;
case 'close-notif':
widgetContainers.classList.remove('oc-widget-notif-new-message');
widgetContainers.style.height = '';
updateBg(0);
break;
case 'oc-show-overlay-image':
var iframe = document.getElementById('oc-modal-frame');
iframe.style.top = 0;
iframe.style.display = 'block';
iframe.style.left = 0;
iframe.style.width = '100%';
iframe.style.height = '100%';
iframe.style.position = 'fixed';
iframe.style['z-index'] = 2147483647;
iframe.contentWindow.postMessage(e.data, domain);
break;
case 'oc-hide-overlay-image':
var iframe = document.getElementById('oc-modal-frame');
iframe.style.display = 'none';
iframe.style.width = 0;
iframe.style.height = 0;
break;
case 'oc-escape-pressed':
var iframe = document.getElementById('oc-modal-frame');
iframe.contentWindow.postMessage(e.data, domain);
break;
case 'oc-widget-ready':
Chat3liUtils.ready = true;
break;
case 'visitor:initialized':
try {
if (e.data && e.data.data) {
Chat3liUtils.triggerHook('onVisitor', e.data.data);
Chat3liUtils.visitor = e.data.data;
console.log(Chat3liUtils.visitor);
}
} catch (error) {
}
break;
case 'chat3li:feedback':
initFeedback(e.data.data);
break;
default:
break;
}
}
function updateBg(show) {
// eslint-disable-next-line no-undef
let bg = document.getElementById(Chat3liUtils.backgroundId);
const opacity = show === 1 ? 1 : 0;
if (bg) {
bg.style.opacity = opacity;
return;
}
// eslint-disable-next-line no-undef
bg = document.createElement('iframe');
bg.id = Chat3liUtils.backgroundId;
bg.style.opacity = show;
bg.classList.add('chat3li-radial-background');
if (!Chat3liUtils.wrapper) {
return;
}
Chat3liUtils.wrapper.prepend(bg);
}
function _processWidget(config, context) {
const srcUrl = document.getElementById('chat3li-chat-widget-bootstrap')?.getAttribute('src');
const appToken = getUrlParameter(srcUrl, 'token');
const widgetId = 'chat3li-widget';
const lang = getUrlParameter(srcUrl, 'lang') || 'vi';
const wrapper = document.createElement('div');
Chat3liUtils.wrapper = wrapper;
wrapper.id = widgetId;
wrapper.classList.add('chat3li-widget');
wrapper.classList.add('custom-css-override');
if (window.chat3liSetting && window.chat3liSetting.custom_launcher_selector) {
wrapper.classList.add('chat3li-cl');
}
widgetContainers = wrapper
let iframe = document.getElementById(Chat3liUtils.widgetId);
const data = JSON.stringify({
title: window.document.title,
referrer: window.document.referrer,
url: window.location.href,
search: window.location.search,
userAgent: window.navigator.userAgent
})
let src = `${domain}/app/chat?widget-id=${widgetId}&token=${appToken}&chat3lidata=${Chat3liUtils.encode(data)}`;
if (!iframe || iframe.length === 0) {
_appendCSS(appToken);
iframe = document.createElement('iframe');
iframe.id = Chat3liUtils.widgetId;
iframe.style['border-width'] = '0px';
iframe.setAttribute('allowFullScreen', '');
iframe.style.width = '100%';
iframe.style.setProperty('height','100%','important');
iframe.style.setProperty('min-height','unset');
iframe.style.setProperty('max-height','unset');
iframe.classList.add('chat3li-iframe');
iframe.scrolling = 'no';
iframe.src = src;
wrapper.appendChild(iframe);
_addMainFrame(wrapper, appToken, context);
} else {
iframe.src = src;
}
}
function _addMainFrame(frame, appToken, context) {
const readyStateCheckInterval = setInterval(() => {
if (!document || !document.body) {
return;
}
clearInterval(readyStateCheckInterval);
if (Chat3liUtils.lazyLoad.indexOf(appToken) >= 0) {
Chat3liUtils.delayLoad(() => {
_addFrames(frame, context);
}, 2000);
} else {
_addFrames(frame, context);
}
}, 10);
}
function _addFrames(frame, context = {}) {
if (context.initTime !== Chat3liApp.initTime) {
return;
}
_addIframeToBody(frame);
// _addModalFrameToBody();
}
function _addIframeToBody(wrapper, cb) {
document.body.appendChild(wrapper);
if (cb) cb();
}
function _addModalFrameToBody() {
let iframe = document.getElementById('chat3li-modal-frame');
if (iframe) {
return;
}
iframe = document.createElement('iframe');
iframe.id = 'chat3li-modal-frame';
iframe.src = `${domain}/modal.html`;
iframe.frameBorder = 0;
_addIframeToBody(iframe);
}
function _appendCSS(appToken) {
_appendCSSUrl(`${domain}/api/v1/resources-api/widget-style.css?token=${appToken}&t=${new Date().getTime()}`);
_appendCSSUrl(`${domain}/api/v1/resources-api/widget-style-override.css?token=${appToken}&t=${new Date().getTime()}`);
}
function _appendCSSUrl(url) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = url;
document.head.appendChild(link);
}
function getUrlParameter(url, name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
const regex = new RegExp(`[\\?&]${name}=([^&#]*)`);
const results = regex.exec(url || window.location.search);
return results === null
? ''
: decodeURIComponent(results[1].replace(/\+/g, ' '));
}
function _checkFocus() {
if (this.isFocus === document.hasFocus()) {
return;
}
this.isFocus = document.hasFocus();
_sendMessage({
value: this.isFocus,
type: 'browser:focus-change',
});
}
},
}
try {
Chat3liApp.init(window.chat3liSetting, {initTime: new Date().getTime()});
} catch (ex) {
console.log('Chat3li Error: ', ex);
}