EditorAPI

Motivation

This is a Brainstorming topic about how to organize the javascript behind the scene to implement different editors, even mix different editors on the same page or even on the same input field.

The classic approach is that you "view" a page, and then click a button to kick the page into an "edit" mode. When "edit" mode starts up, various JS editor components "camp" on the different HTML components used for input fields. When the user switches back to "view" mode, the components are closed down and a completed page is "saved". There are a number of problems with this approach:
  1. Usability: It is clunky to use; you have to edit the entire page to change one character in a form field, and it's painfully slow
  2. Implementation: the JS components can conflict and fall over eachother, and it's the very devil to configure everything so they work together.

The current situation is that more and more javascript editor components are available. The most important editor component is obviously the topic text editor. There are other editor components as well that don't necessarily go through an "edit page" cycle. These are inline editor components. While both classes of editor components have different requirements they also share the inner need to organize various events like initialisation and form submission.

Editor components of various kinds are specified in the Type field of DataForms as well, though a lot more fine-grained. Still these are "editor components".

Another example of an "editor component" would be a single button "add attachment" that triggers a flash based uploader. This uploader would then start to upload as soon as you close the selection box, and report when it is done. This too is a kind of "editor", as you changed the current page. The thing missing now is that views of the current page need to be refreshed, as the list of attachments at the bottom of the topic is outdated. Other potential listeners, such as an image gallery would like to be updated as well.

The general situation is: an (inline) editor changed some content, you don't want to do a full page refresh but some content areas need to be updated on the page.

We currently have at least three extensions that would like to hijack the standard textarea: TinyMCEPlugin, NatEditPlugin and EditChapterPlugin. There is a deeper reason why these don't function properly when installed all together ... they don't know anything about each other. This is for a good reason; we don't want to create artificial dependencies between then. However there is common functionality which is currently duplicated between them, and they have similar requirements, especially in the startup and shutdown phases.

All these components need to be coordinated in a way to play together. Some of these need special treatment or even interact with each other: a client selection box interacts with a projects selection box; a group selection box constraints a members selection box; a web selection box constraints a topic selection box; a form is only valid if a certain set of selections have been made. Just to name a few quite common requirements on forms.

The thesis is that they should at least use a central API to make sure that any potential additional javascript component gets a chance to do what it needs to do on certain events, like form submission.

Issues

Editor types

Starting back in the server, we need to be able to associate an editor with a particular datum or (user) event. For example, I might want to have a form field which uses a WYSIWYG editor, but stores its contents in HTML rather than TML. Or I might want to be able to (as a user) specify a preference to use a particular type of WYSIWYG editor, or maybe no WYSIWYG editor at all, but a different flavour of raw editor (natEdit or smartEdit). So we need to be able to associate an "editor profile" with an editable object in such a way that sensible defaults can be cleanly overridden by user preferences.

Have a look at drupals wysiwyg api, i.e. their notion of editor profiles. This is a list of configurations for various editors that application developers then can chose from in form definitions.

wysiwyg-profile-overview.png

The editor profile approach has the attraction that it's simple to associate large sets of options with data types. For example, I might have a form definition in a macro library:
Name Type Size Values Tooltip message Attributes
MacroName text 1 name of this macro blah blah...  
Description textarea,editor=wysiwyg_html 50x5   blah blah...  
TML textarea,editor=raw 50x10   blah blah...  
The 'text' area could use the same style of specification, but in a macro definition:
  • Set TEXT_EDITOR = wysiwyg
