Magnolia 5.3 reached end of life on June 30, 2017. This branch is no longer supported, see End-of-life policy.

Page tree
Skip to end of metadata
Go to start of metadata

It is common to use a custom content app in a choose dialog. Here we create a dialog that allows editors to choose an image from Flickr. We use the Flickr browser app in a component template to browse the photos.

Required modules

Makes sure that your webapp contains the following modules from flickr-integration-parent:

  • flickr-templates
  • flickr-browser
  • flickr-accounts
  • flickr-integration

The flickr-templates module installs a component template with a choose dialog. The dialog launches the Flickr browser app to select a photo. The flickr-browser module contains a custom field and its definition and some custom classes. The flickr-accounts and flickr-integration modules are used by the flickr-browser module.

Creating a component template

Template definition

A template definition gives the component a name and makes it available to the system. The node name flickr-image-simple is used to the reference the component later.

 Click here to display the template definition

Node name

Value

 modules

 

 flickr-templates

 

 templates

 

 components

 

 flickr-image-simple

 

 dialog

flickr-templates:components/flickr-image-simple

 renderType

freemarker

 templateScript

/flickr-templates/components/flickr-image-simple.ftl

 modelClass

info.magnolia.flickr.templates.templates.components.FlickrImageSimpleModel

Dialog definition

To select an item from a content app we usually use a Link field. However, the default link field is rather JCR centric and not suitable for choose dialogs that reach out to custom content apps. We have to create a custom field. See flickrPictureId in the dialog definition:

Node name

Value

 modules

 

 flickr-templates

 

 dialogs

 

 components

 

 flickr-image-simple

 

 actions

 

 form

 

 tabs

 

 mainTab

 

 fields

 

 flickrPictureId

 

 contentPreviewDefinition

 

 contentPreviewClass

info.magnolia.flickr.browser.app.field.FlickrItemPreviewComponent

 appName

flickr-browser

 class

info.magnolia.flickr.browser.app.field.FlickrItemFieldDefinition

 type

String

Field properties:

  • appName: The name of the app we want to launch in the dialog.
  • class: The definition of the field to be used. Note that we don't use the default LinkFieldDefinition but a custom FlickrItemFieldDefinition. See field definition below.
  • contentPreviewDefinition: Renders a preview of the selected content.
    • class: FlickrItemPreviewComponent is a custom implementation of ContentPreviewComponent , see below.

The dialog will store the Flickr photo_id, for instance "14786302241", in a flickrPictureId property in the JCR.

Creating and registering a custom Link field

Since the default  LinkField  is not suitable we need a custom definition class and a custom factory class. Read Custom fields to understand what classes a custom field requires.

Field definition class

In the definition class all we have to do is to extend LinkFieldDefinition.

info.magnolia.flickr.browser.app.field.FlickrItemFieldDefinition
public class FlickrItemFieldDefinition extends LinkFieldDefinition {
}

Field factory class

In the factory class we override createChooseDialogCallback(). This method makes sure that the value which we store in the flickrPictureId property in the JCR is set to the field. We have the FlickrItemId of the selected item, from the ItemId we can access the photoId and set it to the same value.

info.magnolia.flickr.browser.app.field.FlickrItemFieldFactory
public class FlickrItemFieldFactory extends LinkFieldFactory {
    private Field<String> field;
    public FlickrItemFieldFactory(LinkFieldDefinition definition, Item relatedFieldItem, AppController appController, UiContext uiContext, ComponentProvider componentProvider) {
        super(definition, relatedFieldItem, appController, uiContext, componentProvider);
    }

    protected ChooseDialogCallback createChooseDialogCallback() {
        return new ChooseDialogCallback() {
            @Override
            public void onItemChosen(String actionName, final Object chosenValue) {
                String newValue = null;
                if (chosenValue instanceof FlickrItemId) {
                    String photoId = ((FlickrItemId) chosenValue).getPhotoId();
                    if (StringUtils.isNotBlank(photoId)) {
                        newValue = photoId;
                    }
                }
                field.setValue(newValue);
            }
            @Override
            public void onCancel() {
            }
        };
    }
    @Override
    protected Field<String> createFieldComponent() {
        field = super.createFieldComponent();
        return field;
    }
}

Registering the custom field

Register the new field in the flickr-browser module since the field is specifically built to be used with the flickr-browser app.

Node nameValue

 modules

 

 flickr-browser

 

   fieldTypes

 

 flickrItemField

 

 definitionClass           

info.magnolia.flickr.browser.app.field.FlickrItemFieldDefinition

 factoryClass

info.magnolia.flickr.browser.app.field.FlickrItemFieldFactory

Now we can use the field like we already done in the Dialog.

Content preview component

A content preview component renders a preview of the selected photo in the choose dialog. The preview component typically displays an image thumbnail and some metadata. Here we create a FlickrItemPreviewComponent which displays a thumbnail and a photo title.

To build the custom preview component extend AbstractContentPreviewComponent :

info.magnolia.flickr.browser.app.field.FlickrItemPreviewComponent
public class FlickrItemPreviewComponent extends AbstractContentPreviewComponent<FlickrItem> {
    private FlickrBrowserPreviewImageProvider imageProvider;
    private FlickrService flickrService;
    @Inject
    public FlickrItemPreviewComponent(String workspace, FlickrService flickrService) {
        super(workspace);
        this.imageProvider = new FlickrBrowserPreviewImageProvider(flickrService);
        this.flickrService = flickrService;
        VerticalLayout verticalLayout = new VerticalLayout();
        verticalLayout.addComponent(new Label(""));
        setCompositionRoot(verticalLayout);
        rootLayout = verticalLayout;
    }
    @Override
    protected Component refreshContentDetail(FlickrItem item) {
        CssLayout layout = new CssLayout();
        displayProperty(item, FlickrItem.PROPERTY_TITLE, layout);
        displayProperty(item, FlickrItem.PROPERTY_DESCRIPTION, layout);
        return layout;
    }
    @Override
    protected Component refreshContentPreview(FlickrItem item) {
        String photoId = (String) item.getItemProperty(FlickrItem.PROPERTY_PHOTOID).getValue();
        Resource resource = imageProvider.getSmallThumbnailResource(photoId);
        Image image = new Image();
        image.setSource(resource);
        return image;
    }
    @Override
    protected FlickrItem refreshItem(String itemPath) {
        if (StringUtils.isNotBlank(itemPath)) {
            Photo photo = flickrService.getPhoto(itemPath);
            if (photo != null) {
                FlickrItem flickrItem = FlickrItemUtil.createItemByPhoto(photo);
                if (flickrItem != null) {
                    return flickrItem;
                }
            }
        }
        return null;
    }
    private void displayProperty(FlickrItem item, String itemPropertyId, CssLayout layout) {
        String valueTxt = (String) item.getItemProperty(itemPropertyId).getValue();
        if (StringUtils.isNotBlank(valueTxt)) {
            layout.addComponent(new Label(valueTxt));
        }
    }
}