[whatwg] behavior when typing in contentEditable elements
Ojan Vafai
ojan at chromium.org
Mon Dec 21 10:21:44 PST 2009
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>
More information about the whatwg
mailing list