Attachment Picker Module
Reference
The RequireJS module xwiki-attachment-picker, one of the two modules of the Attachment Picker WebJar, turns markup into a working picker: it builds the search field, fills the grid of results, and reports what the reader picks.
Markup of a Picker
A picker is an element carrying the class attachmentGalleryPicker, holding four blocks that the JavaScript looks up inside it by class:
| Block class | Holds |
|---|---|
| attachmentPickerSearch | The search field, which the JavaScript builds into it, and the class xform, which it adds. The field is a Bootstrap input-group: a text input and a pair of radio buttons named scope, of values local and global, with local checked. |
| attachmentPickerResults | The grid of results, filled and emptied at every search. |
| attachmentPickerNoResults | The message shown when a search returns nothing. Rendered with the class hidden, which the JavaScript removes and adds back. |
| attachmentPickerGlobalSelection | The warning shown while the selected attachment belongs to another Page. Rendered hidden too. |
Three optional attributes on the root element configure it. The JavaScript only reads them, and they are the three parameters of the attachmentGalleryPicker macro:
| Attribute | Passed to SolrSearch as | Default |
|---|---|---|
| data-xwiki-attachment-picker-limit | limit, parsed as an integer | 20, both for an absent attribute and for a value that does not parse |
| data-xwiki-attachment-picker-target | target | The Page the picker is displayed on |
| data-xwiki-attachment-picker-filter | filter of the Solr options, where it becomes a media type clause of every query | No filter |
The macro writes exactly that markup, but any markup carrying those classes works, once the module is loaded on the Page as described below:
<div class="attachmentGalleryPicker"
data-xwiki-attachment-picker-filter="image/*"
data-xwiki-attachment-picker-limit="10"
data-xwiki-attachment-picker-target="Sandbox.WebHome">
<div class="attachmentPickerSearch"></div>
<div class="attachmentPickerResults"></div>
<div class="attachmentPickerNoResults hidden">No attachment matches your search.</div>
<div class="attachmentPickerGlobalSelection hidden">The attachment you picked belongs to another
page.</div>
</div>Initialisation
The module registers the jQuery plugin $.fn.attachmentGalleryPicker():
require(['jquery', 'xwiki-attachment-picker'], function ($) {
// The module exports nothing: requiring it is what registers the plugin.
$('#my-picker').attachmentGalleryPicker();
});| Trigger | What happens |
|---|---|
| A call of the plugin | One picker is built and initialised per matched element. |
| The document being ready, then every xwiki:dom:updated event | The module initialises every element of class attachmentGalleryPicker by itself, among the elements the event carries or in the whole document, so a picker inserted by an asynchronous request needs no call of your own. |
| Initialising a picker | It is marked with the class initialized, and a first search runs with an empty query, so the grid is filled before the reader types anything. |
| Initialising a picker that already carries initialized | Nothing, which is what makes the automatic initialisation safe. |
| Typing in the search field, or switching scope | A new search, debounced by 500 milliseconds on both. |
Results
Every result of a search is one attachmentGroup element:
<span class="attachmentGroup localAttachment"> <!-- jQuery data "id": the attachment reference -->
<a title="logo.png" href="/xwiki/bin/download/Sandbox/WebHome/logo.png">
<span class="previewWrapper">
<img loading="lazy" alt="logo.png"
src="/xwiki/bin/download/Sandbox/WebHome/logo.png?width=150&height=150&keepAspectRatio=true">
</span>
<span class="attachmentTitle" title="logo.png">logo.png</span>
</a>
</span>| Carried by a result | Value |
|---|---|
| The class localAttachment or globalAttachment | Whether the attachment comes from the Page being searched or from another one |
| The class selected | Set on the selected result |
| The jQuery data id, on the group | The reference of the attachment, held as data rather than as an attribute |
| The jQuery data index, on the link | The rank of the result in the grid, held the same way |
| The attachmentTitle span, and the title of both the span and the link | The file name |
| Preview | Shown for |
|---|---|
| The attachment itself, in an img whose address carries ?width=150&height=150&keepAspectRatio=true, so the wiki resizes it into a 150 by 150 box while preserving its aspect ratio | A media type starting with image/ |
| A span carrying the class of the media type's icon, taken from xwiki-attachments-icon, plus the class attachmentIcon | Any other media type, with a font icon theme |
| An image element pointing at the address of that icon | Any other media type, with a theme that is not a font one |
While a search runs, the results block is emptied and carries the class loading. A search that fails is logged to the browser console and reported to the reader as an error notification.
Selection
A picker reports what the reader picks through two events fired on its root element, documented with an example on the attachmentGalleryPicker macro page.
| Rule | Behaviour |
|---|---|
| Selection is single | Selecting a result unselects every other. |
| Clicking the selected result | Clears the selection. |
| Double click | Only the first click of a chain selects, so the second click does not undo the selection the first one made. |
| A new search | Keeps the selection while the attachment is still among the results, and clears it otherwise. |
| The attachmentPickerGlobalSelection block | Shown exactly while the selected result carries globalAttachment, and hidden again when the selection is cleared or a new search runs. |
Messages
The four messages of the picker are loaded through xwiki-l10n!, under the prefix attachment.picker., and none of them is defined in this WebJar:
| Key | Labels | Defined by |
|---|---|---|
| solrSearch.query.errorMessage | The notification shown when a search fails | The attachmentGalleryPicker macro module |
| searchField.placeholder | The search field | The Attachment.Picker.Code.Translations page of the Attachment Picker Application |
| searchField.scope.currentPage | The scope button of the current Page | The same page |
| searchField.scope.allPages | The scope button of every Page | The same page |
The texts of the two blocks the JavaScript only shows and hides, attachment.picker.macro.notResult.message and attachment.picker.macro.globalSelection.message, belong to the macro module as well.
FAQ
Which of the four blocks may I leave out?
Any of them. Each one is looked up inside the root element, and a block that is not there is quietly skipped instead of raising an error, which costs the picker the feature that block carries: no search field, or a reader who is never told that a search found nothing or that the attachment they picked belongs to another Page.