Interactive Editor Plugin Guide

Overview

Version 2.0 of the template framework unifies all types of templates into a common, programmable structure that allows developers to create and contribute templates that can be directly embedded in the authoring tool. Currently, the item data are created via the portal the corresponding templates are embedded in the content during authoring.

This doesn't give an author a lot of control over configuring the template, and its behavior. Moreover, it is also limited to the data available as part of an item. The template v2.0 frameworks make it possible for templates to be directly configured from within the authoring tool. Developers can write the custom runtime logic, custom configuration editor, and custom editing experience (WYSIWYG) to make it easier for authors to discover and reuse these templates

These templates can include informational aspects such as a Flashcard that presents the word details or include engaging tasks such as exploring a noun and its related nouns, verbs, etc. Such templates are used for enabling learning tasks - Reading, Writing/Scribbling, Recording, Exploring, Interacting, and so on. The actual templates can range from simple single stage tasks (flashcard, scribble pad, recorder activity) to complex multi-stage tasks that guide the learner through a pre-configured learning activity.

The following aspects of extensions in the authoring tool are described:

Registration and lifecycle

Registering a plugin associates a class (prototype) with a custom plugin object. The element provides callbacks to manage its lifecycle. Uses behaviors to share code.

The plugins core is implemented in its plugin.js file. The file is loaded by the plugin manager and initialized during the load time. The plugins themselves are instantiated when the user creates that object in the editor.

Namespaces: Proposed namespace is editor.* for Editor plugins, renderer.* for Renderer plugins. The community contributed plugins should follow the same convention - org.editor.* and org.renderer.*

var editor.Plugin = Class.extend({
    initialize: function(data) {}, // When the plugin is registered, it can set up its dependencies
    properties: function(data) {}, // The attributes of the plugin
    converter: function(instance) {}, // returns the converter object for this plugin
    editor: function(instance) {}, // returns the canvas editor object for the given instance
    views: function(instance) {}, // returns the views associated with this plugin
    behaviors: function(instance) {}, // returns the behavior mixins for the given instance
    create: function(data) {}, // Instantiate an object of the plugin's type (e.g on canvas)
    remove: function(data) {} // When the object of the plugin's type is deleted from canvas
// TODO - base class methods
})
Properties

For content plugins only, the properties exposed by the plugin are declared. This allows the plugin to inherit the default behaviors related to rendering the properties. Properties are declared by the plugin as follows:

[
    {
        "propertyName": "", // Name of the property
        "title": "", // Display label
        "description": "", // Tooltip text
        "category": "", // Category of the property for rendring        
        "dataType": "Text", // Data type (number, text, word, wordlist, color)
        "encoding": "", // How the property is saved (attribute, json, cdata)
        "required": true,
        "displayProperty": "Editable",
        "defaultValue": "",    
        "renderingHints": "{'editor': 'colorpicker'}"
    },
    ... // other properties
]

The base plugin declares the default properties for all plugins:

  1. Bounding Box - x, y, w, h

  2. Border - stroke (border color), stroke-width (border size)

  3. Shadow - shadow, offsetX, offsetY, blur

Each custom plugin can extend the properties list and add its own declarable properties. Any other config is generated and handled directly by the plugin and added to its CDATA section config.

Converter & Parser

Converter modifies the content DOM tree and adds the current instance to the DOM. Any cross-plugin modifications (e.g. horizontal concerns) should not be implemented as converters, but as converter behavior that can receive and apply across multiple instances.

var editor.Converter = Class.extend({
    // Converts the current object to ECML. Passes the ECML DOM object
    toECML: function(instance, dom) {}
    // Converts the ECML node into the appropriate plugin object
    fromECML: function(node, dom) {}
})
Editing

Editor is the base class for all canvas editor plugins. The base class extends the Fabric.js rendering system and provides default functionality to render the editor object on canvas. Default for any editor shows a thumbnail for that object on the canvas.

var editor.Editor = Class.extend({
    // Returns the native fabric object to render this plugin's editor
    canvasObject: function(instance) {}
})
View

View is a visual widget (non-canvas) that is placed in the layout. View is instantiated by the plugin and is manipulated by its behaviors. Any actions within the view are handled by its own handlers. It may or may not fire events for its actions. The view is expected to be bound to its object and update the state internally.

Actions and Events

Actions are executables that are defined by a plugin. Action can be bound to a toolbar, menu bar etc. When the action is clicked, the callback method is called allowing the action to perfom its task. In addition, the action also fires the custom action event to allow any other behaviors to respond to the action. Clicking the action would generally show/hide a view, or add/edit state on the canvas.

Action Data

Note: There may be a need to bind the action to some specific property. E.g. when we put a color selector action, bind it to the color property automatically. Need to think this through.

Behaviors

The basic interfaces are as follows:

Text Provider

Text providers are plugins that expose a textual representation of their content. This allows the authoring tool and other plugins to work with the text and leverage the language platform (e.g. to work with the parser API).

State Listener

Listener for state in the authoring tool. The callback pattern allows the behavior to listen for events while the action is happening (e.g. rotating), or after the action is completed (e.g. rotated). If the action is cancelled, the end event is called with state=CANCELLED. Understandably, the progress events are called on every tick while the end event is called once per action (on finished or cancelled).

Clipboard Listener

Listener for clipboard events - when an object is copied on the clipboard or when it is pasted.

Action Listener

Listener for custom actions. E.g. when read-along editing is completed, it fires the event, that is handled by the appropriate listener.

Note: This mechanism doesn't allow listeners to prevent the action from happening (there is no "beforeXX" event callback and no way defined to cancel an event). This is intentional. If an action has to be disabled based on some condition, the listener should observe the condition and disable the action itself (prevent the user from taking the action rather than trying to cancel it).

Reusable Views/Plugin Artifacts

  1. PropertyConfigFormView - Popup that generates a form based on properties data. For most simple widgets, this form view might be sufficient to configure them

  2. DefaultButtonAction - Default toolbar action (simple button).

  3. WordSelectorView - Uses APIs and provides UI to select a single word from repo

  4. WordlistSelectorView - Uses APIs and provides a UI to select multiple words from repo

Property Observer

Handles the property change notifications for the plugins

Examples/Illustrations

1. Read-Along Widget (Content Plugin)

Plugin.js

ReadAlongConfigView.js

2. Editor Extension - Word Complexity Provider

plugin.js

WordComplexityListener.js

WordComplexityView.js

3. ECML Template

Example of a template that has read-along and recorder widgets on the same page.

plugin.js

DefaultTemplateSelectorView.js

Last updated

Was this helpful?