## 2.1. Document resources

Let's suppose you want to insert an image into a news article. After using the Picture button of the toolbar to insert an `<img>` element and double-clicking (or right-clicking) the image placeholder icon, a dialog box reporting an "openResource not implemented" error is displayed. See figure below.
Therefore the only way to specify the `@src` attribute of the newly inserted `<img>` element is to use the Edit Attributes dialog box. However, after doing that, the image placeholder icon just changes its color from blue to green and you'll not see the image you have specified.
Figure 6-3. The NewsApp web application without any `ResourceStorage` registered with `XMLEditor`
This limitation is due to the fact that `XMLEditor` makes very few assumptions about how documents and also document resources like images, video, audio, are stored by your web application.
This limitation may be removed by implementing a `ResourceStorage` and registering it with `XMLEditor` using its `resourceStorage` property.
A `ResourceStorage` object must implement:

`loadResource(uri)`
  Load and return the `Resource` having specified URI.
`storeResource(data, uri)`
  Save resource data (for example, an image `File` dragged from the desktop and dropped onto the image placeholder icon) to specified URI and return the corresponding newly created `Resource`.
`openResource(options)`
  Display a dialog box letting the user choose an existing resource and return the chosen `Resource` object.

A `Resource` is a very simple object essentially associating the resource URI to the resource data (a JavaScript `Blob` or `File`).
The NewsApp web application has a `ResourceStorage` implementation called `NewsStorage` and a `Resource` implementation called `NewsResource`.
Figure 6-4. Excerpts from `apidemo/newsapp.js`

    class NewsResource extends XXE.Resource {
        constructor(uri, data) {
            super(uri, data);
        }
    }

    class NewsStorage extends XXE.ResourceStorage {
        constructor(xmlEditor, newsItems) {
            super(xmlEditor);
            this._newsItems = newsItems;
        }

        async loadResource(uri) { ... }

        async openResource(options) {
            let uri = await NewsResourceChooser.showDialog(this._newsItems,
                                                           options);
            if (uri === null) {
                // Canceled by user.
                return null;
            }

            return this.loadResource(uri);
        }
    }
    ...
    export class NewsApp {
        ...
        async loadNews(rssURL) {
          ...
          this._items = items;
          this._xmlEditor.resourceStorage =
                new NewsStorage(this._xmlEditor, items);
          ...
        }
        ...
    }

`NewsStorage.openResource` displays a `NewsResourceChooser` dialog box to let the user choose an image. See figure below.
Figure 6-5. The NewsApp web application having its `NewsStorage` registered with `XMLEditor`