Fabric.js: IText not editable when canvas is in a fullscreen element on chrome

Created on 28 Jul 2018  ·  40Comments  ·  Source: fabricjs/fabric.js

Version

2.3.3 (At this moment at the official test page)
I am still using 1.7.20 in my app.
chrome Version 67.0.3396.99 (Official Build) (64-bit)

Test Case

Fabric.js tests · IText tests
http://fabricjs.com/test/misc/itext.html

Steps to reproduce

open the official IText demo in chrome
open console and run this code :
document.querySelector('.example > .canvas-container').webkitRequestFullscreen()
double click in text and try to edit.

Expected Behavior

Text be edited and I can see the typed characters
works as expected in FireFox

Actual Behavior

Nothing happens! Keyboard does not work at all !!!

needs_confirmation stale

Most helpful comment

I think I was having a similar issue when using the canvas within a bootstrap modal (using fabric 2.3.6). I was able to get the text selection but no keyboard input had any affect at changing the text.

The only change I made was in initHiddenTextarea: function(), change the following lines:

fabric.document.body.appendChild(this.hiddenTextarea)

becomes:

this.canvas.wrapperEl.appendChild(this.hiddenTextarea);

This made the IText and Texbox items editable again

All 40 comments

i think it is because the hiddenTextarea responsible for editing is actually in the body and not in .canvas-container

Can you link me some doc about this webkitRequestFullscreen so that i can read how is supposed to behave and if is detectable?

i m open to the idea of having a check if there is a fullscreen element and in that case append the textarea to the canvas-container instead of the body.
In case this creates other problems i will revert the patch.

I think I was having a similar issue when using the canvas within a bootstrap modal (using fabric 2.3.6). I was able to get the text selection but no keyboard input had any affect at changing the text.

The only change I made was in initHiddenTextarea: function(), change the following lines:

fabric.document.body.appendChild(this.hiddenTextarea)

becomes:

this.canvas.wrapperEl.appendChild(this.hiddenTextarea);

This made the IText and Texbox items editable again

Facing the same problem with canvas on bootstrap modal

my patch for now based on @marshall76963 's answer

  const _original_initHiddenTextarea   = fabric.IText.prototype.initHiddenTextarea;
  fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {    
    //fix for : IText not editable when canvas is in a fullscreen element on chrome
    // https://github.com/fabricjs/fabric.js/issues/5126
    initHiddenTextarea: function() {
      _original_initHiddenTextarea.call(this);
      this.canvas.wrapperEl.appendChild(this.hiddenTextarea);
    }
  });

After being fighting with this for a while I found this issue was already reported solved and the solution reverted because it gives selections issues on I.E.

This is the pr with a fix similar to the one proposed by @Exlord https://github.com/fabricjs/fabric.js/pull/3754

Here a picture of the selection issue on IE when the textarea is inside the dialog element. It will highlight the iText on the canvas but it will not be reflected on the textarea.
insidedialog

The issue caused by this change is documented here https://github.com/fabricjs/fabric.js/pull/3137

Here the same selection with the textarea placed on the body. Note how the focus now is not in the textarea but in the canvas container (red border) so typing doesn't work anymore.
insidebody

@asturur maybe you can help us understand how the selection is mapped between the iText and the hidden texteara and why doesn't work when adding the component inside the container on I.E.

Thanks!

The selection is mapped and has to stay mapped so that we can edit complex text situation where knowing selectionstart-selectionend is not enough.
Example:

the macOS long press popup makes a substitution without any kind of keydown/keyup event
Some text has ha visual representation that does not match the byte count ( 2 letter selected at screen, 8 positions in textarea)
Japanese/chinese text do have some kind of replacement logic in their input method that can't be tracked manually.

To solve all of this we need the hidden textarea to process those inputs rather than our JS, and then listen to the input event and have the fabric code represent the new textarea situation.

For this to happen while we modify the fabric selection we have to be sure that the textarea is selected in the sameway so that is ready to get the input events and react how the user would expect

I.E. is I.E. it makes strange things and we cannot do much about it.

Since I.E. does not support fullscreen mode presumably, you can still append the textarea somewhere else when you enter fullscreen mode. There may be other things that will make the textarea position (top/left) go wrong but if you do not use chines/japanese that may be not an issue

