Customizing Content Editor pickers

November 14, 2023

Pickers are one of the selector types used in Content Editor. They are used to select pages, contents and files, when creating links or when referencing such items from a content. This topic describes how to override pickers and how to configure new ones. If you need to create your own selector from scratch, and not reuse the default Jahia UI, you should refer to Creating custom selector types for Content Editor

Available pickers

Content Editor provides several picker configurations out-of-the-box for basic page, file and content selection. If no picker suits your needs, you can declare your own, or you can override some configuration for a given type, for instance to restrict the selectable types.

The following pickers are available:

Picker name Description Selectable types*
Default picker
(default)
The default picker is used to browse pages, content folders and files. As most of the content types can be selected, it is best to define content type restrictions not to provide an overwhelming experience to the editors.
Available with Content Editor 4.1.0
  • jnt:content
  • jnt:file
  • jnt:page
  • jmix:navMenuItem
Editorial picker
(editorial)
 
This is the picker to use when referencing editorial content (e.g. a news or a rich text). Pages and content folders can be browsed.
  • jnt:page
  • jnt:contentList
  • jnt:contentFolder
  • jmix:siteContent
  • jmix:editorialContent
Droppable content picker
(droppableContent)
 

This is the picker to use when referencing droppable content. Pages and content folders can be browsed.
An overlap is possible with the Editorial picker, as many default droppable content  types are also editorial contents.
Available with Content Editor 4.1.0

 

  • jmix:droppableContent
File picker
(file)
Picker used to browse the media folders to select files.
  • jnt:file
Image picker
(image)
Picker used to browse the media folders to select images.
  • jmix:image
Video picker (video) Picker used to browse the media folders to select video files.
Available with Content Editor 4.1.0
  • jnt:file with video mime type
PDF picker (pdf) Picker used to browse the media folders to select pdf files.
Available with Content Editor 4.1.0
  • jnt:file with pdf mime type
Page picker
(page)
Picker displaying the page tree to only allow the selection of pages, e.g. when building links.
If you rely on jmix:mainResource to display some content in a full page view, then you need to use the Editorial link picker below.
  • jnt:page
Editorial link picker
(editoriallink)
This picker is pretty similar to the page picker, as its main purpose is to select pages or content displayable in a full page view (jmix:mainResource).
As such content can be created under pages or in content folders, it’s possible to browse both the page tree and the content folders.
  • jnt:page
  • jmix:mainResource
Media folder picker
(folder)
This picker is used to browse and select media folders (folders containing files)
  • jnt:folder
Content folder picker
(contentfolder)
This picker is used to browse and select content folders (folders containing editorial content)
  • jnt:contentFolder
Category picker
(category)
This picker is used to browse and select content folders.
This is different from the category selector, used by default to assign categories to contents.
  • jnt:category
User picker
(user)
This picker is used to search and select users
  • jnt:user
User group picker
(usergroup)
This picker is used to search and select user groups
  • jnt:group
Site picker
(site)
This picker is used to search and select sites.
Note that if you need to select a site, we advise to use the following statement in the definition in order to display a more convenient drop down listing the sites instead of displaying a picker in a modal:
- site (weakreference,choicelist[nodes='/sites;jnt:virtualsite']) nofulltext

 

  • jnt:virtualsite

* if type restrictions are set for the property in the definition file, then these types take precedence over the selectable types provided by the picker, so the user can only select types allowed by the definition. See Setting content type restrictions

Assigning a picker to a content property

In the definitions.cnd file, a weak reference property using a picker is defined as:

[qant:myContent] > jnt:content, jmix:editorialContent
- myFilePicker (weakreference) < jnt:file

As no picker is explicitly provided, the myFilePicker property will use the default picker.

It is possible to specify which picker to use directly in the definition, or by specifying it in a json override.
It is usually a better option to use json overrides as they will offer more flexibility when maintaining content types in the long run. 

