ddraper

Aikau Development Process Example - Inline Comment Rendering

Blog Post created by ddraper on Oct 20, 2014

Introduction

I've previously provided a few examples and techniques of how to implement a variety of use cases using Aikau, but now I'd like to provide an example of the process I follow to implement a solution. Whilst this process might not be suitable for everyone it should at least be informative and show the ways in which you can leverage existing widgets to achieve your use case.

 

As a background exercise I've been working on re-implementing the Document Library using Aikau and my aim is not simply to achieve feature parity but to improve what is currently available. Something that I believe could be a potentially useful addition would be the ability to view and add comments on a document without needing to access the details page for that document.

 

 

Step 1 - Break Everything Down

Rather than trying to tackle everything in one go (e.g. as a single widget) it's important to determine whether elements of your target solution already exist and whether or not it is worth abstracting other elements into widgets that could be re-used in other use cases.

Almost everything in a web application boils down to lists, forms and layout and this use case is another example of that. We know that we want to be able to...

    1. See a list of existing comments (obviously a list)
    2. Add a new comment (a form)
    3. Edit an existing comment (another form)
    4. Delete an existing comment (an action on a list)
    5. Only reveal (and load) comments on demand (layout)


Aikau provides a good support for list rendering as shown in the previous Data List blog post - and in fact steps 1, 2 and 4 are almost identical to uses cases covered in that blog (it's only the data that is changing).

We can therefore re-use one the Aikau list widgets (e.g. 'alfresco/lists/AlfList') and the 'alfresco/services/CrudService' as a means to render the list, the 'alfresco/dialogs/AlfDialogService' to pop-up a form that can be used to add a new comment and an 'alfresco/renderers/PublishAction' widget to issue the delete request.

At this stage it's worth noting a couple of important points...

    1. There could very well be more comments than can easily be accommodated
    2. We don't yet have all the widgets we need to render the comments view as we'd like (in this case we don't have a widget for rendering user avatar thumbnails).


The nice thing about Aikau is that you don't need to get bogged down in such details because it's easy to come back and iterate over your page models without needing to throw anything away.

    • It's easy to update a list view to add in additional renderers.


We want to simply get our commenting use case implemented as quickly as possible. Focus on the key goals, get your solution working and then iterate to polish it up to the required level.

 

Step 2 - Use What You've Got

Rather immediately diving into writing widgets at this point I started with a new Aikau page WebScript to get as far as possible with the previously mentioned widgets and services at my disposal. You should probably use the Alfresco SDK for this, but I prefer to create and work with files directly in my Tomcat structure for maximum speed.

 

Rather than worrying about integrating this comments list into my detailed view, I just want to get some data to work with so I create a new document in my Alfresco repository using Share and then add some comments to it. I then take a note of the NodeRef and use that directly in my page model because I know that I can swap it out for contextual data at a later point.

 

Use a browsers developing tooling it's easy to capture the XHR requests that are made when working with existing comments and I can build this simple page model for listing the comments of my target node.

{
  name: 'alfresco/lists/AlfList',
  config: {
    loadDataPublishTopic: 'ALF_CRUD_GET_ALL',
    loadDataPublishPayload: {
      url: 'components/node/workspace/SpacesStore/eb98d7af-c311-4ab8-9596-6fcda675fe6e/comments?reverse=true&startIndex=0&pageSize=10',
      urlType: 'SHARE'
    },
    widgets: [
    ...
    ]
  }
}

 

I've not included the view definition here (which would appear in as the 'widgets' array) because views have previously been covered in other blog posts.

 

We now able to render a list of comments for a given NodeRef.

 

Step 3 - Identify What's Missing

From our breakdown above and with some knowledge of the Aikau widget library (e.g. by reviewing the JSDocs) we know that there a couple of key widgets missing...

    1. A widget for revealing and dynamically building new Aikau components (this is different from simply toggling visibility of previously rendered widgets described in this previous blog post which would be inefficient).
    2. The ability to toggle between reading and editing comments in an HTML editor.


Well, as it happens I'd already been working on editor widgets for another use case (inline content creation) and have a TinyMCE based HTML editor form control ready to go, but with no means to toggle between read and edit mode. We also need a widget for revealing and building new AIkau widgets.

 

Step 4 - Create Missing Widgets

The widgets I ended up building for this example are now committed to the Alfresco source code so I won't be including them here. I also don't want to go into too much detail on how they were developed as I want to cover widget development in another blog post, however I do want to call out a view key points in their development process.

The first widget I created was the 'alfresco/renderers/EditableComment' widget which allows your to switch between a read-only view and an editable view of data which can then be persisted.

This widget is essentially a wrapper around a form that contains the 'alfresco/forms/controls/TinyMCE' form control. When developing widgets we try to recognize that they may want to be either extended or re-configured in the future so we try to write them so that they can be used as they are with a minimum amount of configuration but make define the default behaviour within configurable variables. So for example...

    • The topic the widget subscribes to that will trigger the edit mode is defined by the 'subscriptionTopic' but has a default of 'ALF_EDIT_COMMENT'
    • The form and form controls as defined in the 'widgets' variable so that they can be easily be changed either in the page definition, by dynamic extension module or an extending widget
    • The labels for the save button is further abstracted so that it's not necessary to re-define the entire form to simply change their labels.
    • The property of the editable content is defined in the 'propertyToRender' variable so that the widget can be used with different data models
    • The property name that the updated comment will be POST back to the server as is defined in the 'postParam' variable so that the widget can be used with different services.


Essentially our widget becomes a configurable container around previously created widgets as we try to maximise re-use out of the existing widget library capabilities.

 

Similarly the new 'alfresco/layout/VerticalReveal' widget extends an existing widget and heavily uses existing widget processing capabilities for on reveal processing the JSON model that it can be configured with.

 

This widget was also written with respect to the fact that is is undoubtedly not the only use case that it would be suitable for. It contains no references to comments or indeed anything else relating to the use case it was written with. It's important for us to recognise when we're creating something that has multiple uses and not prevent ourselves from re-using it or extending it in the future.

 

Step 5 - Integrate New Widgets

Once the missing widgets have been developed they can be integrated into the our page WebScript to be tested out. The first issue that presents itself is that all the EditableComment widgets are publishing and subscribing on common topics. This means that editing one comment puts all comments into edit mode.

 

The solution to this is to scope each row of the in the list of comments. This is done by setting 'generatePubSubScope' to true on the Row widget in the view as this means that the widgets for each item in the list will have their own 'pubSubScope' attribute value and prevent cross-talk between widgets.

...
{
  name: 'alfresco/documentlibrary/views/AlfDocumentListView',
  config: {
    widgets: [
    {
      name: 'alfresco/documentlibrary/views/layouts/Row',
      config: {
        generatePubSubScope: true,
        widgets: [
...

 

Comment context is largely addressed in the 'url' attributes in the 'publishPayload' objects created for the EditableComment, PublishAction widgets along with the button for creating a dialog to create a new comment. It's worth noting that at some stage we'll want to introduce a dedicated CommentService module which will make the JSON model much simpler as it would only require the 'currentItem' to be published rather than there being a need to process payload configuration.

 

Step 6 - Create a Composite Widget

We don't want to have to re-declare the JSON model that has been created every time we want to render a list of comments. Instead we want to create a new widget that is little more than a alias to our model - this will be the widget that we reference in our Document Library view and means that we can pervasively change how comments lists are rendered in a single widget.

 

The 'alfresco/documentlibrary/views/AlfDetailedView' widget (another example of a composite widget) is then updated to include our CommentsList widget.

 

...
{
  name: 'alfresco/documentlibrary/views/layouts/Cell',
  config: {
    widgets: [
      {
        name: 'alfresco/layout/VerticalReveal',
        config: {
          subscriptionTopic: 'ALF_REVEAL_COMMENTS',
          widgets: [
            {
              name: 'alfresco/renderers/CommentsList'
            }
          ]
        }
      }
    ]
  }
}
...

 

Comments were previously shown as a simple count that when clicked take the user to the comments section of the detailed page. Since we wanted to retain the existing code that renders the comments count but change the behaviour to allow a click action to reveal the comments list I made an additive change so that if a specific 'publishTopic' attribute is configured then the behaviour changes so that the link becomes a simple comment toggle.

 

Changing the widget in this way means that all existing uses of the Comment widget behave exactly as they did before but the AlfDetailedView is able to reconfigure it to use it in a new way.

 

...
{
  name: 'alfresco/renderers/Comments',
  config: {
    publishTopic: 'ALF_REVEAL_COMMENTS'
  }
},
...

 

Changing the widget in this way means that all existing uses of the Comment widget behave exactly as they did before but the AlfDetailedView is able to reconfigure it to use it in a new way.

 

Step 7 - Addressing Further Context and Scoping Issues

Now that our CommentsList widget is being repeated multiple times within a single page we need to ensure that there is no cross-talk between the widgets when revealing comments. The same approach as before was taken to generate a new 'pubSubScope' for each item in the list.

 

We're also able to update our previous JSON model for the list to use the NodeRef of the document to retrieve comments for.

 

...
{
  name: 'alfresco/lists/AlfList',
  config: {
    waitForPageWidgets: false,
    loadDataPublishTopic: 'ALF_CRUD_GET_ALL',
    loadDataPublishPayload: {
      url: 'components/node/{nodeRef}/comments?reverse=true&startIndex=0&pageSize=10',
      urlType: 'SHARE'
    },
    widgets: [
...

 

Again, adding in a dedicated CommentService module will make this section of the model much simpler.

 

The Current (Not Final) Result

Rendering the Aikau based Document Library page now allows us to view, add, delete and edit comments for a Document without needing to access it's details page. It's quite clearly not the finished article but it's been relatively straightforward to get something working that we can being to polish into the finished article.

 

Aikau Document Library showing comment counts

 

 

Having revealed the current comments 

Prompt when deleting a comment Inline editing a comment using TinyMCE Creating a new comment 

 

Next Steps

Hopefully an Aikau based Document Library will be a key feature of an Alfresco 5.1 release (whenever that might be) and this is just a starting point for making comment handling much simpler.

The next steps to be implemented would be:

    1. Create a dedicated 'alfresco/services/CommentService' module and simplify the existing JSON model
    2. Switch to using the 'alfresco/lists/AlfSortablePaginatedList' and add pagination controls
    3. Add a user avatar thumbnail widget and include it in the comments list view
    4. Improve the styling of the VerticalReveal widget.
    5. Update the Comment widget further to subscribe to commenting topics to allow it to refresh the count as comments are added and deleted.

    Outcomes