rjaros / kvision

Object oriented web framework for Kotlin/JS
https://kvision.io
MIT License
1.23k stars 65 forks source link

Ability to intercept image load errors #506

Closed reubenfirmin closed 9 months ago

reubenfirmin commented 9 months ago

This image will render:

val img = Image(src = "https://cdn.britannica.com/08/1108-050-416D8AF2/Guyana-map-features-locator.jpg")

Now add this to it, and it will fail to render:

img.setAttribute("crossorigin", "anonymous")

Other images (which have Access-Control-Allow-Origin headers configured correctly) will work with this attribute, e.g. https://miro.medium.com/v2/resize:fit:1000/1*zD10J5eFnTSjy-ZdA2_Krw.jpeg

When the image fails to load, the browser dumps out:

Access to image at 'https://cdn.britannica.com/08/1108-050-416D8AF2/Guyana-map-features-locator.jpg' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

In javascript, (apparently, according to gpt) you can do this to catch the load error:

    const myImage = document.getElementById('myImage');

    myImage.onerror = function() {
        console.error('Image failed to load!');
        // You can handle the error or perform any necessary actions here
    };

Similar ability in kvision would be useful. There is no onerror available on Element, and putting a timeout around this to give it a change to be rendered and become an HTMLElement apparently misses the error:

(img.getElement() as HTMLElement).onerror = { b: dynamic, s: String, i: Int, i1: Int, any: Any? ->
            console.error("error")
            Unit
        }}, 500)

Specifically what I'd want to do is catch the error, drop the crossorigin attribute so that it renders, and mark it with some kind of warning to the user.

rjaros commented 9 months ago

Hello, use addAfterInsertHook before accessing the DOM element:

image(src = "https://cdn.britannica.com/08/1108-050-416D8AF2/Guyana-map-features-locator.jpg") {
    setAttribute("crossorigin", "anonymous")
    addAfterInsertHook {
        getElement()?.onerror = { _, _, _, _, _ ->
            console.log("error loading image, removing crossorigin attribute")
            this.removeAttribute("crossorigin")
        }
    }
}
reubenfirmin commented 9 months ago

Ah indeed - that does work. Thanks