From the definition file

The picker configuration to use can be specified by adding the type option in the definition:

[qant:myContent] > jnt:content, jmix:editorialContent
- myFilePicker (weakreference,picker[type='file']) < jnt:file

Please note that if json override exists for this property, it will then override the picker defined in the definition.

Using a json override

It is possible to use a json override to specify which picker to use. This is described in the Picker type section.

Setting content type restrictions

Similarly to the picker assignment to a property, it is possible to restrict the types of content to be referenced/selectable in the picker, either by specifying them in the definition or in a json override.

Note: only the constraint specified in the definition will be a back-end / low-level content type restriction.

In the following example, we want to force the selection of jnt:news for the newsReference property:

[qant:myContent] > jnt:content, jmix:editorialContent
- newsReference (weakreference,picker[type='editorial'])

Type restriction from the definition file

The type restriction can also be specified by adding the type option in the definition:

[qant:myContent] > jnt:content, jmix:editorialContent
- newsReference (weakreference,picker[type='editorial']) < jnt:news

It is possible to specify several types:

[qant:myContent] > jnt:content, jmix:editorialContent
- newsReference (weakreference,picker[type='editorial']) < jnt:news, jnt:event

Type restriction in a json override

See the Restricting the selectable types section.

Overriding a picker configuration for a given property

This section applies to Content Editor 4.1+

Content Editor provides an out-of-the-box mechanism to override the way a content property is displayed for creation/edition using json overrides. This mechanism can be used to specify which picker to use for a given property, and also to configure such pickers to simplify the content selection by editors.

If you need to re-use such configuration for other properties or content types, it’s better to declare a new picker configuration.

Declaring an override

The json override file shall be added in the  src/main/resources/META-INF/jahia-content-editor-forms/fieldsets/ folder of your module.

The file should have the following name, nodetype.json (jnt_pickerOverride.json).

All the property overrides are optional, and if not specified, the default value/configuration will be used.

The following example shows an override for the property propertyName of the jnt:pickerOverride content type:

[qant:myContent] > jnt:content, jmix:editorialContent
- myFilePicker (weakreference,picker[type='file']) < jnt:file

The override of the picker configuration is done in the selectorOptionsMap node:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
       "type":"default",
       "accordionItem": {
         "picker-pages": {
           "label":"News in pages",
           "rootPath": "/sites/{site}/home/newsroom/news-entry",
           "treeConfig": {
             "hideRoot": false
           }
         },
         "picker-content-folders": {
           "label":"News in content folders",
           "rootPath": "/sites/{site}/contents/news",
           "treeConfig": {
             "hideRoot": false
           }
         },
         "picker-media": {
           "label":"Images",
           "rootPath": "/sites/{site}/files/images/news-illustrations",
           "treeConfig": {
             "hideRoot": false
           }
         }
       },
       "pickerConfig": {
         "selectableTypesTable": ["jnt:news", "jmix:image"],
         "pickerDialog": {
           "displaySiteSwitcher": true,
           "displayTree": true,
           "dialogTitle": "my-module-ID:label.picker.title",
           "displaySearch": true
         },
         "pickerTable": {
           "columns": ["publicationStatus", "name", "type", "lastModified"]
         }
       }
     }
   }
 ]
}

This example contains all the picker overriding capabilities, and thus needs to be adapted to your content type.

Picker type

The type of picker to use for a property is defined by type in the selectorOptionsMap node:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
       "type":"file"
     }
   }
 ]
}

In this example, the file picker will be used to fill the propertyName when contributing a jnt:pickerOverride. If you want to use a different picker than the file picker, e.g. the image picker, simply specify the desired picker in the type property, e.g. “type”=”image”. The list and description of available picker types is provided in the Available pickers section.

If no type is specified in the json override, then the system will use the picker defined in the definition file.

Restricting the selectable types

