Quill: Quill 2.0.0-dev.3 is broken on iOS with Chinese IME

Created on 20 Nov 2018  ·  9Comments  ·  Source: quilljs/quill

Steps for Reproduction

  1. Visit https://codepen.io/intptr/full/yQPdxW
  2. Switch to Chinese IME
  3. Input something

Expected behavior:

Everything works fine

Actual behavior:

Editor is broken

Platforms:

Safari on iOS 11 / 12

Version:

2.0.0-dev.3

Most helpful comment

Actual behavior supplement:

Can't delete character after input, quill.getContents get empty content.

I think it cause by safari's insert behavior, here is how I found the problem:

First, add some logs in quill constructor:

this.root.addEventListener('compositionstart', () => {
  console.log('compositionstart')
})

this.root.addEventListener('compositionend', () => {
  console.log('compositionend')
})

let logObserver = new MutationObserver((mutations) => {
  console.log(mutations)
})

logObserver.observe(this.root, {
  attributes: true,
  characterData: true,
  characterDataOldValue: true,
  childList: true,
  subtree: true,
})

Then input one Chinese character in editor.

2018-12-05 23 13 05

Chrome

2018-12-05 23 09 40

It's what we expect, when compositionend trigger, changes content will store in mutations.

Safari

2018-12-05 23 10 00

There are two different:

  1. In mutations before compositionend, characterData target's content is empty.
  2. In mutations after compositionend, safari do few things: 1) remove text content in step 1. 2) add a <br> tag. 3) insert user input before <br>. 4) remove <br> tag.

So when compositionend trigger, quill can not get correct inputs. I don't know why safari works like that, and could not found any documents after search.

I add a patch in core/selection.js:

  handleComposition() {
    this.root.addEventListener('compositionstart', () => {
      this.composing = true;
      this.scroll.batchStart();
    });
    this.root.addEventListener('compositionend', () => {
      setTimeout(() => { // <- add this line
        this.scroll.batchEnd();
        this.composing = false;
        if (this.cursor.parent) {
          const range = this.cursor.restore();
          if (!range) return;
          setTimeout(() => {
            this.setNativeRange(
              range.startNode,
              range.startOffset,
              range.endNode,
              range.endOffset,
            );
          }, 1);
        }
      }, 0) // <- and this
    });
  }

This patch delay this.scroll.batchEnd() execution after the second time observe callback execute, then quill will get the correct inputs.

I don't know if it will break something, and is it the right way to fix? @jhchen

All 9 comments

Actual behavior supplement:

Can't delete character after input, quill.getContents get empty content.

I think it cause by safari's insert behavior, here is how I found the problem:

First, add some logs in quill constructor:

this.root.addEventListener('compositionstart', () => {
  console.log('compositionstart')
})

this.root.addEventListener('compositionend', () => {
  console.log('compositionend')
})

let logObserver = new MutationObserver((mutations) => {
  console.log(mutations)
})

logObserver.observe(this.root, {
  attributes: true,
  characterData: true,
  characterDataOldValue: true,
  childList: true,
  subtree: true,
})

Then input one Chinese character in editor.

2018-12-05 23 13 05

Chrome

2018-12-05 23 09 40

It's what we expect, when compositionend trigger, changes content will store in mutations.

Safari

2018-12-05 23 10 00

There are two different:

  1. In mutations before compositionend, characterData target's content is empty.
  2. In mutations after compositionend, safari do few things: 1) remove text content in step 1. 2) add a <br> tag. 3) insert user input before <br>. 4) remove <br> tag.

So when compositionend trigger, quill can not get correct inputs. I don't know why safari works like that, and could not found any documents after search.

I add a patch in core/selection.js:

  handleComposition() {
    this.root.addEventListener('compositionstart', () => {
      this.composing = true;
      this.scroll.batchStart();
    });
    this.root.addEventListener('compositionend', () => {
      setTimeout(() => { // <- add this line
        this.scroll.batchEnd();
        this.composing = false;
        if (this.cursor.parent) {
          const range = this.cursor.restore();
          if (!range) return;
          setTimeout(() => {
            this.setNativeRange(
              range.startNode,
              range.startOffset,
              range.endNode,
              range.endOffset,
            );
          }, 1);
        }
      }, 0) // <- and this
    });
  }

This patch delay this.scroll.batchEnd() execution after the second time observe callback execute, then quill will get the correct inputs.

I don't know if it will break something, and is it the right way to fix? @jhchen

