WYSIWYG editing behavior. It allows to edit HTML and/or wiki text in WYSIWYG manner.
The richtext is aimed to be used as:
The richtext uses so called flat DOM that is:
<div>s;<li> is a kind of <p> - can contain only text and spans;<a>) and foreground (<strong>, <em>, etc.) spans;Screenshot of the sample below:
One more screenshot, "show rulers" mode:
Floating image:
that have this behavior applied by default (see master style sheet):
<richtext> ..initial html.. </richtext> - richtext is intrinsically dispaly:block element.
get/set_value methods (htmlayout) and value property (sciter) reflect current editing document and can be either HTML text or wiki (dokuwiki by default) format.
Editor allow images to be inserted from system clipboard so the value may contain image bits as base64 encoded chunks. Exact format will be specified later.
that this behavior knows about:
tools=“css selector” - CSS selector of the element containing tool buttons/elements. See below.content-style=“url” - url of style sheet that that defines list of elements supported by the instance of the editor and their styles.allow-clipboard-images[=yes|no] - allows images to be inserted (pasted) from clipboard. If allowed and document contains pasted images (that have no permanent location) then bodies of such images will be emitted as: <script type="text/base64" id="..."> ... base64 encoded image bits </script>elements inside the
<head> section of the document.Together with the standard set of events (mouse, keyboard, focus) behavior: button generates:
Richtext supports following so called xcall() methods, see dom::element::xcall() function.
xcall(“canUndo”): bool - returns boolean wrapped into json::value, true - if undo is available and false if not;xcall(“doUndo”) - executes undo operation;xcall(“canRedo”): bool - returns true - if redo is available and false if not;xcall(“doRedo”) - executes redo operation;xcall(“canCut”): bool - returns true - if cut is available and false if not;xcall(“doCut”) - executes cut operation - copy selection into the clipboard and deletes selected text;xcall(“canCopy”): bool - returns true - if copy is available and false if not;xcall(“doCopy”) - executes copy operation - copy selection into the clipboard;xcall(“canPaste”): bool - returns true - if paste is available and false if not;xcall(“doPaste”) - executes paste operation - pastes content of the the clipboard;xcall(“canSelectAll”): bool - returns true - if select all[text] is available in current state and false if not;xcall(“doSelectAll”) - selects all text;xcall(“readOnly”): bool - returns true - if editor is in read-only mode;xcall(“readOnly”, bool) - switches readOnly mode on and off;xcall(“showRulers”,bool) - show/hide formatting rulers;xcall(“loadHTML”, html:string) - replaces current content from html string;xcall(“loadHTML”, html:string, base_url:string) - replaces current content from html string, uses base_url for resolution of relative urls;xcall(“saveHTML”) : string - returns current content as html string;xcall(“saveHTML”, baseUrl:string, mode:string ) : string - returns current content as html string; mode here accepts following values:“emit-pasted-images” - emit also bodies of images that was pasted from clipboard;“emit-local-images” - emit bodies of clipboard and images with urls starting from file:;“emit-all-images” - emit bodies of all images used in the document.xcall(“savePlainText”) : string - returns current content as plain text string;xcall(“loadFile”, path:string) - replaces current content from html file given by the path;xcall(“saveFile”, path:string) - saves current content to the file given by the path;xcall(“saveContent”):map - saves current document as an object having following structure: { "html": html-string, "resources": { "url1": { data: bytes | string, // data of the resource content-type: string, // mime type of the resource content-disposition: string, // url where this resource came from id: string // uuid of the resource } ... } }
xcall(“loadContent”, envelope:map) - replaces current content from the envelope object having structure defined above;
xcall(“moveCaretTo”, where:string, keepAnchor:true|false) - moves the caret from current position to where:“next-char” - next character;“prev-char” - previous character;“next-word” - start of next word;“prev-word” - end of previous word;“doc-end” - end of the doc;“doc-start” - start of the doc;“line-end” - end of the line;“line-start” - start of the line;“line-up” - character in the previous line;“line-down” - character in the next line;“page-up” - previous page;“page-down” - next page;
If keepAnchor is true then this function is not changing anchor position of the selection. So this sequence
moveCaretTo(line-end,false); moveCaretTo(line-end,true); will set selection on current line of text.
xcall(“searchNext”,modes:int, word:string) - search next word entry in the text, modes is an integer - ORed combination of these flags:SEARCH_FORWARD = 0x00,SEARCH_BACKWARD = 0x01,SEARCH_WHOLE_WORD = 0x10,SEARCH_MATCH_CASE = 0x20 xcall(“insertHtml”, string) - does insertion of html fragment contained in the string at current caret position;xcall(“appendHtml”, string) - appends the html fragment to the end of the document;xcall(“replaceBy”, text:string) - replaces current selection by the text, if there is no selection then inserts the text at caret position.xcall(“getCurrentObjects”): array - returns array of “tagname.classname” strings - stack of current objects at the caret position;xcall(“getCurrentObjectAttributes”, index:int): map - returns collection of attributes defined on element at index position in stack of current objects;xcall(“setCurrentObjectAttributes”, index:int, attributes: map) - sets attributes of element at index position in stack of current objects;xcall(“getCurrentStyle”): map - returns cumulative collection of CSS properties in effect at current caret position; xcall(“getStyleRules”): array - returns list of CSS rules applied at current position; xcall(“getStyleRule”, index:int): map - returns list of CSS properties of particular rule applied at current position; xcall(“setSpan”,tag:string, attributes: undefined | map) - set span to the selection or caret position. Spans are b,strong, em, a, etc.xcall(“setBlock”, tag:string, attributes: undefined | map) - set block to the selection or to current block element. tag here can accept following values: “p”,”h1”…“h6”, “pre” or two pseudo tags “ol/li” and “ul/li” for list items.xcall(“setFontColor”, color:string | color) - set current color of the text by injecting <font color=…> span;xcall(“setFontName”, fontFamilyName:string) - set current font name by injecting <font family=…> span;xcall(“setFontSize”, fontSize:1..7) - set current font size by injecting <font size=…> span;xcall(“toggleSpan”, tagName:string) - switches on/off bold/italic/underline spans by adding/removing correspondent tags;xcall(“canIndentPlus”): undefined | bool - returns true or false if editor can or cannot apply indentation+. Will return undefined if context does not support indentation (e.g. inside pre). xcall(“doIndentPlus”) - increases indentation;xcall(“canIndentMinus”): undefined | bool - returns true or false if editor can or cannot apply indentation-. Will return undefined if context does not support indentation (e.g. inside pre). xcall(“doIndentMinus”) - decreases indentation;xcall(“setTextAlign”, align:int) - sets text alignment, align here is one of:ALIGN_LEFT = 1,ALIGN_CENTER = 2,ALIGN_RIGHT = 3,ALIGN_JUSTIFY = 4,xcall(“setListUnordered”) - wraps selection into <UL>;xcall(“setListOrdered”) - wraps selection into <OL>;
The richtext allows to do all editing operations by using keyboard shortcuts (see below) but for convenience it also allows to bound tool buttons (a.k.a. toolbar) with internal so called editing registers of the editor. Tools container (e.g. toolbar) may contain elements with command attribute. Such elements reflect state of internal registers and allow to modify them by clicking on them (richtext-tools handles BUTTON_PRESS behavior event). The richtext changes :checked and :disabled attributes of the tool elements so this states can be styled appropriately.
Commands that the richtext knows about so far:
command=richtext:cutcommand=richtext:copycommand=richtext:pastecommand=richtext:undocommand=richtext:redocommand=richtext:strong - either <b> or <strong>, on click <strong> span will be applied.command=richtext:em - either <i> or <em>, on click <em> span will be applied.command=richtext:code - either <code> or <tt>, on click <code> span will be applied. command=richtext:u - <u> element.command=richtext:p - <p>, paragraph command=richtext:h1 command=richtext:h2 command=richtext:h3command=richtext:h4command=richtext:h5command=richtext:h6 - headerscommand=richtext:pre - block of pre-formatted text (plain text block) command=richtext:li-ul - item in unordered listcommand=richtext:li-ol - item in ordered list command=richtext:indent-dec - decrease indentation: either move list item one level up or unquote <blockquote>command=richtext:indent-inc - increase indentation: either move list item one level deep or quote fragment by <blockquote> CTRL-B - apply <strong> span to selection;CTRL-I - apply <em> span to selection;CTRL-U - apply <u> span to selection;ENTER - break paragraph into two;SHIFT-ENTER - insert <br>;DELETE - delete character on the right or remove selection. See also table actions below;BACKSPACE - delete character on the left or remove selection. If selection is a table cell selection then cells will be merged into single cell;DELETE - delete character on the right or remove selection. If selection is a table cell selection then those cells will be removed from the table;CTRL-DELETE - if selection: remove foreground spans (<strong>, <em>, etc.), if no selection - remove word on the right;CTRL-BACKSPACE - if selection: remove background spans (<a>, etc.), if no selection - remove word on the left;CTRL-NUMPAD+ - indent +, either wrap selected paragraphs in <blockquote> or as sub list;CTRL-NUMPAD- - indent -, either unwrap selected paragraphs from <blockquote> or move list items level up;CTRL-NUMPAD. - wrap selected paragraphs to <ul>;CTRL-NUMPAD0 - wrap selected paragraphs to <ol>;CTRL-NUMPAD1 - CTRL-NUMPAD6 - convert selected paragraphs to <H1>-<H6>;CTRL-1 - split cell(s) by rows;CTRL-2 - split cell(s) by columns;CTRL-3 - insert column before current;CTRL-4 - insert column after current;DELETE - delete cells. If whole row(s) or column(s) are selected then thye will be deleted. Otherwise cells will be merged into one and cleared;BACKSPACE - merge cells. Merge selected cells into single cell;
By default <richtext> and <textarea>/<plaintext> are defined as this:
richtext { behavior:richtext; context-menu:url(res:behavior-richtext-menu.htm); ... } texarea, plaintext { behavior:plaintext; context-menu:url(res:behavior-text-menu.htm); ... }
context-menu:url(…) there means that context menu is located at address res:behavior-richtext-menu.htm.
Therefore if you need to provide your own version (e.g. localized) of these menus you can:
res:behavior-richtext-menu.htm ans res:behavior-text-menu.htm or
richtext { behavior:richtext; context-menu:selector( menu#for-richtext); ... }
In this case you will need to declare such <menu id=“for-richtext”> element somewhere in your markup:
<menu .context #for-richtext > <li command="richtext:undo" style="foreground-image:url(res:edit-undo.png)" >Undo<span .accesskey>Ctrl+Z</span></li> <hr/> <li command="richtext:cut" style="foreground-image:url(res:edit-cut.png)" >Cut<span .accesskey>Ctrl+X</span></li> ... </menu>
Here is default content of Richtext Context Menu and Plaintext Context Menu.
Note attribute command in menu items - it is used as command identifier for the behavior. Other portions of the markup can be changed but not command's.
Here is a sample of <richtext> and toolbar integration in HTML:
<div .editor> <widget .toolbar> <widget .tb-button command=richtext:cut title="Cut"><img src="res:edit-cut.png" /></widget> <widget .tb-button command=richtext:copy title="Copy"><img src="res:edit-copy.png" /></widget> <widget .tb-button command=richtext:paste title="Paste"><img src="res:edit-paste.png" /></widget> <hr/> <widget .tb-button command=richtext:undo title="Undo"><img src="res:edit-undo.png" /></widget> <widget .tb-button command=richtext:redo title="Redo"><img src="res:edit-redo.png" /></widget> <hr/> <widget .tb-button command=richtext:strong title="Strong emphasis"><b>B</b></widget> <widget .tb-button command=richtext:em title="Emphasis"><i>I</i></widget> <widget .tb-button command=richtext:code title="Code"><tt style="font-size:9px">code</tt></widget> <hr/> <widget .tb-button command=richtext:p title="Paragraph"><b>P</b></widget> <widget .tb-button.h command=richtext:h1 title="Header 1">H<b>1</b></widget> <widget .tb-button.h command=richtext:h2 title="Header 2">H<b>2</b></widget> <widget .tb-button.h command=richtext:h3 title="Header 3">H<b>3</b></widget> <widget .tb-button.h command=richtext:h4 title="Header 4">H<b>4</b></widget> <hr/> <widget .tb-button command=richtext:pre title="Block of plain text, pre"><tt>pre</tt></b></widget> <hr/> <widget .tb-button command=richtext:li-ul title="List item, unordered list">ul</widget> <widget .tb-button command=richtext:li-ol title="List item, unordered list">ol</widget> <widget .tb-button command=richtext:indent-dec title="Increase level of list item or quote">i-</widget> <widget .tb-button command=richtext:indent-inc title="Decrease level of list item or un-quote">i+</widget> </widget> <richtext toolbar="widget.toolbar" > Hello <i>richtext</i> world! </richtext> </div>
[tbc]