WYSIWYG HTML editor in the browser. Part 2
- Transfer
This is the second part of the translation of the article about designMode and contentEditable properties, their behavior and features.
The article discusses the basic principles and problems of unification of editing features in modern browsers. Topics covered in the article:
WYSIWYG HTML editor in the browser. Part 1 is here.
Browsers support many editing commands. The HTML generated by these commands is not standardized and differs from browser to browser. For example, in IE, “Bold” will generate code:
The code, at least in IE, is somewhat old-fashioned. Many commands use the awful font tag:
The generated markup is not valid XHTML and, as a rule, even valid HTML code.
Opera generates code similar to IE (no, not completely) using the font tag and so on.
Safari generates formatting using spans and inline CSS. The advantage of the Safari approach is that it is at least valid HTML 4.01 Strict.
Mozilla supports 2 modes of operation - it either generates presentation tags like IE / Opera or stylizes containers like Safari.
If you are sure that you need valid HTML code, then you should clean the server-generated code from the editor to get valid (X) HTML from this mess. (Well, you should do this anyway to avoid XSS attacks).
Many commands are available through hotkeys, for example Ctrl / Cmd + B for bold, Ctrl / Cmd + Z to undo the last action, etc. But these combinations may vary depending on the location of the browser.
Assigned keyboard shortcuts cannot be changed, but they can be rewritten using a keyboard event capturing script.
You might want to make a control panel to allow the user to use editing commands. This can be done using the editor API. This API is not like the usual DOM API, in fact it is a script adaptation of the IOleCommandTarget interface, which is the COM interface used by Microsoft to synchronize the control panel and edit the document.
The API is located in the document object and consists of the execCommand method and several methods with the query prefix that returns information about the command.
All methods accept the command ID as the first argument, this is a string containing the name of the command. Actually, the methods:
Executes a command in relation to the current selection. Some commands switch between states depending on the context. For example, if you apply the “Bold” command to a selection that already has a bold style, the selection will be displayed in normal style. Some commands have arguments, for example forecolor requires a color code as an argument.
Some commands invoke modal dialogs — for example, the link command invokes a dialog that prompts you to enter a URL. Dialogs cannot be changed, but it is possible to replace them. For instance:
command: String; team name.
useDialog: Boolean type; Whether to show the built-in dialog (Not all commands can call dialogs).
value: The value accepted by the command. Not all commands accept values; If it invokes a dialogue, then the value is taken from it.
result: true if the command is executed, false if canceled by the user (closing the dialog) or the command cannot be executed.
If there is no selection (only the cursor), text formatting commands are applied differently, depending on the browser. If the cursor is inside a word, IE will apply formatting to the word; other browsers will apply it to the next character, which will be typed if the cursor is not moved backward.
It makes sense to use Query commands to determine the state of buttons on the control panel depending on the current selection and cursor position.
Determines whether a command can be applied to the current selection. For example, "unlink" can be applied only if the cursor is inside the link. If the selection contains an area inaccessible for editing, then no commands will be executed.
Indicates whether the command was applied to the selection, that is, if the selection is bold, then QueryCommandState will return true for the bold command.
Returns the value of some command to highlight. The value corresponds to that which was set when using execCommand, that is, for example, for ForeColor it will be a color code (as a string) for the current selection.
The format will be different in different browsers. For example, ForeColor returns a hexadecimal value in IE (such as # ff0000), while others will return an RGB expression such as Rgb (255,0,0).
Some values vary depending on the localization of the browser, for example, the value for FormatBlock in IE will return the name for the paragraph in the localization language of the browser interface.
Commands for which there are no values, such as bold, will simply return false. (The API contains two additional methods, queryCommandSupported and queryCommandIndeterminate, but they are too buggy to use them at least somehow.)
Built-in commands are useful, but it is not possible to change their behavior or add a custom implementation. Using the Range and Selection API you can use arbitrary HTML transformations that you can use to implement custom commands.
The problem is that any transformations affecting the DOM destroy the undo stack, which is used to implement UnDo / ReDo commands. This is not too good, but may be an acceptable price for non-standard teams.
Range / selection APIs have two main classes:
Range - a continuous range of document characters. A range can overlap the boundaries of elements. The range has a start and end point. If the start point coincides with the end point, then the range is called degenerate.
Selection - represents the current user selection in the document. The selection contains one highlighted range. If the selection range is degenerate, then it is displayed as a cursor. (Ranges and selections can be used outside the elements in edit mode. You can create a selection in a read-only document. However, such a selection cannot be degenerate, because the cursor only appears when the element is in edit mode.)
These principles are identical. in all browsers, but the APIs themselves differ in implementation in IE and all other browsers. IE uses its own proprietary solution for the range m selection API, other browsers use the W3C DOM Range API in combination with the non-standardized selection API.
The main difference is that in IE, the contents of the range are available as a string with HTML markup. In the W3C DOM Range API, the contents of a range are available as a tree of DOM nodes.
To show the different approaches, the following is a command that applies the "code" tag to the current selection.
In IE (editWindow is a link to frame in designMode):
IE supports control highlighting, which is different from regular range highlighting. A control is highlighted when you click on an object, such as an image, form control, or table frame.
In IE, it is possible to select more than one element at the same time using the combination ctrl + click. Other browsers do not support the concept of highlighting controls; in other browsers, highlighting is always a text range.
This article discusses the basic principles of editing data in a browser. Part two of the article shows many examples of the application of the above APIs.
From a translator: if this is interesting not only to me, then I will translate the second article .
And a couple of links to additional materials:
The article discusses the basic principles and problems of unification of editing features in modern browsers. Topics covered in the article:
- Various editing mode enable methods
- Editing commands
- HTML generated during editing
- DOM interaction
WYSIWYG HTML editor in the browser. Part 1 is here.
Editing commands
Browsers support many editing commands. The HTML generated by these commands is not standardized and differs from browser to browser. For example, in IE, “Bold” will generate code:
Safari generates:
- Hello!
- hello!
The code, at least in IE, is somewhat old-fashioned. Many commands use the awful font tag:
- 23
The generated markup is not valid XHTML and, as a rule, even valid HTML code.
Opera generates code similar to IE (no, not completely) using the font tag and so on.
Safari generates formatting using spans and inline CSS. The advantage of the Safari approach is that it is at least valid HTML 4.01 Strict.
Mozilla supports 2 modes of operation - it either generates presentation tags like IE / Opera or stylizes containers like Safari.
If you are sure that you need valid HTML code, then you should clean the server-generated code from the editor to get valid (X) HTML from this mess. (Well, you should do this anyway to avoid XSS attacks).
Hotkeys
Many commands are available through hotkeys, for example Ctrl / Cmd + B for bold, Ctrl / Cmd + Z to undo the last action, etc. But these combinations may vary depending on the location of the browser.
Assigned keyboard shortcuts cannot be changed, but they can be rewritten using a keyboard event capturing script.
Editor API
You might want to make a control panel to allow the user to use editing commands. This can be done using the editor API. This API is not like the usual DOM API, in fact it is a script adaptation of the IOleCommandTarget interface, which is the COM interface used by Microsoft to synchronize the control panel and edit the document.
The API is located in the document object and consists of the execCommand method and several methods with the query prefix that returns information about the command.
All methods accept the command ID as the first argument, this is a string containing the name of the command. Actually, the methods:
Execcommand
Executes a command in relation to the current selection. Some commands switch between states depending on the context. For example, if you apply the “Bold” command to a selection that already has a bold style, the selection will be displayed in normal style. Some commands have arguments, for example forecolor requires a color code as an argument.
Some commands invoke modal dialogs — for example, the link command invokes a dialog that prompts you to enter a URL. Dialogs cannot be changed, but it is possible to replace them. For instance:
What is what:
- result = document.execCommand (command, useDialog, value)
command: String; team name.
useDialog: Boolean type; Whether to show the built-in dialog (Not all commands can call dialogs).
value: The value accepted by the command. Not all commands accept values; If it invokes a dialogue, then the value is taken from it.
result: true if the command is executed, false if canceled by the user (closing the dialog) or the command cannot be executed.
If there is no selection (only the cursor), text formatting commands are applied differently, depending on the browser. If the cursor is inside a word, IE will apply formatting to the word; other browsers will apply it to the next character, which will be typed if the cursor is not moved backward.
Querycommands
It makes sense to use Query commands to determine the state of buttons on the control panel depending on the current selection and cursor position.
QueryCommandEnabled
Determines whether a command can be applied to the current selection. For example, "unlink" can be applied only if the cursor is inside the link. If the selection contains an area inaccessible for editing, then no commands will be executed.
QueryCommandState
Indicates whether the command was applied to the selection, that is, if the selection is bold, then QueryCommandState will return true for the bold command.
QueryCommandValue
Returns the value of some command to highlight. The value corresponds to that which was set when using execCommand, that is, for example, for ForeColor it will be a color code (as a string) for the current selection.
The format will be different in different browsers. For example, ForeColor returns a hexadecimal value in IE (such as # ff0000), while others will return an RGB expression such as Rgb (255,0,0).
Some values vary depending on the localization of the browser, for example, the value for FormatBlock in IE will return the name for the paragraph in the localization language of the browser interface.
Commands for which there are no values, such as bold, will simply return false. (The API contains two additional methods, queryCommandSupported and queryCommandIndeterminate, but they are too buggy to use them at least somehow.)
Range and Selection API
Built-in commands are useful, but it is not possible to change their behavior or add a custom implementation. Using the Range and Selection API you can use arbitrary HTML transformations that you can use to implement custom commands.
The problem is that any transformations affecting the DOM destroy the undo stack, which is used to implement UnDo / ReDo commands. This is not too good, but may be an acceptable price for non-standard teams.
Range / selection APIs have two main classes:
Range - a continuous range of document characters. A range can overlap the boundaries of elements. The range has a start and end point. If the start point coincides with the end point, then the range is called degenerate.
Selection - represents the current user selection in the document. The selection contains one highlighted range. If the selection range is degenerate, then it is displayed as a cursor. (Ranges and selections can be used outside the elements in edit mode. You can create a selection in a read-only document. However, such a selection cannot be degenerate, because the cursor only appears when the element is in edit mode.)
These principles are identical. in all browsers, but the APIs themselves differ in implementation in IE and all other browsers. IE uses its own proprietary solution for the range m selection API, other browsers use the W3C DOM Range API in combination with the non-standardized selection API.
The main difference is that in IE, the contents of the range are available as a string with HTML markup. In the W3C DOM Range API, the contents of a range are available as a tree of DOM nodes.
Range example
To show the different approaches, the following is a command that applies the "code" tag to the current selection.
In IE (editWindow is a link to frame in designMode):
In Mozilla:
- var rng = editWindow.document.selection.createRange ();
- rng.pasteHTML ("" + rng.htmlText + "");
- var rng = editWindow.getSelection (). getRangeAt (0);
- rng.surroundContents (document.createElement ("code"));
Highlighting Controls
IE supports control highlighting, which is different from regular range highlighting. A control is highlighted when you click on an object, such as an image, form control, or table frame.
In IE, it is possible to select more than one element at the same time using the combination ctrl + click. Other browsers do not support the concept of highlighting controls; in other browsers, highlighting is always a text range.
conclusions
This article discusses the basic principles of editing data in a browser. Part two of the article shows many examples of the application of the above APIs.
From a translator: if this is interesting not only to me, then I will translate the second article .
And a couple of links to additional materials: