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
buttonSwitch 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 andmarkdown
field will store Markdown as it was in the old editordata
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 toProblemBlock
. Thewysiwyg
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 havemarkdown
/wysiwyg
value options. Whether to open Advanced editor determining logic will be the same andeditor_mode
will be used for WYSIWYG/Markdown switchingeditor_mode
would havemarkdown
/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 thedata
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 widgetthe Advanced editor will have
Switch to Markdown
andSwitch 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 addmarkdown
field toapiMethods.normalizeContent
if we choose to add a new
editor_mode
field toProblemBlock
, we need to includeeditor_mode
into the problem metadata inapiMethods.normalizeContent
Consequences
Extend
ProblemBlock
fields set if it was decided during the solution option choosing.Refactor and extend the legacy Markdown to OLX converter and move it to
frontend-lib-content-components
.Create OLX to Markdown converter.
Implement Markdown editor widget.
Extend problem editors switching. Add the corresponding buttons and their listeners to editors. Show an alert widget if data loss is possible.
Extend editors content saving by including additional fields into the data sent to backend. Show an alert widget if data loss is possible.