- From: Ojan Vafai <ojan@chromium.org>
- Date: Mon, 21 Dec 2009 10:21:44 -0800
Dealing with inconsistencies in browser behavior during typing is one of the hardest parts of writing a sane web-based rich-text editor. We have researched what a variety of text editors (Word, Powerpoint, Wordpad, TextEdit) and browsers using contentEditable/DesignMode currently do when you press different keys on the keyboard, in a number of rich text situations, with a variety of text selections. From this data, we attempt to identify recommendations that are OS-agnostic for editing behaviors inside a contentEditable element. Since we've used a bunch of tables and formatting, we've attached the doc as an HTML file in addition to inline. Ojan Julie Parent, Ojan Vafai, Alex Russel, Eric Seidel About this document We have researched what a variety of text editors (Word, Powerpoint, Wordpad, TextEdit) and browsers using contentEditable/DesignMode currently do when you press different keys on the keyboard, in a number of rich text situations, with a variety of text selections. From this data, we have identified a set of common behaviors, listed below in the terminology section. Finally, we have formed recommendations for default behaviors in these circumstances and, when necessary, added additional execCommands or specification details to existing execCommands.The execCommands match the behavior of the user-initiated action in order to give developers control over these behaviors when the defaults are incorrect for a specific use case. We tried to avoid defining any behaviors that are OS-specific and to make the descriptions as clear as possible, but there's a lot of detail here that could use the scrutiny of more eyes. We also tried to make the text as clear as possible, but are not spec writers and don't intend this to be the actual text used in the spec. Please comment on any text that doesn't make sense. 1. Terminology <#Terminology> 2. Collapsed selections (carets) <#Collapsed_selections_carets_> 1. Text insertion <#Text_insertion__15327099990099669> 1. Alphanumerics <#Alphanumerics_5657284623011947> 2. Paste <#Paste_6935868207365274> 2. Text deletion <#Text_deletion__7460317360237241> 1. Backspace <#Backspace_76161671243608> 2. Forward Delete <#Forward_Delete> 3. Cut <#Cut> 3. Tab Key <#Tab_Key_> 4. Enter <#Enter__35112586710602045> 3. Non collapsed selections <#Non_collapsed_selections> 1. Text insertion <#Text_insertion_> 1. Alphanumerics <#Alphanumerics> 2. Paste <#Paste> 2. Text deletion <#Text_deletion_> 1. Backspace <#Backspace> 2. Delete <#Delete> 3. Tab <#Tab_> 4. Enter <#Enter_> 4. Appendix <#Appendix_8992731962352991_0404_9370131157338619> Terminology *Typeable Position:* A normalized position (node, offset), for which inserting a character produces valid html. Arrow keys move by typeable positions. Basically, anywhere you can put a character and it isn't an HTML5 error. *Typing style:* Internal state of formatting that should be applied when text is inserted. The typing style is automatically emptied when the user modifies the selection (e.g. moves the caret). This is used for things like execCommand('bold') on a collapsed selection. *Caret:* Collapsed selection. *Block context:* The type of block to use when adding a block during a split. *Legend: Common behaviors* See Appendix <#Appendix> for details on differences in the current implementations of these behaviors. Short name DescriptionUndo: add entryAdds a new entry to the undo stackUndo: combine with text Treat like any other text insertion - UA can group together to form a single entry.focus nextContents: nop. Undo: nop. Selection: Focus moved to next tabable item.focus prevLike focus next, but moves to the previous item in tab order focus next cellContents: nop. undo: nop. Selection: Focus is moved to the next cell (either next cell in a row, or to the first cell in the next row) Cursor is at start of next cell or cell contents are selected. See below for current details select(item)Cause the user visible selection to fully select the item.indent paragraph(s) Indent each paragraph individually. Undo: add entry Selection: unchangedoutdent pragraph(s)If indented, outdent one level. undo: add entry If not indented, nop. Selection: unchangedindent liContents: See table below for current implementation differences. Undo: add entry. Selection: Cursor is unchanged visibly. indent listContents: Html is no longer list based (this is word only). Undo: add entry Selection: Cursor is unchanged visbily.insert tab charContents: Inserts tab character at typeable caret location. Undo: combined with text. Selection: Caret is after tab char.insert spacesContents: See table below for different implementations of inserting spaces. Undo: combine with text. Selection: Cursor is after the spaces and any tags they added.insert table rowContents: Adds a new table row Undo: add entry Selection: Cursor in first cell of new row break outbreaks out of the current node and adds a new node of the type of the new context it's in. Note: Anytime a node is split, all copyable properties end up on both nodes (as an example, ID is not copyable since that would leave you with an invalid DOM).split splits the current block node at the cursorsplit contentssplit contents into two nodes of the block context and make them the child of the parent brinserts a brbreak out and wrap in blockbreaks out of the current node and wraps both new nodes in a block of the type of the new block context split wrap in blocksplit inlines and wrap in two elements of the block context type replace selectedText selected is removed from the document and replaced with new content. Cursor is collapsed at end of the newly inserted text. Undo: Either combine with text or add entry. UA specific.remove(item)Removes the item from the dom. If the item removed would create an empty block tag, the UA should insert a non-breaking space that the user is unable to put the cursor after and is automatically deleted when the user types (this is roughly IE's behavior). If the item removed would create an empty inline styling tag, the tag and it's formatting should be removed and entered into the typing style. For backspace: Cursor moves to typeable position before the removed item. For delete: Cursor moves to typeable poistion after the removed item.maintain stylingRemoves an inline styling tag from the dom and adds it to the typing style. Aka, given "a<b>foo</b>c", if you start at the end of "foo", and backspace 3 times, you are left with "ac", but if you insert a "b" before changing the selection, you'd get "a<b>b</b>c". mergeMerge 2 blocks into 1. The second block (in document order) is merged into the first. The type and styling of the second block are lost. Aka, given <p>paragraph</p><h1>header</h1>, with the cursor at the start of the H1 and pressing backspace results in <p>paragraphheader</p> and the <h1> is lost, and the cursor remains at the merge point, between "paragraph" and "header". For delete, if the cursor is at the end of the P, the result is the same as backspace at the start of the H1. nopNothing happens to contents, selection, undo stack, etc. delete(rangeContents) Delete all fully selected nodes and all selected characters, but preserve partially selected nodes. Cursor is collapsed after this action.no merge Adjacent blocks are not merged into one block.merge + wrap stylingMerge adjacent blocks, but wrap the second blocks's contents in a styled span that keeps the original styling and cancels out any styling from the first block. cursor: end of startCursor is located after the last character of the start node, but before the end node. That is, if you type, the inserted character will go into the start node. Note: in all contexts, selection direction does not effect this.cursor: collapse(toStart)Collapse the cursor to the start/end. backwards mergeMerge 2 blocks, but rather than merging second block into first block, merge first block into second block.no content change Text contents do not change. Not a total nop since selection can still change. *Key to the tables below* Green: Current behavior matches the recommended behavior. Red: Current behavior does not match the recommended behavior. Orange: Current behavior nearly matches the recommended behavior. Difference is usually a platform specific subtlety. N/A: Behavior does not apply in this context. ------------------------------ Collapsed selections (carets) Text insertion1 <#FOOTNOTE-1> Alphanumerics *Recomendation for HTML 5*: 1. Normalize the current caret to a typeable Position. 2. Insert the character at the typeable position. 3. Adjust the typeable position to be collapsed after the inserted text. *execCommand('insertText', false, singleCharacter)* should be equivalent to pressing the alphanumeric key on the keyboard. Currently supported by WebKit. Notes: Current and recommended behaviors match here, and there are no known differences been UA's, other than with undo group formation, white-space rebalancing, and where typeable positions are. Specifically: - Undo: combine with text (UA specific when to start new groups). - Need to deal with white-space rebalancing to enable multiple spaces. - Given a dom with multiple dom positions for the same visible positions, UA's currently vary in which position is considered the typeable position. Example: given foo<b>bar</b>baz: - With the cursor between bar and baz (in the way a user can create, not programatically), insertions happen: - IE: if you click into the location, text goes into the B tag. If you use arrow keys, it goes outside. - FF: If you click in, outside. If you arrow from outside the tag, outside. If you arrow from inside the tag, inside. - Chrome: always in. - Word: always in. - PPT: always in. - With the cursor between foo and bar, insertions happen: - IE: Click, outside B. Arrows, inside. - FF: Click, outside. Arrow from inside the tag, inside. Arrow from outside the tag, outside. - Chrome: Always out. - Word: always out. - PPT: always out. Paste *Recomendation for HTML 5*: 1. Normalize the current caret to a typeable Position. 2. Begin a new undo group 3. Insert the html, performing cleanups to create valid html. 4. End undo group 5. Adjust the typeable position to be collapsed after the inserted text. *execCommand('paste', false, null) *should be equivalent to paste from other sources (edit menu, right click, control + v). Notes: - Current and recommended behaviors match here, except for cleanups required to create valid html on insert. - What if the html to insert would be invalid at that given location? Currently, WebKit and IE do no (?) cleanup, and FF does some cleanup to create valid html. - Example: Pasting a block into an inline: HTML is "<b>fo|o</b>", where | is the cursor. Paste "<h1>bar</h1>". - WebKit: <b>fo<span class="Apple-style-span" style="font-weight: normal; "><h1>bar</h1></span>o</b> (INVALID) - IE 7: <b>fo<h1>bar</h1>o</b> (INVALID) - FF 3: <b>fo</b><h1>bar</h1><b>o</b> (VALID) Text deletion2 <#FOOTNOTE-2> Notes: - Undo behavior for deletions matches insertions, that is, multiple insertions|deletions can combine into a single entry. - In PPT, FF, insertions and deletions do not share an undo group, in Word, IE, Chrome they do. Backspace *Recommendation for HTML 5*: If cursor at the start of a block, merge with previous block. Otherwise, remove previous item. The table below shows how closely current editors match this recommendation. *execCommand('delete', false, null) *should be equivalent to backspace. Current Default Behaviors and Recommendations: Context Previous item is:PPTWordIEFFChromeTextedit Recomendationtextremove(char) remove(char)remove(char)remove(char) remove(char)remove(char)remove(char)beginning of P/H/other blocks mergemergemergemergemergemergemerge imageN/A - PPT doesn't allow images in textselect(image) double backspace: remove(image)remove(image) remove(image)remove(image) remove(image)remove(image)link unlinksunlinksunlinksremove(char), subsequent insert goes inside link remove(char), subsequent insert goes out of linkremove(char),subsequent insert goes inside link remove(char), subsequent insert goes into link (if it still exists) [Informal user study<http://docs.google.com/a/google.com/Doc?docid=0ARN9zHKBPzXFY2c5N2J0dnhfOGhxa2N4emdj&hl=en>: If the link text and href match, and were auto-linked to begin with, then this should also unlink.] tableN/A - PPT doesn't allow tables in textnop remove(table) remove(last char in last table cell)merge into last table cellmerge into last table cellselect(table) [Informal user study<http://docs.google.com/a/google.com/Doc?docid=0ARN9zHKBPzXFY2c5N2J0dnhfOGhxa2N4emdj&hl=en>: Many users concerned here about an entire table just being deleted by a single backspace action] single char of styled textremove(char), maintain stylingremove(char), maintain styling remove(char), maintain stylingremove(char), maintain stylingremove(char), maintain stylingremove(char), maintain stylingremove(char), maintain styling table cellremove(char) cannot step out of cellremove(char) cannot step out of cell remove(char) cannot step out of cellremove(char) cannot step out of cellif at start of cell, move focus to previous cell (if there is one) or move out of table if in first cell if in first cell of empty row - delete row Normal: remove(char) remove(char) cannot step out of cellremove(char) cannot step out of cell list - one char in a liremove(char) li turns into ghost bullet, that will be a bullet if you type into it again but doesn't render as a bullet backspace in a ghost bullet will remove the bulletremove(char)remove(char) remove(char)remove(char)remove(char) remove(char)list - before first char remove(li)remove(li) remove(li) + break outmergemergeremove(li) + break out remove(li) Note: Second backspace performs the merge.listmerge into last limerge into last li merge into list, but not into an limerge into last limerge into last limerge into last limerge into last li list - empty lionly happens as ghost list, remove(li)remove(li)remove(li) + break out mergemergeremove(li) + break outremove(li) Forward Delete *Recomendation for HTML 5*: A forward delete before an item should be equivalent to a backspace after the item. The table below shows how closely editors match this recommendation. If a row is not included in the table below, then the behavior matches the backspace behavior. For individual cells, (m) = matches the backspace behavior. *execCommand('ForwardDelete')* should be equivalent to pressing forward delete key (implemented in Webkit). Current Default Behaviors and Recommendations: Context Next item is:PPTWordIEFFChrome TexteditRecomendationlinkremove(char) subsequent insert out of link select(link) double delete: remove(link)remove(char) subsequent insert out of linkremove(char) subsequent insert into link (m)remove(char) subsequent insert out of link (m)remove(char) subsequent insert out of link (m)remove(char). Subsequent typing into link (if it still exists) If link text matches href and auto-linked, also unlink. (m)tableN/A (m) merge previous content into first table cellremove(table) (m)delete first char in first table cell (m) select(table) double delete: remove(table)merge first cell contents into previous content. Table remains with no first cell. select(table) (m)single char of styled textremove(char)remove(char) remove(char) remove(char) maintain style (m)remove(char) maintain style (m)remove(char) maintain style (m)remove(char) maintain style (m)table cellremove(char) cannot step out of cell (m)remove(char) cannot step out of cell (m)remove(char) cannot step out of cell (m)remove(char) cannot step out of cell (m)Normal: remove(char) (m) end of cell: nop, unless proceeding empty row, remove(row) Normal: remove(char) end of cell: deletes cell + merges contents from that cell into next cell. if last cell, merges content after table into last table cellremove(char) cannot step out of cell (m) list - one char in a lienters ghost bullet mode Unlike backspace, further deletes won't remove the ghost remove(char) (m)remove(char) (m)remove(char) (m)remove(char) (m)remove(char) (m) remove(char) (m)list - after last char in a limergemerge move cursor to start of next li, if there is one, else, mergemerge (m)merge (m)move next li and its contents onto this line, so there are two bullets on one line mergelistmergemergedelete list, leave contents of lis intact, just not in lis mergemergemove first li and its content onto the line with previous content, so there is a bullet halfway through the line mergelist - empty lionly happens as ghost list, remove(li) (m)remove(li) (m)leave li alone, move cursor down to next li, if there is one, else merge into listmerge (m) merge (m)move next li and its contents onto this line.remove(li) (m) Cut For a collapsed selection, this is a noop, it does not modify the undo stack.3 <#FOOTNOTE-3> Tab Key4 <#FOOTNOTE-4> Note: FF 3, IE 7, Chrome 1 always perform focus next for tab, no matter what context. They have been eliminated from the tables to avoid clutter. General undo philosophy 1. If the tab action does not change contents, the undo stack is not modified. 2. If the tab action causes standard text content changes (inserting spaces, spans with spaces, tab character), then the tab action is added to the undo stack just like any other text insertion and can be combined with other text insertion into a single undo entry as the UA sees fit. 3. If the tab action changes contents, but the contents are more structural change (add table row, indent list item), then this action is added as a single entry to the undo stack. *Recomendation for HTML 5:* This is largely context-specific, so recomendations are provided in the far right column of the table below. *execCommand('indent')* should be equivalent to tab when listed in the table as "indent li".* execCommand('insertText', false, " ") or execCommand('insertText', false, "\t")*should be equivalent to tab when listed in the table as "insert tab char/spaces". Current Default Behaviors and Recommendations: ContextPPTWordWord HTML mode FF2 (Linux)Wordpad TextEdit RTF modeTextEdit Mac modeRecommended default behaviorli, with or without text content, cursor at start of li, inside list (not the first li in the list) indent li indent li indent liindent li insert tab char indent li indent liindent li li, with or without text content, cursor at start of li, start of list (first li in list)indent li indent list indent list indent liinsert tab char indent liindent li indent lili, with or without content, cursor inside contentinsert tab char insert tab char insert spaces (8 nbsp + " ")indent liinsert tab char insert tab char insert tab charinsert tab char/spacesli, with content, cursor at end of li insert tab char insert tab char insert spaces (8 nbsp + " ") indent liinsert tab char insert tab char insert tab char insert tab char/spaces table cell - not last cell focus next cell focus next cell focus next cell focus next cell focus next cell focus next cell focus next cellfocus next cell table cell - last cellinsert table rowinsert table rowinsert table rowinsert table rowinsert table row move visibly outside of table if there is a node after table, cursor is there otherwise, cursor is visibly outside of table, but when you type, goes into last table cell move visibly outside of table if there is a node after table, cursor is there otherwise, cursor is visibly outside of table, but when you type, goes into last table cell insert table row PREN/AN/Ainsert spaces (5 nbsp + " ") Insert tab (\t)N/Ainsert tab converts pre to P, insert spacesinsert tab/spaces CODEN/AN/Ainsert spaces (3 nbsp + " ")Insert spaces N/Ainsert tab converts code to P, insert spaces insert tab/spaces normal rich text text (not plaintext area)insert tab char insert tab char Insert spaces (8 nbsp + " ") Insert spaces insert tab char insert tab char Insert spaces insert tab/spaces plaintextareaN/AN/AN/Afocus nextN/A N/AN/Afocus next Enter5 <#FOOTNOTE-5> *Recommendation for HTML 5:* This is largely context-specific, so recomendations are provided in the far right column of the table below. Undo behaves the same as regular text insertion. (shift|option)+enter: Always inserts a br. *execCommand('SplitBlock', false, blockTagName):* Performs the split command. Walks up the tree to find the first parent block and splits all the nodes from the cursor to that block maintaining all attributes on the split nodes, including inline styling. If one of the nodes being split is an anchor tag, the anchor should not be included in the second half. Stops at the first table-cell or contentEditable ancestor. If there is no parent block between the caret and the first table-cell/contentEditable ancestor, then it wraps the inline contents before and after the selection in an element of type blockTagName. We stop at the first table-cell ancestor because splitting it does not actually perform the user-expected behavior of adding a new block. If any nodes that are split have an ID, then the ID is not added to the second node after the split. In the table below, this command is listed below as "split", "split contents", "split wrap in block", and "break out and wrap block". *execCommand('SplitOutOfBlock', false, blockTagName):* Performs a split command and changes the type of the second block to that of blockTagName. In both commands above, blockTagName defaults to 'DIV'. This matches the WebKit behavior as opposed to the IE behavior of defaulting to 'P'. DIV makes more sense to users as it matches other word processor behavior of not having default margins. Also, it is semantically more accurate as the UA does not know what the user intends to put inside the element. In the table below, this command maps to "break out". *execCommand('InsertBreak', false, null):* Inserts a BR element. Current Default Behaviors and Recommendations ContextPPT 2008 Mac Word 2008 Mac Doc mode Word 2008 Mac HTML modeIE 7 FF 3 - Win ChromeWordpad textedit Mac RTF modetextedit Mac HTML mode Recommended default behavior end of headern/a break out break out break out break out and insert two brsbreak outn/a n/asplit and add a bunch of stylingbreak out beginning/middle of headern/a splitsplitsplit splitsplitn/a n/asplit and add a bunch of stylingsplit paragraphssplit splitsplitsplitsplit splitsplitsplit splitsplittable cell split contentssplit contents split contents split contents brbr splitsplit contentssplit contents split contentsdiv n/an/asplit contents splitbrsplit n/an/aturn everything into p with styling splitli splitsplit splitsplit splitsplitsplit splitsplitsplit empty li split with placeholder list item break out (see footnote) break out (see footnote)break out break outbreak outbreak out and add two line breaks break out break outbreak out empty li in nested listsplit with placeholder list item break out break out break out break outbreak outn/a break out break outbreak out inlinesmaintainedmaintained spilt wrap in blocksplit wrap in block brbrmaintained maintainedmaintained split wrap in block linksplit open linkopen link break out and wrap in block brbrn/a splitsplitbreak out and wrap block blockquoten/an/a split contentssplit contents brsplitn/an/a turn everything into p with styling split pren/asplit splitsplitbr splitn/an/a turn everything into p with styling br ------------------------------ Non collapsed selectionsText insertion6 <#FOOTNOTE-6> Notes: Undo behavior is the same as collapsed case. Alphanumerics *Recomendation for HTML 5*: Equivalent to backspace + insert (execCommand('delete') + execCommand('insertText')) on collapsed selection. Paste *Recomendation for HTML 5*: Equivalent to backspace + paste (execCommand('delete') + execCommand('insertHTML')) on collapsed selection. Text deletion7 <#FOOTNOTE-7> Backspace *Recomendation for HTML 5: * Always delete the contents of the selected range. Unless a table cell is one of the endpoints, merge into the previous element, but preserve style from the second. *execCommand('delete')* with a range selected should be equivalent to backspace with the same range selected. Current Default Behaviors and Recommendations Start nodeEnd nodePPT WordIEFFChromeTextEdit RecommendationText Text delete(rangeContents)delete(rangeContents)delete(rangeContents) delete(rangeContents)delete(rangeContents)delete(rangeContents) delete(rangeContents)inlineinline delete(rangeContents) cursor: end of startdelete(rangeContents) cursor: end of startdelete(rangeContents) cursor: end of startdelete(rangeContents) cursor: end of startdelete(rangeContents) cursor: end of start delete(rangeContents) cursor: end of startdelete(rangeContents) cursor: end of start DEFAULT BACKSPACE inline/block/header/li (any combo that isn't inline to inline)DEFAULT BACKSPACE inline/block/header/li (any combo that isn't inline to inline)delete(rangeContents) merge + preserve styling cursor: end of start delete(rangeContents) no merge cursor: end of start Note: Word 2003 delete(rangeContents) + backwards merge delete(rangeContents) merge + preserve styling cursor: end of start delete(rangeContents) no merge cursor: end of start delete(rangeContents) merge + preserve styling cursor: end of start delete(rangeContents) merge + preserve styling cursor: end of startdelete(rangeContents) merge + preserve style cursor: end of start inline/blocktable cellN/A delete(rangeContent) backwards merge cursor: end of startno content change cursor: collapse(true) DEFAULT BACKSPACE delete(rangeContents) no merge cursor: end of startdelete(rangeContents) no merge cursor: start of enddelete(rangeContents) no merge cursor: end of start table cellinline/blockN/A delete(rangeContents) no merge cursor: start of end no content change cursor: collapse(true)DEFAULT BACKSPACE DEFAULT BACKSPACE delete(rangeContents) no merge cursor: start of end, but once you type, contents jump back up into table cell. delete(rangeContents) no merge cursor: end of starttable cell table celldelete cell contents cursor: collapse(true)UI prompt - delete entire row|column, shift cells up|left (unless table cells are in different tables, then does delete(rangeContents) + merge)no content change cursor: collapse(true) DEFAULT BACKSPACEdelete(rangeContents) no merge cursor: end of startdelete(rangeContents) no merge cursor: start of end, but if you type, cells mergedelete(rangeContents) no merge cursor: end of start liliDEFAULT BACKSPACE DEFAULT BACKSPACE8 <#FOOTNOTE-8> DEFAULT BACKSPACEdelete(rangeContents) mergeDEFAULT BACKSPACEDEFAULT BACKSPACEDEFAULT BACKSPACE Delete *Recommendation for HTML 5: * Like in the collapsed cursor case, delete and backspace should be the same. Current exceptions: - Firefox, only change is in cursor placement. With backspace, cursor goes at the end of the start node. With delete, it goes at the start of the end node. This subtle change is noticeable when you type after performing a backspace/delete - does it take the style of the first or second original node? - IE, only change is with table cells. With backspace, contents are not changed, but the cursor is collapsed. With delete, it is a complete nop. - Word, only change is with table cell to table cell selection. With backspace, a prompt is raised with several options on what to do (delete entire row, delete entire column, shift cells up, etc). With delete, the cell contents are just deleted and the cursor is collapsed to start. - IE 8 is different from IE 7 for both backspace and delete cases. The tables above show IE 7 behavior. Biggest difference is that IE 8 uses directionality information and does different cursor placement for backspace/delete. Behavior seems to be: forward selection + backspace: end of start, forward selection + delete, backward selection + backspace, backwards selection + delete: start of end *execCommand('ForwardDelete') *with a range selected should be equivalent to delete with the same range selected. Tab9 <#FOOTNOTE-9> Notes: - FF 3, IE 7, Chrome 1 always perform focus next for tab, no matter what context. They have been eliminated from the tables below to avoid clutter. - I've combined Word in Doc mode and HTML mode into one column. Only differences are with tab vs spaces. *Recommendation for HTML 5:* This is largely context-specific, so recomendations are provided in the far right column of the table below. *execCommand('insertText', false, ' ' | '\t')* should be equivalent to "replace selected(tab|spaces)" with the same range selected, which should be equivalent to calling execCommand('Delete') and then execCommand('insertText'). The assorted indent behaviors should be equivalent to execCommand('indent') when given the same selection, likewise, for the outdent behaviors and execCommand('outdent'). Current Default Behaviors and Recommendations: ContextPPT 2003 Win PPT 2007 WinWord 2003 Win Doc/HTML mode Word 2007 Doc/HTML Mode FF2 (linux)WordpadTextEdit Mac Recommended default behaviorText content selected, inside a single paragraph replace selected(tab) replace selected(tab |10 spaces) replace selected(4 spaces) replace selected(tab) replace selected(tab)replace selected(tab|spaces) Text content selected, inside a single paragraph, SHIFT+TAB replace selected(tab) replace selected(tab | 10 spaces) focus prev replace selected(tab) nopreplace selected(tab|spaces) Text content selected, span 2 paragraphs partiallyindent paragraphs Delete selected indent paragraph cursor collapsed to start of paragraph undo: add entry(delete) add entry(indent) replace selected(4 spaces) replace selected(tab) replace selected(space) indent paragraphsText content selected, span 2 paragraphs partially, SHIFT + Tab outdent paragraph delete selected outdent paragraph collapse cursor to start of paragraph undo: add entry(delete) add entry(outdent) focus prevreplace selected(tab) nopoutdent paragraphs Text content, full paragraph(s)selectedindent paragraph(s) indent paragraph(s) replace selected(4 spaces)replace selected(tab) replace selected(tab)indent paragraph(s) text content, full paragraph(s) selected, SHIFT + TABoutdent paragraph(s) outdent paragraph(s) focus prevreplace selected(tab) nopoutdent paragraph(s) text content, select 2 paragraphs, first paragraph fully selected, second partial indent paragraphs indent paragraphs replace selected(4 spaces) replace selected(tab) replace selected(tab)indent paragraphs text content, select 2 paragraphs, first paragraph fully selected, second partial, SHIFT + TAB outdent paragraphs outdent paragraphs focus prev replace selected(tab) nopoutdent paragraphs text content, select 2 paragraphs, first paragraph partially selected, second fully indent paragraphs replace selected(tab | 10 spaces) replace selected(4 spaces) replace selected(tab) replace selected(space)indent paragraphs text content, select 2 paragraphs, first paragraph partially selected, second fully, SHIFT + TAB outdent paragraphs replace selected(tab | 10 spaces) focus prevreplace selected(tab) nopoutdent paragraphs contained inside single lireplace selected(tab) replace selected(tab | 7 spaces)indent li OR indent just the text node containing the selection. Seems to depend on underlying html. replace selected(tab)replace selected(tab)replace selected(tab | spaces) contained inside single li, SHIFT + TAB replace selected(tab) replace selected(tab | 7 spaces)outdentreplace selected(tab) outdentreplace selected(tab | spaces) partially spanning multiple liindent lisdelete selected indent li cursor at start of li undo: add entry(delete) add entry(indent li)indent lis replace selected(tab)replace selected(tab)indent lis partially spanning multiple li, SHIFT + TAB outdent lisdelete selected outdent li cursor at start of li undo: add entry(delete) add entry (outdent li) or add entry (move cursor)outdent lis replace selected(tab)outdent first li (regardless of direction) cursor collapsed at start of second li, no matter ohw many selected outdent lisli(s) fully selected indent li(s)indent li(s) OR if contains first li, indent listindent li(s) replace selected(tab) if one: indent li, collapse cursor to start of li if multiple: indent first li, collapse cursor to start of second li indent li(s)li(s) fully selected, SHIFT + TAB outdent li(s)outdent li(s) OR if contsint the first li, outdent list outdent li(s)replace selected(tab) if one: outdent li if multiple: outdent first li, collapse cursor to start of second li outdent li(s)spanning multiple li's, first li fully selected indent lisindent lis OR if contains first li, indent list indent lisreplace selected(tab) indent first li indent lisspanning multiple li's, first li fully selected, SHIFT + TAB outdent lisoutdent li(s)outdent lis replace selected(tab) outdent first lioutdent lis spanning multiple li's, first li not fully selectedindent lis delete selected indent li cursor at start of li undo: add entry(delete) add entry(indent) indent lisreplace selected(tab) replace selected(tab) indent lisspanning multiple li's, first li not fully selected, SHIFT + TAB outdent lisdelete selected outdent li cursor at start of li undo: add entry(delete) add entry(outdent) or addentry(move cursor) outdent lis replace selected(tab) outdent first lioutdent lis table cell - inside one cellfocus next cell / insert table row (same as collapsed) focus next cell / insert table row (same as collapsed)focus next cell / insert table rowfocus next cell / insert table row focus next cell / move to next linefocus next cell / insert table row table cell - span 2 cellscannot select partial multiple cells focus moves to first cell in selection, and that cell is fully selected cannot select partial multiple cells focus moves to first cell in selection, and that cell is fully selectedfocus moves to second selected cell. cursor collapsedcannot select partial multiple cells forward selection: focus is moved 2 cells past the last selected cell, cell is fully selected backwards selection: focus is moved 1 cel past the last selected cell (document order), cell is fully selected insert table row if focus would move to cell in a row that doesn't existcollapse cursor to start of second cell, no matter how many selected focus next cell PREN/A replace (3 spaces)replace (\t)N/A replace (\t)replace (tab | spaces) CODE N/Areplace (1 space)replace (4 spaces) N/Areplace (\t) Enter10 <#FOOTNOTE-10> *Recomendation for HTML 5*: Perform a delete then an enter (as defined above in Part I). No exceptions. Undo: Behaves the same as regular text insertion. (shift|option) + enter: inserts a br. Notes: - Word 2008 - Basically the same as a backspace (not a forward-delete) followed by an enter. It does something different if the text is selected via an undo command (it pretends the selection is collapsed at the end of the selection). It also does something different for tables. Iff the selection is partially in a table then the selection is just collapsed to the beginning. If the selection spans multiple TDs, then the selection is shrunk down to the first TD and then a regular enter is performed within that TD. - Behaviors are marked green in the table below if they match this recommendation even if their delete or enter implementations do not match those recommendations. Current Default Behaviors: ContextWord 2008 Mac Doc and HTML mode IE 7 FF 3 - WinChromeWordpadtextedit Mac RTF/HTML mode Base behaviorbackspace (not forward-delete), then caret enter - maintain inline formatting Delete then caret enter - maintain inline formattingDelete then caret enter - inconsistent about maintaining inline formatting, but mostly does not keep any Delete then caret enter - maintains some inline formatting (e.g. sometimes loses background-color)Delete then caret enter except it loses inline formatting Delete/backspace then caret enter - maintain inline formattingAfter Undo/Redo Collapse to end of the selection, then perform enter. Selection starts before table ends in table Just collapse to beginning of selection. noopDelete all the text in the TDs, truncate selection to not include the table, do a regular delete+enter Delete all the text in the TDs, truncate selection to not include the table, do a regular delete+enterdelete + enter Shrink selection to end just before the table and perform enterEntire table row selected deletes the contents of the first selected cell, collapses cursor in that cell, then performs enternopdelete all text in the tds, collapse to start, regular delete + enter Any time a selection contains an entire table row, enter deletes that rowdelete row Selection starts in a table and ends after itDeletes the selected rows, performs a backspace, then enter. noopDelete all the text in the TDs and the nodes selected after the table, then perform enter in the first TDDelete all the text in the TDs and the nodes selected after the table, then perform enter in the first TD delete + enterShrink selection to end at the end of the first TD selected and perform enter. Selection spans multiple TDsCollapse the selection to the first TD and then perform enter.noop Delete all the TD's contents and perform enter in the first TDDelete all the TD's contents and perform enter in the first TD move selection to first cell not in selection, perform enterShrink selection to end at the end of the first TD selected and perform enter. Entire table-contents selectedDelete the table and then perform enter.noop Delete table contentsDelete the table and perform enter. delete the table + enter Delete all the TDs in the table and leave just one TD, then perform enter.Entire table selected Delete the table and then perform enter. Delete the table and perform enter.Delete table perform enter Delete the table and perform enter. delete + enterDelete the table and perform enter. linkDelete, then split the link (not delete + enter, since enter in a link in word navigates to the link) delete + enterdelete + enterdelete + enterdelete + enter li contents delete + enter delete + enterdelete + enterDelete + enterif fully selected, delete li contents, add a new li if partial selection, delete + enter node contents + line break after li delete then enter, but the delete does funky things ------------------------------ Appendix *Common Behavior Implementation Differences and Recomendations* Context PPTWordWord HTML mode FF2 (Linux) WordpadTextEdit RTF modeTextEdit Mac modeRecommended default behavior indent liif one type of list - follow type if mixed types but indenting one type- follows type of li being indented if mixed types, indenting mixed types- follows mixed types (not collapsed cursor)one type - follows type mixed types, single type selected - follows top type mixed types, multiple types selected - follows mixed types (not collapsed cursor) one type - follows type mixed types, single type selected - follows top type mixed types, multiple types selected - follows mixed types (not collapsed cursor) if one type - follow type mixed types, single type selected- follow type mixed types, mixed types selected - follows mixed types (not collapsed cursor) N/Aalways UL always ULif one type - follow type if mixed type - follow selected type insert spacesN/AN/A Inserts a span with spaces (variable #  ): <span style='mso-tab-count:1'> </span> " " or " <br>" if end of block. N/AN/A<span class="Apple-tab-span"> </span> UA specificfocus next cellmoves focus to next table cell (next cell in row or first cell in next row) selects all text in that cell moves focus to next table cell (next cell in row or first cell in next row) selects all text in that cell moves focus to next table cell (next cell in row or first cell in next row) selects all text in that cell focus moves to next table cell cursor collapsed at start of that cellmoves focus to next table cell (next cell in row or first cell in next row) selects all text in that cell moves focus to next table cell cursor collapsed at start of cellmoves focus to next table cell cursor collapsed at start of cell moves focus to next table cell cursor selecting all text in cell notes 1 For more details, see Eric's original research<http://docs.google.com/a/google.com/Doc?id=dcr67n6m_35d9cbdxd8> . 2 For more details, see Eric's original research<http://docs.google.com/a/google.com/Doc?id=dcr67n6m_35d9cbdxd8> and Julie's original research<http://docs.google.com/a/google.com/View?docid=cg97btvx_7ghwkdwds>. In this section, data is from Chrome 2.0.170.0. 3 Tested on IE 7, FF 3, Chrome 2, Word 2003, all on Windows. 4 For more details, see Julie's original research<http://docs.google.com/a/google.com/Doc?id=cg97btvx_2hnf88kch> 5 For more details, see Ojan's original research<http://docs.google.com/a/google.com/Doc?id=afz5pfkg6n_3c4tpxgcf> 6 For more details, see Eric's original research<http://docs.google.com/a/google.com/Doc?id=dcr67n6m_35d9cbdxd8> and Julie's original research<http://docs.google.com/a/google.com/Edit?docid=cg97btvx_7ghwkdwds> . 7 For more details, see Eric's original research<http://docs.google.com/a/google.com/Doc?id=dcr67n6m_35d9cbdxd8> and Julie's original research<http://docs.google.com/a/google.com/Edit?docid=cg97btvx_7ghwkdwds> . 8 Does perform this UA's DEFAULT BACKSCPACE behavior, but that doesn't match recommended DEFAULT BACKSPACE behavior. 9 For more details, see Julie's original research<http://docs.google.com/a/google.com/Doc?id=cg97btvx_2hnf88kch> . 10 For more details, see Ojan's original research<http://docs.google.com/a/google.com/Doc?id=afz5pfkg6n_3c4tpxgcf> -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.whatwg.org/pipermail/whatwg-whatwg.org/attachments/20091221/8ac1e7ea/attachment-0001.htm>
Received on Monday, 21 December 2009 10:21:44 UTC