You can restrict the type of content that can be selected in the picker. If no restriction is defined in the json override file, the constraints defined in the definition file for the property (see Setting content type restrictions) will be used by default.

Note: The types specified in the json override need to be compatible with the constraints set in the definition, otherwise editors will be able to select such contents in the user interface, but the save operation will fail.

 The selectable types is defined by selectableTypesTable in the selectorOptionsMap node:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
       "pickerConfig": {
         "selectableTypesTable": ["jnt:news"]
       }
     }
   }
 ]
}

In this example, the picker will only allow the selection of contents of type jnt:news . It is possible to specify several types, for instance: "selectableTypesTable": ["jnt:news", "jnt:event"] and/or to use mixins:"selectableTypesTable": ["jmix:image", "jmix:customMixin"]

Overriding the accordions

It’s possible to update the label and the parent node of the accordions displayed in the left navigation of the pickers. This is done per accordion (picker-pages, picker-content-folders, picker-media) in the accordionItem node.

It is not possible to redefine which accordions to display (by adding or removing one). This can only be done by using a different picker, or declaring a new one.

Changing the label

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
       "type":"default",
       "accordionItem": {
         "picker-pages": {
           "label":"News in pages"
         },
         "picker-media": {
           "label":"my-module-artifactID:label.picker.accordion.media"
         }
       }
     }
   }
 ]
}

The accordion labels can either be hard-coded directly in the json file (here: News in pages), in such case it will be the same in all the languages, or you can use a resource bundle, by specifying the artifactID of the module containing the label and the label key, e.g. "label":"my-module-artifactID:label.picker.accordion.media".

To use a resource bundle, you will need to “declare your module” and to “Register the translation namespace”. These two easy steps are described in the Extending Jahia UI page.

Defining the root node

It is possible to restrict the selection of a page/content/file in a picker to certains sections of the site, by specifying the root node for each accordion. In the following example, the Media accordion will only display folders and files located in the /files/images/news-illustrations folder of the selected site:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
       "accordionItem": {
         "picker-media": {
           "rootPath": "/sites/{site}/files/images/news-illustrations",
           "treeConfig": {
             "hideRoot": false
           }
         }
       }
     }
   }
 ]
}

{site} is a placeholder which is replaced by the currently selected site. It is possible to specify an absolute path like: "rootPath": "/sites/systemsite/files/shared-images"

hideRoot

If set to false, the node defined in the rootPath will be displayed in the left navigation:

hideRootFalse.png

Here the news-illustrations folder is displayed in the navigation and can be selected

If set to true, the first level of pages or folders to be displayed in the left navigation are the children of the rootPath node:

hideRootTrue.png

Here, the news-illustrations folder does not appear in the navigation, and thus cannot be selected.

It is also possible to combine hideRoot=true with an accordion label override:

hideRootTrue-Label.png

Display/hide the site switcher

By default, it is possible to switch between sites in the picker, so the editor can reference a page/content/file from a different site of the platform. If needed, the site switcher can be hidden, by setting displaySiteSwitcher to false:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
       "pickerConfig": {
         "pickerDialog": {
           "displaySiteSwitcher": false
         }
       }
     }
   }
 ]
}

Edit the dialog title

The picker dialog title can be overridden, for instance to provide more context to the user. Similarly to the accordion labels, the title can be set directly in the json file or you can use a resource label:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
        "pickerConfig": {
         "pickerDialog": {
           "dialogTitle": "my-module-ID:label.picker.title"
         }
       }
     }
   }
 ]
}

Hiding the search field

It is possible to hide the search field (so no search can be done in the picker) by setting the displaySearch property to false:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
        "pickerConfig": {
         "pickerDialog": {
           "displaySearch": false
         }
       }
     }
   }
 ]
}

Specify the columns to display

