/
Implementation Approaches

Implementation Approaches

Context

New WYSIWYG-based problem editors are introduced to simplify course creators' experience of complicated makrup creation for OLX entities. They allow to format text quickly, to add media files, links etc without needing to know HTML. It’s located in frontend-lib-content-components library.

But there are situations when we need to quickly copy and paste the entire problem content. As in the new problem editor different OLX entities are located in separate input fields (question, explanation, answers, hints etc.), all of them are needed to be manipulated separately. When we need to process a lot of problems, it becomes time-consuming.

The old Mardown editor was convenient for it and a significant amount of course creators had a positive experience working with it. So, it’s proposed to implement the Mardown editor inside the new React problem editor and allow to switch to it as an alternative to WYSIWYG-based editor.

Decision

To display the Markdown mode in the new problem editor, we will need to create a new widget for it in ProblemEditor inside frontend-lib-content-components. It will contain:

  • the textarea for Markdown content editing

  • hints how to use the editor sidebar (like in the old editor, but we need to add a description of how to add hints and feedbacks)

  • buttons that insert Markdown items (heading, explanation etc.) like in the old editor

  • the right settings panel with the same items as the Advanced editor but also contains Switch to Advanced editor button

  • Switch to WYSIWYG button

For the Markdown state value storing, it is needed to add markdown field to the problem Redux reducer. Also, we need to create the corresponding Redux selector. This state is populated during the editor loading, switching and data collection before the block saving.

We need to process the editor saving and editor switching. First, let’s examine how the problem xblock setup data is persisted.

ProblemBlock class has data field that contains the block OLX and markdown field with the corresponding Markdown data. markdown field value is used only during editing, data field value is also used during block rendering.

When we use the old editor, after changes saving in Markdown mode we get markdown field content from the input textarea, convert it to OLX using the converter on the frontend side to get the new data field value. Xblock fields including the considered markdown and data are sent to the <CMS_BASE_URL>/xblock/<block_id> endpoint. After switching to Advanced editor and saving changes, the actual block setup is stored only in the data field, markdown value becomes None. After the next editor opening, frontend detects markdown nullish value and makes a decision to open Advanced editor. It’s impossible to switch back to Markdown mode.

When we use a new editor, markdown is not processed at all. After editor saving in WYSIWYG mode, the OLX is composed from the parsed WYSIWYG editors and Redux store state, in Advanced mode OLX is just a content of Advanced editor. And such OLX is sent in data field to <CMS_BASE_URL>/xblock/<block_id> endpoint. To determine the editor type to open (Single select problem, Dropdown problem, Advanced problem etc.), the OLX problem child tags in data field fetched from <CMS_BASE_URL>/xblock/<block_id> endpoint are analized. It means that for OLX with single <multiplechoiceresponse> tag the Single select problem editor is opened, for OLX with single optionresponse tag the Dropdown problem editor is opened etc. When there are advanced types that don’t have their own WYSIWYG editors or several problem types are located in OLX, it is decided to open Advanced editor. This logic is described in OLXParser.getProblemType method inside src/editors/containers/ProblemEditor/data/OLXParser.js.

The block setup data can be stored in the ProblemBlock in a couple of ways during implementing the Markdown mode:

  • data field will store OLX and markdown field will store Markdown as it was in the old editor

  • data field will store OLX and Markdown will be gotten by converting OLX data

Also, we need to detect in what mode to open editor (WYSIWYG/Markdown/Advanced editor). We have several options:

  • leave the editor choosing logic as it is. WYSIWYG editor will be the default one and the Markdown editor will be the fallback one (WYSIWYG editor will alway be opend initially if Advanced editor is not chosen and we can further switch to the Markdown editor from it)

  • add a new editor_mode field to ProblemBlock. The wysiwyg value option is proposed to be default. This value will be sent to backend during block saving and will be used for the editor type to open determining. Here we also have several options:

    • editor_mode would have markdown/ wysiwyg value options. Whether to open Advanced editor determining logic will be the same and editor_mode will be used for WYSIWYG/Markdown switching

    • editor_mode would have markdown/ wysiwyg/ advanced value options. It will allow us to switch back to WYSIWYG/Markdown from advanced editor, but such switching can cause data loss because the advanced editor supports a wide variety of OLX tags that other editors don’t support. So, during the switching the warning about data loss will be shown and OLX will be modified by removing unsupported by other editors tags and attributes before sending in the data field to backend.

As was mentioned, during WYSIWYG editor saving its inputs content is used to create OLX. So, to switch from WYSIWYG and Advanced editor to Markdown mode we will need to have OLX to Markdown converter that will be used to build the corresponding Markdown content to display it in the switched editor input. There is no such converter either on the backend or on the frontend side for now, so it must be implemented from scratch.

When we need to switch from Markdown to WYSIWYG mode, we need to use Markdown to OLX converter. This converter will also be needed if we decide not to store Markdown in markdown field on the backend side but to build it from OLX during every editor loading. It already exists in edx-platform (xmodule/js/src/problem/edit.js MarkdownEditingDescriptor.markdownToXml) but it should be refactored, extended and moved into frontend-lib-content-components. There is a problem during switching from Markdown to WYSIWYG mode: Markdown can contain several problem types definitions (we can have Single select and Dropdown problem, two Single selects in one Markdown value). Here we need to choose:

  • discard the second and further input types, questions and explanations during Markdown to WYSIWYG switching but persist them during Markdown editor saving

  • discard the second and further input types, questions and explanations during both Markdown to WYSIWYG switching and Markdown editor saving

When data loss is possible during editors switching, the created for this case alert widget is shown.

The editors switching UI will be the next:

  • the WYSIWYG editor will contain a button Switch to Markdown

  • the Markdown editor will have a button Switch to WYSIWYG

  • the WYSIWYG and Markdown editors will have Switch to Advanced editor button in the settings widget

  • the Advanced editor will have Switch to Markdown and Switch to WYSIWYG buttons if the option of accepting data loss is chosen. Otherwise, such buttons won’t be presented

When we save Markdown editor, OLX is built by Markdown to OLX converter. When we save OLX and Advanced editor editor, Markdown is built by OLX to Markdown converter if we choose to persist Markdown in markdown block field. If data loss is possible, the alert widget is shown. The data to send to backend is defined in src/editors/data/services/cms/api.js apiMethods.normalizeContent, so this method altering should be considered during problem fields set to save changing. The block saving depends on the chosen options above. There are such options:

  • if we choose to persist Markdown in markdown block field, we need to add markdown field to apiMethods.normalizeContent

  • if we choose to add a new editor_mode field to ProblemBlock, we need to include editor_mode into the problem metadata in apiMethods.normalizeContent

Consequences

  1. Extend ProblemBlock fields set if it was decided during the solution option choosing.

  2. Refactor and extend the legacy Markdown to OLX converter and move it to frontend-lib-content-components.

  3. Create OLX to Markdown converter.

  4. Extend the problem editor Redux state and selectors.

  5. Implement Markdown editor widget.

  6. Extend problem editors switching. Add the corresponding buttons and their listeners to editors. Show an alert widget if data loss is possible.

  7. Extend editors content saving by including additional fields into the data sent to backend. Show an alert widget if data loss is possible.