Handling Undo/Redo in custom Editor?

Vote:
 

Hi,

I have created a custom field which represents a set of CSS Classes that a content author can select.

[EditorDescriptor(EditorDescriptorType = typeof(StyleEditorDescriptor))]
public virtual string Styles { get; set; }

My editor descriptor is quite simple.  It loads a list of CSS class objects and instantiates a custom dojo widget.  The widget uses ChoicesJS to draw a fancy multi-select UI.  I have simplified the widget in this case:

define([
    // dojo core
    "dojo",
    "dojo/on",
    "dojo/_base/declare", // Used to declare the actual widget
    
    // dijit core
    "dijit/_Widget", // Base class for all widgets
    "dijit/_TemplatedMixin", // Widgets will be based on an external template (string literal, external file, or URL request)
    
    "./vendor/choices",

    // css
    'xstyle/css!./theme/choices.css',
    'xstyle/css!./theme/style.css'
], function (
        // dojo core
        dojo,
        on,
        declare,
        
        // dijit core
        _Widget,
        _TemplatedMixin,

        // vendor
        Choices
) {
    return declare("app.editors.classSelector",
        [_Widget, _TemplatedMixin],
        {
            templateString: dojo.cache("app", "./editors/classSelector.html"),

            constructor: function(widget, widgetsInTemplateMixin, contextMixin) {
                _Widget = widget;
            },
            postCreate: function () {
                this.inherited(arguments);

                var module = this;

                // initialize choicesjs module with css classes passed from editor descriptor

                on(module.Input, 'change', function(ev) {
                    var result = // calculate result ...
                    module._setValueAttr(result);
                });
            },
            /* If you need to be sure parsing and creation of any child widgets has completed, use startup. This is often used for layout widgets like BorderContainer. If the widget does JS sizing, then startup() should call resize(), which does the sizing. */
            startup: function() {
                this.inherited(arguments);

                // allow Choices plugin to "flow" outside of this control, overlapping other elements
                dojo.style(this.domNode.parentNode, "overflow", "visible");
            },


            // Setter for value property (invoked by EPiServer on load)
            _setValueAttr: function (value) {
                this.inherited(arguments);

                // ensure choices JS always aligns visually with the incoming value ... removed for brevity
                
                this.onFocus(); // set focus because choicesjs module loses focus sometimes
                this._set("value", value);

                this.onChange(value);
            }
        });
})

I have everything working, except one thing: Undo and Redo.

What is the proper way to handle Undo and Redo from a custom editor widget?  When Undo/Redo are clicked, I need to tap into this with my widget and redraw my UI to ensure what is visible to the user represents the current "state" of the data.  How do you do this?  setValueAttr doesn't appear to be called when Undo is clicked.

#216208
Edited, Jan 29, 2020 19:37
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.