The pickers can display the following columns: the publication status (“publicationStatus”), the name of the item (“name”), its type (“type”), the last modification date (“lastModified”), the creator name (“createdBy”), the file size (“fileSize”). You can decide to display or hide some of them, or re-order them, for each accordion, by specifying them in the tableConfig.columns config:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
       "accordionItem": {
         "picker-pages": {
           "tableConfig": {
             "columns": ["publicationStatus", "name", "type", "lastModified"]
         }
       }
     }
   }
 ]
}

To add other, or custom, columns, you need to declare a new picker, as it is not possible to do so in an override. 

Hide the left navigation tree

In some very specific cases, it may be interesting to hide the left navigation tree (so no accordions will be displayed), by setting displayTree to false:

{
"name": "jnt:pickerOverride",
 "fields": [
   {
     "name": "propertyName",
     "selectorType": "Picker",
     "selectorOptionsMap": {
        "pickerConfig": {
         "pickerDialog": {
           "displayTree": false
         }
       }
     }
   }
 ]
}

Set auto-expand level

For picker dialogs that uses structured view to display its contents, it is possible to set default depth level that the tree auto-expands and displays. Setting autoExpandLevels: 0 collapses the view entirely. This value is set to 1 by default and can be set up to a maximum of 5

{
  "name": "jnt:pickerOverride",
  "fields": [
    {
      "name": "propertyName",
      "selectorType": "Picker",
      "selectorOptionsMap": {
        "accordionItem": {
          "picker-category": {
            "tableConfig": {
              "autoExpandLevels": 2
            }
          }
        }
      }
    }
  ]
}

 

Declaring a new picker

This section applies to Content Editor 4.1+

The declaration of a new picker consists of an extension of the Jahia UI. See the Extending Jahia UI page for more information.

Registering the picker

To declare your picker, you need to declare a UI extension in your module.This can be done by creating the following jahia.json file in the src/main/resources/javascript/apps folder of your module:

{
 "jahia": {
   "apps": {
     "jahia": "javascript/apps/picker-register.js"
   }
 }
}

The jahia.apps.jahia should refer to the path of your registration file. Create the file picker-register.js alongside your jahia.json one. This file will contain your picker declaration.
The following example adds a simple “Event” picker:
 

window.jahia.uiExtender.registry.add('callback', 'eventPickerRegistration', {
   //Content-Editor initialisation callback as a priority of 2
   targets: ['jahiaApp-init:33'],
   callback: () => {
       window.jahia.uiExtender.registry.add('pickerConfiguration', 'event', {
           pickerInput: {
               // Label displayed in Content Editor when no item has been selected
               emptyLabel: 'No event here',
               // Label displayed in Content Editor when the reference is broken
               notFoundLabel: 'No event Found',
           },
           pickerDialog: {
               // Default view when opening the picker
               view: 'List',
               // Title of the picker window.
               dialogTitle: 'my-module:label.picker.title',
               // Display or hide the left navigation tree.
               displayTree: true,
               // Display or hide the site switcher
               displaySiteSwitcher: true,
               // Display or hide the search field
               displaySearch: true
           },
           // Specifies the content types returned by the search
           searchContentType: 'jnt:event',
           // Specifies which content types can be selected in this picker
           selectableTypesTable: ['jnt:event'],
           // Specifies which accordions to use in the picker.
           accordions: ['picker-pages']
       });
   }
});
The Event module provides an example of an event picker. In this example, you’ll see most of the available capabilities when declaring a new picker. 

Basic parameters

