mirror of
https://github.com/flarum/framework.git
synced 2025-01-24 21:12:59 +08:00
1 line
62 KiB
Plaintext
1 line
62 KiB
Plaintext
{"version":3,"sources":["webpack://@flarum/emoji/webpack/bootstrap","webpack://@flarum/emoji/external \"flarum.core.compat['extend']\"","webpack://@flarum/emoji/./node_modules/twemoji/2/twemoji.npm.js","webpack://@flarum/emoji/external \"flarum.core.compat['models/Post']\"","webpack://@flarum/emoji/external \"flarum.core.compat['app']\"","webpack://@flarum/emoji/./node_modules/textarea-caret/index.js","webpack://@flarum/emoji/external \"flarum.core.compat['components/ComposerBody']\"","webpack://@flarum/emoji/external \"flarum.core.compat['components/TextEditor']\"","webpack://@flarum/emoji/external \"flarum.core.compat['components/TextEditorButton']\"","webpack://@flarum/emoji/external \"flarum.core.compat['utils/KeyboardNavigatable']\"","webpack://@flarum/emoji/external \"flarum.core.compat['Component']\"","webpack://@flarum/emoji/(webpack)/buildin/global.js","webpack://@flarum/emoji/./src/forum/helpers/getEmojiIconCode.js","webpack://@flarum/emoji/./src/forum/components/AutocompleteDropdown.js","webpack://@flarum/emoji/./node_modules/@babel/runtime/helpers/esm/inheritsLoose.js","webpack://@flarum/emoji/./src/forum/addComposerAutocomplete.js","webpack://@flarum/emoji/./src/forum/index.js","webpack://@flarum/emoji/./src/forum/renderEmoji.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","flarum","core","compat","global","location","twemoji","base","ext","size","className","convert","fromCodePoint","codepoint","code","parseInt","fromCharCode","toCodePoint","onerror","this","parentNode","replaceChild","createText","alt","parse","what","how","callback","str","options","replace","rawText","attrib","attrname","ret","iconId","grabTheRightIcon","src","concat","attributes","indexOf","escapeHTML","node","modified","fragment","subnode","text","match","index","img","allText","grabAllTextNodes","nodeType","childNodes","length","push","shouldntBeParsed","test","nodeName","toLowerCase","document","createDocumentFragment","nodeValue","re","exec","appendChild","slice","Image","setAttribute","hasAttribute","defaultImageSrcGenerator","returnNull","folder","toSizeSquaredAsset","lastIndex","result","escaper","&","<",">","'","\"","UFE0Fg","U200D","String","rescaper","clean","createTextNode","replacer","icon","unicodeSurrogates","sep","charCodeAt","toString","join","protocol","properties","isBrowser","window","isFirefox","mozInnerScreenX","getCaretCoordinates","element","position","Error","debug","el","querySelector","removeChild","div","createElement","id","body","style","computed","getComputedStyle","currentStyle","isInput","whiteSpace","wordWrap","visibility","forEach","prop","lineHeight","height","scrollHeight","overflowY","overflow","textContent","substring","span","coordinates","top","offsetTop","left","offsetLeft","backgroundColor","g","Function","eval","e","AutocompleteDropdown","subClass","superClass","constructor","__proto__","init","active","keyWasJustPressed","view","app","translator","trans","props","items","map","item","attrs","show","$","css","hide","navigate","delta","_this","setIndex","clearTimeout","keyWasJustPressedTimeout","setTimeout","complete","eq","find","click","scrollToItem","$dropdown","$items","rangedIndex","$item","removeClass","addClass","scrollTop","dropdownScroll","dropdownTop","offset","dropdownBottom","outerHeight","itemTop","itemBottom","stop","animate","Component","addComposerAutocomplete","emojiKeys","keys","emojiMap","extend","ComposerBody","original","isInitialized","emojiStart","typed","composer","$container","dropdown","$textarea","wrap","navigator","KeyboardNavigatable","when","onUp","onDown","onSelect","onCancel","bindTo","after","on","which","cursor","selectionStart","selectionEnd","character","substr","makeSuggestion","_ref","emoji","onclick","replacement","insert","content","editor","setValue","setSelectionRange","applySuggestion","onmouseenter","parent","class","draggable","similarEmoji","regTyped","reEscape","RegExp","fuzzyRegexp","maxSuggestions","findMatchingEmojis","matcher","curEmoji","_iterator","_isArray","Array","isArray","_i2","iterator","_ref2","next","done","suggestions","getEmojiIconCode","render","width","outerWidth","offsetParent","Math","max","buildSuggestions","TextEditor","_this2","add","TextEditorButton_default","a","insertAtCursor","initializers","override","Post","contentHtml","oldContentHtml","emojifiedContentHtml","s9e","TextFormatter"],"mappings":"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","file":"forum.js","sourcesContent":[" \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, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\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\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 12);\n","module.exports = flarum.core.compat['extend'];","var location = global.location || {};\n/*jslint indent: 2, browser: true, bitwise: true, plusplus: true */\nvar twemoji = (function (\n /*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*\n https://github.com/twitter/twemoji/blob/gh-pages/LICENSE\n */\n\n // WARNING: this file is generated automatically via\n // `node twemoji-generator.js`\n // please update its `createTwemoji` function\n // at the bottom of the same file instead.\n\n) {\n 'use strict';\n\n /*jshint maxparams:4 */\n\n var\n // the exported module object\n twemoji = {\n\n\n /////////////////////////\n // properties //\n /////////////////////////\n\n // default assets url, by default will be Twitter Inc. CDN\n base: 'https://twemoji.maxcdn.com/2/',\n\n // default assets file extensions, by default '.png'\n ext: '.png',\n\n // default assets/folder size, by default \"72x72\"\n // available via Twitter CDN: 72\n size: '72x72',\n\n // default class name, by default 'emoji'\n className: 'emoji',\n\n // basic utilities / helpers to convert code points\n // to JavaScript surrogates and vice versa\n convert: {\n\n /**\n * Given an HEX codepoint, returns UTF16 surrogate pairs.\n *\n * @param string generic codepoint, i.e. '1F4A9'\n * @return string codepoint transformed into utf16 surrogates pair,\n * i.e. \\uD83D\\uDCA9\n *\n * @example\n * twemoji.convert.fromCodePoint('1f1e8');\n * // \"\\ud83c\\udde8\"\n *\n * '1f1e8-1f1f3'.split('-').map(twemoji.convert.fromCodePoint).join('')\n * // \"\\ud83c\\udde8\\ud83c\\uddf3\"\n */\n fromCodePoint: fromCodePoint,\n\n /**\n * Given UTF16 surrogate pairs, returns the equivalent HEX codepoint.\n *\n * @param string generic utf16 surrogates pair, i.e. \\uD83D\\uDCA9\n * @param string optional separator for double code points, default='-'\n * @return string utf16 transformed into codepoint, i.e. '1F4A9'\n *\n * @example\n * twemoji.convert.toCodePoint('\\ud83c\\udde8\\ud83c\\uddf3');\n * // \"1f1e8-1f1f3\"\n *\n * twemoji.convert.toCodePoint('\\ud83c\\udde8\\ud83c\\uddf3', '~');\n * // \"1f1e8~1f1f3\"\n */\n toCodePoint: toCodePoint\n },\n\n\n /////////////////////////\n // methods //\n /////////////////////////\n\n /**\n * User first: used to remove missing images\n * preserving the original text intent when\n * a fallback for network problems is desired.\n * Automatically added to Image nodes via DOM\n * It could be recycled for string operations via:\n * $('img.emoji').on('error', twemoji.onerror)\n */\n onerror: function onerror() {\n if (this.parentNode) {\n this.parentNode.replaceChild(createText(this.alt, false), this);\n }\n },\n\n /**\n * Main method/logic to generate either <img> tags or HTMLImage nodes.\n * \"emojify\" a generic text or DOM Element.\n *\n * @overloads\n *\n * String replacement for `innerHTML` or server side operations\n * twemoji.parse(string);\n * twemoji.parse(string, Function);\n * twemoji.parse(string, Object);\n *\n * HTMLElement tree parsing for safer operations over existing DOM\n * twemoji.parse(HTMLElement);\n * twemoji.parse(HTMLElement, Function);\n * twemoji.parse(HTMLElement, Object);\n *\n * @param string|HTMLElement the source to parse and enrich with emoji.\n *\n * string replace emoji matches with <img> tags.\n * Mainly used to inject emoji via `innerHTML`\n * It does **not** parse the string or validate it,\n * it simply replaces found emoji with a tag.\n * NOTE: be sure this won't affect security.\n *\n * HTMLElement walk through the DOM tree and find emoji\n * that are inside **text node only** (nodeType === 3)\n * Mainly used to put emoji in already generated DOM\n * without compromising surrounding nodes and\n * **avoiding** the usage of `innerHTML`.\n * NOTE: Using DOM elements instead of strings should\n * improve security without compromising too much\n * performance compared with a less safe `innerHTML`.\n *\n * @param Function|Object [optional]\n * either the callback that will be invoked or an object\n * with all properties to use per each found emoji.\n *\n * Function if specified, this will be invoked per each emoji\n * that has been found through the RegExp except\n * those follwed by the invariant \\uFE0E (\"as text\").\n * Once invoked, parameters will be:\n *\n * iconId:string the lower case HEX code point\n * i.e. \"1f4a9\"\n *\n * options:Object all info for this parsing operation\n *\n * variant:char the optional \\uFE0F (\"as image\")\n * variant, in case this info\n * is anyhow meaningful.\n * By default this is ignored.\n *\n * If such callback will return a falsy value instead\n * of a valid `src` to use for the image, nothing will\n * actually change for that specific emoji.\n *\n *\n * Object if specified, an object containing the following properties\n *\n * callback Function the callback to invoke per each found emoji.\n * base string the base url, by default twemoji.base\n * ext string the image extension, by default twemoji.ext\n * size string the assets size, by default twemoji.size\n *\n * @example\n *\n * twemoji.parse(\"I \\u2764\\uFE0F emoji!\");\n * // I <img class=\"emoji\" draggable=\"false\" alt=\"❤️\" src=\"/assets/2764.gif\"/> emoji!\n *\n *\n * twemoji.parse(\"I \\u2764\\uFE0F emoji!\", function(iconId, options) {\n * return '/assets/' + iconId + '.gif';\n * });\n * // I <img class=\"emoji\" draggable=\"false\" alt=\"❤️\" src=\"/assets/2764.gif\"/> emoji!\n *\n *\n * twemoji.parse(\"I \\u2764\\uFE0F emoji!\", {\n * size: 72,\n * callback: function(iconId, options) {\n * return '/assets/' + options.size + '/' + iconId + options.ext;\n * }\n * });\n * // I <img class=\"emoji\" draggable=\"false\" alt=\"❤️\" src=\"/assets/72x72/2764.png\"/> emoji!\n *\n */\n parse: parse,\n\n /**\n * Given a string, invokes the callback argument\n * per each emoji found in such string.\n * This is the most raw version used by\n * the .parse(string) method itself.\n *\n * @param string generic string to parse\n * @param Function a generic callback that will be\n * invoked to replace the content.\n * This calback wil receive standard\n * String.prototype.replace(str, callback)\n * arguments such:\n * callback(\n * rawText, // the emoji match\n * );\n *\n * and others commonly received via replace.\n */\n replace: replace,\n\n /**\n * Simplify string tests against emoji.\n *\n * @param string some text that might contain emoji\n * @return boolean true if any emoji was found, false otherwise.\n *\n * @example\n *\n * if (twemoji.test(someContent)) {\n * console.log(\"emoji All The Things!\");\n * }\n */\n test: test\n },\n\n // used to escape HTML special chars in attributes\n escaper = {\n '&': '&',\n '<': '<',\n '>': '>',\n \"'\": ''',\n '\"': '"'\n },\n\n // RegExp based on emoji's official Unicode standards\n // http://www.unicode.org/Public/UNIDATA/EmojiSources.txt\n re = /(?:\\ud83d[\\udc68\\udc69])(?:\\ud83c[\\udffb-\\udfff])?\\u200d(?:\\u2695\\ufe0f|\\u2696\\ufe0f|\\u2708\\ufe0f|\\ud83c[\\udf3e\\udf73\\udf93\\udfa4\\udfa8\\udfeb\\udfed]|\\ud83d[\\udcbb\\udcbc\\udd27\\udd2c\\ude80\\ude92]|\\ud83e[\\uddb0-\\uddb3])|(?:\\ud83c[\\udfcb\\udfcc]|\\ud83d[\\udd74\\udd75]|\\u26f9)((?:\\ud83c[\\udffb-\\udfff]|\\ufe0f)\\u200d[\\u2640\\u2642]\\ufe0f)|(?:\\ud83c[\\udfc3\\udfc4\\udfca]|\\ud83d[\\udc6e\\udc71\\udc73\\udc77\\udc81\\udc82\\udc86\\udc87\\ude45-\\ude47\\ude4b\\ude4d\\ude4e\\udea3\\udeb4-\\udeb6]|\\ud83e[\\udd26\\udd35\\udd37-\\udd39\\udd3d\\udd3e\\uddb8\\uddb9\\uddd6-\\udddd])(?:\\ud83c[\\udffb-\\udfff])?\\u200d[\\u2640\\u2642]\\ufe0f|(?:\\ud83d\\udc68\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d\\udc68|\\ud83d\\udc68\\u200d\\ud83d\\udc68\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc68\\u200d\\ud83d\\udc68\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc68\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc8b\\u200d\\ud83d[\\udc68\\udc69]|\\ud83d\\udc69\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc69\\u200d\\ud83d\\udc69\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\u2764\\ufe0f\\u200d\\ud83d\\udc68|\\ud83d\\udc68\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc68\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\ud83d\\udc68\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc68\\u200d\\ud83d\\udc69\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\u2764\\ufe0f\\u200d\\ud83d[\\udc68\\udc69]|\\ud83d\\udc69\\u200d\\ud83d\\udc66\\u200d\\ud83d\\udc66|\\ud83d\\udc69\\u200d\\ud83d\\udc67\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\ud83d\\udc69\\u200d\\ud83d[\\udc66\\udc67]|\\ud83c\\udff3\\ufe0f\\u200d\\ud83c\\udf08|\\ud83c\\udff4\\u200d\\u2620\\ufe0f|\\ud83d\\udc41\\u200d\\ud83d\\udde8|\\ud83d\\udc68\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc69\\u200d\\ud83d[\\udc66\\udc67]|\\ud83d\\udc6f\\u200d\\u2640\\ufe0f|\\ud83d\\udc6f\\u200d\\u2642\\ufe0f|\\ud83e\\udd3c\\u200d\\u2640\\ufe0f|\\ud83e\\udd3c\\u200d\\u2642\\ufe0f|\\ud83e\\uddde\\u200d\\u2640\\ufe0f|\\ud83e\\uddde\\u200d\\u2642\\ufe0f|\\ud83e\\udddf\\u200d\\u2640\\ufe0f|\\ud83e\\udddf\\u200d\\u2642\\ufe0f)|[\\u0023\\u002a\\u0030-\\u0039]\\ufe0f?\\u20e3|(?:[\\u00a9\\u00ae\\u2122\\u265f]\\ufe0f)|(?:\\ud83c[\\udc04\\udd70\\udd71\\udd7e\\udd7f\\ude02\\ude1a\\ude2f\\ude37\\udf21\\udf24-\\udf2c\\udf36\\udf7d\\udf96\\udf97\\udf99-\\udf9b\\udf9e\\udf9f\\udfcd\\udfce\\udfd4-\\udfdf\\udff3\\udff5\\udff7]|\\ud83d[\\udc3f\\udc41\\udcfd\\udd49\\udd4a\\udd6f\\udd70\\udd73\\udd76-\\udd79\\udd87\\udd8a-\\udd8d\\udda5\\udda8\\uddb1\\uddb2\\uddbc\\uddc2-\\uddc4\\uddd1-\\uddd3\\udddc-\\uddde\\udde1\\udde3\\udde8\\uddef\\uddf3\\uddfa\\udecb\\udecd-\\udecf\\udee0-\\udee5\\udee9\\udef0\\udef3]|[\\u203c\\u2049\\u2139\\u2194-\\u2199\\u21a9\\u21aa\\u231a\\u231b\\u2328\\u23cf\\u23ed-\\u23ef\\u23f1\\u23f2\\u23f8-\\u23fa\\u24c2\\u25aa\\u25ab\\u25b6\\u25c0\\u25fb-\\u25fe\\u2600-\\u2604\\u260e\\u2611\\u2614\\u2615\\u2618\\u2620\\u2622\\u2623\\u2626\\u262a\\u262e\\u262f\\u2638-\\u263a\\u2640\\u2642\\u2648-\\u2653\\u2660\\u2663\\u2665\\u2666\\u2668\\u267b\\u267f\\u2692-\\u2697\\u2699\\u269b\\u269c\\u26a0\\u26a1\\u26aa\\u26ab\\u26b0\\u26b1\\u26bd\\u26be\\u26c4\\u26c5\\u26c8\\u26cf\\u26d1\\u26d3\\u26d4\\u26e9\\u26ea\\u26f0-\\u26f5\\u26f8\\u26fa\\u26fd\\u2702\\u2708\\u2709\\u270f\\u2712\\u2714\\u2716\\u271d\\u2721\\u2733\\u2734\\u2744\\u2747\\u2757\\u2763\\u2764\\u27a1\\u2934\\u2935\\u2b05-\\u2b07\\u2b1b\\u2b1c\\u2b50\\u2b55\\u3030\\u303d\\u3297\\u3299])(?:\\ufe0f|(?!\\ufe0e))|(?:(?:\\ud83c[\\udfcb\\udfcc]|\\ud83d[\\udd74\\udd75\\udd90]|[\\u261d\\u26f7\\u26f9\\u270c\\u270d])(?:\\ufe0f|(?!\\ufe0e))|(?:\\ud83c[\\udf85\\udfc2-\\udfc4\\udfc7\\udfca]|\\ud83d[\\udc42\\udc43\\udc46-\\udc50\\udc66-\\udc69\\udc6e\\udc70-\\udc78\\udc7c\\udc81-\\udc83\\udc85-\\udc87\\udcaa\\udd7a\\udd95\\udd96\\ude45-\\ude47\\ude4b-\\ude4f\\udea3\\udeb4-\\udeb6\\udec0\\udecc]|\\ud83e[\\udd18-\\udd1c\\udd1e\\udd1f\\udd26\\udd30-\\udd39\\udd3d\\udd3e\\uddb5\\uddb6\\uddb8\\uddb9\\uddd1-\\udddd]|[\\u270a\\u270b]))(?:\\ud83c[\\udffb-\\udfff])?|(?:\\ud83c\\udff4\\udb40\\udc67\\udb40\\udc62\\udb40\\udc65\\udb40\\udc6e\\udb40\\udc67\\udb40\\udc7f|\\ud83c\\udff4\\udb40\\udc67\\udb40\\udc62\\udb40\\udc73\\udb40\\udc63\\udb40\\udc74\\udb40\\udc7f|\\ud83c\\udff4\\udb40\\udc67\\udb40\\udc62\\udb40\\udc77\\udb40\\udc6c\\udb40\\udc73\\udb40\\udc7f|\\ud83c\\udde6\\ud83c[\\udde8-\\uddec\\uddee\\uddf1\\uddf2\\uddf4\\uddf6-\\uddfa\\uddfc\\uddfd\\uddff]|\\ud83c\\udde7\\ud83c[\\udde6\\udde7\\udde9-\\uddef\\uddf1-\\uddf4\\uddf6-\\uddf9\\uddfb\\uddfc\\uddfe\\uddff]|\\ud83c\\udde8\\ud83c[\\udde6\\udde8\\udde9\\uddeb-\\uddee\\uddf0-\\uddf5\\uddf7\\uddfa-\\uddff]|\\ud83c\\udde9\\ud83c[\\uddea\\uddec\\uddef\\uddf0\\uddf2\\uddf4\\uddff]|\\ud83c\\uddea\\ud83c[\\udde6\\udde8\\uddea\\uddec\\udded\\uddf7-\\uddfa]|\\ud83c\\uddeb\\ud83c[\\uddee-\\uddf0\\uddf2\\uddf4\\uddf7]|\\ud83c\\uddec\\ud83c[\\udde6\\udde7\\udde9-\\uddee\\uddf1-\\uddf3\\uddf5-\\uddfa\\uddfc\\uddfe]|\\ud83c\\udded\\ud83c[\\uddf0\\uddf2\\uddf3\\uddf7\\uddf9\\uddfa]|\\ud83c\\uddee\\ud83c[\\udde8-\\uddea\\uddf1-\\uddf4\\uddf6-\\uddf9]|\\ud83c\\uddef\\ud83c[\\uddea\\uddf2\\uddf4\\uddf5]|\\ud83c\\uddf0\\ud83c[\\uddea\\uddec-\\uddee\\uddf2\\uddf3\\uddf5\\uddf7\\uddfc\\uddfe\\uddff]|\\ud83c\\uddf1\\ud83c[\\udde6-\\udde8\\uddee\\uddf0\\uddf7-\\uddfb\\uddfe]|\\ud83c\\uddf2\\ud83c[\\udde6\\udde8-\\udded\\uddf0-\\uddff]|\\ud83c\\uddf3\\ud83c[\\udde6\\udde8\\uddea-\\uddec\\uddee\\uddf1\\uddf4\\uddf5\\uddf7\\uddfa\\uddff]|\\ud83c\\uddf4\\ud83c\\uddf2|\\ud83c\\uddf5\\ud83c[\\udde6\\uddea-\\udded\\uddf0-\\uddf3\\uddf7-\\uddf9\\uddfc\\uddfe]|\\ud83c\\uddf6\\ud83c\\udde6|\\ud83c\\uddf7\\ud83c[\\uddea\\uddf4\\uddf8\\uddfa\\uddfc]|\\ud83c\\uddf8\\ud83c[\\udde6-\\uddea\\uddec-\\uddf4\\uddf7-\\uddf9\\uddfb\\uddfd-\\uddff]|\\ud83c\\uddf9\\ud83c[\\udde6\\udde8\\udde9\\uddeb-\\udded\\uddef-\\uddf4\\uddf7\\uddf9\\uddfb\\uddfc\\uddff]|\\ud83c\\uddfa\\ud83c[\\udde6\\uddec\\uddf2\\uddf3\\uddf8\\uddfe\\uddff]|\\ud83c\\uddfb\\ud83c[\\udde6\\udde8\\uddea\\uddec\\uddee\\uddf3\\uddfa]|\\ud83c\\uddfc\\ud83c[\\uddeb\\uddf8]|\\ud83c\\uddfd\\ud83c\\uddf0|\\ud83c\\uddfe\\ud83c[\\uddea\\uddf9]|\\ud83c\\uddff\\ud83c[\\udde6\\uddf2\\uddfc]|\\ud83c[\\udccf\\udd8e\\udd91-\\udd9a\\udde6-\\uddff\\ude01\\ude32-\\ude36\\ude38-\\ude3a\\ude50\\ude51\\udf00-\\udf20\\udf2d-\\udf35\\udf37-\\udf7c\\udf7e-\\udf84\\udf86-\\udf93\\udfa0-\\udfc1\\udfc5\\udfc6\\udfc8\\udfc9\\udfcf-\\udfd3\\udfe0-\\udff0\\udff4\\udff8-\\udfff]|\\ud83d[\\udc00-\\udc3e\\udc40\\udc44\\udc45\\udc51-\\udc65\\udc6a-\\udc6d\\udc6f\\udc79-\\udc7b\\udc7d-\\udc80\\udc84\\udc88-\\udca9\\udcab-\\udcfc\\udcff-\\udd3d\\udd4b-\\udd4e\\udd50-\\udd67\\udda4\\uddfb-\\ude44\\ude48-\\ude4a\\ude80-\\udea2\\udea4-\\udeb3\\udeb7-\\udebf\\udec1-\\udec5\\uded0-\\uded2\\udeeb\\udeec\\udef4-\\udef9]|\\ud83e[\\udd10-\\udd17\\udd1d\\udd20-\\udd25\\udd27-\\udd2f\\udd3a\\udd3c\\udd40-\\udd45\\udd47-\\udd70\\udd73-\\udd76\\udd7a\\udd7c-\\udda2\\uddb4\\uddb7\\uddc0-\\uddc2\\uddd0\\uddde-\\uddff]|[\\u23e9-\\u23ec\\u23f0\\u23f3\\u267e\\u26ce\\u2705\\u2728\\u274c\\u274e\\u2753-\\u2755\\u2795-\\u2797\\u27b0\\u27bf\\ue50a])|\\ufe0f/g,\n\n // avoid runtime RegExp creation for not so smart,\n // not JIT based, and old browsers / engines\n UFE0Fg = /\\uFE0F/g,\n\n // avoid using a string literal like '\\u200D' here because minifiers expand it inline\n U200D = String.fromCharCode(0x200D),\n\n // used to find HTML special chars in attributes\n rescaper = /[&<>'\"]/g,\n\n // nodes with type 1 which should **not** be parsed\n shouldntBeParsed = /^(?:iframe|noframes|noscript|script|select|style|textarea)$/,\n\n // just a private shortcut\n fromCharCode = String.fromCharCode;\n\n return twemoji;\n\n\n /////////////////////////\n // private functions //\n // declaration //\n /////////////////////////\n\n /**\n * Shortcut to create text nodes\n * @param string text used to create DOM text node\n * @return Node a DOM node with that text\n */\n function createText(text, clean) {\n return document.createTextNode(clean ? text.replace(UFE0Fg, '') : text);\n }\n\n /**\n * Utility function to escape html attribute text\n * @param string text use in HTML attribute\n * @return string text encoded to use in HTML attribute\n */\n function escapeHTML(s) {\n return s.replace(rescaper, replacer);\n }\n\n /**\n * Default callback used to generate emoji src\n * based on Twitter CDN\n * @param string the emoji codepoint string\n * @param string the default size to use, i.e. \"36x36\"\n * @return string the image source to use\n */\n function defaultImageSrcGenerator(icon, options) {\n return ''.concat(options.base, options.size, '/', icon, options.ext);\n }\n\n /**\n * Given a generic DOM nodeType 1, walk through all children\n * and store every nodeType 3 (#text) found in the tree.\n * @param Element a DOM Element with probably some text in it\n * @param Array the list of previously discovered text nodes\n * @return Array same list with new discovered nodes, if any\n */\n function grabAllTextNodes(node, allText) {\n var\n childNodes = node.childNodes,\n length = childNodes.length,\n subnode,\n nodeType;\n while (length--) {\n subnode = childNodes[length];\n nodeType = subnode.nodeType;\n // parse emoji only in text nodes\n if (nodeType === 3) {\n // collect them to process emoji later\n allText.push(subnode);\n }\n // ignore all nodes that are not type 1, that are svg, or that\n // should not be parsed as script, style, and others\n else if (nodeType === 1 && !('ownerSVGElement' in subnode) &&\n !shouldntBeParsed.test(subnode.nodeName.toLowerCase())) {\n grabAllTextNodes(subnode, allText);\n }\n }\n return allText;\n }\n\n /**\n * Used to both remove the possible variant\n * and to convert utf16 into code points.\n * If there is a zero-width-joiner (U+200D), leave the variants in.\n * @param string the raw text of the emoji match\n * @return string the code point\n */\n function grabTheRightIcon(rawText) {\n // if variant is present as \\uFE0F\n return toCodePoint(rawText.indexOf(U200D) < 0 ?\n rawText.replace(UFE0Fg, '') :\n rawText\n );\n }\n\n /**\n * DOM version of the same logic / parser:\n * emojify all found sub-text nodes placing images node instead.\n * @param Element generic DOM node with some text in some child node\n * @param Object options containing info about how to parse\n *\n * .callback Function the callback to invoke per each found emoji.\n * .base string the base url, by default twemoji.base\n * .ext string the image extension, by default twemoji.ext\n * .size string the assets size, by default twemoji.size\n *\n * @return Element same generic node with emoji in place, if any.\n */\n function parseNode(node, options) {\n var\n allText = grabAllTextNodes(node, []),\n length = allText.length,\n attrib,\n attrname,\n modified,\n fragment,\n subnode,\n text,\n match,\n i,\n index,\n img,\n rawText,\n iconId,\n src;\n while (length--) {\n modified = false;\n fragment = document.createDocumentFragment();\n subnode = allText[length];\n text = subnode.nodeValue;\n i = 0;\n while ((match = re.exec(text))) {\n index = match.index;\n if (index !== i) {\n fragment.appendChild(\n createText(text.slice(i, index), true)\n );\n }\n rawText = match[0];\n iconId = grabTheRightIcon(rawText);\n i = index + rawText.length;\n src = options.callback(iconId, options);\n if (iconId && src) {\n img = new Image();\n img.onerror = options.onerror;\n img.setAttribute('draggable', 'false');\n attrib = options.attributes(rawText, iconId);\n for (attrname in attrib) {\n if (\n attrib.hasOwnProperty(attrname) &&\n // don't allow any handlers to be set + don't allow overrides\n attrname.indexOf('on') !== 0 &&\n !img.hasAttribute(attrname)\n ) {\n img.setAttribute(attrname, attrib[attrname]);\n }\n }\n img.className = options.className;\n img.alt = rawText;\n img.src = src;\n modified = true;\n fragment.appendChild(img);\n }\n if (!img) fragment.appendChild(createText(rawText, false));\n img = null;\n }\n // is there actually anything to replace in here ?\n if (modified) {\n // any text left to be added ?\n if (i < text.length) {\n fragment.appendChild(\n createText(text.slice(i), true)\n );\n }\n // replace the text node only, leave intact\n // anything else surrounding such text\n subnode.parentNode.replaceChild(fragment, subnode);\n }\n }\n return node;\n }\n\n /**\n * String/HTML version of the same logic / parser:\n * emojify a generic text placing images tags instead of surrogates pair.\n * @param string generic string with possibly some emoji in it\n * @param Object options containing info about how to parse\n *\n * .callback Function the callback to invoke per each found emoji.\n * .base string the base url, by default twemoji.base\n * .ext string the image extension, by default twemoji.ext\n * .size string the assets size, by default twemoji.size\n *\n * @return the string with <img tags> replacing all found and parsed emoji\n */\n function parseString(str, options) {\n return replace(str, function (rawText) {\n var\n ret = rawText,\n iconId = grabTheRightIcon(rawText),\n src = options.callback(iconId, options),\n attrib,\n attrname;\n if (iconId && src) {\n // recycle the match string replacing the emoji\n // with its image counter part\n ret = '<img '.concat(\n 'class=\"', options.className, '\" ',\n 'draggable=\"false\" ',\n // needs to preserve user original intent\n // when variants should be copied and pasted too\n 'alt=\"',\n rawText,\n '\"',\n ' src=\"',\n src,\n '\"'\n );\n attrib = options.attributes(rawText, iconId);\n for (attrname in attrib) {\n if (\n attrib.hasOwnProperty(attrname) &&\n // don't allow any handlers to be set + don't allow overrides\n attrname.indexOf('on') !== 0 &&\n ret.indexOf(' ' + attrname + '=') === -1\n ) {\n ret = ret.concat(' ', attrname, '=\"', escapeHTML(attrib[attrname]), '\"');\n }\n }\n ret = ret.concat('/>');\n }\n return ret;\n });\n }\n\n /**\n * Function used to actually replace HTML special chars\n * @param string HTML special char\n * @return string encoded HTML special char\n */\n function replacer(m) {\n return escaper[m];\n }\n\n /**\n * Default options.attribute callback\n * @return null\n */\n function returnNull() {\n return null;\n }\n\n /**\n * Given a generic value, creates its squared counterpart if it's a number.\n * As example, number 36 will return '36x36'.\n * @param any a generic value.\n * @return any a string representing asset size, i.e. \"36x36\"\n * only in case the value was a number.\n * Returns initial value otherwise.\n */\n function toSizeSquaredAsset(value) {\n return typeof value === 'number' ?\n value + 'x' + value :\n value;\n }\n\n\n /////////////////////////\n // exported functions //\n // declaration //\n /////////////////////////\n\n function fromCodePoint(codepoint) {\n var code = typeof codepoint === 'string' ?\n parseInt(codepoint, 16) : codepoint;\n if (code < 0x10000) {\n return fromCharCode(code);\n }\n code -= 0x10000;\n return fromCharCode(\n 0xD800 + (code >> 10),\n 0xDC00 + (code & 0x3FF)\n );\n }\n\n function parse(what, how) {\n if (!how || typeof how === 'function') {\n how = {callback: how};\n }\n // if first argument is string, inject html <img> tags\n // otherwise use the DOM tree and parse text nodes only\n return (typeof what === 'string' ? parseString : parseNode)(what, {\n callback: how.callback || defaultImageSrcGenerator,\n attributes: typeof how.attributes === 'function' ? how.attributes : returnNull,\n base: typeof how.base === 'string' ? how.base : twemoji.base,\n ext: how.ext || twemoji.ext,\n size: how.folder || toSizeSquaredAsset(how.size || twemoji.size),\n className: how.className || twemoji.className,\n onerror: how.onerror || twemoji.onerror\n });\n }\n\n function replace(text, callback) {\n return String(text).replace(re, callback);\n }\n\n function test(text) {\n // IE6 needs a reset before too\n re.lastIndex = 0;\n var result = re.test(text);\n re.lastIndex = 0;\n return result;\n }\n\n function toCodePoint(unicodeSurrogates, sep) {\n var\n r = [],\n c = 0,\n p = 0,\n i = 0;\n while (i < unicodeSurrogates.length) {\n c = unicodeSurrogates.charCodeAt(i++);\n if (p) {\n r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));\n p = 0;\n } else if (0xD800 <= c && c <= 0xDBFF) {\n p = c;\n } else {\n r.push(c.toString(16));\n }\n }\n return r.join(sep || '-');\n }\n\n}());\nif (!location.protocol) {\n twemoji.base = twemoji.base.replace(/^http:/, \"\");\n}\nmodule.exports = twemoji;","module.exports = flarum.core.compat['models/Post'];","module.exports = flarum.core.compat['app'];","/* jshint browser: true */\n\n(function () {\n\n// We'll copy the properties below into the mirror div.\n// Note that some browsers, such as Firefox, do not concatenate properties\n// into their shorthand (e.g. padding-top, padding-bottom etc. -> padding),\n// so we have to list every single property explicitly.\nvar properties = [\n 'direction', // RTL support\n 'boxSizing',\n 'width', // on Chrome and IE, exclude the scrollbar, so the mirror div wraps exactly as the textarea does\n 'height',\n 'overflowX',\n 'overflowY', // copy the scrollbar for IE\n\n 'borderTopWidth',\n 'borderRightWidth',\n 'borderBottomWidth',\n 'borderLeftWidth',\n 'borderStyle',\n\n 'paddingTop',\n 'paddingRight',\n 'paddingBottom',\n 'paddingLeft',\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/font\n 'fontStyle',\n 'fontVariant',\n 'fontWeight',\n 'fontStretch',\n 'fontSize',\n 'fontSizeAdjust',\n 'lineHeight',\n 'fontFamily',\n\n 'textAlign',\n 'textTransform',\n 'textIndent',\n 'textDecoration', // might not make a difference, but better be safe\n\n 'letterSpacing',\n 'wordSpacing',\n\n 'tabSize',\n 'MozTabSize'\n\n];\n\nvar isBrowser = (typeof window !== 'undefined');\nvar isFirefox = (isBrowser && window.mozInnerScreenX != null);\n\nfunction getCaretCoordinates(element, position, options) {\n if (!isBrowser) {\n throw new Error('textarea-caret-position#getCaretCoordinates should only be called in a browser');\n }\n\n var debug = options && options.debug || false;\n if (debug) {\n var el = document.querySelector('#input-textarea-caret-position-mirror-div');\n if (el) el.parentNode.removeChild(el);\n }\n\n // The mirror div will replicate the textarea's style\n var div = document.createElement('div');\n div.id = 'input-textarea-caret-position-mirror-div';\n document.body.appendChild(div);\n\n var style = div.style;\n var computed = window.getComputedStyle ? window.getComputedStyle(element) : element.currentStyle; // currentStyle for IE < 9\n var isInput = element.nodeName === 'INPUT';\n\n // Default textarea styles\n style.whiteSpace = 'pre-wrap';\n if (!isInput)\n style.wordWrap = 'break-word'; // only for textarea-s\n\n // Position off-screen\n style.position = 'absolute'; // required to return coordinates properly\n if (!debug)\n style.visibility = 'hidden'; // not 'display: none' because we want rendering\n\n // Transfer the element's properties to the div\n properties.forEach(function (prop) {\n if (isInput && prop === 'lineHeight') {\n // Special case for <input>s because text is rendered centered and line height may be != height\n style.lineHeight = computed.height;\n } else {\n style[prop] = computed[prop];\n }\n });\n\n if (isFirefox) {\n // Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275\n if (element.scrollHeight > parseInt(computed.height))\n style.overflowY = 'scroll';\n } else {\n style.overflow = 'hidden'; // for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'\n }\n\n div.textContent = element.value.substring(0, position);\n // The second special handling for input type=\"text\" vs textarea:\n // spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037\n if (isInput)\n div.textContent = div.textContent.replace(/\\s/g, '\\u00a0');\n\n var span = document.createElement('span');\n // Wrapping must be replicated *exactly*, including when a long word gets\n // onto the next line, with whitespace at the end of the line before (#7).\n // The *only* reliable way to do that is to copy the *entire* rest of the\n // textarea's content into the <span> created at the caret position.\n // For inputs, just '.' would be enough, but no need to bother.\n span.textContent = element.value.substring(position) || '.'; // || because a completely empty faux span doesn't render at all\n div.appendChild(span);\n\n var coordinates = {\n top: span.offsetTop + parseInt(computed['borderTopWidth']),\n left: span.offsetLeft + parseInt(computed['borderLeftWidth']),\n height: parseInt(computed['lineHeight'])\n };\n\n if (debug) {\n span.style.backgroundColor = '#aaa';\n } else {\n document.body.removeChild(div);\n }\n\n return coordinates;\n}\n\nif (typeof module != 'undefined' && typeof module.exports != 'undefined') {\n module.exports = getCaretCoordinates;\n} else if(isBrowser) {\n window.getCaretCoordinates = getCaretCoordinates;\n}\n\n}());\n","module.exports = flarum.core.compat['components/ComposerBody'];","module.exports = flarum.core.compat['components/TextEditor'];","module.exports = flarum.core.compat['components/TextEditorButton'];","module.exports = flarum.core.compat['utils/KeyboardNavigatable'];","module.exports = flarum.core.compat['Component'];","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//*\n https://github.com/twitter/twemoji/blob/gh-pages/LICENSE\n*/\n\nimport twemoji from 'twemoji/2/twemoji.npm';\n\n// avoid using a string literal like '\\u200D' here because minifiers expand it inline\nconst U200D = String.fromCharCode(0x200D);\n\n// avoid runtime RegExp creation for not so smart,\n// not JIT based, and old browsers / engines\nconst UFE0Fg = /\\uFE0F/g;\n\n/**\n * Used to both remove the possible variant\n * and to convert utf16 into code points.\n * If there is a zero-width-joiner (U+200D), leave the variants in.\n * @param string the raw text of the emoji match\n * @return string the code point\n */\nexport default function getEmojiIconCode(emoji) {\n return twemoji.convert.toCodePoint(emoji.indexOf(U200D) < 0 ?\n emoji.replace(UFE0Fg, '') :\n emoji\n );\n}\n","import Component from 'flarum/Component';\n\nexport default class AutocompleteDropdown extends Component {\n init() {\n this.active = false;\n this.index = 0;\n this.keyWasJustPressed = false;\n }\n\n view() {\n return (\n <ul className=\"Dropdown-menu EmojiDropdown\">\n <li className=\"Dropdown-header\" key=\"0\">{app.translator.trans('flarum-emoji.forum.composer.type_to_search_text')}</li>\n {this.props.items.map(item => <li key={item.attrs.key}>{item}</li>)}\n </ul>\n );\n }\n\n show(left, top) {\n this.$().show().css({\n left: left + 'px',\n top: top + 'px'\n });\n this.active = true;\n }\n\n hide() {\n this.$().hide();\n this.active = false;\n }\n\n navigate(delta) {\n this.keyWasJustPressed = true;\n this.setIndex(this.index + delta, true);\n clearTimeout(this.keyWasJustPressedTimeout);\n this.keyWasJustPressedTimeout = setTimeout(() => this.keyWasJustPressed = false, 500);\n }\n\n complete() {\n this.$('li:not(.Dropdown-header)').eq(this.index).find('button').click();\n }\n\n setIndex(index, scrollToItem) {\n if (this.keyWasJustPressed && !scrollToItem) return;\n\n const $dropdown = this.$();\n const $items = $dropdown.find('li:not(.Dropdown-header)');\n let rangedIndex = index;\n\n if (rangedIndex < 0) {\n rangedIndex = $items.length - 1;\n } else if (rangedIndex >= $items.length) {\n rangedIndex = 0;\n }\n\n this.index = rangedIndex;\n\n const $item = $items.removeClass('active').eq(rangedIndex).addClass('active');\n\n if (scrollToItem) {\n const dropdownScroll = $dropdown.scrollTop();\n const dropdownTop = $dropdown.offset().top;\n const dropdownBottom = dropdownTop + $dropdown.outerHeight();\n const itemTop = $item.offset().top;\n const itemBottom = itemTop + $item.outerHeight();\n\n let scrollTop;\n if (itemTop < dropdownTop) {\n scrollTop = dropdownScroll - dropdownTop + itemTop - parseInt($dropdown.css('padding-top'), 10);\n } else if (itemBottom > dropdownBottom) {\n scrollTop = dropdownScroll - dropdownBottom + itemBottom + parseInt($dropdown.css('padding-bottom'), 10);\n }\n\n if (typeof scrollTop !== 'undefined') {\n $dropdown.stop(true).animate({scrollTop}, 100);\n }\n }\n }\n}\n","export default function _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n subClass.__proto__ = superClass;\n}","import getCaretCoordinates from 'textarea-caret';\n\nimport { extend } from 'flarum/extend';\nimport ComposerBody from 'flarum/components/ComposerBody';\nimport TextEditor from 'flarum/components/TextEditor';\nimport TextEditorButton from 'flarum/components/TextEditorButton';\nimport emojiMap from './generated/emojiMap.json';\nimport getEmojiIconCode from './helpers/getEmojiIconCode';\nimport KeyboardNavigatable from 'flarum/utils/KeyboardNavigatable';\n\nimport AutocompleteDropdown from './components/AutocompleteDropdown';\n\nexport default function addComposerAutocomplete() {\n const emojiKeys = Object.keys(emojiMap);\n\n extend(ComposerBody.prototype, 'config', function(original, isInitialized) {\n if (isInitialized) return;\n\n const composer = this;\n const $container = $('<div class=\"ComposerBody-emojiDropdownContainer\"></div>');\n const dropdown = new AutocompleteDropdown({items: []});\n const $textarea = this.$('textarea').wrap('<div class=\"ComposerBody-emojiWrapper\"></div>');\n let emojiStart;\n let typed;\n\n const applySuggestion = function(replacement) {\n const insert = replacement + ' ';\n\n // When calling setValue(), emojiStart will be set back to 0 so we need to compute this beforehand\n const index = emojiStart - 1 + insert.length;\n\n const content = composer.content();\n composer.editor.setValue(content.substring(0, emojiStart - 1) + insert + content.substr($textarea[0].selectionStart));\n\n composer.editor.setSelectionRange(index, index);\n\n dropdown.hide();\n };\n\n this.navigator = new KeyboardNavigatable();\n this.navigator\n .when(() => dropdown.active)\n .onUp(() => dropdown.navigate(-1))\n .onDown(() => dropdown.navigate(1))\n .onSelect(dropdown.complete.bind(dropdown))\n .onCancel(dropdown.hide.bind(dropdown))\n .bindTo($textarea);\n\n $textarea\n .after($container)\n .on('click keyup input', function(e) {\n // Up, down, enter, tab, escape, left, right.\n if ([9, 13, 27, 40, 38, 37, 39].indexOf(e.which) !== -1) return;\n\n const cursor = this.selectionStart;\n\n if (this.selectionEnd - cursor > 0) return;\n\n // Search backwards from the cursor for an ':' symbol. If we find\n // one and followed by a whitespace, we will want to show the\n // autocomplete dropdown!\n const value = this.value;\n emojiStart = 0;\n for (let i = cursor - 1; i >= 0; i--) {\n const character = value.substr(i, 1);\n // check what user typed, emoji names only contains alphanumeric,\n // underline, '+' and '-'\n if (!/[a-z0-9]|\\+|\\-|_|\\:/.test(character)) break;\n // make sure ':' followed by a whitespace or newline\n if (character === ':' && (i == 0 || /\\s/.test(value.substr(i - 1, 1)))) {\n emojiStart = i + 1;\n break;\n }\n }\n\n dropdown.hide();\n dropdown.active = false;\n\n if (emojiStart) {\n typed = value.substring(emojiStart, cursor).toLowerCase();\n\n const makeSuggestion = function({emoji, name, code}) {\n return (\n <button\n key={emoji}\n onclick={() => applySuggestion(emoji)}\n onmouseenter={function() {\n dropdown.setIndex($(this).parent().index() - 1);\n }}>\n <img alt={emoji} class=\"emoji\" draggable=\"false\" src={'//twemoji.maxcdn.com/2/72x72/' + code + '.png'}/>\n {name}\n </button>\n );\n };\n\n const buildSuggestions = () => {\n const similarEmoji = [];\n\n // Build a regular expression to do a fuzzy match of the given input string\n const fuzzyRegexp = function(str) {\n const reEscape = new RegExp('\\\\(([' + ('+.*?[]{}()^$|\\\\'.replace(/(.)/g, '\\\\$1')) + '])\\\\)', 'g');\n return new RegExp('(.*)' + (str.toLowerCase().replace(/(.)/g, '($1)(.*?)')).replace(reEscape, '(\\\\$1)') + '$', 'i');\n };\n const regTyped = fuzzyRegexp(typed);\n\n let maxSuggestions = 7;\n\n const findMatchingEmojis = matcher => {\n for (let i = 0; i < emojiKeys.length && maxSuggestions > 0; i++) {\n const curEmoji = emojiKeys[i];\n\n if (similarEmoji.indexOf(curEmoji) === -1) {\n const names = emojiMap[curEmoji];\n for (let name of names) {\n if (matcher(name)) {\n --maxSuggestions;\n similarEmoji.push(curEmoji);\n break;\n }\n }\n }\n }\n };\n\n // First, try to find all emojis starting with the given string\n findMatchingEmojis(emoji => emoji.indexOf(typed) === 0);\n\n // If there are still suggestions left, try for some fuzzy matches\n findMatchingEmojis(emoji => regTyped.test(emoji));\n\n const suggestions = similarEmoji.map(emoji => ({\n emoji,\n name: emojiMap[emoji][0],\n code: getEmojiIconCode(emoji),\n })).map(makeSuggestion);\n\n if (suggestions.length) {\n dropdown.props.items = suggestions;\n m.render($container[0], dropdown.render());\n\n dropdown.show();\n const coordinates = getCaretCoordinates(this, emojiStart);\n const width = dropdown.$().outerWidth();\n const height = dropdown.$().outerHeight();\n const parent = dropdown.$().offsetParent();\n let left = coordinates.left;\n let top = coordinates.top + 15;\n if (top + height > parent.height()) {\n top = coordinates.top - height - 15;\n }\n if (left + width > parent.width()) {\n left = parent.width() - width;\n }\n top = Math.max(-$(this).offset().top, top);\n left = Math.max(-$(this).offset().left, left);\n dropdown.show(left, top);\n }\n };\n\n buildSuggestions();\n\n dropdown.setIndex(0);\n dropdown.$().scrollTop(0);\n dropdown.active = true;\n }\n });\n });\n\n extend(TextEditor.prototype, 'toolbarItems', function(items) {\n items.add('emoji', (\n <TextEditorButton onclick={() => this.insertAtCursor(':')} icon=\"far fa-smile\">\n {app.translator.trans('flarum-emoji.forum.composer.emoji_tooltip')}\n </TextEditorButton>\n ));\n });\n}\n","import { override } from 'flarum/extend';\nimport app from 'flarum/app';\nimport Post from 'flarum/models/Post';\n\nimport addComposerAutocomplete from './addComposerAutocomplete';\nimport renderEmoji from './renderEmoji';\n\napp.initializers.add('flarum-emoji', () => {\n // After typing ':' in the composer, show a dropdown suggesting a bunch of\n // emoji that the user could use.\n addComposerAutocomplete();\n\n // render emoji as image in Posts content and title.\n renderEmoji();\n});\n","/*global s9e*/\n\nimport twemoji from 'twemoji/2/twemoji.npm';\n\nimport { override } from 'flarum/extend';\nimport Post from 'flarum/models/Post';\n\nexport default function renderEmoji() {\n override(Post.prototype, 'contentHtml', function(original) {\n const contentHtml = original();\n\n if (this.oldContentHtml !== contentHtml) {\n this.emojifiedContentHtml = twemoji.parse(contentHtml);\n this.oldContentHtml = contentHtml;\n }\n\n return this.emojifiedContentHtml;\n });\n\n override(s9e.TextFormatter, 'preview', (original, text, element) => {\n original(text, element);\n\n twemoji.parse(element);\n });\n}\n"],"sourceRoot":""} |