/******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./client/src/connect.ts"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./client/src/connect.ts": /*!*******************************!*\ !*** ./client/src/connect.ts ***! \*******************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var formatInput_1 = __webpack_require__(/*! ./lib/formatInput */ "./client/src/lib/formatInput.ts"); var camel_1 = __webpack_require__(/*! ./lib/camel */ "./client/src/lib/camel.ts"); var numberInEnrollment = null; var updateCount = 0; var resetUpdateCount = function () { updateCount = 0; }; var STATE = { CLOSED: 'CLOSED', OPEN: 'OPEN', SENDING: 'SENDING', SUCCESS: 'SUCCESS', FAILED: 'FAILED' }; var ButtonVariant; (function (ButtonVariant) { ButtonVariant["CTA"] = "cta"; ButtonVariant["PRODUCT"] = "product"; ButtonVariant["CHECKOUT"] = "checkout"; })(ButtonVariant || (ButtonVariant = {})); var OptIn; (function (OptIn) { OptIn["MODE"] = "MODE"; OptIn["KEYWORD"] = "KEYWORD"; })(OptIn || (OptIn = {})); var Connect = /** @class */ (function () { function Connect() { this.observer = null; this.hosts = []; this.preventCallback = false; this.site = ''; if (window.__connect__) { console.log('[connect] already loaded on page'); return; } window.__connect__ = true; // eslint-disable-next-line @typescript-eslint/camelcase window.__connect_requesting__ = false; for (var _i = 0, _a = Array.from(document.getElementsByTagName('script')); _i < _a.length; _i++) { var script = _a[_i]; var apiHost = (script.src.match(/(https?:\/\/([^/]*)\/mode-connect.*)\/client\/connect\.js/) || [])[1]; if (apiHost) { // eslint-disable-next-line @typescript-eslint/camelcase window.__connect_host__ = apiHost; } var siteId = (script.src.match(/https?:\/\/[^/]*\/mode-connect.*\/client\/connect\.js\?siteId=(.*)$/) || [])[1]; if (siteId) { // eslint-disable-next-line @typescript-eslint/camelcase window.__connect_site__ = siteId; } } document.addEventListener('DOMContentLoaded', this.loaded.bind(this)); console.log('[connect] initiated'); } Connect.prototype.loaded = function () { this.checkUserTag(); this.startObserver(); this.updateDom(); }; Connect.prototype.checkUserTag = function () { var userTag = Connect.getCookie('userTag'); if (!userTag) { var now = Date.now(); var salt = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); var tag = now + "-" + salt; Connect.setCookie('userTag', tag, 99999); } Connect.apiLog({ action: 'LOAD' }); }; Connect.prototype.startObserver = function () { var targetNode = document.getElementsByTagName('body')[0]; // Options for the observer (which mutations to observe) var config = { attributes: true, childList: true, subtree: true }; // Create an observer instance linked to the callback function this.observer = new MutationObserver(this.mutationCallback.bind(this)); // Start observing the target node for configured mutations this.observer.observe(targetNode, config); window.onbeforeunload = this.onBeforeUnload.bind(this); window.onunload = this.stopObserver.bind(this); }; Connect.prototype.stopObserver = function () { if (this.observer) { this.observer.disconnect(); } }; Connect.prototype.onBeforeUnload = function () { // Ask confirmation to leave the page, while a request is hanging if (window.__connect_requesting__) return ''; return undefined; }; Connect.prototype.renderDataModeChildren = function (node) { var _this = this; if (node instanceof Element) { if (node.hasAttribute('data-mode')) { var state = node.getAttribute('data-state'); this.render(node, state === STATE.OPEN || state === STATE.SENDING); return; } if (node.hasChildNodes()) { node.childNodes.forEach(function (node) { return _this.renderDataModeChildren(node); }); } } }; Connect.prototype.mutationCallback = function (mutations) { var _this = this; if (this.preventCallback || updateCount > 100) { return; } updateCount++; this.preventCallback = true; for (var _i = 0, mutations_1 = mutations; _i < mutations_1.length; _i++) { var mutation = mutations_1[_i]; if (mutation.type === 'childList') { // added/removed mutation.addedNodes.forEach(function (node) { return _this.renderDataModeChildren(node); }); // this.updateDom() } else if (mutation.type === 'attributes') { var target = mutation.target; this.renderDataModeChildren(target); } } this.preventCallback = false; }; Connect.prototype.updateDom = function () { var _this = this; var orderButtons = document.querySelectorAll('div[data-mode]'); orderButtons.forEach(function (button) { var id = button.hasAttribute('data-id') ? parseInt(button.getAttribute('data-id') || '') || -1 : -1; var state = button.getAttribute('data-state') || ''; if (id === -1) { button.setAttribute('data-id', "" + _this.hosts.length); } if (!state) { button.setAttribute('data-state', STATE.CLOSED); } _this.render(button); }); }; Connect.apiEnroll = function (phoneNumber, hostData) { return new Promise(function (resolve) { var req = new XMLHttpRequest(); req.open('POST', window.__connect_host__ + "/api/v1/enroll/+1" + phoneNumber); req.setRequestHeader('token', window.__connect_site__); req.send(JSON.stringify(hostData)); // eslint-disable-next-line @typescript-eslint/camelcase window.__connect_requesting__ = true; req.onreadystatechange = function () { if (req.readyState === 4) { // eslint-disable-next-line @typescript-eslint/camelcase window.__connect_requesting__ = false; resetUpdateCount(); resolve(req.responseText); } }; }); }; // no need to return a promise, since the script shouldn't hold for log responses Connect.apiLog = function (_a) { var action = _a.action, phone = _a.phone, buttonId = _a.buttonId, buttonVariant = _a.buttonVariant, details = _a.details; var siteId = window.__connect_site__; var phoneNumber = phone; var userTag = Connect.getCookie('userTag') || undefined; var data = { siteId: siteId, phoneNumber: phoneNumber, userTag: userTag, action: action, buttonId: buttonId, buttonVariant: buttonVariant, optIn: OptIn.MODE, details: details, userAgent: window && window.navigator ? window.navigator.userAgent : '', location: window && window.location ? window.location.href : '' }; var req = new XMLHttpRequest(); req.open('POST', window.__connect_host__ + "/api/v1/log"); req.setRequestHeader('token', siteId); req.send(JSON.stringify(data)); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Connect.scrapeCartProducts = function () { // This only works for shopify checkout page // find all elements with cart_row class and filter header out var rows = []; for (var _i = 0, _a = Array.from(document.getElementsByClassName('cart__row')); _i < _a.length; _i++) { var el = _a[_i]; if (el.tagName === 'TR') { rows.push(el); } } if (!rows.length) { return {}; } var products = []; // scrape each product title, price, quantity and url for (var _b = 0, rows_1 = rows; _b < rows_1.length; _b++) { var row = rows_1[_b]; products.push({ title: row.getAttribute('data-cart-item-title') || '', price: row.getAttribute('data-cart-item-price') || '', quantity: row.getAttribute('data-cart-item-quantity') || '', url: window.location.origin + row.getAttribute('data-cart-item-url') || '' }); } // scrape price subTotal var subTotalEls = document.getElementsByClassName('cart-subtotal__price'); if (subTotalEls) { var subTotal = subTotalEls[0].innerText.split(' ')[0]; if (subTotal) return { products: products, subTotal: subTotal }; } return { products: products }; }; Connect.getHostData = function (host) { var buttonVariant = host.getAttribute('data-button-variant') || ButtonVariant.CTA; var productsJson = ''; if (buttonVariant === ButtonVariant.PRODUCT) { productsJson = host.getAttribute('data-product') || host.getAttribute('data-product-name') || ''; } else if (buttonVariant === ButtonVariant.CHECKOUT) { var checkoutData = host.getAttribute('data-checkout-products') || host.getAttribute('data-product-variant-name') || ''; productsJson = JSON.stringify(checkoutData === 'scrape' ? this.scrapeCartProducts() : { products: checkoutData }); } return { location: window && window.location ? window.location.href : '', userAgent: window && window.navigator ? window.navigator.userAgent : '', store: host.getAttribute('data-store') || '', topProducts: host.getAttribute('data-top-products') || '', cartName: host.getAttribute('data-cart-name') || 'cart', buttonVariant: buttonVariant, productsJson: productsJson, optIn: OptIn.MODE }; }; Connect.parseAttributes = function (host, prefix, defaults) { return Object.keys(defaults).reduce(function (values, attr) { var name = prefix ? prefix + "-" + camel_1.fromCamelCase(attr) : camel_1.fromCamelCase(attr); values[attr] = (host.hasAttribute(name) ? host.getAttribute(name) : defaults[attr]) || ''; return values; }, {}); }; Connect.prototype.render = function (host, focusInput) { if (focusInput === void 0) { focusInput = false; } var store = host.getAttribute('data-store'); var attrs = { policies: Connect.parseAttributes(host, 'data-policy', { tos: 'https://stylust.com/terms/', privacy: 'https://stylust.com/privacy/' }), labels: Connect.parseAttributes(host, 'data-label', { button: 'Buy Via Text', enter: 'Go', success: 'Cheers! We\'ll send a text message shortly to get a drink in your hand', failed: 'Ops! Try again later' }), placeholders: Connect.parseAttributes(host, 'data-placeholder', { phone: 'Mobile Number' }), help: Connect.parseAttributes(host, 'data-help', { enroll: "Buy " + store + " via text message:", sending: 'Sending...' }), class: Connect.parseAttributes(host, 'data', { class: '' }).class }; var id = host.getAttribute('data-id'); if (!id) { this.hosts.push(host); host.setAttribute('data-id', "" + (this.hosts.length - 1)); id = host.getAttribute('data-id'); } var state = host.getAttribute('data-state'); if (!state) { host.setAttribute('data-state', STATE.CLOSED); state = STATE.CLOSED; } var clx = attrs.class; // eslint-disable-next-line @typescript-eslint/camelcase var clickable = !window.__connect_requesting__ && [STATE.CLOSED, STATE.OPEN].includes(state); var showButton = state === STATE.CLOSED; var showInput = [STATE.OPEN, STATE.SENDING].includes(state); if (showButton) { var buttonLabel = attrs.labels.button; host.innerHTML = "\n \n "; } else if (showInput) { var helpMessage = state === STATE.SENDING ? attrs.help.sending : attrs.help.enroll; var sending = state === STATE.SENDING; var value = numberInEnrollment && !clickable ? numberInEnrollment : ''; host.innerHTML = "\n