Parameter Description Default value
pickerInput.emptyLabel Label of the button in Content Editor to open the picker, when no content has been selected.
You can use a resource bundle or hard code this label.
“Select a content”
pickerInput.notFoundLabel Label of the button in Content Editor to open the picker, when the content cannot be found (e.g. if it has been deleted)
You can use a resource bundle or hard code this label.
“Content not found”
pickerDialog.view Specify the default view to use when opening the picker.
The other available option is “Thumbnail”, which can be used when the picker only has a media accordion.
List
pickerDialog.dialogTitle Title of the picker window.
You can use a resource bundle or hard code this label.
Select a content
pickerDialog.displayTree Display or hide the left navigation tree.
In some very specific cases where the editors shall not navigate in folders or pages, it can be useful to hide the left navigation tree to simplify the content selection (so no accordions will be displayed)
true
pickerDialog.displaySiteSwitcher Display (true) or hide (false) the site switcher, allowing a user to switch sites when using this picker true
pickerDialog.displaySearch Display (true) or hide (false) the search field, allowing or not a user to search with the picker true
searchContentType Specifies on which type (it can only contain one type) search requests need to be performed. If only one type is configured for selectableTypesTable, we suggest using the same for searchContentType. Otherwise, specify a more generic type, like jmix:searchable (by default) or jmix:editorialContent (if the selectable types are also of type editorial content). jmix:searchable
selectableTypesTable Specifies which content types can be selected in this picker Any node
accordions Specify which accordions to use in the picker.
The default accordions are:
  • picker-pages
  • picker-content-folder
  • picker-media
New accordions can be declared, see Creating new accordions.
picker-pages, picker-content-folders, picker-media
 To use a resource bundle, you will need to “declare your module” and to “Register the translation namespace”. These two easy steps are described in the Extending Jahia UI page.

Configuring the accordions

It is possible to individually adjust/override the accordions of the picker by specifying the corresponding properties, per accordion, in the accordionItem property:

window.jahia.uiExtender.registry.add('callback', 'eventPickerRegistration', {
   //Content-Editor initialisation callback as a priority of 2
   targets: ['jahiaApp-init:33'],
   callback: () => {
       window.jahia.uiExtender.registry.add('pickerConfiguration', 'event', {
           // Specifies the content types returned by the search
           searchContentType: 'jnt:event',
           // Specifies which content types can be selected in this picker
           selectableTypesTable: ['jnt:event'],
           // Specifies which accordions to use in the picker
           accordions: ['picker-pages', 'picker-content-folders'],
           accordionItem: {
              "picker-pages": {
                  // Specifies the root node for the Pages accordion
                  rootPath: "/sites/{site}/home/investors/events",
                  treeConfig: {
                      //Hide or not in the left navigation tree the node specified by the rootPath property
                      hideRoot: false,
                      // List of content types that can be expanded in the left tree
                      openableTypes: ['jmix:visibleInContentTree', 'jnt:contentFolder', 'jnt:eventList'],
                      // List of content types that can be selected in the left tree, so their content is displayed in the main table
                      selectableTypes: ['jmix:visibleInContentTree', 'jnt:contentFolder', 'jnt:eventList']
                  },
                  tableConfig: {
                       // List of types that can be expanded in the main table, when using the Structured view
                       openableTypes: ['jmix:list'],
                   }
                  // Label of the Pages accordion
                  label: "Events in page"
              },
              "picker-content-folders": {
                  // Specifies the root node for the Content folder accordion
                  rootPath: "/sites/{site}/home/investors/events",
                  treeConfig: {
                      hideRoot: false
                  },
                  // Icon to use for the Content folder accordion
                  icon: window.jahia.moonstone.toIconComponent('<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M19 6V5A2 2 0 0 0 17 3H15A2 2 0 0 0 13 5V6H11V5A2 2 0 0 0 9 3H7A2 2 0 0 0 5 5V6H3V20H21V6M19 18H5V8H19Z" /></svg>'),
label: "Events in folders"
              }
           }
       });
   }
});

Basic accordion parameters

Parameter Description Default value
rootPath

Specify the root node for the accordion.
{site} can be used as a placeholder for the sitekey (but the sitekey can also be hardcoded)

Ensure that there are no trailing / character at the end of the path 
  • picker-pages: /sites/{site}
  • picker-content-folders: /sites/{site}/contents
  • picker-media: /sites/{site}/files
