Feature: Website SDK (#653)

Add SDK functions

Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
Pranav Raj S 2020-04-03 13:04:58 +05:30 committed by GitHub
parent 7fcd2d0e85
commit cb22b396eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 734 additions and 262 deletions

View file

@ -0,0 +1,63 @@
import { SDK_CSS } from '../widget/assets/scss/sdk';
export const loadCSS = () => {
const css = document.createElement('style');
css.type = 'text/css';
css.innerHTML = `${SDK_CSS}`;
document.body.appendChild(css);
};
export const wootOn = (elm, event, fn) => {
if (document.addEventListener) {
elm.addEventListener(event, fn, false);
} else if (document.attachEvent) {
// <= IE 8 loses scope so need to apply, we add this to object so we
// can detach later (can't detach anonymous functions)
// eslint-disable-next-line
elm[event + fn] = function() {
// eslint-disable-next-line
return fn.apply(elm, arguments);
};
elm.attachEvent(`on${event}`, elm[event + fn]);
}
};
export const classHelper = (classes, action, elm) => {
let search;
let replace;
let i;
let has = false;
if (classes) {
// Trim any whitespace
const classarray = classes.split(/\s+/);
for (i = 0; i < classarray.length; i += 1) {
search = new RegExp(`\\b${classarray[i]}\\b`, 'g');
replace = new RegExp(` *${classarray[i]}\\b`, 'g');
if (action === 'remove') {
// eslint-disable-next-line
elm.className = elm.className.replace(replace, '');
} else if (action === 'toggle') {
// eslint-disable-next-line
elm.className = elm.className.match(search)
? elm.className.replace(replace, '')
: `${elm.className} ${classarray[i]}`;
} else if (action === 'has') {
if (elm.className.match(search)) {
has = true;
break;
}
}
}
}
return has;
};
export const addClass = (elm, classes) => {
if (classes) {
elm.className += ` ${classes}`;
}
};
export const toggleClass = (elm, classes) => {
classHelper(classes, 'toggle', elm);
};

View file

@ -0,0 +1,134 @@
import Cookies from 'js-cookie';
import { wootOn, loadCSS } from './DOMHelpers';
import {
body,
widgetHolder,
createBubbleHolder,
disableScroll,
enableScroll,
createBubbleIcon,
bubbleImg,
chatBubble,
closeBubble,
bubbleHolder,
createNotificationBubble,
onClickChatBubble,
onBubbleClick,
} from './bubbleHelpers';
export const IFrameHelper = {
getUrl({ baseUrl, websiteToken }) {
return `${baseUrl}/widget?website_token=${websiteToken}`;
},
createFrame: ({ baseUrl, websiteToken }) => {
const iframe = document.createElement('iframe');
const cwCookie = Cookies.get('cw_conversation');
let widgetUrl = IFrameHelper.getUrl({ baseUrl, websiteToken });
if (cwCookie) {
widgetUrl = `${widgetUrl}&cw_conversation=${cwCookie}`;
}
iframe.src = widgetUrl;
iframe.id = 'chatwoot_live_chat_widget';
iframe.style.visibility = 'hidden';
widgetHolder.className = 'woot-widget-holder woot--hide';
widgetHolder.appendChild(iframe);
body.appendChild(widgetHolder);
IFrameHelper.initPostMessageCommunication();
IFrameHelper.initLocationListener();
IFrameHelper.initWindowSizeListener();
},
getAppFrame: () => document.getElementById('chatwoot_live_chat_widget'),
sendMessage: (key, value) => {
const element = IFrameHelper.getAppFrame();
element.contentWindow.postMessage(
`chatwoot-widget:${JSON.stringify({ event: key, ...value })}`,
'*'
);
},
initLocationListener: () => {
window.onhashchange = () => {
IFrameHelper.setCurrentUrl();
};
},
initPostMessageCommunication: () => {
window.onmessage = e => {
if (
typeof e.data !== 'string' ||
e.data.indexOf('chatwoot-widget:') !== 0
) {
return;
}
const message = JSON.parse(e.data.replace('chatwoot-widget:', ''));
if (typeof IFrameHelper.events[message.event] === 'function') {
IFrameHelper.events[message.event](message);
}
};
},
initWindowSizeListener: () => {
wootOn(window, 'resize', () => {
IFrameHelper.toggleCloseButton();
});
},
events: {
loaded: message => {
Cookies.set('cw_conversation', message.config.authToken, {
expires: 365,
});
window.$chatwoot.hasLoaded = true;
IFrameHelper.sendMessage('config-set', {});
IFrameHelper.onLoad(message.config.channelConfig);
IFrameHelper.setCurrentUrl();
IFrameHelper.toggleCloseButton();
if (window.$chatwoot.user) {
IFrameHelper.sendMessage('set-user', window.$chatwoot.user);
}
},
toggleBubble: () => {
onBubbleClick();
},
},
onLoad: ({ widget_color: widgetColor }) => {
const iframe = IFrameHelper.getAppFrame();
iframe.style.visibility = '';
iframe.setAttribute('id', `chatwoot_live_chat_widget`);
iframe.onmouseenter = disableScroll;
iframe.onmouseleave = enableScroll;
loadCSS();
createBubbleHolder();
if (!window.$chatwoot.hideMessageBubble) {
const chatIcon = createBubbleIcon({
className: 'woot-widget-bubble',
src: bubbleImg,
target: chatBubble,
});
const closeIcon = closeBubble;
closeIcon.className = 'woot-widget-bubble woot--close woot--hide';
chatIcon.style.background = widgetColor;
closeIcon.style.background = widgetColor;
bubbleHolder.appendChild(chatIcon);
bubbleHolder.appendChild(closeIcon);
bubbleHolder.appendChild(createNotificationBubble());
onClickChatBubble();
}
},
setCurrentUrl: () => {
IFrameHelper.sendMessage('set-current-url', {
refererURL: window.location.href,
});
},
toggleCloseButton: () => {
if (window.matchMedia('(max-width: 668px)').matches) {
IFrameHelper.sendMessage('toggle-close-button', { showClose: true });
} else {
IFrameHelper.sendMessage('toggle-close-button', { showClose: false });
}
},
};

View file

@ -0,0 +1,51 @@
import { addClass, toggleClass, wootOn } from './DOMHelpers';
export const bubbleImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg==';
export const body = document.getElementsByTagName('body')[0];
export const widgetHolder = document.createElement('div');
export const bubbleHolder = document.createElement('div');
export const chatBubble = document.createElement('div');
export const closeBubble = document.createElement('div');
export const notificationBubble = document.createElement('span');
const bodyOverFlowStyle = document.body.style.overflow;
export const createBubbleIcon = ({ className, src, target }) => {
target.className = className;
const bubbleIcon = document.createElement('img');
bubbleIcon.src = src;
target.appendChild(bubbleIcon);
return target;
};
export const createBubbleHolder = () => {
addClass(bubbleHolder, 'woot--bubble-holder');
body.appendChild(bubbleHolder);
};
export const createNotificationBubble = () => {
addClass(notificationBubble, 'woot--notification');
return notificationBubble;
};
export const onBubbleClick = () => {
window.$chatwoot.isOpen = !window.$chatwoot.isOpen;
toggleClass(chatBubble, 'woot--hide');
toggleClass(closeBubble, 'woot--hide');
toggleClass(widgetHolder, 'woot--hide');
};
export const onClickChatBubble = () => {
wootOn(bubbleHolder, 'click', onBubbleClick);
};
export const disableScroll = () => {
document.body.style.overflow = 'hidden';
};
export const enableScroll = () => {
document.body.style.overflow = bodyOverFlowStyle;
};