How Image Plugin Finds Images

There is something slightly mysterious about how the image plugin finds images. Here I will take a look at how this works.

# Backstory

The early versions of the image plugin solved the problem of where the image was by injecting the URL encoded version of the image into the page. This could make pages very big. Something not helped by the image item getting saved in the journal each time the caption was edited. But, this did have the advantage as the image travelled along with the page.

Sometimes the half page width image that the plugin provided was not big enough. To get a full page image the HTML plugin was used. But, there was no consistent solution. Sometimes the image would still be visible on a forked paged. But, when a relative URL to image was used it wouldn't be. But, often there a reliance either the original wiki, or other service hosting the image. Sometimes they disappear.

❖ ❖ ❖

A 2022 update of the image plugin changed this by: * giving image files a name using a hash of the image file, * saving compressed image files in an well known location in the assets folder. * using the wiki page's context to find the image file, and * providing a mechanism for forking an image file.

Lets use an image item from Ward's daily photo challenge.

chain fence playground slide

The JSON for this image item is:

{ "type": "image", "id": "6f5472890e6cc304", "prompt": "Image for Sunday", "location": { "latitude": "45.47148888888889", "longitude": "-122.74859722222223" }, "text": "chain fence playground slide", "size": "wide", "width": 420, "height": 315, "url": "/assets/plugins/image/4a3c8b6b73f40dab6e34d2ab8cd00c5e.jpg" }

You will notice that there is a relative URL. This is used as the initial value for the image source in the generated HTML. But if you examine the HTML you will see:

<img class="wide" src="//photos.ward.dojo.fed.wiki/assets/plugins/image/4a3c8b6b73f40dab6e34d2ab8cd00c5e.jpg" width="420" height="315" >

There is nothing in the image item to suggest that image is over on Ward's wiki, rather than in the origin. Let's look at the code to see what is happening.

**Note:** The code shown below is in CoffeeScript

In `emit()` we see:

$item.append "<img class='#{item.size or 'thumbnail'}' src='#{item.url}'> <p>#{wiki.resolveLinks(item.text)}</p>"

This looks fairly standard, but `src` is getting set to the item's url attribute, and when we looked in the HTML we had a `src` over on `photos.ward.dojo.wiki`.

As I don't have a copy of the image in my wiki, we would expect to have a broken image.

Looking further we see that the plugin is adding an error handler:

img.on('error', () -> sites = $( this ).data('sites') site = sites.shift() $( this ).data('sites', sites) $( this ).attr('src', site ) if sites.length is 0 $( this ).off('error') )

and some data for it to use:

img.data('sites', alternates($item))

`alternates()` looks at the wiki page's journal, and extracts the page's context (list of sites). While is used to create an array of links, using the site adapter `getURL()`.

alternates = ($item) -> sites = [] if remote = $item.parents('.page').data('site') unless remote == location.host sites.push remote journal = $item.parents('.page').data('data').journal for action in journal.slice(0).reverse() if action.site? and not sites.includes(action.site) sites.push action.site if action.attribution?.site? and not sites.includes(action.attribution.site) sites.push action.attribution.site sites.map( (site) -> wiki.site(site).getURL(item.url.replace(/^\//, '')))

So, stepping through what is happening.

When the image item is first added to the page, image source will be `/assets/plugins/image/4a3c8b6b73f40dab6e34d2ab8cd00c5e.jpg`, and the `sites` data item `[//photos.ward.dojo.fed.wiki/assets/plugins/image/4a3c8b6b73f40dab6e34d2ab8cd00c5e.jpg]`.

The image will fail to load, and trigger the img's `onerror` event. This will take the first item off the `sites` array, and set the img's `src` to that value. It will also update the saved list of site's, in this case now an empty array. As the list of sites is now empty it will also remove the `onerror` event handler.