treeConfig.hideRoot Hide or not in the left navigation tree the node specified by the rootPath property
Set it to true, if no content can be selected in the rootPath node (e.g. if the rootPath node is a menu-label)
  • picker-pages: true
  • picker-content-folders: false
  • picker-media: false
tableConfig.openableTypes Make the given types expandable in the main table when the structured view is selected  
icon Specify the icon to use for the accordion.
See Providing a new icon for the accordion
 
label Label of the accordion.
You can use a resource bundle or hard code this label.
  • picker-pages: Pages
  • picker-content-folders: Content Folders
  • picker-media: Media

Providing a new icon for the accordion

You can provide the svg tag directly:

icon: window.jahia.moonstone.toIconComponent('<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M19 6V5A2 2 0 0 0 17 3H15A2 2 0 0 0 13 5V6H11V5A2 2 0 0 0 9 3H7A2 2 0 0 0 5 5V6H3V20H21V6M19 18H5V8H19Z" /></svg>')

Or provide the url to an SVG file:

icon: window.jahia.moonstone.toIconComponent('https://raw.githubusercontent.com/Jahia/moonstone/develop/src/icons/assets/Event.svg')

Display custom content types in the left navigation tree

It is possible to specify which node types to display in each of the accordion navigation tree, by specifying the openableTypes and selectableTypes properties:

  • openableTypes: this is the list of content types that can be expanded in the left tree
  • selectableTypes: this is the list of content types that can be selected in the left tree, in order to display their sub-contents in the main table

The default values are:

Accordion openableTypes selectableTypes
picker-pages
  • jnt:page
  • jnt:virtualsite
  • jnt:navMenuText
  • jnt:page
  • jnt:virtualsite
picker-content-folders
  • jmix:visibleInContentTree
  • jnt:contentFolder
  • jmix:visibleInContentTree
  • jnt:contentFolder
picker-media
  • jnt:folder
  • jnt:folder

 

Configuring the columns

This feature is provided as-is. Due to its open nature, it is possible that not all the limitations have been identified. When customizing columns, please carefully test your implementation to ensure that no limitation is encountered.

 For each accordion, it is possible to redefine the columns to display. By default, the picker display the following columns:

  • Publication status (publicationStatus)
  • Content displayable name (name)
  • Type (type)
  • Last modification date (lastModified)

When declaring a picker, it is possible to remove the default columns, and add new ones. 
This is done in the tableConfig property. It contains  a GraphQL fragment to retrieve the desired property for the content, and the list of columns. The following example shows how to add a “Creation date” column:

window.jahia.uiExtender.registry.add('callback', 'eventPickerRegistration', {
   //Content-Editor initialisation callback as a priority of 2
   targets: ['jahiaApp-init:33'],
   callback: () => {
       window.jahia.uiExtender.registry.add('pickerConfiguration', 'event', {
           searchContentType: 'jnt:event',
           selectableTypesTable: ['jnt:event'],
           accordions: ['picker-pages'],
           accordionItem: {
              "picker-pages": {
                  tableConfig: {
                     fragments: [{
                         gql: window.jahia.graphqlTag('fragment MyProp on JCRNode { creationDate: property(name: "jcr:created") { value }}'),
                         applyFor: 'node'
                     }],
                     columns: ["publicationStatus", "name",
                         {
                             id: 'create-date',
                             accessor: row => row.creationDate && row.creationDate.value,
                             label: 'Created on',
                             width: '150px',
                             sortable: true,
                             property: 'creationDate.value'
                         }
                         ,"lastModified"]
                  },
                  rootPath: "/sites/{site}/home/investors/events",
                  treeConfig: {
                      hideRoot: false
                  },
                  label: "Events in page"
              }
           }
       });
   }
});
Note: For a nicer display of date fields, you can use the following code for the accessor:
accessor: row => row.creationDate && new Date(row.creationDate.value).toLocaleDateString()
Unfortunately, the day.js library used to format the last modification date, is not available in simple modules to format “custom” date properties.
The table used in the picker does not dynamically resizes. This has the two following implications:
  • Long values will be truncated to not overflow on the next column
  • Adding too many columns may break the layout on smaller screens

