UNPKG

nodebb-plugin-composer-quill

Version:

Quill Composer for NodeBB

117 lines (104 loc) 3.29 kB
'use strict'; /* globals $, define, socket, app, config */ /** * DEVELOPER NOTE * * It isn't particularly scalable to have a separate file for integration with * each individual plugin. Eventually, it is expected that Quill will fire off * hooks that plugins can listen for and invoke, therefore the code contained * here would be better located in the emoji plugin instead. * * .enable() is called from quill-nbb.js but it could very well be listening * for action:quill.load * * .convert() is called during composer autocomplete, which could be listening * for a hook to be fired by autocomplete, of which there is none right now. */ define('quill-emoji', ['quill'], function (quill) { var Emoji = { table: {}, blots: {}, }; // Emoji Blot var imageBlot = quill.import('formats/image'); var emojiAttributes = ['alt', 'class']; Emoji.blots.emoji = $.extend(true, imageBlot, { blotName: 'emoji', formats: function (domNode) { return emojiAttributes.reduce((formats, attribute) => { if (domNode.hasAttribute(attribute)) { formats[attribute] = domNode.getAttribute(attribute); } return formats; }, {}); }, }); Emoji.blots.emoji.prototype.format = function (name, value) { if (emojiAttributes.includes(name)) { if (value) { this.domNode.setAttribute(name, value); } else { this.domNode.removeAttribute(name); } } else { imageBlot.format(name, value); } }; quill.register(Emoji.blots.emoji); Emoji.enable = function (quill) { if (!Object.keys(Emoji.table).length) { socket.emit('plugins.composer-quill.getEmojiTable', {}, function (err, table) { if (err) { app.alertError(err.message); } if (table !== null) { Emoji.table = table; quill.on('text-change', Emoji.convert.bind(quill)); } }); } }; Emoji.convert = function (delta) { var quill = this; var contents = quill.getContents(); var emojiRegex = /:([\w+-]+):/g; // Special handling for emoji plugin if (!delta || delta.ops.some(command => command.insert && (command.insert === ':' || String(command.insert).endsWith(':') || String(command.insert).endsWith(': \n')))) { // Check all nodes for emoji shorthand and replace with image contents.reduce(function (retain, cur) { var match = emojiRegex.exec(cur.insert); var contents; var emojiObj; while (match !== null) { emojiObj = Emoji.table[match[1]]; if (emojiObj) { contents = [{ insert: { emoji: config.relative_path + '/plugins/nodebb-plugin-emoji/emoji/' + emojiObj.pack + '/' + emojiObj.image + '?' + app.cacheBuster, }, attributes: { alt: emojiObj.character, class: 'not-responsive emoji emoji-' + emojiObj.pack + ' emoji--' + emojiObj.name, }, }]; if (match[0].length) { contents.unshift({ delete: match[0].length }); } if (retain + match.index) { contents.unshift({ retain: retain + match.index }); } quill.updateContents({ ops: contents, }); } // Reset search and continue emojiRegex.lastIndex = retain + match.index + 1; match = emojiRegex.exec(cur.insert); } retain += cur.insert.length || 1; return retain; }, 0); } }; return Emoji; });