I like the general idea, but I think it can be simplified and maybe made more stable if you just go ahead and create the proxy button whether activeElement can be used or not. There shouldn't be a performance issue as it's always user initiated and can be removed from dom after use.
What do you think? ________________________________ From: Maria Jose Esteve <mjest...@iest.com> Sent: Thursday, April 24, 2025 2:12 AM To: Yishay Weiss <yishayj...@hotmail.com>; dev@royale.apache.org <dev@royale.apache.org> Cc: Harbs <harbs.li...@gmail.com> Subject: RE: mx.net.FileReference chrome I have done a little investigation [1], and I propose the following changes to the bead [2]: - Added “isElementClickFriendly(el:WrappedHTMLElement)” to verify if the current “document.activeElement” is a valid trigger for programmatic “.click()” based on visibility, interactivity, and semantics. (Maybe this feature could be moved to some kind of utilities) - If the active element is not valid, a fallback invisible proxy button is created and used to trigger the “input[type=file]” click safely. - Avoids use of “display: none” on the proxy element, using “position: absolute”, “opacity: 0” and “left: -9999px” instead - ensuring Chrome accepts the interaction. - Keeps existing logic for cancel detection, “modelChanged” dispatch, and encapsulation intact. How do you see it now? Hiedra [1] In HTML/DOM, most elements can handle click events, but some don't accept them by default or don't make sense as clickable elements, especially if they're disabled, don't render visually, or don't participate in the browser's interactive tree. As elements that don't accept "click" directly (or don't make sense for them to do so): <meta> Doesn't render anything, just metadata <title> Not visible/interactive in the DOM <script> Only contains code, no UI <style> Only defines CSS, not part of the UI <link> (no href) If it doesn't point to something, it's not interactive <base> Defines base URL, not visible or clickable <param> Used inside <object>, not visual <source> In <audio>, <video>, not visible <track> Like <source>, not directly displayed <template> Its content is not automatically rendered <noscript> Only displayed if JS is disabled Also to consider: - Disabled elements (<button disabled>, <input disabled>, etc.) do not trigger clicks. - Hidden elements (display: none or visibility: hidden) do not trigger clicks either. - Plain text in the DOM (text nodes) cannot receive events directly. - SVGs or canvases without specific listeners may not capture clicks depending on how they are structured. Although it's also worth keeping in mind that you can force something to receive a click. Any element can receive a click event if we apply: element.tabIndex = 0; // o -1 element.addEventListener("click", function() { ... }); [2] https://github.com/apache/royale-asjs/commit/64782b4a003a9ac22a056833abd6e378813517a7 https://github.com/apache/royale-asjs/blob/64782b4a003a9ac22a056833abd6e378813517a7/frameworks/projects/Network/src/main/royale/org/apache/royale/file/beads/FileBrowser.as De: Yishay Weiss <yishayj...@hotmail.com> Enviado el: miércoles, 23 de abril de 2025 15:20 Para: Maria Jose Esteve <mjest...@iest.com>; dev@royale.apache.org CC: Harbs <harbs.li...@gmail.com> Asunto: Re: mx.net.FileReference chrome I don't think activeElement can necessarily dispatch a click() event... ________________________________ From: Maria Jose Esteve <mjest...@iest.com> Sent: Wednesday, April 23, 2025 12:58 PM To: dev@royale.apache.org <dev@royale.apache.org> Cc: Harbs <harbs.li...@gmail.com>; Yishay Weiss <yishayj...@hotmail.com> Subject: RE: mx.net.FileReference chrome The email subject is incorrect, please forgive me. The fix I'm proposing is for the core bead org.apache.royale.file.beads.FileBrowser. Last week, I made some changes to address unintended behavior in browsers like Chrome. I've been actively working with my application since I made the change locally, and everything works fine. I've also tested the code that Cristallium uses in theirs, and it also works fine. One of the two issues is solved by increasing the value of the CANCEL_TIMEOUT constant. For now, I've modified it directly, but it might be better to implement a more flexible modification, such as creating a property. For now, I'm going to leave it as is, and if in the future someone more skilled than me thinks we should do it differently, we'll change it. @Harbs, @Yishay Weiss I know spectrum-royale uses this bead, for example in the DropZone component. Could you test the modification I proposed to make sure it won't affect this project? I'm going to wait until Friday to port this small FileBrowser modification to royale-asjs. Hiedra -----Mensaje original----- De: Maria Jose Esteve <mjest...@iest.com> Enviado el: martes, 15 de abril de 2025 1:24 Para: dev@royale.apache.org Asunto: RE: mx.net.FileReference chrome I've already solved it by "modifying FileBrower.as" do you think it's correct to commit it? public function browse():void { COMPILE::SWF { delegate.browse(); } COMPILE::JS { focusedButton = document.activeElement as WrappedHTMLElement; //trace("activeElement is: " + focusedButton); focusedButton.addEventListener("blur", blurHandler); focusedButton.addEventListener("focus", focusHandler); window.addEventListener("keydown", keyHandler); window.addEventListener("mousemove", mouseHandler); window.addEventListener("mousedown", mouseHandler); //delegate.click(); focusedButton.addEventListener("click", clickHandler); focusedButton.click(); focusedButton.removeEventListener("click", clickHandler); } } //New COMPILE::JS private function clickHandler(e:Object):void { delegate.click(); } This way there are no problems, everything is legal for Chrome, BUT the same problem occurs again as https://github.com/apache/royale-asjs/issues/886 If I increase the CANCEL_TIMEOUT constant to 250, everything works fine. What would be the best way to change the value of the static constant CANCEL_TIMEOUT? Hiedra -----Mensaje original----- De: Josh Tynjala <joshtynj...@bowlerhat.dev> Enviado el: lunes, 14 de abril de 2025 21:21 Para: dev@royale.apache.org Asunto: Re: mx.net.FileReference chrome I just tested one of my non-Royale apps that calls click() on the <input type="file"> element. It still works in that app when tested in Chrome. It's a very similar situation, where I have a separate <div> element with a "click" listener, and the listener calls click() on the <input type="file"> element. Perhaps you should add a breakpoint in the debugger and check what your call stack looks like. Maybe there's a clue there. -- Josh Tynjala Bowler Hat LLC https://bowlerhat.dev/ On Mon, Apr 14, 2025 at 11:37 AM Maria Jose Esteve <mjest...@iest.com> wrote: > Yes, I understand the problem; it's not new, and I understand that > Chrome must have tightened this policy. > > I'm wondering if, just as we added the Input-Type-file (delegate), it > would be appropriate to add a "hidden button" that would call > delegate.browser. > > I've run a test. I created a button in the createDelegate() function, > called delegateFileButton, and in its "click" event I called > delegate.click [1] and in the browse function I launched a > delegateFileButton.click() [2] but it didn't work. ☹ (In FireFox it > still works fine) > > > > [1] > > COMPILE::JS > > public function createDelegate():void > > { > > delegate = > document.createElement('input') as WrappedHTMLElement; > > > delegate.setAttribute('type', 'file'); > > > goog.events.listen(delegate, 'change', fileChangeHandler); > > > > delegateFileButton = > document.createElement('button') as WrappedHTMLElement; > > > delegateFileButton.style.display = "none"; > > > delegateFileButton.onclick = function():void { > > > delegate.click(); > > }; > > // I have also tried this: > > /* > > > goog.events.listen(delegateFileButton, 'click', > > function():void { > > > delegate.click(); > > } ); > > */ > > } > > [2] public function browse():void > > { > > COMPILE::SWF > > { > > > delegate.browse(); > > } > > COMPILE::JS > > { > > > focusedButton = document.activeElement as WrappedHTMLElement; > > > //trace("activeElement is: " + focusedButton); > > > focusedButton.addEventListener("blur", blurHandler); > > > focusedButton.addEventListener("focus", focusHandler); > > > window.addEventListener("keydown", keyHandler); > > > window.addEventListener("mousemove", mouseHandler); > > > window.addEventListener("mousedown", mouseHandler); > > > delegateFileButton.click(); > > } > > } > > > > > > Hiedra > > > > -----Mensaje original----- > De: Josh Tynjala <joshtynj...@bowlerhat.dev<mailto: > joshtynj...@bowlerhat.dev>> > Enviado el: lunes, 14 de abril de 2025 19:36 > Para: dev@royale.apache.org<mailto:dev@royale.apache.org> > Asunto: Re: mx.net.FileReference chrome > > > > Browsers have certain security restrictions where you can't call > certain APIs unless the user has interacted with the page in some way. > In this case, if you want to call FileReference.browse(), it must be > triggered by a listener for a user gesture, such as mouse click or key down. > > > > -- > > Josh Tynjala > > Bowler Hat LLC > > https://bowlerhat.dev/ > > > > > > On Mon, Apr 14, 2025 at 9:42 AM Maria Jose Esteve <mjest...@iest.com > <mailto:mjest...@iest.com>> wrote: > > > > > Hi, > > > I need your help because I'm stuck. > > > In one of my applications, I use mx.net.FileReference to select a > > > user's photo. > > > It's always worked fine for me, but yesterday, while testing, I > > > noticed that it stopped working in Chrome, although it still works > > as > > > expected in Firefox. > > > I'm not getting any errors, but I do see a warning in the debug console: > > > "File chooser dialog can only be shown with a user activation." > > > The traceback points to org.apache.royale.file.beads.FileBrowser in > > > the > > > browse() method: > > > > > > public function browse():void > > > { > > > COMPILE::SWF > > > { > > > delegate.browse(); > > > } > > > COMPILE::JS > > > { > > > focusedButton = document.activeElement as > > > WrappedHTMLElement; > > > //trace("activeElement is: " + focusedButton); > > > focusedButton.addEventListener("blur", blurHandler); > > > focusedButton.addEventListener("focus", > > focusHandler); > > > window.addEventListener("keydown", keyHandler); > > > window.addEventListener("mousemove", mouseHandler); > > > window.addEventListener("mousedown", mouseHandler); > > > delegate.click(); // <<<<<<<<<< > > > -------------------------- Error > > > } > > > } > > > > > > I've verified that the delegate is still valid; it references the > > > "input, type file" that's created. > > > Any ideas on how to fix this? > > > > > > Thx. > > > Hiedra > > > > > > >