GraphQL fragment

window.jahia.graphqlTag('fragment MyProp on JCRNode { creationDate: property(name: "jcr:created") { value }}')

Where:

  • creationDate : name of the property, which will be re-used when declaring the new column
  • jcr:created: is the JCR property to retrieve. It can be any JCR property (e.g. one specific to a certain content type)
    • if the property is internationalized (a different value per language), you need to provide the language in the fragment. Use language: $language to provide the current language:
       
      window.jahia.graphqlTag('fragment MyProp on JCRNode { propName: property(name: "jcrI18nProperty", language: $language) { value }}')

Note: if there is a resource bundle associated with the property, you can retrieve its value (instead of the system one) by using value:choicelistValue(renderer:"resourceBundle", language: $language) instead of just value. For instance:

fragment MyProp on JCRNode {eventsType: property(name: "eventsType") { value:choicelistValue(renderer:"resourceBundle", language: $language) }}'

Columns

Provide the columns to display. The default one are publicationStatus, name, type, lastModified. Open brackets to declare your new column:

Parameter Description
id Specify an id for the column
accessor Use the property name declared in the GraphQL fragment (creationDate in this example):
accessor: row => row.creationDate && row.creationDate.value

Note that js basic formatting can be used, for instance the following code provides a nicer way to display a date:
 

accessor: row => row.creationDate && new Date(row.creationDate.value).toLocaleDateString()

Unfortunately, the day.js library used to format the last modification date, is not available in simple modules to format “custom” date properties.

label Label of the accordion.
You can use a resource bundle or hard code this label.
 
width - Optional Specify the width of the column

sortable - Optional

property - required when using sortable

Set sortable to true, if you want the users to be able to sort on the column. In such case, you need to provide the property to use for the sorting

You can see an example of an “Event picker” in the event module, where the picker displays the following columns:

  • Publication status
  • Content displayable name (corresponding to the Event title)
  • Event type
  • Event start date
  • Event end date

Creating new accordions

This feature is provided as-is. Due to its open nature, it is possible that not all the limitations have been identified. When creating new accordions, please carefully test your implementation to ensure that no limitation is encountered.

 It is possible to declare new accordions which extend existing ones. Such accordions can either be manually or automatically added to the pickers.

This feature allows to have, for example,  two “Content Folder” accordions, with two different rootPath pointing to two different folders of the site.

The following example creates an accordion pointing to an “event” folder created under the “/contents” folder of a site:

window.jahia.uiExtender.registry.add('callback', 'systemSiteContentFoldersAccordionRegistration', {
   targets: ['jahiaApp-init:35'],
   callback: () => {
       const registry = window.jahia.uiExtender.registry;
       const jcontent = window.jahia.jcontent;

       registry.add('accordionItem', 'picker-events', jcontent.jcontentUtils.mergeDeep({}, registry.get('accordionItem', 'picker-content-folders'), {
           targets: [],
           label: 'Event folder',
           icon: window.jahia.moonstone.toIconComponent('Folder', {size: 'default'}),
           treeConfig: {
               hideRoot: false
           },
           rootPath: '/sites/{site}/contents/events'
       }));

   }
});

If targets  is left empty, then you will need to reference this new accordion in your picker configuration by adding it to the accordion list, e.g. :

accordions: ['picker-pages', 'picker-events']

The target property can also contain the list of pickers to which the accordion needs to be automatically added. The format being: <picker-name>:<priority>

The priority is used to define the position of the accordion. The default priorities are:

  • picker-pages: 50
  • picker-content-folders: 60
  • picker-media: 70

Example:

targets: ['editorial:65','event:55']