I am using Material-UI (https://material-ui.com/) and especially, the Dialog component (https://material-ui.com/components/dialogs/).

I can't make IText or Textbox object work when the canvas is inside a Dialog. I don't understand why I am not able to do it

I was able to fix it by changing the initHiddenTextarea method defined here: https://github.com/fabricjs/fabric.js/blob/031144a58e1974395c9c16b5ec6e658b5d9b568b/src/mixins/itext_key_behavior.mixin.js#L6

I used this code:

  fabric.util.object.extend(fabric.IText.prototype, {    
    initHiddenTextarea: function() {
      // The original function code with some modifications
    }
  });

where the modifications are:

  • replacing this fabric.document.body.appendChild(this.hiddenTextarea); by this.canvas.wrapperEl.appendChild(this.hiddenTextarea);
  • replacing this this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top + '; left: ' + style.left + '; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px;' + ' paddingーtop: ' + style.fontSize + ';'; by 'z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; padding: 0;'

@asturur Why do you set left, top, padding-top properties on the hiddenTextarea? I don't understand their purpose

Left and top needs to be updated because the hidden text area needs to follow the blinking cursor in order to properly support chinese/japanese and other languages that need the textarea to display suggestions.

padding-top had to be some workaround to position the textarea enough under the text we are painting. Probably there was some difficulties if i would set the height of the textarea directly.

Appending the the textarea to canvas container rather than document.body was creating some difficulties to ie11.

Thank you for this detailed answer!

If you don't support IE11 anymore, I think it would be better to add textarea to canvas container again, because otherwise, it makes embedding the textarea in popup impossible

in theory we support ie10 up.
I tested this nearly 3 years ago. If you have a ie11 machine i would reverify it. The main problem was the document jumping up and down, but it could also be that sequent changes solved the problem elsewhere.

I'd never heard of fabric.js until yesterday so please excuse my ignorance. I'm using TUI Image Editor which uses fabric.js, and I'm having a similar issue to this.

My image editor (using fabric.js) is inside a Bootstrap modal. When I add a text area to the canvas and try to type, as others have described here, nothing happens. I can select the text but presses of keyboard keys have no effect. This is in the latest version of Chrome and I'm using fabric.js v3.6.0.

I've noticed that if I hit the ESC key whilst trying to edit the text, I can see the Bootstrap modal close behind the fabric.js canvas (so that key press obviously isn't being handled by fabric.js as expected), but after that the text becomes editable, so the problem is definitely somehow related to the canvas element being inside the modal.

I tried to make the changes outlined by @lcswillems but unfortunately they haven't solved the problem for me.

EDIT: I've also tried the patch mentioned above by @Exlord but I'm still unable to edit the text and now, when I double-click on the text area to try and edit, the image jumps around the page.

before moving forward we should agree at least that modals do not exists. Bootstrap creates a div structure that looks like a modal. If they catch the key events or if they focus something else, the textarea stop to works. is it possible to recreate your setup in a fiddle or codepen?

before moving forward we should agree at least that modals do not exists. Bootstrap creates a div structure that looks like a modal. If they catch the key events or if they focus something else, the textarea stop to works.

Agreed!

is it possible to recreate your setup in a fiddle or codepen?

This fiddle was created by @kghandi a couple of years ago but it seems to be exactly the same issue and I experience the same problem of being unable to edit the text. This is from #3754.

we have currently 2 issues with the inputs. one is the fullscreen option and other is the event blocking container.

both could be resolved putting back the textarea in the canvas container, if this won t make the page jumps start again. The problem is that i have no time to dedicate to ie11 and i have no a reproducible test case for the page jumps. If we want this to move forward i need help.

first step would be digup the pr in which we initially moved again the textarea outside and look at comments if there are tracks of reproducible issues.

My solution (with all the caveats mentioned above by many previous commentors) was to add this this to a seperate JS file and include it after fabric.js:

fabric.IText.prototype.initHiddenTextarea = (function (initHiddenTextarea) {
    return function () {
        var result = initHiddenTextarea.apply(this);
        fabric.document.body.removeChild(this.hiddenTextarea);
        this.canvas.wrapperEl.appendChild(this.hiddenTextarea);
        return result;
    };
})(fabric.IText.prototype.initHiddenTextarea);

