{"version":3,"sources":["webpack:///chat-banner-b36e10c3fbb944f9d5fa.js","webpack:///webpack/bootstrap bada3fc95fc820b6f189","webpack:///./components/chat-banner/chat-banner.js","webpack:///./src/js/lib/text_anim.js"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","object","property","prototype","hasOwnProperty","p","s","121","122","__webpack_exports__","_toConsumableArray","arr","Array","isArray","arr2","length","from","_classCallCheck","instance","Constructor","TypeError","_possibleConstructorReturn","self","ReferenceError","_inherits","subClass","superClass","create","constructor","value","writable","setPrototypeOf","__proto__","__WEBPACK_IMPORTED_MODULE_0__src_js_lib_text_anim__","_createClass","defineProperties","target","props","descriptor","key","protoProps","staticProps","_get","receiver","Function","desc","getOwnPropertyDescriptor","undefined","parent","getPrototypeOf","_window$Liftoff","window","Liftoff","Component","DOMUtils","Utils","register","_Component","ChatBanner","config","this","_this","assign","mergePropertiesWithDefaults","charAnimationInterval","passButton","likeButton","isInteractive","buttonAnimation","messageShouldType","photoShouldPulse","showMessageCount","photoStyles","captionStyles","buttonStyles","messageCountStyle","people","filter","_ref","image","map","person","personData","caption","personEl","captionEl","currentTextTypingIndex","currentlyTyping","startIfReady","loading","animating","buttonAnimationTimeout","peopleSwitchTimeout","currentPersonIndex","passButtonEl","likeButtonEl","switchPeople","numLikes","numPasses","imagesLoadedPromises","_ref2","concat","url","loadImage","imagesLoadedPromise","Promise","all","sliceResult","captionDom","tree","captionDomLen","parentNode","_this2","el","strToElement","TEMPLATE","peopleEl","querySelector","PERSON_TEMPLATE","imageEl","src","style","messageCountEl","classList","toggle","curIndex","getPersonCaptionLen","setPersonCaption","appendChild","forEach","_ref3","add","remove","then","imagesRenderedPromises","querySelectorAll","img","imageIsRendered","catch","finally","resizeFont","addEventListeners","start","_this3","_ref4","innerHTML","getFontSizeToFit","tempClass","fontSize","fontSizeThatFits","Math","min","apply","_ref5","clearTimeout","animateNextWhenReady","direction","arguments","setAnimationStartClasses","classes","className","forceReflow","currentPerson","nextPerson","resetTypingMessage","emit","_this4","messageTypeTime","timeToSwitch","max","setTimeout","animateNext","_this5","addNextLetter","_this6","stopButtonAnimation","startButtonAnimation","stopSwitchingPeople","startSwitchingPeople","_this7","addEventListener","e","animationDirection","contains","recordInteraction","totalChoicesMade","passes","likes","choices","stop","startTyping","startPhotoAnimation","stopTyping","stopPhotoAnimation","123","30","domCountCharacters","domSlice","moveChildrenFromNode","getTextDom","isVariationSelector","cstr","code","charCodeAt","mergeVariationSelectors","unicodechars","reduce","acc","push","unicodeLen","str","unicodeSlice","slice","join","nodeType","Node","TEXT_NODE","nodeValue","numChars","hasChildNodes","childNodes","child","charcount","text","textLen","numCharsToPreserve","newText","document","createTextNode","charCount","ret","cloneNode","children","slicedChild","textContent","dstnode","srcnode","empty","firstChild","removeChild","div","createElement"],"mappings":"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","file":"chat-banner-b36e10c3fbb944f9d5fa.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 121);\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ 121:\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(122);\nmodule.exports = __webpack_require__(123);\n\n\n/***/ }),\n\n/***/ 122:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_js_lib_text_anim__ = __webpack_require__(30);\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if (\"value\" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\n\n\nvar _window$Liftoff = window.Liftoff,\n Component = _window$Liftoff.Component,\n DOMUtils = _window$Liftoff.DOMUtils,\n Utils = _window$Liftoff.Utils;\n\n// Duration (in ms) of gap between restarts of the typing effect.\n\nvar RESTART_TYPING_INTERVAL = 3000;\n// Minimum interval (in ms) between switching profiles/captions.\nvar PEOPLE_SWITCH_INTERVAL = 3200;\n// Minimum time to show a person _after_ the message has completely finished typing.\nvar MIN_MESSAGE_DISPLAY_TIME = 1000;\n// Interval (in ms) after which to restart the button animation if the user hasn't interacted.\nvar BUTTON_ANIMATION_INTERACTION_DELAY = 3000;\n// Interval (in ms) after which to restart the profile switching animation if the user hasn't interacted.\nvar PEOPLE_SWITCH_INTERACTION_DELAY = 8000;\n// Duration of the transition between people. Used to delay the message typing effect to only start typing\n// after the person has fully transitioned in.\nvar PERSON_TRANSITION_DURATION = 500;\n\nvar TEMPLATE = \"\\n <div class=\\\"chat-banner loading\\\">\\n <div class=\\\"people\\\"></div>\\n <div class=\\\"buttons\\\">\\n <img class=\\\"pass-button\\\" />\\n <img class=\\\"like-button\\\" />\\n </div>\\n </div>\\n\";\nvar PERSON_TEMPLATE = \"\\n <div class=\\\"person\\\">\\n <div class=\\\"photo-container\\\">\\n <img class=\\\"profile-photo\\\" />\\n <div class=\\\"message-count\\\">1</div>\\n </div>\\n <div class=\\\"caption\\\"></div>\\n </div>\\n\";\n\nComponent.register(\"chat-banner\", function (_Component) {\n _inherits(ChatBanner, _Component);\n\n function ChatBanner(config) {\n _classCallCheck(this, ChatBanner);\n\n var _this = _possibleConstructorReturn(this, (ChatBanner.__proto__ || Object.getPrototypeOf(ChatBanner)).call(this, config));\n\n Object.assign(_this, Utils.mergePropertiesWithDefaults({\n charAnimationInterval: 50,\n passButton: null,\n likeButton: null,\n isInteractive: false,\n buttonAnimation: \"alternate growing\",\n messageShouldType: true,\n photoShouldPulse: true,\n showMessageCount: true\n }, config));\n _this.photoStyles = config.photoStyles || {};\n _this.captionStyles = config.captionStyles || {};\n _this.buttonStyles = config.buttonStyles || {};\n _this.messageCountStyle = config.messageCountStyle || {};\n _this.people = (config.people || []).filter(function (_ref) {\n var image = _ref.image;\n return image != null;\n }).map(function (person) {\n var personData = Object.assign({\n image: null,\n caption: \"\",\n personEl: null,\n captionEl: null,\n currentTextTypingIndex: 0,\n currentlyTyping: false\n }, person);\n personData.caption = personData.caption || \"\";\n return personData;\n });\n _this.startIfReady = false;\n _this.loading = true;\n _this.animating = false;\n // Timeout for restarting button animation after user interaction.\n _this.buttonAnimationTimeout = null;\n // Timeout for restarting automatic people switching after user interaction.\n _this.peopleSwitchTimeout = null;\n _this.currentPersonIndex = 0;\n _this.passButtonEl = null;\n _this.likeButtonEl = null;\n _this.switchPeople = true;\n _this.numLikes = 0;\n _this.numPasses = 0;\n return _this;\n }\n\n _createClass(ChatBanner, [{\n key: \"load\",\n value: function load() {\n var imagesLoadedPromises = this.people.map(function (_ref2) {\n var image = _ref2.image;\n return image;\n }).concat([this.passButton, this.likeButton]).filter(function (url) {\n return url;\n }).map(function (url) {\n return Utils.loadImage(url);\n });\n this.imagesLoadedPromise = Promise.all(imagesLoadedPromises);\n return this.imagesLoadedPromise;\n }\n\n // Proper way to set the contents of a person's caption element.\n\n }, {\n key: \"setPersonCaption\",\n value: function setPersonCaption(person, currentTextTypingIndex) {\n var captionEl = person.captionEl;\n\n var sliceResult = __WEBPACK_IMPORTED_MODULE_0__src_js_lib_text_anim__[\"b\" /* domSlice */](person.captionDom, currentTextTypingIndex);\n\n __WEBPACK_IMPORTED_MODULE_0__src_js_lib_text_anim__[\"d\" /* moveChildrenFromNode */](captionEl, sliceResult.tree);\n }\n\n // Proper way to read the number of \"typable\" characters in a person's caption element.\n\n }, {\n key: \"getPersonCaptionLen\",\n value: function getPersonCaptionLen(person) {\n return person.captionDomLen;\n }\n }, {\n key: \"layout\",\n value: function layout(parentNode) {\n var _this2 = this;\n\n _get(ChatBanner.prototype.__proto__ || Object.getPrototypeOf(ChatBanner.prototype), \"layout\", this).call(this, parentNode);\n this.el = DOMUtils.strToElement(TEMPLATE);\n this.peopleEl = this.el.querySelector(\".people\");\n this.people = this.people.map(function (person) {\n var caption = person.caption,\n image = person.image;\n\n var personEl = person.personEl = DOMUtils.strToElement(PERSON_TEMPLATE);\n var imageEl = person.imageEl = personEl.querySelector(\".profile-photo\");\n var captionEl = person.captionEl = personEl.querySelector(\".caption\");\n imageEl.src = image;\n Object.assign(imageEl.style, _this2.photoStyles);\n\n var messageCountEl = personEl.querySelector(\".message-count\");\n messageCountEl.classList.toggle(\"visible\", _this2.showMessageCount);\n Object.assign(messageCountEl.style, _this2.messageCountStyle);\n\n person.captionDom = __WEBPACK_IMPORTED_MODULE_0__src_js_lib_text_anim__[\"c\" /* getTextDom */](caption);\n person.captionDomLen = __WEBPACK_IMPORTED_MODULE_0__src_js_lib_text_anim__[\"a\" /* domCountCharacters */](person.captionDom);\n\n var curIndex = _this2.messageShouldType ? 0 : _this2.getPersonCaptionLen(person);\n _this2.setPersonCaption(person, curIndex);\n Object.assign(captionEl.style, _this2.captionStyles);\n person.currentTextTypingIndex = curIndex;\n _this2.peopleEl.appendChild(person.personEl);\n return person;\n });\n\n if (this.people.length > 0) {\n this.people.forEach(function (_ref3, i) {\n var personEl = _ref3.personEl;\n\n if (i === _this2.currentPersonIndex) return;\n personEl.classList.add(\"staged\", \"down\");\n });\n }\n\n this.passButtonEl = this.el.querySelector(\".pass-button\");\n if (this.passButton != null) {\n this.passButtonEl.src = this.passButton;\n Object.assign(this.passButtonEl.style, this.buttonStyles);\n } else {\n this.passButtonEl.remove();\n }\n\n this.likeButtonEl = this.el.querySelector(\".like-button\");\n if (this.likeButton != null) {\n this.likeButtonEl.src = this.likeButton;\n Object.assign(this.likeButtonEl.style, this.buttonStyles);\n } else {\n this.likeButtonEl.remove();\n }\n\n this.parentNode.appendChild(this.el);\n // If the user doesn't explicitly set the caption font size, then size automatically so that the longest\n // message fits completely. All images must have non-zero widths/heights (i.e. be fully rendered) in order\n // to accurately determine font size. Wrap in the imagesLoaded promise so the imagesRenderedPromise time-\n // out starts after all images are loaded.\n var imagesRenderedPromise = this.imagesLoadedPromise.then(function () {\n var imagesRenderedPromises = [].concat(_toConsumableArray(_this2.el.querySelectorAll(\"img\"))).map(function (img) {\n return DOMUtils.imageIsRendered(img, 1000);\n });\n\n // TODO(brian): Investigate how this promise can reject.\n return Promise.all(imagesRenderedPromises).catch(function () {});\n });\n\n imagesRenderedPromise.finally(function () {\n _this2.resizeFont();\n _this2.addEventListeners();\n _this2.loading = false;\n _this2.el.classList.remove(\"loading\");\n if (_this2.startIfReady) {\n _this2.start();\n }\n });\n }\n }, {\n key: \"resizeFont\",\n value: function resizeFont() {\n var _this3 = this;\n\n if (this.captionStyles[\"font-size\"] != null) return;\n this.people.forEach(function (_ref4) {\n var captionEl = _ref4.captionEl,\n caption = _ref4.caption;\n return captionEl.innerHTML = caption;\n });\n\n // Same as DOMUtils.getFontSizeToFit, but applies a class to the element temporarily.\n //\n // RATIONALE:\n // We need to do this because, in chat-banner.less, we unset the \"display: flex\" style for the caption\n // element and its children. And we set \"height: auto\" to bring the caption back into vertical centering.\n // But this breaks the algorithm used by DOMUtils.getFontSizeToFit. So we temporarily set \"height: 100%\"\n // while resizing.\n var getFontSizeToFit = function getFontSizeToFit(el, tempClass) {\n el.classList.add(tempClass);\n var fontSize = DOMUtils.getFontSizeToFit(el);\n el.classList.remove(tempClass);\n return fontSize;\n };\n\n var fontSizeThatFits = Math.min.apply(Math, _toConsumableArray(this.people.map(function (_ref5) {\n var captionEl = _ref5.captionEl;\n return getFontSizeToFit(captionEl, \"during-resize\");\n })));\n\n this.people.forEach(function (person) {\n var captionEl = person.captionEl,\n currentTextTypingIndex = person.currentTextTypingIndex;\n\n\n _this3.setPersonCaption(person, currentTextTypingIndex);\n\n captionEl.style.fontSize = fontSizeThatFits + \"px\";\n });\n }\n }, {\n key: \"startButtonAnimation\",\n value: function startButtonAnimation() {\n if (this.buttonAnimation === \"alternate growing\") {\n if (this.likeButton != null) {\n this.likeButtonEl.classList.add(\"alternate-growing\");\n }\n\n if (this.passButton != null) {\n this.passButtonEl.classList.add(\"alternate-growing\");\n }\n } else if (this.buttonAnimation === \"pulse like\" && this.likeButton != null) {\n this.likeButtonEl.classList.add(\"pulse\");\n }\n }\n }, {\n key: \"stopButtonAnimation\",\n value: function stopButtonAnimation() {\n clearTimeout(this.buttonAnimationTimeout);\n if (this.passButton != null) {\n this.passButtonEl.classList.remove(\"alternate-growing\");\n }\n\n if (this.likeButton != null) {\n this.likeButtonEl.classList.remove(\"alternate-growing\");\n this.likeButtonEl.classList.remove(\"pulse\");\n }\n }\n }, {\n key: \"startSwitchingPeople\",\n value: function startSwitchingPeople() {\n this.switchPeople = true;\n this.animateNextWhenReady();\n }\n }, {\n key: \"stopSwitchingPeople\",\n value: function stopSwitchingPeople() {\n this.switchPeople = false;\n clearTimeout(this.peopleSwitchTimeout);\n }\n }, {\n key: \"startPhotoAnimation\",\n value: function startPhotoAnimation() {\n if (!this.photoShouldPulse) return;\n [].concat(_toConsumableArray(this.el.querySelectorAll(\".profile-photo\"))).forEach(function (el) {\n return el.classList.add(\"pulse\");\n });\n }\n }, {\n key: \"stopPhotoAnimation\",\n value: function stopPhotoAnimation() {\n if (!this.photoShouldPulse) return;\n [].concat(_toConsumableArray(this.el.querySelectorAll(\".profile-photo\"))).forEach(function (el) {\n return el.classList.remove(\"pulse\");\n });\n }\n\n /** @param {(\"up\"|\"down\"|\"left\"|\"right\")} direction - Animates the current person out and the next\n person in given a particular animation direction. */\n\n }, {\n key: \"animateNext\",\n value: function animateNext() {\n var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : \"up\";\n\n if (this.people.length <= 1) return;\n var setAnimationStartClasses = function setAnimationStartClasses(el, classes) {\n // Set classes that specify the element's starting position for the animation.\n [\"staged\", \"exited\", \"up\", \"right\", \"down\", \"left\"].forEach(function (className) {\n return el.classList.remove(className);\n });\n classes.forEach(function (className) {\n return el.classList.add(className);\n });\n DOMUtils.forceReflow(el);\n };\n\n var currentPerson = this.people[this.currentPersonIndex];\n this.currentPersonIndex = (this.currentPersonIndex + 1) % this.people.length;\n var nextPerson = this.people[this.currentPersonIndex];\n setAnimationStartClasses(currentPerson.personEl, [direction]);\n setAnimationStartClasses(nextPerson.personEl, [direction, \"staged\"]);\n // Start the animation by transitioning the current element into the \"exited\" position and the next\n // element into the visible (non-\"staged\", non-\"exited\") position.\n currentPerson.personEl.classList.add(\"exited\");\n nextPerson.personEl.classList.remove(\"staged\");\n DOMUtils.forceReflow(this.peopleEl);\n if (this.messageShouldType) {\n currentPerson.currentlyTyping = false;\n nextPerson.currentlyTyping = true;\n this.resetTypingMessage(nextPerson);\n }\n\n this.emit(\"personChanged\");\n this.animateNextWhenReady(direction);\n }\n }, {\n key: \"animateNextWhenReady\",\n value: function animateNextWhenReady() {\n var _this4 = this;\n\n var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : \"up\";\n\n if (!this.switchPeople || this.people.length <= 1) return;\n var currentPerson = this.people[this.currentPersonIndex];\n var messageTypeTime = this.messageShouldType ? this.getPersonCaptionLen(currentPerson) * this.charAnimationInterval : 0;\n var timeToSwitch = Math.max(PEOPLE_SWITCH_INTERVAL, PERSON_TRANSITION_DURATION + messageTypeTime + MIN_MESSAGE_DISPLAY_TIME);\n this.peopleSwitchTimeout = setTimeout(function () {\n return _this4.animateNext(direction);\n }, timeToSwitch);\n }\n }, {\n key: \"resetTypingMessage\",\n value: function resetTypingMessage(person) {\n var _this5 = this;\n\n if (!person.currentlyTyping) return;\n person.currentTextTypingIndex = 0;\n person.captionEl.innerHTML = \"\";\n var addNextLetter = function addNextLetter() {\n if (!person.currentlyTyping) {\n person.captionEl.innerHTML = person.caption;\n return;\n }\n\n if (person.currentTextTypingIndex < _this5.getPersonCaptionLen(person)) {\n _this5.setPersonCaption(person, person.currentTextTypingIndex + 1);\n\n person.currentTextTypingIndex += 1;\n setTimeout(addNextLetter, _this5.charAnimationInterval);\n } else {\n setTimeout(function () {\n return _this5.resetTypingMessage(person);\n }, RESTART_TYPING_INTERVAL);\n }\n };\n\n setTimeout(addNextLetter, PERSON_TRANSITION_DURATION);\n }\n }, {\n key: \"startTyping\",\n value: function startTyping() {\n if (!this.messageShouldType || this.people.length < 1) return;\n var currentPerson = this.people[this.currentPersonIndex];\n currentPerson.currentlyTyping = true;\n this.resetTypingMessage(currentPerson);\n }\n }, {\n key: \"stopTyping\",\n value: function stopTyping() {\n this.people.forEach(function (person) {\n person.currentlyTyping = false;\n });\n }\n }, {\n key: \"recordInteraction\",\n value: function recordInteraction() {\n var _this6 = this;\n\n _get(ChatBanner.prototype.__proto__ || Object.getPrototypeOf(ChatBanner.prototype), \"recordInteraction\", this).call(this);\n this.stopButtonAnimation();\n this.buttonAnimationTimeout = setTimeout(function () {\n return _this6.startButtonAnimation();\n }, BUTTON_ANIMATION_INTERACTION_DELAY);\n this.stopSwitchingPeople();\n this.peopleSwitchTimeout = setTimeout(function () {\n return _this6.startSwitchingPeople();\n }, PEOPLE_SWITCH_INTERACTION_DELAY);\n }\n }, {\n key: \"addEventListeners\",\n value: function addEventListeners() {\n var _this7 = this;\n\n if (!this.isInteractive || this.people.length === 0) return;\n this.el.querySelector(\".buttons\").addEventListener(\"click\", function (e) {\n var animationDirection = void 0;\n if (e.target.classList.contains(\"pass-button\")) {\n _this7.numPasses += 1;\n animationDirection = \"left\";\n } else if (e.target.classList.contains(\"like-button\")) {\n _this7.numLikes += 1;\n animationDirection = \"right\";\n } else {\n return;\n }\n\n _this7.recordInteraction();\n _this7.animateNext(animationDirection);\n\n var totalChoicesMade = _this7.numPasses + _this7.numLikes;\n _this7.emit(\"passedOrLiked\", {\n passes: _this7.numPasses,\n likes: _this7.numLikes,\n choices: totalChoicesMade\n });\n // The allChoicesMade event is emitted when the user has liked or passed as many people as there are.\n // Since the animation runs in a loop automatically if the user doesn't interact, the choices aren't\n // necessarily for distinct people.\n if (_this7.people.length === totalChoicesMade) {\n _this7.emit(\"allChoicesMade\");\n }\n });\n }\n }, {\n key: \"resize\",\n value: function resize() {\n this.resizeFont();\n }\n }, {\n key: \"restart\",\n value: function restart() {\n this.stop();\n this.start();\n }\n }, {\n key: \"start\",\n value: function start() {\n this.startIfReady = true;\n if (this.loading || this.animating) return;\n this.animating = true;\n this.startButtonAnimation();\n this.startTyping();\n this.startPhotoAnimation();\n this.startSwitchingPeople();\n }\n }, {\n key: \"stop\",\n value: function stop() {\n this.startIfReady = false;\n this.stopButtonAnimation();\n this.stopTyping();\n this.stopPhotoAnimation();\n this.stopSwitchingPeople();\n this.animating = false;\n }\n }]);\n\n return ChatBanner;\n}(Component));\n\n/***/ }),\n\n/***/ 123:\n/***/ (function(module, exports) {\n\n// removed by extract-text-webpack-plugin\n\n/***/ }),\n\n/***/ 30:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* unused harmony export unicodeLen */\n/* unused harmony export unicodeSlice */\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return domCountCharacters; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return domSlice; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"d\", function() { return moveChildrenFromNode; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"c\", function() { return getTextDom; });\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nvar DOMUtils = window.Liftoff.DOMUtils;\n\n\nvar isVariationSelector = function isVariationSelector(cstr) {\n if (cstr.length !== 1) {\n return false;\n }\n\n var code = cstr.charCodeAt(0);\n\n return 0xfe00 <= code && code <= 0xfe0f;\n};\n\n// Expects an array generated by [...str].\n// Merges variation selectors into the previous character so that they do not occupy their own slot in the\n// array.\n// REFERENCE: See\n// - https://blog.jonnew.com/posts/poo-dot-length-equals-two\n// - https://codepoints.net/U+fe0f\n// - https://codepoints.net/variation_selectors\nvar mergeVariationSelectors = function mergeVariationSelectors(unicodechars) {\n return unicodechars.reduce(function (acc, cstr) {\n if (acc.length > 0 && isVariationSelector(cstr)) {\n acc[acc.length - 1] += cstr;\n } else {\n acc.push(cstr);\n }\n return acc;\n }, []);\n};\n\nvar unicodeLen = function unicodeLen(str) {\n return mergeVariationSelectors([].concat(_toConsumableArray(str))).length;\n};\n\n// Returns a string consisting of the leftmost 'n' Unicode characters of 'str'.\nvar unicodeSlice = function unicodeSlice(str, n) {\n return mergeVariationSelectors([].concat(_toConsumableArray(str))).slice(0, n).join(\"\");\n};\n\nvar domCountCharacters = function domCountCharacters(tree) {\n if (tree == null) {\n return 0;\n }\n\n if (tree.nodeType === Node.TEXT_NODE) {\n return unicodeLen(tree.nodeValue);\n }\n\n var numChars = 0;\n\n if (tree.hasChildNodes()) {\n [].concat(_toConsumableArray(tree.childNodes)).forEach(function (child) {\n numChars += domCountCharacters(child);\n });\n }\n\n return numChars;\n};\n\n// Return a copy of the tree, such that only the leftmost n characters in the text elements are preserved.\n//\n// The return value includes the new tree and the number of characters in it.\n//\nvar domSlice = function domSlice(tree, n) {\n if (tree == null) {\n return { tree: null, charcount: 0 };\n }\n\n if (tree.nodeType === Node.TEXT_NODE) {\n var text = tree.nodeValue;\n var textLen = unicodeLen(text);\n var numCharsToPreserve = Math.min(n, textLen);\n var newText = unicodeSlice(text, numCharsToPreserve);\n\n return {\n tree: document.createTextNode(newText),\n charCount: numCharsToPreserve\n };\n }\n\n var ret = {\n tree: tree.cloneNode(false),\n charCount: 0\n };\n\n if (tree.hasChildNodes()) {\n var children = [].concat(_toConsumableArray(tree.childNodes));\n children.forEach(function (child) {\n var slicedChild = domSlice(child, n - ret.charCount);\n\n ret.charCount += slicedChild.charCount;\n\n if (slicedChild.charCount > 0 || child.textContent.length === 0) {\n ret.tree.appendChild(slicedChild.tree);\n }\n });\n }\n\n return ret;\n};\n\n// Removes any children of dstnode and moves the children of srcnode into dstnode.\nvar moveChildrenFromNode = function moveChildrenFromNode(dstnode, srcnode) {\n dstnode = DOMUtils.empty(dstnode);\n\n while (srcnode.firstChild) {\n var child = srcnode.removeChild(srcnode.firstChild);\n\n dstnode.appendChild(child);\n }\n\n return dstnode;\n};\n\nvar getTextDom = function getTextDom(caption) {\n var div = document.createElement(\"div\");\n div.innerHTML = caption;\n\n return div;\n};\n\n/***/ })\n\n/******/ });\n\n\n// WEBPACK FOOTER //\n// chat-banner-b36e10c3fbb944f9d5fa.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 121);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap bada3fc95fc820b6f189","import * as TextAnim from \"../../src/js/lib/text_anim\";\n\nconst { Component, DOMUtils, Utils } = window.Liftoff;\n\n// Duration (in ms) of gap between restarts of the typing effect.\nconst RESTART_TYPING_INTERVAL = 3000;\n// Minimum interval (in ms) between switching profiles/captions.\nconst PEOPLE_SWITCH_INTERVAL = 3200;\n// Minimum time to show a person _after_ the message has completely finished typing.\nconst MIN_MESSAGE_DISPLAY_TIME = 1000;\n// Interval (in ms) after which to restart the button animation if the user hasn't interacted.\nconst BUTTON_ANIMATION_INTERACTION_DELAY = 3000;\n// Interval (in ms) after which to restart the profile switching animation if the user hasn't interacted.\nconst PEOPLE_SWITCH_INTERACTION_DELAY = 8000;\n// Duration of the transition between people. Used to delay the message typing effect to only start typing\n// after the person has fully transitioned in.\nconst PERSON_TRANSITION_DURATION = 500;\n\nconst TEMPLATE = `\n <div class=\"chat-banner loading\">\n <div class=\"people\"></div>\n <div class=\"buttons\">\n <img class=\"pass-button\" />\n <img class=\"like-button\" />\n </div>\n </div>\n`;\nconst PERSON_TEMPLATE = `\n <div class=\"person\">\n <div class=\"photo-container\">\n <img class=\"profile-photo\" />\n <div class=\"message-count\">1</div>\n </div>\n <div class=\"caption\"></div>\n </div>\n`;\n\nComponent.register(\n \"chat-banner\",\n class ChatBanner extends Component {\n constructor(config) {\n super(config);\n Object.assign(\n this,\n Utils.mergePropertiesWithDefaults(\n {\n charAnimationInterval: 50,\n passButton: null,\n likeButton: null,\n isInteractive: false,\n buttonAnimation: \"alternate growing\",\n messageShouldType: true,\n photoShouldPulse: true,\n showMessageCount: true,\n },\n config\n )\n );\n this.photoStyles = config.photoStyles || {};\n this.captionStyles = config.captionStyles || {};\n this.buttonStyles = config.buttonStyles || {};\n this.messageCountStyle = config.messageCountStyle || {};\n this.people = (config.people || [])\n .filter(({ image }) => image != null)\n .map((person) => {\n const personData = Object.assign(\n {\n image: null,\n caption: \"\",\n personEl: null,\n captionEl: null,\n currentTextTypingIndex: 0,\n currentlyTyping: false,\n },\n person\n );\n personData.caption = personData.caption || \"\";\n return personData;\n });\n this.startIfReady = false;\n this.loading = true;\n this.animating = false;\n // Timeout for restarting button animation after user interaction.\n this.buttonAnimationTimeout = null;\n // Timeout for restarting automatic people switching after user interaction.\n this.peopleSwitchTimeout = null;\n this.currentPersonIndex = 0;\n this.passButtonEl = null;\n this.likeButtonEl = null;\n this.switchPeople = true;\n this.numLikes = 0;\n this.numPasses = 0;\n }\n\n load() {\n const imagesLoadedPromises = this.people\n .map(({ image }) => image)\n .concat([this.passButton, this.likeButton])\n .filter((url) => url)\n .map((url) => Utils.loadImage(url));\n this.imagesLoadedPromise = Promise.all(imagesLoadedPromises);\n return this.imagesLoadedPromise;\n }\n\n // Proper way to set the contents of a person's caption element.\n setPersonCaption(person, currentTextTypingIndex) {\n const captionEl = person.captionEl;\n\n const sliceResult = TextAnim.domSlice(\n person.captionDom,\n currentTextTypingIndex\n );\n\n TextAnim.moveChildrenFromNode(captionEl, sliceResult.tree);\n }\n\n // Proper way to read the number of \"typable\" characters in a person's caption element.\n getPersonCaptionLen(person) {\n return person.captionDomLen;\n }\n\n layout(parentNode) {\n super.layout(parentNode);\n this.el = DOMUtils.strToElement(TEMPLATE);\n this.peopleEl = this.el.querySelector(\".people\");\n this.people = this.people.map((person) => {\n const { caption, image } = person;\n const personEl = (person.personEl =\n DOMUtils.strToElement(PERSON_TEMPLATE));\n const imageEl = (person.imageEl =\n personEl.querySelector(\".profile-photo\"));\n const captionEl = (person.captionEl =\n personEl.querySelector(\".caption\"));\n imageEl.src = image;\n Object.assign(imageEl.style, this.photoStyles);\n\n const messageCountEl = personEl.querySelector(\".message-count\");\n messageCountEl.classList.toggle(\"visible\", this.showMessageCount);\n Object.assign(messageCountEl.style, this.messageCountStyle);\n\n person.captionDom = TextAnim.getTextDom(caption);\n person.captionDomLen = TextAnim.domCountCharacters(person.captionDom);\n\n const curIndex = this.messageShouldType\n ? 0\n : this.getPersonCaptionLen(person);\n this.setPersonCaption(person, curIndex);\n Object.assign(captionEl.style, this.captionStyles);\n person.currentTextTypingIndex = curIndex;\n this.peopleEl.appendChild(person.personEl);\n return person;\n });\n\n if (this.people.length > 0) {\n this.people.forEach(({ personEl }, i) => {\n if (i === this.currentPersonIndex) return;\n personEl.classList.add(\"staged\", \"down\");\n });\n }\n\n this.passButtonEl = this.el.querySelector(\".pass-button\");\n if (this.passButton != null) {\n this.passButtonEl.src = this.passButton;\n Object.assign(this.passButtonEl.style, this.buttonStyles);\n } else {\n this.passButtonEl.remove();\n }\n\n this.likeButtonEl = this.el.querySelector(\".like-button\");\n if (this.likeButton != null) {\n this.likeButtonEl.src = this.likeButton;\n Object.assign(this.likeButtonEl.style, this.buttonStyles);\n } else {\n this.likeButtonEl.remove();\n }\n\n this.parentNode.appendChild(this.el);\n // If the user doesn't explicitly set the caption font size, then size automatically so that the longest\n // message fits completely. All images must have non-zero widths/heights (i.e. be fully rendered) in order\n // to accurately determine font size. Wrap in the imagesLoaded promise so the imagesRenderedPromise time-\n // out starts after all images are loaded.\n const imagesRenderedPromise = this.imagesLoadedPromise.then(() => {\n const imagesRenderedPromises = [...this.el.querySelectorAll(\"img\")].map(\n (img) => {\n return DOMUtils.imageIsRendered(img, 1000);\n }\n );\n\n // TODO(brian): Investigate how this promise can reject.\n return Promise.all(imagesRenderedPromises).catch(() => {});\n });\n\n imagesRenderedPromise.finally(() => {\n this.resizeFont();\n this.addEventListeners();\n this.loading = false;\n this.el.classList.remove(\"loading\");\n if (this.startIfReady) {\n this.start();\n }\n });\n }\n\n resizeFont() {\n if (this.captionStyles[\"font-size\"] != null) return;\n this.people.forEach(\n ({ captionEl, caption }) => (captionEl.innerHTML = caption)\n );\n\n // Same as DOMUtils.getFontSizeToFit, but applies a class to the element temporarily.\n //\n // RATIONALE:\n // We need to do this because, in chat-banner.less, we unset the \"display: flex\" style for the caption\n // element and its children. And we set \"height: auto\" to bring the caption back into vertical centering.\n // But this breaks the algorithm used by DOMUtils.getFontSizeToFit. So we temporarily set \"height: 100%\"\n // while resizing.\n const getFontSizeToFit = (el, tempClass) => {\n el.classList.add(tempClass);\n const fontSize = DOMUtils.getFontSizeToFit(el);\n el.classList.remove(tempClass);\n return fontSize;\n };\n\n const fontSizeThatFits = Math.min(\n ...this.people.map(({ captionEl }) =>\n getFontSizeToFit(captionEl, \"during-resize\")\n )\n );\n\n this.people.forEach((person) => {\n const { captionEl, currentTextTypingIndex } = person;\n\n this.setPersonCaption(person, currentTextTypingIndex);\n\n captionEl.style.fontSize = `${fontSizeThatFits}px`;\n });\n }\n\n startButtonAnimation() {\n if (this.buttonAnimation === \"alternate growing\") {\n if (this.likeButton != null) {\n this.likeButtonEl.classList.add(\"alternate-growing\");\n }\n\n if (this.passButton != null) {\n this.passButtonEl.classList.add(\"alternate-growing\");\n }\n } else if (\n this.buttonAnimation === \"pulse like\" &&\n this.likeButton != null\n ) {\n this.likeButtonEl.classList.add(\"pulse\");\n }\n }\n\n stopButtonAnimation() {\n clearTimeout(this.buttonAnimationTimeout);\n if (this.passButton != null) {\n this.passButtonEl.classList.remove(\"alternate-growing\");\n }\n\n if (this.likeButton != null) {\n this.likeButtonEl.classList.remove(\"alternate-growing\");\n this.likeButtonEl.classList.remove(\"pulse\");\n }\n }\n\n startSwitchingPeople() {\n this.switchPeople = true;\n this.animateNextWhenReady();\n }\n\n stopSwitchingPeople() {\n this.switchPeople = false;\n clearTimeout(this.peopleSwitchTimeout);\n }\n\n startPhotoAnimation() {\n if (!this.photoShouldPulse) return;\n [...this.el.querySelectorAll(\".profile-photo\")].forEach((el) =>\n el.classList.add(\"pulse\")\n );\n }\n\n stopPhotoAnimation() {\n if (!this.photoShouldPulse) return;\n [...this.el.querySelectorAll(\".profile-photo\")].forEach((el) =>\n el.classList.remove(\"pulse\")\n );\n }\n\n /** @param {(\"up\"|\"down\"|\"left\"|\"right\")} direction - Animates the current person out and the next\n person in given a particular animation direction. */\n animateNext(direction = \"up\") {\n if (this.people.length <= 1) return;\n const setAnimationStartClasses = (el, classes) => {\n // Set classes that specify the element's starting position for the animation.\n [\"staged\", \"exited\", \"up\", \"right\", \"down\", \"left\"].forEach(\n (className) => el.classList.remove(className)\n );\n classes.forEach((className) => el.classList.add(className));\n DOMUtils.forceReflow(el);\n };\n\n const currentPerson = this.people[this.currentPersonIndex];\n this.currentPersonIndex =\n (this.currentPersonIndex + 1) % this.people.length;\n const nextPerson = this.people[this.currentPersonIndex];\n setAnimationStartClasses(currentPerson.personEl, [direction]);\n setAnimationStartClasses(nextPerson.personEl, [direction, \"staged\"]);\n // Start the animation by transitioning the current element into the \"exited\" position and the next\n // element into the visible (non-\"staged\", non-\"exited\") position.\n currentPerson.personEl.classList.add(\"exited\");\n nextPerson.personEl.classList.remove(\"staged\");\n DOMUtils.forceReflow(this.peopleEl);\n if (this.messageShouldType) {\n currentPerson.currentlyTyping = false;\n nextPerson.currentlyTyping = true;\n this.resetTypingMessage(nextPerson);\n }\n\n this.emit(\"personChanged\");\n this.animateNextWhenReady(direction);\n }\n\n animateNextWhenReady(direction = \"up\") {\n if (!this.switchPeople || this.people.length <= 1) return;\n const currentPerson = this.people[this.currentPersonIndex];\n const messageTypeTime = this.messageShouldType\n ? this.getPersonCaptionLen(currentPerson) * this.charAnimationInterval\n : 0;\n const timeToSwitch = Math.max(\n PEOPLE_SWITCH_INTERVAL,\n PERSON_TRANSITION_DURATION + messageTypeTime + MIN_MESSAGE_DISPLAY_TIME\n );\n this.peopleSwitchTimeout = setTimeout(\n () => this.animateNext(direction),\n timeToSwitch\n );\n }\n\n resetTypingMessage(person) {\n if (!person.currentlyTyping) return;\n person.currentTextTypingIndex = 0;\n person.captionEl.innerHTML = \"\";\n const addNextLetter = () => {\n if (!person.currentlyTyping) {\n person.captionEl.innerHTML = person.caption;\n return;\n }\n\n if (person.currentTextTypingIndex < this.getPersonCaptionLen(person)) {\n this.setPersonCaption(person, person.currentTextTypingIndex + 1);\n\n person.currentTextTypingIndex += 1;\n setTimeout(addNextLetter, this.charAnimationInterval);\n } else {\n setTimeout(\n () => this.resetTypingMessage(person),\n RESTART_TYPING_INTERVAL\n );\n }\n };\n\n setTimeout(addNextLetter, PERSON_TRANSITION_DURATION);\n }\n\n startTyping() {\n if (!this.messageShouldType || this.people.length < 1) return;\n const currentPerson = this.people[this.currentPersonIndex];\n currentPerson.currentlyTyping = true;\n this.resetTypingMessage(currentPerson);\n }\n\n stopTyping() {\n this.people.forEach((person) => {\n person.currentlyTyping = false;\n });\n }\n\n recordInteraction() {\n super.recordInteraction();\n this.stopButtonAnimation();\n this.buttonAnimationTimeout = setTimeout(\n () => this.startButtonAnimation(),\n BUTTON_ANIMATION_INTERACTION_DELAY\n );\n this.stopSwitchingPeople();\n this.peopleSwitchTimeout = setTimeout(\n () => this.startSwitchingPeople(),\n PEOPLE_SWITCH_INTERACTION_DELAY\n );\n }\n\n addEventListeners() {\n if (!this.isInteractive || this.people.length === 0) return;\n this.el.querySelector(\".buttons\").addEventListener(\"click\", (e) => {\n let animationDirection;\n if (e.target.classList.contains(\"pass-button\")) {\n this.numPasses += 1;\n animationDirection = \"left\";\n } else if (e.target.classList.contains(\"like-button\")) {\n this.numLikes += 1;\n animationDirection = \"right\";\n } else {\n return;\n }\n\n this.recordInteraction();\n this.animateNext(animationDirection);\n\n const totalChoicesMade = this.numPasses + this.numLikes;\n this.emit(\"passedOrLiked\", {\n passes: this.numPasses,\n likes: this.numLikes,\n choices: totalChoicesMade,\n });\n // The allChoicesMade event is emitted when the user has liked or passed as many people as there are.\n // Since the animation runs in a loop automatically if the user doesn't interact, the choices aren't\n // necessarily for distinct people.\n if (this.people.length === totalChoicesMade) {\n this.emit(\"allChoicesMade\");\n }\n });\n }\n\n resize() {\n this.resizeFont();\n }\n\n restart() {\n this.stop();\n this.start();\n }\n\n start() {\n this.startIfReady = true;\n if (this.loading || this.animating) return;\n this.animating = true;\n this.startButtonAnimation();\n this.startTyping();\n this.startPhotoAnimation();\n this.startSwitchingPeople();\n }\n\n stop() {\n this.startIfReady = false;\n this.stopButtonAnimation();\n this.stopTyping();\n this.stopPhotoAnimation();\n this.stopSwitchingPeople();\n this.animating = false;\n }\n }\n);\n\n\n\n// WEBPACK FOOTER //\n// ./components/chat-banner/chat-banner.js","const { DOMUtils } = window.Liftoff;\n\nconst isVariationSelector = (cstr) => {\n if (cstr.length !== 1) {\n return false;\n }\n\n const code = cstr.charCodeAt(0);\n\n return 0xfe00 <= code && code <= 0xfe0f;\n};\n\n// Expects an array generated by [...str].\n// Merges variation selectors into the previous character so that they do not occupy their own slot in the\n// array.\n// REFERENCE: See\n// - https://blog.jonnew.com/posts/poo-dot-length-equals-two\n// - https://codepoints.net/U+fe0f\n// - https://codepoints.net/variation_selectors\nconst mergeVariationSelectors = (unicodechars) =>\n unicodechars.reduce((acc, cstr) => {\n if (acc.length > 0 && isVariationSelector(cstr)) {\n acc[acc.length - 1] += cstr;\n } else {\n acc.push(cstr);\n }\n return acc;\n }, []);\n\nexport const unicodeLen = (str) => mergeVariationSelectors([...str]).length;\n\n// Returns a string consisting of the leftmost 'n' Unicode characters of 'str'.\nexport const unicodeSlice = (str, n) =>\n mergeVariationSelectors([...str])\n .slice(0, n)\n .join(\"\");\n\nexport const domCountCharacters = (tree) => {\n if (tree == null) {\n return 0;\n }\n\n if (tree.nodeType === Node.TEXT_NODE) {\n return unicodeLen(tree.nodeValue);\n }\n\n let numChars = 0;\n\n if (tree.hasChildNodes()) {\n [...tree.childNodes].forEach((child) => {\n numChars += domCountCharacters(child);\n });\n }\n\n return numChars;\n};\n\n// Return a copy of the tree, such that only the leftmost n characters in the text elements are preserved.\n//\n// The return value includes the new tree and the number of characters in it.\n//\nexport const domSlice = (tree, n) => {\n if (tree == null) {\n return { tree: null, charcount: 0 };\n }\n\n if (tree.nodeType === Node.TEXT_NODE) {\n const text = tree.nodeValue;\n const textLen = unicodeLen(text);\n const numCharsToPreserve = Math.min(n, textLen);\n const newText = unicodeSlice(text, numCharsToPreserve);\n\n return {\n tree: document.createTextNode(newText),\n charCount: numCharsToPreserve,\n };\n }\n\n const ret = {\n tree: tree.cloneNode(false),\n charCount: 0,\n };\n\n if (tree.hasChildNodes()) {\n const children = [...tree.childNodes];\n children.forEach((child) => {\n const slicedChild = domSlice(child, n - ret.charCount);\n\n ret.charCount += slicedChild.charCount;\n\n if (slicedChild.charCount > 0 || child.textContent.length === 0) {\n ret.tree.appendChild(slicedChild.tree);\n }\n });\n }\n\n return ret;\n};\n\n// Removes any children of dstnode and moves the children of srcnode into dstnode.\nexport const moveChildrenFromNode = (dstnode, srcnode) => {\n dstnode = DOMUtils.empty(dstnode);\n\n while (srcnode.firstChild) {\n const child = srcnode.removeChild(srcnode.firstChild);\n\n dstnode.appendChild(child);\n }\n\n return dstnode;\n};\n\nexport const getTextDom = (caption) => {\n const div = document.createElement(\"div\");\n div.innerHTML = caption;\n\n return div;\n};\n\n\n\n// WEBPACK FOOTER //\n// ./src/js/lib/text_anim.js"],"sourceRoot":""}