QuillEditor (quill.js) - OhMinsSup/tip-review GitHub Wiki

'use strict';
import './register';
import Quill from 'quill';
import inJectEditor from './inject';

const checker = {
  youtube: text => {
    const regex = /^https:\/\/www.youtube.com\/embed\/(.*?)$/;
    const result = regex.exec(text);
    if (!result) return null;
    return result[1];
  },
  twitter: text => {
    const pathMatch = /twitter.com\/(.*?)\?/.exec(text);
    if (!pathMatch) return null;
    return pathMatch[1];
  },
};

class QuillEditor extends inJectEditor {
  _quill = null;
  _element = '';
  _isModify = false;
  _html = '';
  _text = '';
  constructor(element, options, title, isModify, initialHtml) {
    super();
    this._element = element;
    if (isModify) {
      this._isModify = isModify;
      this._html = initialHtml;
    }

    const isOption = options && Object.keys(options).length > 0;
    if (isOption) {
      $(this._element).before('<div id="editor-header"></div>');
      $(this._element).after('<div id="editor-footer"></div>');
      $('#editor-header').after(`<h3 class="custom-h3 pb-2">${title || '๋‚ด์šฉ'}</h3>`);
      // opinion, eventTime, postTime, using, version, title
      const keys = Object.keys(options);
      keys.forEach(key => {
        const property = options[key];
        const { use, injectEle, required } = property;
        if (use) {
          const option = {
            injectEle,
            required,
          };
          this.injectFn(key, option);
        }
        return property;
      });
    } else {
      $(this._element).before(`<h3 class="custom-h3 pb-2">${title || '๋‚ด์šฉ'}</h3>`);
    }

    this.created();
  }

  created() {
    const bindings = {
      removeCodeBlock: {
        key: 'backspace',
        empty: true,
        format: ['code-block'],
        handler: () => {
          this._quill.format('code-block', false);
        },
      },
      removeQuote: {
        key: 'enter',
        empty: true,
        format: ['blockquote'],
        handler: () => {
          this._quill.format('blockquote', false);
        },
      },
      removeQuoteWithBackspace: {
        key: 'backspace',
        empty: true,
        format: ['blockquote'],
        handler: () => {
          this._quill.format('blockquote', false);
        },
      },
    };

    this._quill = new Quill(this._element, {
      theme: 'snow',
      modules: {
        keyboard: {
          bindings,
        },
        toolbar: [
          [{ font: [] }, { size: [] }],
          ['bold', 'italic', 'underline', 'strike'],
          [{ color: [] }, { background: [] }],
          [{ header: [false, 1, 2, 3, 4, 5, 6] }, 'blockquote'],
          [{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
          ['link', 'image'],
          ['tweet', 'youtube']
        ],
        clipboard: {
          // https://quilljs.com/docs/modules/clipboard/#matchvisual
          matchVisual: false,
        },
      },
      bounds: document.querySelector('#quill-editor'),
      placeholder: '๋‚ด์šฉ์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.',
    });

    this.applyEventListeners();

    if (this._isModify) {
      this._quill.root.innerHTML = this._html;
    }
  }

  addImageToEditor = image => {
    if (!this._quill) return false;
    this._quill.focus();
    const range = this._quill.getSelection();
    if (!range) return false;
    this._quill.insertEmbed(range.index, 'image', image);
    this._quill.insertText(range.index + 2, '');
    this._quill.setSelection(range.index + 2, 0);
    this._quill.focus();
    return true;
  };

  addYoutubeToEditor = (url) => {
    if (!this._quill) return false;
    this._quill.focus();
    const range = this._quill.getSelection(true);
    if (!range) return false;
    // 'https://www.youtube.com/embed/QHH3iSeDBLo?showinfo=0';
    this._quill.insertText(range.index, '\n', Quill.sources.USER);
    this._quill.insertEmbed(range.index + 1, 'video', url, Quill.sources.USER);
    this._quill.formatText(range.index + 1, 1, { height: '400', width: '500' });
    this._quill.setSelection(range.index + 2, Quill.sources.SILENT);
    this._quill.focus();
    return true;
  };

  addTwitterToEditor = (id) => {
    if (!this._quill) return false;
    this._quill.focus();
    const range = this._quill.getSelection(true);
    if (!range) return false;
    // '464454167226904576';
    this._quill.insertText(range.index, '\n', Quill.sources.USER);
    this._quill.insertEmbed(range.index + 1, 'tweet', id, Quill.sources.USER);
    this._quill.setSelection(range.index + 2, Quill.sources.SILENT);
    this._quill.focus();
    return true;
  };

  applyEventListeners = () => {
    const that = this;
    this._quill.on('text-change', () => {
      that._html = that._quill.root.innerHTML;
      that._text = that._quill.getText();
      console.log(that._html);
    });

    this._quill.getModule('toolbar').addHandler('image', () => {
      const input = document.createElement('input');
      input.type = 'file';
      input.onchange = () => {
        if (!input.files) return;
        const file = input.files[0];
        console.log(file);
        // TODO: ์ถ”ํ›„ ์—…๋กœ๋“œํ•˜๋Š” api์ถ”๊ฐ€
        const image =
          'https://images.velog.io/post-images/velopert/8bd63950-b353-11e8-b01f-598f1220d1c8/mobx.png';
        that.addImageToEditor(image);
      };
      input.click();
    });

    this._quill.getModule('toolbar').addHandler('tweet', () => {
      const value = prompt('Enter URL:');
      const checked = checker.twitter(value);
      if (value && checked) {
        const splitValue = checked.split('/');
        const id = splitValue[splitValue.length - 1];
        that.addTwitterToEditor(id);
      }
    });

    this._quill.getModule('toolbar').addHandler('youtube', () => {
      const value = prompt('Enter URL:');
      if (value && checker.youtube(value)) {
        that.addYoutubeToEditor(value);
      }
    });
  };

  injectFn = (key, option) => {
    switch (key) {
      case 'opinion':
        this.injectOpinionOption(option);
        break;
      case 'eventTime':
        this.injectEventTimeOption(option);
        break;
      case 'postTime':
        this.injectPostTimeOption(option);
        break;
      case 'using':
        this.injectUsingOption(option);
        break;
      case 'version':
        this.injectVersionOption(option);
        break;
      case 'title':
        this.injectTitleOption(option);
        break;
      case 'classification':
        this.inJectClassificationOption(option);
        break;
      case 'template':
        this.injectTemplateOption(option);
        break;
      default:
        console.log('์œ ํšจํ•˜์ง€ ์•Š๋Š” injectํƒ€์ž…::', key);
        break;
    }
  };
}

export default QuillEditor;
โš ๏ธ **GitHub.com Fallback** โš ๏ธ