I can confirm that this works on IE11 (and other browsers) whilst using a fabric canvas in a bootstrap (v3) popup.

@marshall76963 For some reason, when I try this solution, as with one or two of the others suggested, clicking on the text to edit it causes the image to jump around the screen, and the text never becomes editable. I don't know what I'm doing differently that prevents this from working for me.

it may depend from the current hiddenTextArea style.

Well, I've spent about 2 days on this now and haven't got the time to get right to the bottom of the issue but this is where I'm at:

  • I'm using Froala's WYSIWYG text editor, which uses TUI Image Editor (which uses Fabric.js) for advanced image editing. The text editor is inside a Bootstrap (v3) modal.
  • When Froala instantiates the TUI Image Editor it adds the element as a direct descendent of the DOM body.
  • When I add text to an image and try to edit it, the hiddentTextarea is therefore also added as a direct descendent of the body. The text is not editable.
  • If I use the DevTools console to manually remove the open modal element from the DOM (which is not visible on screen because it's behind the TUI Image Editor element), the text becomes editable. So it's definitely the open modal that's interfering.

As a result, I've come up with this hacky solution which works for me, given my current project time constraints. It uses the patch from @marshall76963, but slightly modified.

fabric.IText.prototype.initHiddenTextarea = (function (initHiddenTextarea) {
    return function () {
        var result = initHiddenTextarea.apply(this);        
        if (document.querySelectorAll(".modal.fade.in").length > 0) {
            fabric.document.body.removeChild(this.hiddenTextarea);
            document.getElementsByClassName("modal fade in")[0].appendChild(this.hiddenTextarea);
        }        
        return result;
    };
})(fabric.IText.prototype.initHiddenTextarea);

By adding the hiddenTextarea to the modal element in this way if a modal is visible, it allows the text to always be editable.

because the modal div/box is probably eating and killing keyboard events, somehow is also stealing the focus from it? i m not sure how it can steal events if the textarea is outside of it and has focus....

Does it work out of the box if you try to do textbox.hiddenTextarea.focus() with a setTimeout at some point? just as a try

@asturur Doesn't seem to. I modified the patch as follows to test:

fabric.IText.prototype.initHiddenTextarea = (function (initHiddenTextarea) {
    return function () {
        var result = initHiddenTextarea.apply(this);
        window.setTimeout(function () {
            document.querySelectorAll('[data-fabric-hiddentextarea]')[0].focus();
            console.log("focussed");
        }, 5000);
        return result;
    };
})(fabric.IText.prototype.initHiddenTextarea);

The text is still not editable after the timeout.

I would really appreciate if someone could throw in a simple demo page that is broken on fabricjs.com ( copy pasting another itext demo page ) to replicate this bug.
A canvas with an IText in a modal that can't be edited.

Having a broken example makes easier to fix it and the mantain it fixed.
Automated testing for this is hard

I think my post from yesterday contains a link to exactly such a fiddle.

I guess this issue relates to : #3695

My solution was to change :

fabric.document.body.appendChild(this.hiddenTextarea); ( line : 28350, Fabricjs 3.6.1 )
to
this.canvas.upperCanvasEl.parentElement.appendChild(this.hiddenTextarea);

This way the Textarea is created within the scope of the canvas elemt itself wherever it is in the DOM. It will get the same events fired within a modal, the same way any other will get it. Modals WILL prevent events from bubling upto body elements, thats why they _are_ modal.

Might be worth checking for a patch ?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

I'm having the same problem, except in my page I'm not using Bootstrap modal, but a pure HTML5 <dialog>.

The tui-image-editor isn't located inside the <dialog>, it's actually loaded into an <iframe> elsewhere on the page while the <dialog> element is in the root DOM, but the <dialog> does not have the open attribute set - yet despite that, something about the <dialog> is blocking keyboard events to the hidden <textarea>.

None of my own scripts set-up keyboard event-handlers or call anything like ev.preventDefault().

My workaround for now is to destroy the <dialog> instead of hiding it and to recreate it when the tui-image-editor is closed.

I still don't know what is special about <dialog> that causes it to block keyboard input to other iframes when the <dialog> is closed - perhaps it's a bug in Chrome?

FWIW, things are fine in Firefox - but I think Firefox is using the dialog-polyfill I'm using.


I believe this code below should repro the problem in Chrome (I'm not actually able to verify that this actually does repro it right now - if someone could test it and see if it doesn't repro then I'll put more effort into making a reliable repro).

<html>
<body>
<dialog>Foobar</dialog> <!-- Note this dialog is not `<dialog open>`. -->
<div>
    <iframe src="tuiImageEditorDemo.html"></iframe>
</div>
</body>
</html>

(where tuiImageEditorDemo.html is this page: https://github.com/nhn/tui.image-editor/blob/master/examples/example01-includeUi.html

i did not even know we had a dialog html element. Definetely there is that textarea bug to solve and maybe put a switch for ie11 to keepmit working. The reason why i did not keep working in this bug is because i do not have a dev friendly ie11 setup

i do not have a dev friendly ie11 setup

So why do you still support ie11? You can't even test the code under ie11. Stoping supporting ie11 (that is not used anymore) would help to solve this issue

because is still out there and has a canvas. ie10 and ie11 in theory works. Ie10
could go out of support easily since if you are stuck in that you probably have a terrible internet experience with or without fabricjs.

Fabric 4 is still in beta so we could remove it. I l not 100% sure i want to do it.

Probably who wants really make something new and still support ie11 can eventually leave with 3.6.2 and backport stuff.

Another reason is that in my everyday work i do support ie11 and i would create a problem to myself unsupporting it.

@asturur

The reason why i did not keep working in this bug is because i do not have a dev friendly ie11 setup

But this issue happens in (at least) Chrome 80, which was released a week ago - the polar opposite of IE11.

FWIW, you can download an IE11 virtual-machine for dev/testing directly from Microsoft: https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/

@Jehoel is right. It seems you prefer support IE11 rather than Chrome 80...

@lcswillems As a bonus, I used to work on Internet Explorer 11 when I was at Microsoft 😁

...not that this should influence this discussion at all.

The bug is older, everytime the canvas is either in a div catching events,
or this new dialog element, or a fullscreen element. IText won't work.
Is not related to chrome 80 only. Is related to keypresses not reaching the
hiddentextarea.
I also proposed to make a configuration option, in order to attach the
hiddenTextarea to the canvas container to fix the problem and support the
necessary different calculations.
But no one opened a PR.
Having another option could be better than break ie11.
As a plus ie11 would be broken only for languages using composition (
chinese, japanese and others ). So for people wanting to use this option,
they would not be affected in ie11 if not targeting those languages.

Il giorno lun 24 feb 2020 alle ore 13:58 Dai notifications@github.com ha
scritto:

@lcswillems https://github.com/lcswillems As a bonus, I used to work on
Internet Explorer 11 when I was at Microsoft :D


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/fabricjs/fabric.js/issues/5126?email_source=notifications&email_token=AAJDQQEW26GHIFAZ4X7ICGLREO77PA5CNFSM4FMT43X2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMXV66Q#issuecomment-590307194,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAJDQQBCF6ANPSVBT4J4WZTREO77PANCNFSM4FMT43XQ
.

I also proposed to make a configuration option, in order to attach the
hiddenTextarea to the canvas container to fix the problem and support the
necessary different calculations.

@asturur FWIW, I did try this and unfortunately that didn't fix the problem for me. It seems that whenever a <dialog> is present (and not necessarily open) in the parent page then any other hidden <textarea> in an <iframe> in the same page won't receive keyboard events.

i would need to read the dialog specifications, there could be no fix
available then.
The problem with supporting ie11 is just attaching the textarea in the
canvas container. If that does not fix your problem, ie11 is not a problem.

Il giorno lun 24 feb 2020 alle ore 14:06 Dai notifications@github.com ha
scritto:

I also proposed to make a configuration option, in order to attach the
hiddenTextarea to the canvas container to fix the problem and support the
necessary different calculations.

@asturur https://github.com/asturur FWIW, I did try this and
unfortunately that didn't fix the problem for me. It seems that whenever a

is open in the parent page then any other hidden