8

I'm trying to create a custom Quill theme, extending the bubble one. I'm facing a strange ES6 inheritance problem, where it seems I cannot call super() in my constructor. Here is my code:

import BubbleTheme, { BubbleTooltip } from 'quill/themes/bubble'

class LoopTheme extends BubbleTheme {
  constructor (quill, options) {
    super(quill, options)
  }

  extendToolbar (toolbar) {
    super.extendToolbar(toolbar)
    this.tooltip = new LoopTooltip(this.quill, this.options.bounds);
    this.tooltip.root.appendChild(toolbar.container);
  }
}

class LoopTooltip extends BubbleTooltip {

}

LoopTooltip.TEMPLATE = [
  '<span class="ql-tooltip-arrow"></span>',
  '<div class="ql-tooltip-editor">',
    '<input type="text" data-formula="e=mc^2" data-link="https://myurl.com" data-video="Embed URL">',
    '<a class="ql-close"></a>',
  '</div>'
].join('');

export { LoopTooltip, LoopTheme as default }

Bubble theme could be found here

My Babel presets:

{
    "presets": [
        "es2015",
        "es2016",
        "stage-0",
        "react"
    ]
}

Webpack js file config:

  module: {
    rules: [
      {
        test: /\.js$/,
        include: [
          resolve(__dirname, 'app')
        ],
        loader: 'babel-loader',
        exclude: /node_modules/
      }, {...

Output generated code:

var LoopTheme = function (_BubbleTheme) {
  _inherits(LoopTheme, _BubbleTheme);

  function LoopTheme() {
    _classCallCheck(this, LoopTheme);

    return _possibleConstructorReturn(this, (LoopTheme.__proto__ || Object.getPrototypeOf(LoopTheme)).apply(this, arguments));
  }

  _createClass(LoopTheme, [{
    key: 'extendToolbar',
    value: function extendToolbar(toolbar) {
      _get(LoopTheme.prototype.__proto__ || Object.getPrototypeOf(LoopTheme.prototype), 'extendToolbar', this).call(this, toolbar);
      this.tooltip = new LoopTooltip(this.quill, this.options.bounds);
      this.tooltip.root.appendChild(toolbar.container);
    }
  }]);

  return LoopTheme;
}(_bubble2.default);

var LoopTooltip = function (_BubbleTooltip) {
  _inherits(LoopTooltip, _BubbleTooltip);

  function LoopTooltip() {
    _classCallCheck(this, LoopTooltip);

    return _possibleConstructorReturn(this, (LoopTooltip.__proto__ || Object.getPrototypeOf(LoopTooltip)).apply(this, arguments));
  }

  return LoopTooltip;
}(_bubble.BubbleTooltip);

LoopTooltip.TEMPLATE = ['<span class="ql-tooltip-arrow"></span>', '<div class="ql-tooltip-editor">', '<input type="text" data-formula="e=mc^2" data-link="myurl.com" data-video="Embed URL">', '<a class="ql-close"></a>', '</div>'].join('');

exports.LoopTooltip = LoopTooltip;
exports.default = LoopTheme;

I'm having the following error: events.js:59 Uncaught TypeError: Class constructor BubbleTheme cannot be invoked without 'new'. However, the LoopTheme is correctly called with new by Quill here. When I debug step by step, I correctly enter the LoopTheme constructor, and the error is raised when super is called.

Am I missing something here? I've always used inheritance, and I use it elsewhere in my code (between my classes), where here am I having trouble?

Thanks for your help

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
guillaumepotier
  • 7,369
  • 8
  • 45
  • 72
  • And where exactly these classes are used? Consider providing http://stackoverflow.com/help/mcve . A plunk that can replicate the issue would help. – Estus Flask Jun 19 '17 at 08:50
  • Please post here presets you're using. Mb complied code would be useful as well. Is this `super(quill, options)` line 19? – deathangel908 Jun 19 '17 at 09:20
  • Hi there, indeed, I added my babel presets and the output generated code. Would you need something more? I may try to add a jsbin/fiddle example? cc @estus – guillaumepotier Jun 19 '17 at 09:24
  • Is `BubbleTheme` transpiled as well? – Bergi Jun 19 '17 at 09:39
  • Posting a plunk/fiddle or a repo that can replicate the problem will increase the chances to solve the problem. – Estus Flask Jun 19 '17 at 10:07
  • @Bergi I suppose so, https://github.com/quilljs/quill/blob/develop/themes/bubble.js uses es6 too – guillaumepotier Jun 19 '17 at 13:01
  • past the snippet where you create the instance of the child class, something like: `var foo = new Foo()` because it seems you are missing the `new operator` and calling the class as a normal function `var foo = Foo()` – Hitmands Jun 19 '17 at 13:05
  • @Hitmands may be not clear enough, but I already put a link to that call on Quill side : https://github.com/quilljs/quill/blob/develop/core/quill.js#L84 the new operator is present I've checked that too :( – guillaumepotier Jun 19 '17 at 13:12
  • @guillaumepotier No, that it uses ES6 does not mean it is automatically transpiled. And actually the transpilation of the `super(toolbar)` call - that `_get(…).call(this, toolbar);` thing - does *not* use `new`, which appears to be the very problem. – Bergi Jun 19 '17 at 16:41
  • @Bergi I don't understand why importing that ES6 Quill source code in my project to extend it won't be transpiled by webpack. I do it a lot with other libs, like emitter3 and stuff. Why would it be different for Quill ? I added part of my webpack config above. Thx$ – guillaumepotier Jun 20 '17 at 07:32
  • I would suspect it has to do with the `exclude: /node_modules/`, but I have no idea about webpack. – Bergi Jun 20 '17 at 13:15

3 Answers3

14

I ran into the exact same issue while extending Quill’s BaseTheme.

As Bergi correctly pointed out in the comments above, this has to do with the fact that babel-loader isn’t transpiling Quill’s modules because they're inside node_modules/, which is excluded.

You can either update the exclude option in your Webpack config and use a regex to skip the node_modules/quill/ folder or use include instead:

{
  test: /\.js$/,
  loader: 'babel-loader',
  include: [
    path.join(__dirname, '../src'), // + any other paths that need to be transpiled
    /\/node_modules\/quill/,
  ]
}
raphaelsaunier
  • 309
  • 2
  • 7
  • Do you have any ideas to have the same behavior with angular-cli ? – Vincenzo Aug 22 '17 at 15:55
  • Thanks Raphael that was that! Next problem is now svg assets required in `ui/icons`.. do you have a specific webpack loader need for that ones ? I tried to include them to my already existing ones but without any luck. Thanks – guillaumepotier Sep 18 '17 at 13:23
  • Yeah, you need to pass them through `html-loader`. The following lines worked for me: https://gist.github.com/raphaelsaunier/5e296aad093cdc5035827660f95b42bf – raphaelsaunier Sep 19 '17 at 14:58
  • @raphaelsaunier thanks a bunch. I also found the Quill documentation explaining how to integrate it into your webpack assets pipeline. Your answer + that worked like a charm! Merci :) – guillaumepotier Oct 06 '17 at 14:36
5

You can also replace this:

import BubbleTheme from 'quill/themes/bubble'

into this:

const BubbleTheme = Quill.import('themes/bubble')
Maxime Chéramy
  • 17,761
  • 8
  • 54
  • 75
0

I would like to suggest another way. In case you are not building quill in you pipe line, you could very well reference the runtime constructor above the extended class.

    import { sanitize } from 'quill/formats/link';

    let BlockEmbed = window['Quill'].import('blots/block/embed');

    export class MediaBlot extends BlockEmbed {
        ...
    }
Bogdan M.
  • 2,161
  • 6
  • 31
  • 53