Skip to main content

Optimizely

Optimizely CMS – Enabling Drag-and-Drop Support for PropertyList

snowflake time travel

Optimizely’s Generic PropertyLists can be a useful tool for both developers and CMS editors, but it does come with limitations.

Our client recently approached us asking for a better way to organize their PropertyLists. Some of their lists had grown to be quite long and having to move items one slot at a time was not an enjoyable experience.

There is an existing solution out there already for those with Commerce, but our client is CMS only.

A basic knowledge of dojo is recommended, but knowing dojo’s aspect module and the drag-and-drop system(DnD) is required to really understand how the solution works.

Issues

If you’re only interested in the solution, feel free to skip this section and go directly to it.

Surprisingly, I found that DnD is already set up, just not fully functioning. The PropertyList items can be dragged, just not dropped.
Debugging the existing code, I discovered the issue is that PropertyList type isn’t being added to the allowed DnD types.
In the collection editor code, allowedDndTypes is always undefined for PropertyLists.
epi-cms/contentediting/editors/CollectionEditor.js Undefinedalloweddnd
In the DnD code to check if a drop is allowed, the acceptedTypes for PropertytLists is always set to text, which is just the default value.
epi/shell/dnd/_DndDataMixin.js
 Checkacceptanceforitems
dojo/dnd/Source.js
Dndsource

 

Solution

In order to get around this, I extended the base CollectionEditor dojo widget. This solution was tested in both CMS 11 and CMS 12.

Thanks to dojo’s aspect module, we can intercept the DnD call chain where needed instead of trying to force the entire call chain to work with PropertyLists.

Here, I intercepted the problematic call to DnD’s _checkAcceptanceForItems() in order to discard its return value and return my own custom implementation. The key part is line 35, where we check the source items against the PropertyList type(self.itemType).

define('custom-scripts/Editors/PropertyListCollectionEditor', [
  // dojo core
  'dojo/_base/declare', // Used to declare the actual widget
  'dojo/_base/array',
  'dojo/aspect',

  // Optimizely
  'epi-cms/contentediting/editors/CollectionEditor', // Opti base widget to extend,
], 
function (
declare, 
array, 
aspect, 

CollectionEditor) {
  return declare([CollectionEditor], {
    _setupDnD: function () {
      // summary:
      //      Set up the dnd on the grid.
      // tags:
      //      private
      this.inherited(arguments);
      var self = this;

      self.own(
        aspect.after(
          self.grid.dndSource, // Target
          '_checkAcceptanceForItems', // Target's method to watch
          function (items, acceptedTypes) {
            // Run after target's method &
            // replace original return value with logic for PropertyLists
            return array.every(items, (item) => {
              return self.itemType.toLowerCase() === item.data.typeIdentifier;
            });
          },
          true, // Receive target method's original arguments
        ),
      );
    },
  });
});

 

After that, I created an editor descriptor to use the new widget as its editing class.

public class PropertyListEditorDescriptor<T> : CollectionEditorDescriptor<T> where T : new()
{
       public PropertyListEditorDescriptor()
       {
               ClientEditingClass = "custom-scripts/Editors/PropertyListCollectionEditor";
       }
}

 

Now to enable drag and drop support, I only need to use the PropertyListEditorDescriptor in place of CollectionEditorDescriptor when  setting up PropertyLists.

[EditorDescriptor(EditorDescriptorType = typeof(CollectionEditorDescriptor<Location>))]
public virtual IList<Location> Locations { get; set; }

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Justin Zachow

Justin Zachow is an Optimizely CMS certified full-stack developer with experience working in .NET, Typescript, Vue.js, and React. He enjoys tinkering with new technologies, hammock camping, and spending time with his pets in his free time.

More from this Author

Follow Us
TwitterLinkedinFacebookYoutubeInstagram