@chloerei Thanks, your solution helps me a lot.
When I typing with Chinese IME in a empty line, and press delete key to delete all composing, a new unexpected line will appear under current line.
After I merge your solution, it was fixed.
But another problem still alive, if there's a line above the typing empty line, when I press delete key durring composing, the current line with composing chars will be inserted into the start of above line.
Screen shot for Steps
image
image
image
Could you have any ideas ?
THX~

@soccerloway Yes it's broken, but I'm going to ProseMirror witch does not have IME problem...

@chloerei Thanks, your solution helps me a lot.
When I typing with Chinese IME in a empty line, and press delete key to delete all composing, a new unexpected line will appear under current line.
After I merge your solution, it was fixed.
But another problem still alive, if there's a line above the typing empty line, when I press delete key durring composing, the current line with composing chars will be inserted into the start of above line.
Screen shot for Steps
image
image
image
Could you have any ideas ?
THX~

I have the same issue, very annoying

@chloerei Thanks, your solution helps me a lot.
When I typing with Chinese IME in a empty line, and press delete key to delete all composing, a new unexpected line will appear under current line.
After I merge your solution, it was fixed.
But another problem still alive, if there's a line above the typing empty line, when I press delete key durring composing, the current line with composing chars will be inserted into the start of above line.
Screen shot for Steps
image
image
image
Could you have any ideas ?
THX~

I found a solution, add

      // change bindings from const to let
      if (evt.key === 'Backspace' && evt.which === 229) {
        bindings = [];
      }

to modules/keyboard.js listen() around line 105, will fix this issue.

I investigate this issue, find in v1.3.6, the logic in keyboard.js was

      let bindings = (this.bindings[which] || []).filter(function(binding) {
        return Keyboard.match(evt, binding);
      });

but in v2.0.0-dev3, the code change to

      const bindings = (this.bindings[evt.key] || []).concat(
        this.bindings[evt.which] || [],
      );

When in cjk mode, if the input method pop up exists, the evt.key was original key, but evt.which was 229, which will hand by inpout method, not by the editor, so change back to

      const bindings = this.bindings[evt.which] || [];

will fix this problem, hope this will help who trouble with this problem.

@lyuehh

Hello, I also have a problem.

When I format a line by using quill.format('indent', 1) --- just like below
<p class="ql-indent-1"><br></p>

And, I input a Chinese e. g. "你好", I get a right result in Chrome
<p class="ql-indent-1">你好</p>

But I get a wrong result in Safari
<p>你好</p>

It lost the class 'ql-indent-1' format. I also find the MutationObserver print diffrently, but I have no solution.

Do you have any idea?

@lyuehh

Hello, I also have a problem.

When I format a line by using quill.format('indent', 1) --- just like below
<p class="ql-indent-1"><br></p>

And, I input a Chinese e. g. "你好", I get a right result in Chrome
<p class="ql-indent-1">你好</p>

But I get a wrong result in Safari
<p>你好</p>

It lost the class 'ql-indent-1' format. I also find the MutationObserver print diffrently, but I have no solution.

Do you have any idea?

No idea, quill 2.0.0 is not finished, don't use this version.

I think it is not quill 2.0.0 problem. Maybe it’s Safari’s problem.

BTW, 谢谢~

在 2019年5月15日,17:28,lyuehh <[email protected] notifications@github.com> 写道:

@lyuehh https://github.com/lyuehh
Hello, I also have a problem.

When I format a line by using quill.format('indent', 1) --- just like below


And, I input a Chinese e. g. "你好", I get a right result in Chrome

你好

But I get a wrong result in Safari

你好

It lost the class 'ql-indent-1' format. I also find the MutationObserver print diffrently, but I have no solution.

Do you have any idea?

No idea, quill 2.0.0 is not finished, don't use this version.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/quilljs/quill/issues/2405?email_source=notifications&email_token=ACAZPWAHDHURW4OY2L2WMBTPVPJULA5CNFSM4GFMICWKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVOCQZA#issuecomment-492578916, or mute the thread https://github.com/notifications/unsubscribe-auth/ACAZPWB276MGC2N3L4INV73PVPJULANCNFSM4GFMICWA.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ouhman picture ouhman  ·  3Comments

benbro picture benbro  ·  3Comments

scottfr picture scottfr  ·  3Comments

DaniilVeriga picture DaniilVeriga  ·  3Comments

rsdrsd picture rsdrsd  ·  3Comments