Open timoostrich opened 4 years ago
Same issue for me. It is not working in android chrome latest version (85). Working in all other android browsers. I think issue since last chrome update @Timoostrich Please comment if you found any solution
Just did some more tests. Firefox on Android (latest version) works fine - the keyboard comes up. Huawei's Browser has the same problem like chrome - no keyboard comes up.
I also tried to do focus() or click() on the hiddenTextarea, but I had no success.
I found a solution for now.
Modified initHiddenTextarea function like this
const initHiddenTextarea = function() { this.hiddenTextarea = fabric.document.createElement('textarea'); this.hiddenTextarea.setAttribute('autocapitalize', 'off'); this.hiddenTextarea.setAttribute('autocorrect', 'off'); this.hiddenTextarea.setAttribute('autocomplete', 'off'); this.hiddenTextarea.setAttribute('spellcheck', 'false'); this.hiddenTextarea.setAttribute('data-fabric-hiddentextarea', ''); this.hiddenTextarea.setAttribute('wrap', 'off'); var style = this._calcTextareaPosition(); // line-height: 1px; was removed from the style to fix this: // https://bugs.chromium.org/p/chromium/issues/detail?id=870966 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 + ';'; fabric.document.body.appendChild(this.hiddenTextarea); fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'input', this.onInput.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'cut', this.copy.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'compositionstart', this.onCompositionStart.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'compositionupdate', this.onCompositionUpdate.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'compositionend', this.onCompositionEnd.bind(this)); if (!this._clickHandlerInitialized && this.canvas) { fabric.util.addListener(this.canvas.upperCanvasEl, 'touchstart', this.clickFunc.bind(this)); fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.clickFunc.bind(this)); this._clickHandlerInitialized = true; } }
Extra added code is fabric.util.addListener(this.canvas.upperCanvasEl, 'touchstart', this.clickFunc.bind(this));
and extended fabric text box like this,
fabric.util.object.extend(fabric.Textbox.prototype, { initHiddenTextarea: initHiddenTextarea });
i ll give it a look, i do not have an android device anymore.
I found a solution for now. Modified initHiddenTextarea function like this
const initHiddenTextarea = function() { this.hiddenTextarea = fabric.document.createElement('textarea'); this.hiddenTextarea.setAttribute('autocapitalize', 'off'); this.hiddenTextarea.setAttribute('autocorrect', 'off'); this.hiddenTextarea.setAttribute('autocomplete', 'off'); this.hiddenTextarea.setAttribute('spellcheck', 'false'); this.hiddenTextarea.setAttribute('data-fabric-hiddentextarea', ''); this.hiddenTextarea.setAttribute('wrap', 'off'); var style = this._calcTextareaPosition(); // line-height: 1px; was removed from the style to fix this: // https://bugs.chromium.org/p/chromium/issues/detail?id=870966 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 + ';'; fabric.document.body.appendChild(this.hiddenTextarea); fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'input', this.onInput.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'cut', this.copy.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'compositionstart', this.onCompositionStart.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'compositionupdate', this.onCompositionUpdate.bind(this)); fabric.util.addListener(this.hiddenTextarea, 'compositionend', this.onCompositionEnd.bind(this)); if (!this._clickHandlerInitialized && this.canvas) { fabric.util.addListener(this.canvas.upperCanvasEl, 'touchstart', this.clickFunc.bind(this)); fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.clickFunc.bind(this)); this._clickHandlerInitialized = true; } }
Extra added code is fabric.util.addListener(this.canvas.upperCanvasEl, 'touchstart', this.clickFunc.bind(this));
and extended fabric text box like this,
fabric.util.object.extend(fabric.Textbox.prototype, { initHiddenTextarea: initHiddenTextarea });
What does is do? Did you only remove the 1px line-height?
this happened to me too :(, any solution?
My quick workaround is an additional textarea which is synced to the hiddentextarea of fabric: https://lettering.org/lettering-generator/
`//Sync hiddenTextarea and input in containter function syncTextToInput(){ var $textarea = document.querySelector('textarea[data-fabric-hiddentextarea]'); var $input = document.querySelector(".js-synced-text"); $input.value = $textarea.value; }
function syncTextToCanvas(){ var $textarea = document.querySelector('textarea[data-fabric-hiddentextarea]'); var $input = document.querySelector(".js-synced-text"); $textarea.value = $input.value; var event = new Event('input'); $textarea.dispatchEvent(event); }`
Same issue here, Chrome 92 on Android 10 - tapping on a text box doesn't start edit. The most current Firefox for Android is fine.
@Timoostrich Does your workaround work? I've tried https://lettering.org/lettering-generator/ in Android Chrome and seems the issue is still there. Very nice project, though!
Same issue here, Chrome 92 on Android 10 - tapping on a text box doesn't start edit. The most current Firefox for Android is fine.
@Timoostrich Does your workaround work? I've tried https://lettering.org/lettering-generator/ in Android Chrome and seems the issue is still there. Very nice project, though!
Thank you! Well, there should appear some kind of layer whenever you want to edit a textbox. It's just an additional text input which is synced to the hidden input of fabric.
same issue, chromium 92.0.4515.131, Samsung Note Android 10. No keyboard when tapping on itext box. Tried the demo page: http://fabricjs.com/test/misc/itext.html It's a serious bug and it makes fabricjs useless on android phones. Please fix it asap.
i don't have any android device anymore where i can test those kind of things
I've found the root cause of this bug. For Chrome on android, single touch will wrongly trigger touchmove event, while chrome on ios doesn't behave like this. The fix is to record the point of touchstart event, and compare the saved point with current touch point in touchmove event, if they are too close, then we know it's not a touch move event, and this touchmove event is ignored. fix.zip In the attached fix.zip, it contains a diff and fixed version of fabric.js v4.6.0.
single touch should trigger both touchStart and touchMove. If touchStart isn't triggered, this is a chrome bug and i m not sure why fabricJS should fix it
touchstart is triggered on single touch. But touchmove is not supposed to be triggered for single touch if there is no dragging. I think it's a bug in chrome on android. My fix is a workaround to make editing of itext work in chome on android.
So are there any updates regarding this? Becase as is, this is not usable on android phones. Someone got a workaround at least?
Inspired by @KevinShea1990's fix, I built a workaround for the latest Fabric version (6.0.0-beta10). I'm subscribing to the 'touchstart' and 'touchmove' events. If it's Android and the active item on 'touchstart' is an IText item, I'm locking its position, so it cannot be moved on the canvas. Then, in the 'touchmove' event, if the distance is large enough from the 'touchstart' coordinates, I'm unlocking the object again.
This way, entering text edit mode on Android works reliably every time, and not only on ~1/10 attempts like before.
const isAndroid = /Android/.test(navigator.userAgent);
let touchStartX = 0;
let touchStartY = 0;
canvas.getSelectionElement().addEventListener('touchstart', (e) => {
if (isAndroid) {
const touch = e.touches[0] || e.changedTouches[0];
touchStartX = touch.pageX;
touchStartY = touch.pageY;
const active = canvas.getActiveObject();
if (active?.isType('i-text')) {
(active as fabric.IText).lockMovementX = true;
(active as fabric.IText).lockMovementY = true;
}
}
});
canvas.getSelectionElement().addEventListener('touchmove', (e) => {
if (isAndroid) {
const active = canvas.getActiveObject();
if (active?.isType('i-text')) {
const touch = e.touches[0] || e.changedTouches[0];
if (Math.abs(touch.pageX - touchStartX) > 1.5 && Math.abs(touch.pageY - touchStartY) > 1.5) {
(active as fabric.IText).lockMovementX = false;
(active as fabric.IText).lockMovementY = false;
}
}
}
});
You can find a minimal example where I'm using this in an Angular app here: https://codesandbox.io/p/sandbox/strange-burnell-4l5dxt
If this behavior is a bug in Chrome for Android, has anyone found or filed an issue for it, yet?
Hi, the bug still reproduces. I'm not sure about the initial description but seems it's about the same problem, but I have one more cause for reproducing.
I'm using the tablet Samsung Galaxy Tab S7, the last Chrome 114 version.
Steps:
open link http://fabricjs.com/test/misc/itext.html.
Click on the input and start the edit
Click the button to hide the keyboard
Click the input again
Expect:
Actual:
add the video https://github.com/fabricjs/fabric.js/assets/42271438/92273c13-c30b-46e1-8a0d-9ca07c9c42ce
@asturur Is it a known issue? (if exit from the editing and enter editing again, the keyboard is shown) I tried to set the focus on the hidden text field as a workaround but I had no success.
From your description it sounds that we should listen to an event that triggers when the keyboard minimizes. Is there such a thing? Does the textarea blur when the keyboard minimizes? If so maybe trying to override the blur hook will fix this.
From your description it sounds that we should listen to an event that triggers when the keyboard minimizes. Is there such a thing?
Seems we don't have info about this event, therefore we cannot track hide the keyboard
Does the textarea blur when the keyboard minimizes?
No textarea is always in the focus
what’s interesting is the simple click on the focused input must show up the keyboard but not in this case Even if we will be dispatch click event on the textarea. Might textarea have some interceptors
does this works for normal forms after you hide the keyboard? if you have some text input on html without fabric, does the keyboard behave as you want? i don't have an android device to test.
I think we worked around the issue, by just having input we managed ourselfs.
Something like this:
import React, {useState} from "react";
const [hasSelectedObject, setHasSelectedObject] = useState(false)
const [hasSelectedTextObject, setHasSelectedTextObject] = useState(false)
const [selectedTextObjectText, setSelectedTextObjectText] = useState("")
const currentCanvas = new fabric.Canvas(canvasRef.current);
currentCanvas.on('selection:created', (options) => {
setHasSelectedObject(true)
setHasSelectedTextObject(options.selected.some(activeObject => activeObject.type == "i-text"))
setSelectedTextObjectText(options.selected.find(activeObject => activeObject.type == "i-text")?.text)
});
currentCanvas.on('selection:updated', (options) => {
setHasSelectedObject(true)
setHasSelectedTextObject(options.selected.some(activeObject => activeObject.type == "i-text"))
setSelectedTextObjectText(options.selected.find(activeObject => activeObject.type == "i-text")?.text)
});
currentCanvas.on('selection:cleared', (options) => {
setHasSelectedObject(false)
setHasSelectedTextObject(false)
setSelectedTextObjectText("")
});
const onTextInputChange = (e) => {
setSelectedTextObjectText(e.target.value)
if (hasSelectedObject) {
const textObject = canvas.getActiveObjects().find(activeObject => activeObject.type == "i-text")
textObject.text = e.target.value
canvas.renderAll();
}
}
return <>
<canvas
ref={canvasRef}
className={"fabric-canvas"}
/>
{hasSelectedTextObject && <>
<label htmlFor="text-input">
LABEL
</label>
<input
id={"text-input"}
className={"text-input"}
value={selectedTextObjectText}
type="text"
onChange={onTextInputChange}
/>
</>}
</>
but i don't see anything in particular for the onFocus on that input that would help. Is Android discarding the input because is not on view? If you don't hide the keyboard with the button, does it react to input changes? If you click a different text object, does the keyobard come up anyway?
If we are not triggering any focus events when clicking again on text i m not sure is going to do anything.
This way you have full control over the text input field, so you can do whatever you desire I would say, even though it's just a workaround. It's also quite some time ago since I implemented it, so I don't know about the details anymore.
does this works for normal forms after you hide the keyboard? if you have some text input on html without fabric, does the keyboard behave as you want?
I tried so many ways to solve this but without success.
Also, I tested the behavior with pure HTML textarea and manually triggered the event via JS, absolutely did not work and the keyboard did not come up.
Seems this cause is sensitive for Android, and probably the system expects an event with the key isTrusted
equal to true or something like this (with real clicks all works fine)
I don't get a full picture of the issue tbh. The keyboard does not come up after you manually minimize it. How does it behave on normal html input fields outside of fabricJS? What happens if you switch from a fabricJS textbox to another? There are so many combination possible knowing which one do not work could help understanding where the unhappy path is
The basic problem is that the keyboard simply does not show up on chrome android when you try to edit the text of an itext object.
Normal (visible) input fields do work without any problems.
For me, it does show up with my above workaround. (Chrome on Android seems to erroneously emit a touchmove event, even when just tapping on the screen.) However, when hiding it, unlike for normal input fields, it does not reappear when tapping onto the same itext item again, even though tapping again will move the cursor, indicating we're still in editing mode.
I am not using the hidden textarea workaround, though.
The basic problem is that the keyboard simply does not show up on chrome android when you try to edit the text of an itext object.
Normal (visible) input fields do work without any problems.
I that case I wonder... what happens if you change the css and remove the opacity/z-index values?
Will that fix the issue?
Will setting color: transparent
act as a valid workaround?
or what happens if you touch another textbox?
The basic problem is that the keyboard simply does not show up on chrome android when you try to edit the text of an itext object. Normal (visible) input fields do work without any problems.
I that case I wonder... what happens if you change the css and remove the opacity/z-index values? Will that fix the issue? Will setting
color: transparent
act as a valid workaround?
changing styles is not working
or what happens if you touch another textbox?
new focus leads to showing the keyboard
I think it's not a fabric issue, the issue is in the Android system, when we minimized the keyboard we couldn't show it again while using a manual trigger js event
the minimized keyboard we can show only with real touch on the input/textarea
It is an implementation issue with android and the many version of it for sure. If we can work around it great. One example could be that every click, even if the textbox is the same, we destroy and re-create the textarea. Maybe optionally since that could bother other flows with languages that are not english.
We should make a prototype for a quick test and need to rely on someone that can reproduce the bug easily. Is not something we are going to do before 6.0.0 release, but if you want to try and you understood what i mean you are free to spin a test.
It is an implementation issue with android and the many version of it for sure. If we can work around it great. One example could be that every click, even if the textbox is the same, we destroy and re-create the textarea. Maybe optionally since that could bother other flows with languages that are not english.
We should make a prototype for a quick test and need to rely on someone that can reproduce the bug easily. Is not something we are going to do before 6.0.0 release, but if you want to try and you understood what i mean you are free to spin a test.
It sounds pretty hacky, but it's might be working. I'll think about it
I don't know when this stopped working, but it looks like the keyboard does not show up on Android anymore, when you enter the editing mode of an iText object. I tried to set the focus on the hidden textfield as a workaround but I had no success.
So I checked the iText demos and realized it's not working there, too: http://fabricjs.com/test/misc/itext.html On iOS the keyboard shows up.
Any ideas how to fix this? It is an essential feature of my app...
I still love fabric.js and have to thank you so much for this awesome library!