Classic to Touch UI Migration for AEM: More Tips from Experience
In our previous post on Classic to TouchUI migration we described our overall “Hybrid Mode” approach to migrating an entirely Classic UI component library to Touch UI using AEM’s compatibility mode. In the post, we alluded to some “quirks” that we encountered. In this new post, we go into much more detail about these quirks and how to deal with some of these quirks.
Although the Hybrid Mode is extremely useful it has some limitations that can prevent the development team from adopting TouchUI without additional effort on large projects. Here are some of those issues we encountered and the solutions our development team came up with.
Author can’t drag & drop images while editing a component
The ClassicUI Widgets library provides a SmartImage component for uploading and processing images. Image assets by default can be uploaded in two different ways:
- From the file system
- From the DAM (Digital Asset Manager) by dragging the image from the page content finder panel on the left side
Let’s dive deep into the technical details of TouchUI implementation. The compatibility mode renders a ClassicUI dialog inside an iframe. For some reason the compatible mode doesn’t have any logic for tracking drag & drop events out-of-the-box. This restricts authors from dragging images out of the Assets panel (as they are used to doing it within the ClassicUI experience). This means they do not have a way to place the image into the component. Moreover, when an image field is required, the author doesn’t have the option to complete component configuration because of an empty required field.
Solution
To solve this problem we decided to extend the Standard SmartImage component to render a pathfield in addition to existing functionality. As a result, the author gets the ability to select an image by using pathfield and the image appears inside the SmartImage area to preview and/or change the image if needed. For non-existing paths (or non-image paths) the field is highlighted as invalid.
- Re-register the original htmlsamartimage xtype with an inherent custom one that extends the original CQ HtmlSmartImage widget. On the initialization of the new widget, we add an additional PathField widget to the component containers. Additionally, we provide little updates to the default widget layout that’s a common UI update for ExtJS-based UIs.
- Binding controls (PathFields) in all HTMLSmartImages. First of all, we prepare helpers by creating methods for getting and setting values from PathPicker and the same methods for the original component. The first pair is setValue and getValue of the PathField, which is the easy part. The tricky part is dealing with the original component value. HTMLSmartImage doesn’t store its value in an accessible state.
To get the current image path is easily done through using the this.fileReferenceField.getValue() method. But to set the value to the original widget we need to emulate an image resource drop on the component. We can manage that in the following way:
Now when we have all value accessors we need to know when the original and when the Pathfield value are changing. To track Pathfield changes we can use a ‘blur’ event. For the original widget the ‘imagestate’ event is the most suitable. We need to track two types of image state changes: ‘originalremoved’ and ‘originalavailable’, so the listener can be the following:
Now, it’s ready for binding. To keep the validation mechanism in the new implementation, we override the original validation logic for the embedded pathfield instance.
All scaffolding fields dialogs are disabled
AEM Scaffolding mode allows an author to easily create pages based on a specific scaffold form structure. Scaffolds are extremely useful for creating well-defined structured content (e.g., articles, blog posts).
In Hybrid Mode all scaffolding form fields are disabled, which means they can’t be edited.
Solution
Including the cq.security library into the page’s JSP solved the issue and the scaffolding forms started working properly.
Hybrid dialog closes without saving data when clicking outside of the dialog area
All components are edited inside the component configuration dialog window, which pops up in edit mode.
There is a small difference in user experience in Hybrid and TouchUI dialogs:
- If a user clicks away from the TouchUI dialog, nothing happens.
- If a user clicks away from the hybrid dialog, it closes without saving entered data.
This means that all unsaved data is going to be lost in the event of an accidental click outside the component! Needless to say this is quite annoying for authors.
Solution
Luckily the solution is pretty simple. Initially, the dialog backdrop is in “modal” mode. In order to change the dialog backdrop mode the dialog’s JSP file needs to be overlaid and the dialog backdrop mode set to the “static” value.
Some dialog fields do not fit the dialog window area
As we already described before, UI dialogs render in an iframe inside the TouchUI dialog window. This dialog window sometimes does not fit all dynamic content, sometimes causing a weird layout where extra scrollbars appear inside the dialog.
Solution
To overcome this inconvenience, we overlay the JSP file that contains all configuration settings for properly rendering dialogs in the compatibility mode. This JSP file is placed within the following under the following path:
apps/cq/gui/components/authoring/compat/components/dialog/dialog.jsp
We change the window width and height to consider the original dialog’s dimensions, as well as the browser’s window size.
We handle this situation via script that actually provides bind between the Touch UI (Coral) wrapper and embedded Classic dialog in iframe. The event “dialogwrapper-ready” + ns is needed for that with pre-calculated width and height as handler function parameters. It’s also possible to do your own recalculation and then set the width and height to the Coral Dialog content:
Some components can’t be edited in TouchUI (easily)
The authoring experience is one of the most important points to consider while implementing components in AEM. Imagine a carousel component that contains a number of slides. In Edit mode, it’s better to render all carousel slides as a column so that the author can easily rearrange the slide order and access all of them simultaneously without switching between slides. There is one important difference between ClassicUI and TouchUI:
- In ClassicUI the authoring elements (e.g., editbars) are a part of the markup that is rendered with the component in Edit mode.
- In TouchUI the authoring elements are rendered in an overlay. Final component markup is rendered in an iframe. The combination of these conditions leads an author to the situation when it’s not possible to interact with the component in Edit mode at all (e.g., click buttons, flip through the slides of a carousel).
So we face cases where a couple of components in our library require some interaction before the user can start the editing process, but this can not be easily achieved in TouchUI.
Solutions
However, there are a couple of fixes that might be considered as possible solutions:
- There is a quick and simple workaround that requires no dev effort: all editable components can be found in the Content Tree and there is a wrench icon next to each one of them that opens the editing dialog.
2. For complex components with lots of subcomponents the markup of the component in Edit mode can be changed to make all ‘hidden’ component areas open to Author’s ‘eyes’. This would mean everything is visible and accessible through Edit mode.
3. As a best practice, Adobe provides a solution to support such an authoring experience case inside AEM Core Components. Carousel Component and Tabs Component use the Select Panel option in the component toolbar to reorder the slides and views and change the currently previewed element.
The “unlock page” button does not work
There is a standard AEM option to lock and unlock the page for changes. While validating the TouchUI migration approach, we found a situation where the author couldn’t revert a ‘locked’ page to its initial state. Fortunately this functionality works properly via the AEM Site Console.
A similar problem is described here and here.
Solution
The error message in the browser console says that it “Cannot read property ‘shared’ of undefined”. The root cause lies in a missing client library ‘cq.shared’.
Including of ‘cq.shared’ library into the page’s JSP solves the problem and the “Unlock page” button starts working as expected.
Authors: Volha Lunkova, Liubou Masiuk, Aliaksei Stsefanovich
Originally published at https://exadel.com on October 17, 2019.