In this example, the new accordion will be added to the editorial picker, after the content-folders accordion (as its priority is set 65), and it will also be added to an “event” picker, between the page and content-folders accordions.

Limitation when there are two accordions of the same “type”

If you have two accordions of the same type, e.g. two accordions of type “picker-pages”, you will need to provide a regex for each of the accordions, matching the path of the rootPath. This way, when an editor will re-open the picker to select a different item, the picker will be reopened to the location of the currently selected item. Without this, it may be possible that the picker opens a different accordion.

const contentFolderRegex = /^\/sites\/[^/]+\/contents\/.*/;
const siteContentFolderRegex = /^\/sites\/[^/]+\/contents((\/.*)|$)/;

And then the following code needs to be added in the accordion configuration:

canDisplayItem: ({selectionNode, folderNode}) => selectionNode ? contentFolderRegex.test(selectionNode.path) : siteContentFolderRegex.test(folderNode.path),

See the example in the Event module

Limitation when the rootPath of an accordion differs from the current site

When declaring an additional accordion with a hardcoded rootPath, please note that the corresponding site will become the selected one in the picker when re-opening it, which can be confusing for the contributor.

Said differently:

  • A custom picker comes with a custom accordion pointing to the contents folder of systemsite
  • A user opens this picker and selects an item from that custom accordion (thus a content created in systemsite)
  • The user changes their mind and wants to select another content: when re-opening the picker, the selected site will be “System site”, and thus, the Pages and Content Folders accordions will display content coming from System site, and not the content of the current site the user is working on

This is the case of the example Event picker, which declares an accordion pointing to a system-site folder.

 

Custom picker compatibility between CE 3/4.0 and CE 4.1+

Picker declarations for Content Editor 3.x or 4.0 are not compatible with CE 4.1+. However, you can use the following piece of code in your module to load one or the other picker configuration, dependending on which version of Content Editor is deployed on your plateform. This can be useful when planning upgrades to CE 4.1+ .
Doing so, you can deploy your modules with the new configuration before upgrading Content Editor, avoid to have to do the 2 operations at the same time.
Do not forget to clean this code after having validated the upgrade to CE 4.1+ .

window.jahia.uiExtender.registry.add('callback', 'custom-pickers', {
    targets: ['jahiaApp-init:60'],	
    callback: function () {	
        if (window.jahia.uiExtender.registry.get('pickerConfiguration', 'page').cmp === undefined) {	
            console.log("Picker configuration for Content editor >= 4.1")
  	        // Add your new configuration here
        } else {	
            console.log("Picker configuration for Content editor < 4.1")
	        // Move your current configuration here
        }	
    }	
});

Registering a picker for Content Editor 3 - Deprecated

If you are reading these lines, we strongly suggest you to upgrade to Content Editor 4.1+, as the CE 4.1 pickers provide a better user experience and more configuration capabilities.

The following picker configuration adds a configuration for a picker which allows editors to select nodes of the 'qant:location' type in Content Editor.

window.jahia.uiExtender.registry.add('pickerConfiguration', 'location', {
            cmp: {
                picker: window.jahia.uiExtender.registry.get('selectorType', 'ContentPicker'),
                treeConfigs: [{
                    rootPath: site => `/sites/${site}`,
                    openableTypes: ['jnt:page', 'jnt:navMenuText', 'jnt:virtualsite', 'jnt:contentFolder', 'nt:folder', 'jmix:siteContent', 'jmix:browsableInEditorialPicker'],
                    selectableTypes: ['jnt:page', 'jnt:navMenuText', 'jnt:virtualsite', 'jnt:contentFolder', 'nt:folder', 'jmix:siteContent', 'jmix:browsableInEditorialPicker'],
                    type: 'location',
                }],
                searchSelectorType: 'qant:location',
                listTypesTable: ['qant:location'],
                selectableTypesTable: ['qant:location']
            }
        })