(this is consistent with Peter Jones' proposals to the (tm)wiki project for controlling the default editor, which is nice).

Javascript

There are several fields to cover, most important are editor initialisation and form submission. The idea is to have central javascript object - let's call it foswikiEditor. This object standardizes a set of custom javascript events that other components can bind to. Form submission is a bit more special in this set of editor events as handlers registered to the submit event might veto and thus block further submission.

There's a problem with events: the order when which handler is called might become important. For instance, EditChapter needs to recombine the final text input by combining content before and after the current section with the one changed by the user. Only after that step TinyMCE is allowed to do its job by first converting html to tml. The situation is a bit more complicated as TinyMCE does not change the textarea directly as it uses an iframe for the real wysiwyg interaction. So both components need to be coordinated in a way.

Another problem with the order of events; it is different depending on which browser you use, especially during startup. Some frameworks, such as Dojo, go to great lengths to create a canonical event model that users can rely on to deliver the same behaviour on all browsers, but such solutions are rarely 100% reliable.

Form validation is as complex as you want. What an EditorAPI should provide is a way to monitor form validity and veto on it to be submitted. The idea would be to use a form validation component that then binds to specific custom javascript events that are fired by a central editor instance. The event handlers could then veto on the form to be submitted. A much simpler example would be a modal dialog asking "do you really want to abandon your edits - yes - -no".

There's more in the irc logs attached below. Please help to refactor this to make it more concrete.

-- MichaelDaum, CrawfordCurrie - 14 Jul 2009

Regarding editor profiles, I have had lots of thoughts (see WysiwygContentPolicies) about this but sadly only just found this topic.

Behind the scenes, the editor in use (assuming it's a HTML editor) has requirements on the exact way that TML2HTML should work, although that's a separate (backend) issue.

Here are my thoughts:
  • Editor profiles
    • Choosing an editor: I am personally interested in the lightweight jwysiwyg jquery editor (7kb, but no table handling) for formfields, and Wymeditor for semantic markup applications.
    • Configuring the editor: Toolbars, plugins, sizing, options...
  • Content-to-editor requirements (part of editor profile )
    • Solved in the back-end (does not concern the user). But we are looking at adding even more TMCE specific quirks to TML2HTML so this needs to be formalised if we ever want to be able to have more than one editor.
  • Editor-to-content policies
    • The user (or rather, foswiki admin/app tinkerer) will have requirements on what should be allowed into the target content (topic or formfield)
      • Strictly no HTML tables? No spans? Preserve alignment style attributes? Block even TML tables? Etc.
        • I had envisaged that several profiles should be configured in LocalSite.cfg, differing progressively in the amount of HTML pollution allowed into a topic. For topics we would * Set CONTENT_PROFILE = liberal+onlytmltables - where the first keyword would be the profile name, followed by a comma separated list of component policies as modifiers.

I had always imagined that specifying a wysiwyg editor (profile) for a formfield would actually go in the attributes column.

But we should be able to specify what goes back in to the formfield via the Type column. Something like:


Name Type Size Values Tooltip message Attributes
MacroName text 1 name of this macro blah blah...  
Description textarea+liberal+onlytmltables+onlytmllists+noflattenbaredivs 50x5   blah blah... M,EDITOR=wysiwyg+formfield
TML textarea+onlytml 50x10   blah blah... EDITOR=raw
MiscField textarea+liberal 50x10   blah blah... H,EDITOR=wymeditor+formfield;theme=misctheme,M

  • Set WYSIWYG_EDITOR = fckeditor

Content policy

In a similar fashion to the way we do select+multi+etc

  • textarea will take a series of modifiers separated by '+'.
  • The first modifier is a base policy name (made up of component policy modifiers; all configured in LocalSite.cfg hashes because Foswiki vars are too unwieldy for this)
  • Subsequent named component policy modifiers are added to tune the base policy to the user's liking
    • If the name is prefixed with "no", it is substractive (removes the component policy if it is included by default in the base policy)

The example above shows:
  • Description field is based on the liberal policy (don't strip/flatten anything that fails to translate to TML), but enforces TML tables and TML lists, and disables the flattening of bare (no attributes) <div> blocks.
    • It uses the default WYSIWYG editor's formfield profile, in this case the form definition topic itself would default to fckeditor (but normally tinymce's formfield profile)
  • TML field is based on the onlytml policy, which doesn't allow any HTML tags at all.
    • It uses the raw editor.
  • MiscField is based on the liberal policy
    • It uses the wymeditor instead of tinymce, and passes the key 'theme' with value 'misctheme' to the WymEditorPlugin's setup routine which might pass them on to the javascript init object.

Editor profile

Specifies the editor by name. A default profile (toolbar layout, sizing, options etc) specific to the named editor is assumed unless a '+' selects a specific one (which will be defined for the selected editor).

key=value pairs separated by ';' are passed to the editor plugin's setup routine to do what it likes with them.

"wysiwyg+formfield" selects the formfield profile of the default WYSIWYG_EDITOR , whatever that is (normally tinymce )

At the moment the idea is that the editor profile name simply matches up with a corresponding Foswiki *Plugin to be called upon for setting up the textarea for wysiwyg (or not). WysiwygPlugin's TML2HTML will also know which editor it's talking to, and the EditorPlugin's LocalSite.cfg will selectively enable any special requirements for the HTML to be consumed by the editor.

The +formfield and ;key=value parts allow the user to make their customisations by overriding from base configurations defined in LocalSite.cfg hashes.

They should be able to re-use their customisations by setting variables.

-- PaulHarvey - 30 Dec 2009

Changed textarea Type column to use '+' instead of ',content=' to delimit the modifiers, keeping it consistent with the way we do select+multi+etc

-- PaulHarvey - 03 Jan 2010
I Attachment Action Size Date Who Comment
irc-logs.txttxt irc-logs.txt manage 18 K 14 Jul 2009 - 08:47 MichaelDaum  
wysiwyg-profile-overview.pngpng wysiwyg-profile-overview.png manage 11 K 14 Jul 2009 - 08:49 MichaelDaum drupal's client-side editors for input formats
Topic revision: r6 - 03 Feb 2010, PaulHarvey
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy