', '[foo
bar]'],
['
', '[foo
bar]'],
['', '[foo
bar]'],
['
', '[foo
bar]'],
['
', '[foo
bar]'],
['', '[foo
bar]'],
['p', '
[foobar]
'],
'[foo] bar ',
['', '
[foo] bar '],
['', '
foo [bar] '],
['', '
[foo bar] '],
['', '[foo] bar '],
['', 'foo [bar] '],
['', '[foo bar] '],
['', '[foo] bar '],
['', 'foo [bar] '],
['', '[foo bar] '],
['', '[foo] bar '],
['', 'foo [bar] '],
['', '[foo bar] '],
['', ' [foo] bar
'],
['', ' foo [bar]
'],
['', ' [foo bar]
'],
['', '[foo] bar
'],
['', 'foo [bar]
'],
['', '[foo bar]
'],
['', '[foo] bar
'],
['', 'foo [bar]
'],
['', '[foo bar]
'],
['', '
[foo] bar '],
['', '
foo [bar] '],
['', '
[foo bar] '],
['', '[foo] bar '],
['', 'foo [bar] '],
['', '[foo bar] '],
['', '[foo] bar '],
['', 'foo [bar] '],
['', '[foo bar] '],
[' ', '
[foo] bar '],
['', '
foo [bar] '],
['', '
[foo bar] '],
['', '[foo] bar '],
['', 'foo [bar] '],
['', '[foo bar] '],
['', '[foo] bar '],
['', 'foo [bar] '],
['', '[foo bar] '],
['', ' [foo
bar]'],
['', '[foo bar]
'],
['', '
'],
['', '
[foo] '],
['', '
[foo] '],
'
',
'
',
'
[foo
bar] ',
'
[foo bar] ',
'
[foo
bar]',
// https://bugs.webkit.org/show_bug.cgi?id=47054
['
', '
[foo]
'],
// https://bugs.webkit.org/show_bug.cgi?id=47574
['
', '{ foo
ba]r'],
['
', '
[foobar]
'],
// From https://bugs.webkit.org/show_bug.cgi?id=47300
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=14009
['!', '{
foo
bar
}'],
],
//@}
forwarddelete: [
//@{
// Collapsed selection
'foo[]',
'foo[] ',
'foo[]
',
'foo[]bar',
'foo {}bar ',
'foo[ ]bar ',
'foo[]bar baz',
'foo[]baz',
'fo[]öbar',
'fo[]öbar',
'fo[]ö̧bar',
'[]öbar',
'[]öbar',
'[]ö̧bar',
'[]שָׁלוֹם',
'שָׁל[]וֹם',
'foo[]
bar
',
'foo[]
bar',
'foo[]bar
',
'foo[]
bar
',
'foo[]
bar',
'foo[]bar
',
'{}
foo',
'{}
foo',
'foo{} ',
'foo{}
',
'foo{}
',
'foo{}
',
'foo{}
',
'foo{}
',
'foo{}
',
'
foo',
'
foo',
'
foo',
'
bar
',
'
foo[]
',
'
',
'
bar',
'foo[]
',
'
foo[]
bar
',
'
foo[] bar',
'foo[]
bar',
'
foo[] bar',
'foo[]
bar',
'
foo[]
bar',
'
foo[]
bar
',
'
foo[]
bar
',
'
foo[]
bar',
'foo[] bar',
'foo[]bar ',
'foo[]bar ',
'foo[]bar ',
'foo[]bar ',
'foo[]bar ',
'foo[]bar ',
'foo[]bar ',
'foo[]bar ',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo [] ',
'[] foo',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo [] bar',
'foo [] bar',
'foo[] bar',
'foo [] bar',
'foo [] bar',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'
foo [] ',
'
[] foo ',
'
foo[] bar ',
'
foo[] bar ',
'
foo[] bar ',
'
foo []
',
'
[] foo
',
'
foo[] bar
',
'
foo[] bar
',
'
foo[] bar
',
'
foo []
',
'
[] foo
',
'
foo[] bar
',
'
foo[] bar
',
'
foo[] bar
',
'
foo []
',
'
[] foo
',
'
foo[] bar
',
'
foo[] bar
',
'
foo[] bar
',
'
foo []
',
'
[] foo
',
'
foo[] bar
',
'
foo[] bar
',
'
foo[] bar
',
// Tables with collapsed selection
'foo[]
baz',
'foo
baz',
'
foo[]
baz',
'
',
'
',
'foo[]
baz',
'foo
baz',
'
foo[]
baz',
'
foo
baz',
'
',
'
',
'foo
baz',
'foo[]
baz',
'
',
'
',
// Lists with collapsed selection
'foo[]
bar baz ',
'foo[]
bar baz ',
'
foo[] bar ',
'
foo[] bar ',
'
foo[] bar baz ',
'
foo[]
bar ',
'
foo[] bar
',
'
foo[]
bar
',
'
foo[] ',
'foo[]
bar ',
'foo[]
',
'foo[]
bar baz ',
'foo[]
bar ',
'
foo[] bar ',
'
foo[]bar baz ',
'
foo bar[]baz ',
'
foo[] bar',
'
foo[] bar',
'
{} bar',
'
foo {} bar',
'
foo[] bar',
'
foo[] bar',
'
{} bar',
'
foo {} bar',
'
foo[] ',
'
foo[] ',
'
{} ',
'
foo {} ',
'
foo[] ',
'
foo[] ',
'
{} ',
'
foo {} ',
// Indented stuff with collapsed selection
'foo[]
bar ',
'foo[]
bar ',
'foo[]
bar
',
'foo[]
bar ',
'foo[]
bar
baz
',
'foo[]
',
'foo[]
bar
baz
',
'foo[]
bar
baz
',
'foo[]
bar
baz
',
'foo[]
bar
baz
',
'foo[]
bar extra',
'foo[]
barbaz quz extra',
'foo
bar[] baz quz extra',
// Invisible stuff with collapsed selection
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo[] bar',
'foo[]bar ',
'foo[]
',
'foo[]
',
'foo[]
',
'foo[]
',
'foo[]
',
'
bar',
'
bar',
'
bar',
'
bar',
'
bar',
'
',
'
',
'
',
'
',
'
',
'
',
'
',
'
',
// Styled stuff with collapsed selection
'
foo[]
bar',
'
foo[]
bar',
'
foo[]
bar',
'
foo[]
bar',
'
foo[]
bar ',
'
foo[]
bar ',
'
foo[]bar',
'
foo[]bar',
'foo[]
bar',
'foo[]
bar',
'
foo[]
bar',
'
foo[]
bar',
'
foo[]bar',
'
foo[]bar',
'foo[]
bar',
'foo[]
bar',
'
foo[]
bar',
'
foo[]
bar',
'
foo[]
bar',
'
foo[]
bar ',
'
foo[]
bar ',
'
foo[]
bar',
'foo[]bar',
'
bar',
'bar',
'
foo[]
bar',
// Uncollapsed selection (should be same as delete command)
'foo[bar]baz',
'
foo[bar] baz',
'
foo{bar} baz',
'
foo{bar }baz',
'
[foobar] baz',
'
{foobar} baz',
'
foo[bar baz]',
'
foo{bar baz}',
'
foo[bar baz] quz',
'foo[bar] baz',
'foo{bar} baz',
'foo{bar }baz',
'foo[bar] baz',
'foo{bar} baz',
'foo{bar }baz',
'foo[bar baz]quz ',
'
foo
[bar]
baz
',
'
foo
{bar}
baz
',
'
foo
{bar
}
baz
',
'
foo
{
bar}
baz
',
'
foo
{
bar
}
baz
',
'
foo[bar
baz]quz',
'
foo[bar
baz]quz
',
'
foo[bar
baz]quz ',
'
foo[bar
baz]quz',
'
foo[bar baz]quz ',
'
foo[bar
baz]quz',
'
baz]quz',
'
foo[bar
baz]quz
qoz
foo[bar
baz]quz',
'
foo[bar
baz]quz ',
'
',
'foo[
]bar',
'
foo[
]bar
',
'
foo[
]bar baz
',
'foo[
]bar
',
'foo{
}bar
',
'foo[
]bar baz
',
'foo[
]bar
baz',
'foo{
bar
}baz',
'foo
{bar
}baz',
'foo{
bar}
baz',
'
foo[
]bar',
'
foo{
}bar',
'
foo[
]bar
baz',
'
foo[
]bar
baz
',
'foo[
',
'
]bar',
'foo[
',
'foo[
',
'
]baz',
'
]baz',
'
foo {
]bar',
'
foo {
]bar',
'foo
{
]bar
',
'foo
{
]bar
',
'
foo {
}bar
',
'
foo {
}bar
',
'
',
'
',
'
',
'
',
'
',
'
',
'{
}',
'
',
'
fo[o
baz',
'
foo
b]az',
'
fo[o
b]az',
'
foo
ba[r b]az quz',
'
foo
bar [baz] quz',
'
fo[o
b]ar baz quz',
'
foo
bar ba[z q]uz',
'
fo[o
bar b]az quz',
'
fo[o
bar baz q]uz',
'
fo[o b]ar ',
'
fo[o ',
'foo[
]bar ',
'
foo[ ]bar ',
'foo[
]bar baz ',
'foo[
]bar ',
'
foo[ ]bar ',
'
foo[]bar baz ',
'
foo bar[]baz ',
// https://bugs.webkit.org/show_bug.cgi?id=35281
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=13976
'
foo {}
bar ',
'
foo {}
bar ',
'
foo
{}
bar ',
'
foo {}
bar ',
'
foo {}
bar ',
'
foo {}
bar ',
'
foo {}
bar ',
'
foo {}bar ',
'
foo {} bar ',
'
foo[ bar]
baz ',
'
foo[ bar]
baz ',
'
foo[
bar]
baz ',
'
fo[]o bar ',
'
foo [bar
]baz ',
'
foo [bar
]baz ',
'
foo [bar
]baz
',
'
foo []bar ',
'
foo[ bar baz]
quz ',
'
{}
',
'
{}
',
'
foo[ bar] baz quz ',
'
foo {}
',
'
foo {}
',
'
{}
bar ',
'
{}
bar ',
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=13831
'
[foo] ',
'
[foo] ',
'
[foo] ',
'
{foo} ',
'
{foo }',
'
[]f ',
'[foo] ',
'
[foo]
',
],
//@}
hilitecolor: [
//@{
'foo[]bar',
'
[foo
bar]
',
'
[foo bar] ',
'
[foo
bar
baz]
',
'
[foo
bar]',
'foo[]bar ',
'foo[]bar ',
'foo {}bar ',
'foo[ ]bar ',
'foo[bar]baz',
'foo[barbaz]qoz quz',
'foo[barbaz]qoz quz',
'{
foo
}',
'
',
'
',
'
',
'
',
'
',
'{
}',
'
foo[bar]baz
',
'
foo[bar]baz
',
'
foo[bar]baz
',
'{
foo
bar
}',
'
foo[bar] baz ',
'
foo[bar] baz ',
'
foo[bar] baz ',
'
foo[bar] baz ',
'
foob[ar] baz ',
'
foob[ar] baz
',
'
',
'
b[ar] ',
// Tests for queryCommandIndeterm() and queryCommandState()
'fo[o
b]ar baz',
'foo
ba[r b]az',
'fo[o
bar b]az',
'foo[
b]ar baz',
'foo
ba[r ]baz',
'foo[
bar ]baz',
'foo
[bar] baz',
'foo{
bar }baz',
'
fo[o b]ar ',
'
fo[o b]ar ',
'
fo[ob]ar ',
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=13829
'!
[foo] ',
'!
[foo] ',
'!
foo[bar]baz ',
'!
foo[bar]baz ',
'![foo
bar baz]',
'![foo
bar baz]',
],
//@}
indent: [
//@{
// All these have a trailing unselected paragraph, because otherwise
// Gecko is unhappy: it throws exceptions in non-CSS mode, and in CSS
// mode it adds the indentation invisibly to the wrapper div in many
// cases.
'foo[]bar
extra',
'foo {}bar
extra',
'foo[ ]bar
extra',
'foo[bar]baz
extra',
'
פו[בר]בז
נוםף',
'
פו[ברבז
Foobar]baz
Extra',
'
Foo[barbaz
פובר]בז
Extra',
'
Extra',
'foo]bar[baz
extra',
'{
foo
}
extra',
'foo[barbaz]qoz quz
extra',
'[]foo
extra',
'foo[]
extra',
'
[]foo
extra',
'
foo[]
extra',
'
{} foo
extra',
'
foo {}
extra',
'{} foo bar
extra',
'foo {} bar
extra',
'
foo
{}
bar
',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}
extra',
'
foo[bar]
baz
extra',
'
[foobar
ba]z
extra',
'foo[bar] baz
extra',
'foo[bar] baz
extra',
'foobar [ba]z
extra',
'foobar [ba]z
extra',
'foo[bar ba]z
extra',
'
extra',
// These mimic existing indentation in various browsers, to see how
// they cope with indenting twice. This is spec, Gecko non-CSS, and
// Opera:
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
[foo]
bar
extra',
'
[foo
b]ar
extra',
'
foo
bar
[baz]
extra',
'
foo
[bar
baz]
extra',
'
[foo
bar
baz]
extra',
'
foo
[bar]
baz
extra',
'
foo[bar] baz extra',
'
foo[bar b]az extra',
'
foo[bar] baz
extra',
'
foo[bar b]az
extra',
'[foo]
bar extra',
'[foo
b]ar extra',
'foo
bar [baz]
extra',
'[foo
bar baz]
extra',
'
foo [bar]
baz extra',
// IE:
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
[foo]
bar
extra',
'
[foo
b]ar
extra',
'
foo
bar
[baz]
extra',
'
foo
[bar
baz]
extra',
'
[foo
bar
baz]
extra',
'
foo
[bar]
baz
extra',
// Firefox CSS mode:
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
[foo]
bar
extra',
'
[foo
b]ar
extra',
'
foo
bar
[baz]
extra',
'
foo
[bar
baz]
extra',
'
[foo
bar
baz]
extra',
'
foo
[bar]
baz
extra',
// WebKit:
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
[foo]
bar
extra',
'
[foo
b]ar
extra',
'
foo
bar
[baz]
extra',
'
foo
[bar
baz]
extra',
'
[foo
bar
baz]
extra',
'
foo
[bar]
baz
extra',
// MDC says "In Firefox, if the selection spans multiple lines at
// different levels of indentation, only the least indented lines in
// the selection will be indented." Let's test that.
'
f[oob]ar extra',
// Lists!
'
foo [bar] baz ',
'
foo bar baz ',
'
foo [bar]',
'
[foo] bar baz ',
'
foo [bar] baz ',
'
[foo]
barbaz ',
'
foo[bar] baz quz ',
'
foobar [baz] quz ',
'
foo [bar] baz quz ',
'
foo bar baz quz ',
'
foo bar [baz] quz ',
'
foo bar baz quz ',
'
foob[a]r baz ',
'
foo b[a]r baz ',
'
foo{bar } baz ',
'
foo {bar }baz ',
'
[foo]bar baz ',
'
[foo] bar baz ',
'
foo [bar]baz quz ',
'
foo [bar] baz quz ',
'
foobar baz [quz] ',
'
foo bar baz [quz] ',
// Lists with id's:
// http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2009-July/020721.html
'
foo [bar] baz ',
'
foo [bar] baz ',
'
foo [bar] baz ',
'
[bar] baz ',
'
foo [bar] ',
// Try indenting multiple items at once.
'
foo b[ar baz] ',
'
[foobar] baz ',
'
[foo bar] baz ',
'
foob[ar b]az ',
'
foo b[ar b]az ',
'
[foobar baz] extra',
'
[foo bar baz] extra',
// We probably can't actually get this DOM . . .
'
[foo]bar baz ',
'
foo[bar] baz ',
'
foobar [baz] ',
'
[foobar] baz ',
'foo[baz]
extra',
'[foo]baz
extra',
'
foo{}
extra',
'
{}bar
extra',
// Whitespace nodes
'
foo
[bar]',
'
[foo]
bar
',
'
foo
[bar]
baz
',
'
foo bar [baz] ',
'
foo bar [baz] ',
'
foo bar [baz] ',
'
foobar [baz] ',
'
foobar [baz] ',
'
foobar [baz] ',
'
foo [bar] baz ',
'
foo [bar] baz ',
'
foo [bar] baz ',
'
foo [bar] baz ',
'
foo [bar] baz ',
'
foo [bar] baz ',
// https://bugs.webkit.org/show_bug.cgi?id=32003
'
',
],
//@}
inserthorizontalrule: [
//@{
'foo[]bar',
'
foo {}
bar ',
'
foo[ ]bar ',
'
foo[bar
baz]quz',
'
foo {}bar
',
'
foo[ ]bar
',
'
foo {bar }baz
',
'
foo[]bar ',
'
foo[]bar ',
["abc", 'foo[bar]baz'],
'foo[bar]baz',
'foo
[bar] baz',
'foo
{bar} baz',
'foo{
bar }baz',
'
foo
[bar]
baz',
'
foo
{bar}
baz',
'
foo{
bar
}
baz',
'
foo[bar]baz
',
'
foo[bar]baz
',
'
foo[bar]baz ',
'
foob[a]r baz
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
',
'
foo[bar]baz ',
'
foo[bar]baz
',
'
foo[bar]baz ',
'
foo[bar]baz',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz quz',
'
foo[bar]baz ',
'
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]bazquz ',
'
foobar[baz]quz ',
'
foobar[baz]quz qoz qiz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
',
'
',
'
foo[bar]baz ',
'
',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
foo[bar]baz ',
'
',
'fo[o
bar b]az',
],
//@}
inserthtml: [
//@{
'foo[]bar',
'foo[bar]baz',
'foo
[bar] baz',
'foo
{bar} baz',
'foo{
bar }baz',
'[foo
bar] baz',
'{foo
bar} baz',
'foo
[bar baz]',
'foo
{bar baz}',
'foo
[bar baz] quz',
['', 'foo[bar]baz'],
['\0', 'foo[bar]baz'],
['\x07', 'foo[bar]baz'],
// The following line makes Firefox 7.0a2 go into an infinite loop on
// my machine.
//['\ud800', 'foo[bar]baz'],
['
', 'foo[bar]baz'],
['abc', 'foo[bar]baz'],
[' abc', '
foo[bar]baz'],
['
abc', 'foo[bar]baz'],
['
abc', '
{foo }bar '],
['abc', '
foo {bar }baz '],
['abc', '
[foo] bar '],
['abc', 'f[o]o '],
['abc ', 'f[o]o '],
['abc', 'bar'],
['abc ', 'bar'],
['abc ', 'f[o]o '],
['abc ', 'f[o]o '],
[' ', 'f[o]o'],
['
', 'f[o]o '],
['abc ', 'f[o]o '],
['abc ', ''],
['abc ', 'f[o]o'],
['abc ', 'f[o]o bar '],
['abc ', 'foo b[a]r '],
['abc ', 'f[o]o bar '],
['abc ', 'foo b[a]r '],
['abc ', 'f[o]o'],
['abc ', 'f[o]o '],
['abc ', 'f[o]o'],
['abc ', 'f[o]o '],
[' abc ', '
f[o]o '],
['
abc ', '
f[o]o '],
['
abc ', '
'],
['
abc ', '
f[o]o '],
['
abc ', '
f[o]o '],
['
abc ', '
'],
['
abc ', '
f[o]o '],
['
abc ', '
f[o]o '],
['
abc ', '
'],
['
', '
f[o]o '],
['
', '
f[o]o '],
['
', '
'],
['
abc ', 'f[o]o'],
['
abc ', '
f[o]o '],
['
abc ', 'f[o]o'],
['
abc', 'foo[]bar '],
['
abc', 'foo[]bar '],
['
abc', 'foo[]bar '],
[' ', '
[foo]
'],
['
', '
[foo]
'],
['', '
[foo]
'],
['abc', '
{}
'],
['', '
{}
'],
['abc', '
{}
'],
['', '
{}
'],
['abc', '
{}
'],
['', '
{}
'],
['abc', '
{}
'],
['', '
{}
'],
['abc', '
{}
'],
['', '
{}
'],
['abc', '
{}
'],
['', '
{}
'],
],
//@}
insertimage: [
//@{
'foo[]bar',
'
foo {}
bar ',
'
foo[ ]bar ',
["", 'foo[bar]baz'],
'foo[bar]baz',
'foo
[bar] baz',
'foo
{bar} baz',
'foo{
bar }baz',
'[foo
bar] baz',
'{foo
bar} baz',
'foo
[bar baz]',
'foo
{bar baz}',
'foo
[bar baz] quz',
'foo
[bar] baz',
'foo
{bar} baz',
'foo{
bar }baz',
'foo
[bar] baz',
'foo
{bar} baz',
'foo{
bar }baz',
'
foo[bar baz]quz ',
'
foo
[bar]
baz
',
'
foo
{bar}
baz
',
'
foo
{
bar
}
baz
',
'
foo[bar
baz]quz',
'
foo[bar
baz]quz
',
'
foo[bar
baz]quz ',
'
foo[bar
baz]quz',
'
foo[bar baz]quz ',
'
foo[bar
baz]quz',
'
baz]quz',
'
foo[bar
baz]quz
qoz
foo[bar
baz]quz',
'
foo[bar
baz]quz ',
'
',
'foo[
]bar',
'
foo[
]bar
',
'
foo[
]bar baz
',
'foo[
]bar
',
'foo[
]bar baz
',
'foo[
]bar
baz',
'
foo[
]bar',
'
foo[
]bar
baz',
'
foo[
]bar
baz
',
'foo[
',
'
]bar',
'foo[
',
'foo[
',
'
]baz',
'
]baz',
],
//@}
insertlinebreak: [
//@{ Same as insertparagraph (set below)
],
//@}
insertorderedlist: [
//@{
'foo[]bar',
'foo[bar]baz',
'foo
[bar]',
'f[oo
b]ar
baz',
'
[foo] bar
',
'[foo
bar] baz',
'foo
[bar baz]',
'[foo
baz',
'foo
baz]',
'foo
baz] quz',
'foo
[bar quz',
'
',
'
',
'{
}',
'
foo
[bar]
baz',
'
foo
[bar] baz',
'
foo [bar] baz quz ',
'
foo bar [baz] quz ',
'
[foo
bar]
baz',
'
[foo
bar] baz',
'
[foo bar] baz quz ',
'
foo [bar baz] quz ',
'
[foo
bar]
baz
',
// Various
stuff
'foo [bar] baz ',
'foo [bar]',
'[foo]bar ',
'foo [bar]baz ',
'[foo] ',
'[foo] bar baz ',
'foo [bar] baz ',
'[foo]
barbaz ',
'foo[bar] baz quz ',
'foobar [baz] quz ',
'foo [bar] baz quz ',
'foo bar [baz] quz ',
'[foo]bar baz ',
'[foo] bar baz ',
'foo [bar]baz quz ',
'foo [bar] baz quz ',
'foobar baz [quz] ',
'foo bar baz [quz] ',
// Multiple items at once.
'foo [bar baz] ',
'[foobar] baz ',
'foob[ar b]az ',
'[foobar baz] extra',
// We probably can't actually get this DOM . . .
'
[foo]bar baz ',
'foo[bar] baz ',
'foobar [baz] ',
'[foobar] baz ',
// Same stuff but with
'',
'[bar]',
'[foo]',
'[bar]',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
// Multiple items at once.
'',
'',
'',
'extra',
// We probably can't actually get this DOM . . .
'
',
'',
'',
'',
// Mix of and
'foobar quz',
'foobar quz]',
'foobaz quz',
'[foobaz quz',
// Interaction with indentation
'[foo]bar baz',
'foo[bar] baz',
'[foobar] baz',
'foo [bar] baz',
'[foo]bar baz',
'foo[bar] baz ',
'[foobar] baz ',
'foo [bar] baz ',
'[foo]
bar
baz',
'
foo
[bar]
baz',
'
[foo
bar]
baz',
'
foo [bar]
baz',
// Attributes
'
',
'',
'',
'',
'',
'',
'',
'',
'',
// Whitespace nodes
'foo [bar]',
'
[foo]
bar ',
'foo [bar]
baz ',
// This caused an infinite loop at one point due to a bug in "fix
// disallowed ancestors". Disabled because I'm not sure how we want it
// to behave:
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=14578
'!foo[] ',
],
//@}
insertparagraph: [
//@{
'foo[bar]baz',
'fo[o',
'',
'',
'b]ar',
'',
'{}',
'',
'[foo] bar ',
'f[o]o bar ',
'[]foo',
'foo[]',
'foo[] ',
'foo[] ',
'foo[]bar',
' []foo ',
'foo[] ',
'foo[] ',
'foo[]bar ',
'[]foo
',
'foo[]
',
'foo[]
',
'foo[]bar
',
'[]foo bar ',
'foo[] bar ',
'foo[] bar ',
'foo[]bar baz ',
'foo []bar ',
'foo bar[] ',
'foo bar[] ',
'foo bar[]baz ',
'[]foo ',
'foo[] ',
'foo[] ',
'foo[]bar ',
'[]foo ',
'foo[] ',
'foo[] ',
'foo[]bar ',
'[]foo
',
'foo[]
',
'foo[]
',
'foo[]bar
',
'[]foo ',
'foo[] ',
'foo[] ',
'foo[]bar ',
'foo[] ',
'foo {} ',
'foo
[] ',
'foo[]
',
'foo
[]
',
'foo[]bar ',
'baz',
'foo[]bar
baz',
'foo[]bar ',
'{} ',
'foo{} ',
'{} foo',
'foo {} ',
'{} bar ',
'foo ',
'{} ',
'foo {} ',
'{} bar ',
'foo bar{} baz ',
'foo barbaz {} ',
'foo[bar baz]quz
',
'foo[bar
baz]quz ',
'foo
{} ',
'{}foo
',
'foo
{}bar ',
'foo {}bar
',
'foo {}bar ',
'foo
[bar] baz
',
'foo
{bar }baz
',
'',
'',
'[]foo ',
'foo[] ',
'foo[] ',
'foo[]bar ',
'[]foo
',
'foo[]
',
'foo[]bar
',
'foo[]
bar
',
'foo[]bar
baz
',
'foo[]bar ',
'foo[]bar baz',
'foo[]bar ',
'foo[]bar baz',
'foo[] bar',
'foo[]bar ',
'foo[] bar ',
'foo[]bar ',
'foo[]bar baz ',
'foo[]bar
',
'[]foo
',
'foo[]bar
',
'foo[]bar
',
'foo[]bar ',
'foo[]bar baz',
'foo[] bar',
'foo[]bar ',
'foo[]',
'
[]bar',
'
foo[bar] baz',
'
foo{bar} baz',
'
foo{bar }baz',
'
[foobar] baz',
'
{foobar} baz',
'
foo[bar baz]',
'
foo{bar baz}',
'
foo[bar baz] quz',
// https://bugs.webkit.org/show_bug.cgi?id=5036
'
',
'',
'',
'',
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=13841
// https://bugs.webkit.org/show_bug.cgi?id=23507
'foo[]
',
'foo[]
',
'foo[]
',
'foo[]
',
'',
'foo[]',
'
foo[]',
'
foo[]',
'
foo[]',
'
foo[]',
'
',
'
foo[]
',
'
[]foo
',
'
[]foo
',
'
[]foo
',
'
[]foo
',
'
',
'
[]foo',
'
[]foo',
'
[]foo',
'
[]foo',
'
[]foo',
'
',
'
[]foo
',
'
foo[]bar
',
'
foo[]bar
',
'
foo[]bar
',
'
foo[]bar
',
'
',
'
foo[]bar',
'
foo[]bar',
'
foo[]bar',
'
foo[]bar',
'
foo[]bar',
'
',
'
foo[]bar
',
'
foo[]
',
'
',
'
',
'
[]foo
',
'
',
'
',
'
foo[]bar
',
'
',
'
',
],
//@}
inserttext: [
//@{
'foo[bar]baz',
['', 'foo[bar]baz'],
['\t', 'foo[]bar'],
['&', 'foo[]bar'],
['\n', 'foo[]bar'],
['abc\ndef', 'foo[]bar'],
['\x07', 'foo[]bar'],
['
hi ', 'foo[]bar'],
['<', 'foo[]bar'],
['&', 'foo[]bar'],
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=14254
['!\r', 'foo[]bar'],
['!\r\n', 'foo[]bar'],
['!\0', 'foo[]bar'],
['!\ud800', 'foo[]bar'],
// Whitespace tests! The following two bugs are relevant to some of
// these:
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=14119
// https://bugzilla.mozilla.org/show_bug.cgi?id=681626
[' ', 'foo[]bar'],
[' ', 'foo []bar'],
[' ', 'foo[] bar'],
[' ', 'foo []bar'],
[' ', 'foo [] bar'],
[' ', 'foo[] bar'],
[' ', 'foo []bar'],
[' ', 'foo [] bar'],
[' ', 'foo[] bar'],
[' ', 'foo []bar'],
[' ', 'foo [] bar'],
[' ', 'foo[] bar'],
[' ', 'foo [] bar'],
[' ', 'foo []bar'],
[' ', 'foo [] bar'],
[' ', '[]foo'],
[' ', '{}foo'],
[' ', 'foo[]'],
[' ', 'foo{}'],
[' ', 'foo []'],
[' ', 'foo {}'],
[' ', 'foo []'],
[' ', 'foo {}'],
[' ', '
foo[] bar'],
[' ', 'foo[]
bar '],
[' ', 'foo[] '],
[' ', ' foo [] '],
[' ', 'foo[]
'],
[' ', 'foo[]
'],
[' ', ' []foo'],
[' ', ' [] foo '],
[' ', '
[]foo'],
[' ', '
[]foo'],
[' ', '{}
'],
[' ', '
{} '],
[' ', '
foo[]
bar'],
[' ', '
foo []
bar'],
[' ', '
foo[]
bar'],
// Some of the same tests as above, repeated with various values of
// white-space.
[' ', '
foo[]bar '],
[' ', '
foo []bar '],
[' ', '
foo[] bar '],
[' ', '
foo []bar '],
[' ', '
[]foo '],
[' ', '
foo[] '],
[' ', '
foo [] '],
[' ', '
foo [] '],
[' ', '
foo[]bar
'],
[' ', '
foo []bar
'],
[' ', '
foo[] bar
'],
[' ', '
foo []bar
'],
[' ', '
[]foo
'],
[' ', '
foo[]
'],
[' ', '
foo []
'],
[' ', '
foo []
'],
[' ', '
foo[]bar
'],
[' ', '
foo []bar
'],
[' ', '
foo[] bar
'],
[' ', '
foo []bar
'],
[' ', '
[]foo
'],
[' ', '
foo[]
'],
[' ', '
foo []
'],
[' ', '
foo []
'],
[' ', '
foo[]bar
'],
[' ', '
foo []bar
'],
[' ', '
foo[] bar
'],
[' ', '
foo []bar
'],
[' ', '
[]foo
'],
[' ', '
foo[]
'],
[' ', '
foo []
'],
[' ', '
foo []
'],
[' ', '
foo[]bar
'],
[' ', '
foo []bar
'],
[' ', '
foo[] bar
'],
[' ', '
foo []bar
'],
[' ', '
[]foo
'],
[' ', '
foo[]
'],
[' ', '
foo []
'],
[' ', '
foo []
'],
// End whitespace tests
// Autolinking tests
[' ', 'http://a[]'],
[' ', 'ftp://a[]'],
[' ', 'quasit://a[]'],
[' ', '.x-++-.://a[]'],
[' ', '(http://a)[]'],
[' ', '<http://a>[]'],
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=14744
['! ', '[http://a][]'],
['! ', '{http://a}[]'],
[' ', 'http://a![]'],
[' ', '!"#$%&\'()*+,-./:;<=>?\^_`|~http://a!"#$%&\'()*+,-./:;<=>?\^_`|~[]'],
[' ', 'http://a!"\'(),-.:;<>`[]'],
[' ', 'http://a#$%&*+/=?\^_|~[]'],
[' ', 'mailto:a[]'],
[' ', 'a@b[]'],
[' ', 'a@[]'],
[' ', '@b[]'],
[' ', '#@x[]'],
[' ', 'a@.[]'],
[' ', '!"#$%&\'()*+,-./:;<=>?\^_`|~a@b!"#$%&\'()*+,-./:;<=>?\^_`|~[]'],
[' ', '
a@b {}'],
[' ', '
a @ b {}'],
[' ', 'a@b
[]c '],
[' ', '
a@b
[]c
'],
['a', 'http://a[]'],
['\t', 'http://a[]'],
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=14254
['!\r', 'http://a[]'],
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=14745
['!\n', 'http://a[]'],
['\f', 'http://a[]'],
['\u00A0', 'http://a[]'],
[' ', 'foo[]'],
'foo[]bar',
'foo []',
'foo\xa0[]',
'
foo[]',
'
foo
{}',
'
[]foo',
'
{}foo',
'{}
foo',
'
foo
{}
bar
',
'
foo[] bar',
'
foo []bar',
'foo
{} bar',
'
foo[] bar',
'
foo []bar',
'
foo[] bar',
'
foo []bar',
'
fo[o
b]ar',
'
fo[o
bar
b]az',
'{} ',
'
{} ',
'
{} ',
'
foo[bar] baz',
'
foo{bar} baz',
'
foo{bar }baz',
'
[foobar] baz',
'
{foobar} baz',
'
foo[bar baz]',
'
foo{bar baz}',
'
foo[bar baz] quz',
// These are like the corresponding tests in the multitest section, but
// because the selection isn't collapsed, we don't need to do
// multitests to set overrides.
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
// Now repeat but with different selections.
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'[foobar] baz',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
// https://bugs.webkit.org/show_bug.cgi?id=19702
'
[foo] ',
],
//@}
insertunorderedlist: [
//@{
'foo[]bar',
'foo[bar]baz',
'foo
[bar]',
'f[oo
b]ar
baz',
'
[foo] bar
',
'[foo
bar] baz',
'foo
[bar baz]',
'[foo
baz',
'foo
baz]',
'foo
baz] quz',
'foo
[bar quz',
'
',
'
',
'{
}',
'
foo
[bar]
baz',
'
foo
[bar] baz',
'
foo [bar] baz quz ',
'
foo bar [baz] quz ',
'
[foo
bar]
baz',
'
[foo
bar] baz',
'
[foo bar] baz quz ',
'
foo [bar baz] quz ',
'
[foo
bar]
baz
',
// Various
stuff
'foo [bar] baz ',
'foo [bar]',
'[foo]bar ',
'foo [bar]baz ',
'[foo] ',
'[foo] bar baz ',
'foo [bar] baz ',
'[foo]
barbaz ',
'foo[bar] baz quz ',
'foobar [baz] quz ',
'foo [bar] baz quz ',
'foo bar [baz] quz ',
'[foo]bar baz ',
'[foo] bar baz ',
'foo [bar]baz quz ',
'foo [bar] baz quz ',
'foobar baz [quz] ',
'foo bar baz [quz] ',
// Multiple items at once.
'foo [bar baz] ',
'[foobar] baz ',
'foob[ar b]az ',
'[foobar baz] extra',
// We probably can't actually get this DOM . . .
'
[foo]bar baz ',
'foo[bar] baz ',
'foobar [baz] ',
'[foobar] baz ',
// Same stuff but with
'',
'[bar]',
'[foo]',
'[bar]',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
// Multiple items at once.
'',
'',
'',
'extra',
// We probably can't actually get this DOM . . .
'
',
'',
'',
'',
// Mix of and
'foobar quz',
'foobar quz]',
'foobaz quz',
'[foobaz quz',
// Interaction with indentation
'[foo]bar baz',
'foo[bar] baz',
'[foobar] baz',
'foo [bar] baz',
'[foo]bar baz',
'foo[bar] baz ',
'[foobar] baz ',
'foo [bar] baz ',
'[foo]
bar
baz',
'
foo
[bar]
baz',
'
[foo
bar]
baz',
'
foo [bar]
baz',
// Attributes
'
',
'',
'',
'',
'',
'',
'',
'',
'',
// Whitespace nodes
' [bar]',
'
[foo]
',
' [bar]
',
// https://bugs.webkit.org/show_bug.cgi?id=24167
'{1
2
}',
],
//@}
italic: [
//@{
'foo[]bar',
'[foo
bar]
',
'[foo bar] ',
'[foo
bar
baz]
',
'[foo
bar]',
'foo[]bar ',
'foo[]bar ',
'foo {}bar ',
'foo[ ]bar ',
'foo[bar]baz',
'foo[barbaz]qoz quz',
'foo[barbaz]qoz quz',
'{
foo
}',
'',
'',
'',
'',
'',
'{}',
'foo[bar] baz',
'foo [bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo{bar }baz',
'foo{bar }baz',
'foo{bar }baz',
'foo{bar }baz',
'foo{bar }baz',
'foo{bar }baz',
'foob[a]r baz',
'foob[a]r baz',
'foob[a]r baz',
'foob[a]r baz',
'foob[a]r baz',
'foob[a]r baz',
'fo[obar b]az',
'fo[obar b]az',
'fo[obar b]az',
'fo[obar b]az',
'fo[obar b]az',
'fo[obar b]az',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'foo[bar baz]',
'[foobar ]baz',
'[foobar ]baz',
'[foobar ]baz',
'[foobar ]baz',
'[foobar ]baz',
'[foobar ]baz',
'foo[bar] baz',
'foo[bar] baz',
'foob[a]r baz',
'{ foo
bar
}baz
',
'foo[bar }
baz
',
'foo [bar baz] qoz quz sic',
'foo bar baz [qoz quz] sic',
'foo [bar baz] qoz quz sic',
'foo bar baz [qoz quz] sic',
// Tests for queryCommandIndeterm() and queryCommandState()
'fo[ob]ar baz',
'fooba[r b]az',
'fo[obar b]az',
'foo[b]ar baz',
'fooba[r ]baz',
'foo[bar ]baz',
'foo[bar] baz',
'foo{bar }baz',
'fo[ob]ar baz',
'fo[ob]ar baz',
'fo[o b]ar ',
'fo[o b]ar ',
'fo[o b]ar ',
],
//@}
justifycenter: [
//@{
'foo[]barextra',
'foo {}bar
extra',
'foo[ ]bar
extra',
'foo[bar]baz
extra',
'foo[barbaz]qoz quz
extra',
'
foo[]bar
extra',
'
foo[bar]baz
extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
[foo]
bar
extra',
'
[foo
bar]
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
foo [bar]extra',
'[foo]
bar extra',
'
foo [bar]baz extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]
extra',
'
[foo]
bar
extra',
'
foo
[bar]
baz
extra',
'
[foo bar]extra',
'
fo[o b]arextra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'[foo]
extra',
'f[o]o
extra',
'
extra',
'
extra',
'
extra',
'[foo]
extra',
'
',
'',
'',
'',
'{
foo
}
',
'{
foo
}
',
'',
'',
'[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
// Whitespace nodes
'
[bar]',
'
[bar]',
'
foo
[bar]',
'
[foo]
',
'[foo]
',
'[foo]
bar
',
' [bar]
',
' [bar]
',
'foo
[bar]
baz
',
],
//@}
justifyfull: [
//@{
'foo[]barextra',
'foo {}bar
extra',
'foo[ ]bar
extra',
'foo[bar]baz
extra',
'foo[barbaz]qoz quz
extra',
'
foo[]bar
extra',
'
foo[bar]baz
extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
[foo]
bar
extra',
'
[foo
bar]
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]
extra',
'
[foo]
bar
extra',
'
foo
[bar]
baz
extra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'[foo]
extra',
'f[o]o
extra',
'
extra',
'
extra',
'
extra',
'[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
// Whitespace nodes
'
[bar]',
'
[bar]',
'
[foo]
',
'[foo]
',
' [bar]
',
' [bar]
',
],
//@}
justifyleft: [
//@{
'foo[]barextra',
'foo {}bar
extra',
'foo[ ]bar
extra',
'foo[bar]baz
extra',
'foo[barbaz]qoz quz
extra',
'
foo[]bar
extra',
'
foo[bar]baz
extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
[foo]
bar
extra',
'
[foo
bar]
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]
extra',
'
[foo]
bar
extra',
'
foo
[bar]
baz
extra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'[foo]
extra',
'f[o]o
extra',
'
extra',
'
extra',
'
extra',
'[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
// Whitespace nodes
'
[bar]',
'
[bar]',
'
[foo]
',
'[foo]
',
' [bar]
',
' [bar]
',
],
//@}
justifyright: [
//@{
'foo[]barextra',
'foo {}bar
extra',
'foo[ ]bar
extra',
'foo[bar]baz
extra',
'foo[barbaz]qoz quz
extra',
'
foo[]bar
extra',
'
foo[bar]baz
extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
foo[bar]baz extra',
'
[foo]
bar
extra',
'
[foo
bar]
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'{
}extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]extra',
'[foo]
bar
extra',
'
foo
[bar]baz
extra',
'
[bar]
extra',
'
[foo]
extra',
'
[bar]
extra',
'
foo
[bar]
extra',
'
[foo]
bar
extra',
'
foo
[bar]
baz
extra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'
[foo
bar]extra',
'
fo[o
b]arextra',
'[foo]
extra',
'f[o]o
extra',
'
extra',
'
extra',
'
extra',
'[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
'
[foo]
extra',
// Whitespace nodes
'
[bar]',
'
[bar]',
'
[foo]
',
'[foo]
',
' [bar]
',
' [bar]
',
],
//@}
outdent: [
//@{
// These mimic existing indentation in various browsers, to see how
// they cope with outdenting various things. This is spec, Gecko
// non-CSS, and Opera:
'foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
// IE:
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
// Firefox CSS mode:
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
// WebKit:
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
'
foo[bar]
baz
extra',
'
foo[bar
b]az
extra',
// Now let's try nesting lots of stuff and see what happens.
'
foo[bar]baz ',
'foo[bar]baz ',
'foo[bar]baz ',
'foo[bar]baz
',
'foo[bar]baz
',
'foo[bar]baz ',
'foo[bar]baz ',
'foo[bar]
baz
',
'foo[bar]
baz
',
'foo[bar]
baz
',
' ',
' ',
'foo[bar]
baz
',
'foo[bar]
baz
',
'foo[bar]
baz
',
'foo[bar]
baz
',
'foo[bar]
baz
',
'foo[bar]
baz
',
'foo[bar]
baz
',
// Lists!
'foo [bar] baz ',
'foo bar baz ',
'foo [bar]',
'[foo] bar baz ',
'foo [bar] baz ',
'[foo]
barbaz ',
'foo[bar] baz quz ',
'foobar [baz] quz ',
'foo [bar] baz quz ',
'foo bar baz quz ',
'foo bar [baz] quz ',
'foo bar baz quz ',
'foob[a]r baz ',
'foo b[a]r baz ',
'foo{bar } baz ',
'foo {bar }baz ',
'[foo]bar baz ',
'[foo] bar baz ',
'foo [bar]baz quz ',
'foo [bar] baz quz ',
'foobar baz [quz] ',
'foo bar baz [quz] ',
// Try outdenting multiple items at once.
'foo b[ar baz] ',
'[foobar] baz ',
'[foo bar] baz ',
'foob[ar b]az ',
'foo b[ar b]az ',
'[foobar baz] extra',
'
[foo bar baz] extra',
// We probably can't actually get this DOM . . .
'
[foo]bar baz ',
'foo[bar] baz ',
'foobar [baz] ',
'[foobar] baz ',
// Attribute handling on lists
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foo [bar] ',
'',
'foo [bar] baz ',
'foo [bar] baz ',
'foo [bar] baz ',
'foo [bar] baz ',
'foo [bar baz] quz ',
'foo [bar baz] quz ',
'foo [bar baz] quz ',
'foo [bar baz] quz ',
// List inside indentation element
'[foo] extra',
'
foo[bar] baz extra',
'
foo [bar] baz extra',
'
[foo] ',
'[foo] ',
'foo baz ',
// Whitespace nodes
' [foo]
',
'[foo]
',
' [foo]
',
' [foo] ',
'[foo] ',
' [foo] ',
'',
'',
'',
' [foo]
bar
baz
',
' foo
[bar]
baz
',
' foo
bar
[baz]
',
' [foo] bar baz ',
' foo [bar] baz ',
' foo bar [baz] ',
'',
'',
'',
// https://bugs.webkit.org/show_bug.cgi?id=24249
'[]a ',
// https://bugs.webkit.org/show_bug.cgi?id=43447
'foo [bar] ',
],
//@}
removeformat: [
//@{
'foo[]bar',
'foo {}bar ',
'foo[ ]bar ',
'[foobar baz]',
'foo[bar baz]',
'foo[bar ]baz',
'foo[bar] baz',
'foob[a]r baz',
'[foobar baz]',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
// HTML has lots of inline elements, doesn't it?
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar
baz]',
'foob[a]r
baz',
'[foobarbaz]',
'foob[a]rbaz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
// Empty and replaced elements
'[foo bar]',
'[foo bar]',
'[foobar]',
'[foo bar]',
'[foo bar]',
'[foo bar]',
'[foo bar]',
'[foo bar]',
// Unrecognized elements
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
// Random stuff
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'[foobar baz]',
'foob[a]r baz',
'foo[bar]baz
',
'foo[bar]baz
',
'foo[bar]baz
',
'foo[bar]baz
',
'foo[bar]baz
',
'{foobarbaz
}',
'foo[bar]baz
',
'{foobarbaz
}',
// https://bugzilla.mozilla.org/show_bug.cgi?id=649138
// Chrome 15 dev fails this for some unclear reason.
'',
],
//@}
strikethrough: [
//@{
'foo[]bar',
'[foo
bar]
',
'[foo bar] ',
'[foo
bar
baz]
',
'[foo
bar]',
'foo[]bar ',
'foo[]bar ',
'foo {}bar ',
'foo[ ]bar ',
'foo[bar]baz',
'foo[barbaz]qoz quz',
'foo[barbaz]qoz quz',
'{
foo
}',
'',
'',
'',
'',
'',
'{}',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]baz
',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]baz
',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]baz',
'foo[bar]baz',
'foo[bar]ba z',
'foo[bar]ba z',
'foo[bar]ba z',
'foo[bar]ba z',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar]baz
',
'foo[bar]baz
',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
// Tests for queryCommandIndeterm() and queryCommandState()
'fo[ob]ar baz',
'fooba[r b]az',
'fo[obar b]az',
'foo[b]ar baz',
'fooba[r ]baz',
'foo[bar ]baz',
'foo[bar] baz',
'foo{bar }baz',
'fo[ob]ar baz',
'fo[o b]ar ',
'fo[o b]ar',
],
//@}
subscript: [
//@{
'foo[]bar',
'[foo
bar]
',
'[foo bar] ',
'[foo
bar
baz]
',
'[foo
bar]',
'foo[]bar ',
'foo[]bar ',
'foo {}bar ',
'foo[ ]bar ',
'foo[bar]baz',
'foo[barbaz]qoz quz',
'foo[barbaz]qoz quz',
'{
foo
}',
'',
'',
'',
'',
'',
'{}',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
// Tests for queryCommandIndeterm() and queryCommandState()
'fo[ob]ar baz',
'fooba[r b]az',
'fo[obar b]az',
'foo[b]ar baz',
'fooba[r ]baz',
'foo[bar ]baz',
'foo[bar] baz',
'foo{bar }baz',
'fo[o b]ar ',
'fo[o b]ar ',
'foo[bar] baz',
'fo[o b]ar ',
],
//@}
superscript: [
//@{
'foo[]bar',
'[foo
bar]
',
'[foo bar] ',
'[foo
bar
baz]
',
'[foo
bar]',
'foo[]bar ',
'foo[]bar ',
'foo {}bar ',
'foo[ ]bar ',
'foo[bar]baz',
'foo[barbaz]qoz quz',
'foo[barbaz]qoz quz',
'{
foo
}',
'',
'',
'',
'',
'',
'{}',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
'foo[bar] baz',
'foob[a]r baz',
'foob[a] r baz',
// Tests for queryCommandIndeterm() and queryCommandState()
'fo[ob]ar baz',
'fooba[r b]az',
'fo[obar b]az',
'foo[b]ar baz',
'fooba[r ]baz',
'foo[bar ]baz',
'foo[bar] baz',
'foo{bar }baz',
'fo[o b]ar ',
'fo[o b]ar ',
'foo[bar] baz',
'fo[o b]ar ',
// https://bugs.webkit.org/show_bug.cgi?id=28472
'foo[bar] ',
],
//@}
underline: [
//@{
'foo[]bar',
'[foo
bar]
',
'[foo bar] ',
'[foo
bar
baz]
',
'[foo
bar]',
'foo[]bar ',
'foo[]bar ',
'foo {}bar ',
'foo[ ]bar ',
'foo[bar]baz',
'foo[barbaz]qoz quz',
'foo[barbaz]qoz quz',
'{
foo
}',
'',
'',
'',
'',
'',
'{}',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]baz
',
'foo[bar] baz',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]baz
',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar] baz',
'foo[bar]baz ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]ba z ',
'foo[bar]baz',
'foo[bar]baz',
'foo[bar]ba z',
'foo[bar]ba z',
'foo[bar]ba z',
'foo[bar]ba z',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar]baz
',
'foo[bar]baz
',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
'foo[bar] baz',
'foob[a]r baz',
// Tests for queryCommandIndeterm() and queryCommandState()
'fo[ob]ar baz',
'fooba[r b]az',
'fo[obar b]az',
'foo[b]ar baz',
'fooba[r ]baz',
'foo[bar ]baz',
'foo[bar] baz',
'foo{bar }baz',
'fo[ob]ar baz',
'fo[o b]ar ',
'fo[o b]ar ',
],
//@}
unlink: [
//@{
'foo[]bar',
'[foo
bar]
',
'[foo bar] ',
'[foo
bar
baz]
',
'foo[]bar ',
'foo[]bar ',
'foo {}bar ',
'foo[ ]bar ',
'foo[bar]baz',
'foo[barbaz]qoz quz',
'foo[barbaz]qoz quz',
'{
foo
}',
'foo[bar]baz ',
'foo[barbaz }',
'{foobar]baz ',
'{foobarbaz }',
'[foobarbaz] ',
'foob[]ar baz',
'foo[bar] baz',
'foo[bar ]baz',
'foo[bar baz]',
'[foobar] baz',
'[foobar baz]',
'foobar[]baz ',
'foo[bar]baz ',
'[foobarbaz] ',
'foo[bar] baz',
'foo[bar ]baz',
'[foobar baz]',
'foobar[]baz ',
'foo[bar]baz ',
'[foobarbaz] ',
'foo[bar] baz',
'foo[bar ]baz',
'[foobar baz]',
],
//@}
copy: ['!foo[bar]baz'],
cut: ['!foo[bar]baz'],
defaultparagraphseparator: [
//@{
['', 'foo[bar]baz'],
['div', 'foo[bar]baz'],
['p', 'foo[bar]baz'],
['DIV', 'foo[bar]baz'],
['P', 'foo[bar]baz'],
[' div ', 'foo[bar]baz'],
[' p ', 'foo[bar]baz'],
['', 'foo[bar]baz'],
['
', 'foo[bar]baz'],
['li', 'foo[bar]baz'],
['blockquote', 'foo[bar]baz'],
],
//@}
paste: ['!foo[bar]baz'],
selectall: ['foo[bar]baz'],
stylewithcss: [
//@{
['true', 'foo[bar]baz'],
['TRUE', 'foo[bar]baz'],
['TrUe', 'foo[bar]baz'],
['true ', 'foo[bar]baz'],
[' true', 'foo[bar]baz'],
['truer', 'foo[bar]baz'],
[' true ', 'foo[bar]baz'],
[' TrUe', 'foo[bar]baz'],
['', 'foo[bar]baz'],
[' ', 'foo[bar]baz'],
['false', 'foo[bar]baz'],
['FALSE', 'foo[bar]baz'],
['FaLsE', 'foo[bar]baz'],
[' false', 'foo[bar]baz'],
['false ', 'foo[bar]baz'],
['falser', 'foo[bar]baz'],
['falsé', 'foo[bar]baz'],
],
//@}
usecss: [
//@{
['true', 'foo[bar]baz'],
['TRUE', 'foo[bar]baz'],
['TrUe', 'foo[bar]baz'],
['true ', 'foo[bar]baz'],
[' true', 'foo[bar]baz'],
['truer', 'foo[bar]baz'],
[' true ', 'foo[bar]baz'],
[' TrUe', 'foo[bar]baz'],
['', 'foo[bar]baz'],
[' ', 'foo[bar]baz'],
['false', 'foo[bar]baz'],
['FALSE', 'foo[bar]baz'],
['FaLsE', 'foo[bar]baz'],
[' false', 'foo[bar]baz'],
['false ', 'foo[bar]baz'],
['falser', 'foo[bar]baz'],
['falsé', 'foo[bar]baz'],
],
//@}
quasit: ['foo[bar]baz'],
multitest: [
//@{
// Insertion-affecting state. Test that insertText works right, and
// test that various block commands preserve (or don't preserve) the
// state.
['foo[]bar', 'bold', 'inserttext'],
['foo[]bar', 'bold', 'delete'],
['foo[]bar', 'bold', 'delete', 'inserttext'],
['foo[]bar', 'bold', 'formatblock'],
['foo[]bar', 'bold', 'formatblock', 'inserttext'],
['foo[]bar', 'bold', 'forwarddelete'],
['foo[]bar', 'bold', 'forwarddelete', 'inserttext'],
['foo[]bar', 'bold', 'indent'],
['foo[]bar', 'bold', 'indent', 'inserttext'],
['foo[]bar', 'bold', 'inserthorizontalrule'],
['foo[]bar', 'bold', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'bold', 'inserthtml'],
['foo[]bar', 'bold', 'inserthtml', 'inserttext'],
['foo[]bar', 'bold', 'insertimage'],
['foo[]bar', 'bold', 'insertimage', 'inserttext'],
['foo[]bar', 'bold', 'insertlinebreak'],
['foo[]bar', 'bold', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'bold', 'insertorderedlist'],
['foo[]bar', 'bold', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'bold', 'insertparagraph'],
['foo[]bar', 'bold', 'insertparagraph', 'inserttext'],
['foo[]bar', 'bold', 'insertunorderedlist'],
['foo[]bar', 'bold', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'bold', 'justifycenter'],
['foo[]bar', 'bold', 'justifycenter', 'inserttext'],
['foo[]bar', 'bold', 'justifyfull'],
['foo[]bar', 'bold', 'justifyfull', 'inserttext'],
['foo[]bar', 'bold', 'justifyleft'],
['foo[]bar', 'bold', 'justifyleft', 'inserttext'],
['foo[]bar', 'bold', 'justifyright'],
['foo[]bar', 'bold', 'justifyright', 'inserttext'],
['foo[]bar', 'bold', 'outdent'],
['foo[]bar', 'bold', 'outdent', 'inserttext'],
['foo[]bar', 'italic', 'inserttext'],
['foo[]bar', 'italic', 'delete'],
['foo[]bar', 'italic', 'delete', 'inserttext'],
['foo[]bar', 'italic', 'formatblock'],
['foo[]bar', 'italic', 'formatblock', 'inserttext'],
['foo[]bar', 'italic', 'forwarddelete'],
['foo[]bar', 'italic', 'forwarddelete', 'inserttext'],
['foo[]bar', 'italic', 'indent'],
['foo[]bar', 'italic', 'indent', 'inserttext'],
['foo[]bar', 'italic', 'inserthorizontalrule'],
['foo[]bar', 'italic', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'italic', 'inserthtml'],
['foo[]bar', 'italic', 'inserthtml', 'inserttext'],
['foo[]bar', 'italic', 'insertimage'],
['foo[]bar', 'italic', 'insertimage', 'inserttext'],
['foo[]bar', 'italic', 'insertlinebreak'],
['foo[]bar', 'italic', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'italic', 'insertorderedlist'],
['foo[]bar', 'italic', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'italic', 'insertparagraph'],
['foo[]bar', 'italic', 'insertparagraph', 'inserttext'],
['foo[]bar', 'italic', 'insertunorderedlist'],
['foo[]bar', 'italic', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'italic', 'justifycenter'],
['foo[]bar', 'italic', 'justifycenter', 'inserttext'],
['foo[]bar', 'italic', 'justifyfull'],
['foo[]bar', 'italic', 'justifyfull', 'inserttext'],
['foo[]bar', 'italic', 'justifyleft'],
['foo[]bar', 'italic', 'justifyleft', 'inserttext'],
['foo[]bar', 'italic', 'justifyright'],
['foo[]bar', 'italic', 'justifyright', 'inserttext'],
['foo[]bar', 'italic', 'outdent'],
['foo[]bar', 'italic', 'outdent', 'inserttext'],
['foo[]bar', 'strikethrough', 'inserttext'],
['foo[]bar', 'strikethrough', 'delete'],
['foo[]bar', 'strikethrough', 'delete', 'inserttext'],
['foo[]bar', 'strikethrough', 'formatblock'],
['foo[]bar', 'strikethrough', 'formatblock', 'inserttext'],
['foo[]bar', 'strikethrough', 'forwarddelete'],
['foo[]bar', 'strikethrough', 'forwarddelete', 'inserttext'],
['foo[]bar', 'strikethrough', 'indent'],
['foo[]bar', 'strikethrough', 'indent', 'inserttext'],
['foo[]bar', 'strikethrough', 'inserthorizontalrule'],
['foo[]bar', 'strikethrough', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'strikethrough', 'inserthtml'],
['foo[]bar', 'strikethrough', 'inserthtml', 'inserttext'],
['foo[]bar', 'strikethrough', 'insertimage'],
['foo[]bar', 'strikethrough', 'insertimage', 'inserttext'],
['foo[]bar', 'strikethrough', 'insertlinebreak'],
['foo[]bar', 'strikethrough', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'strikethrough', 'insertorderedlist'],
['foo[]bar', 'strikethrough', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'strikethrough', 'insertparagraph'],
['foo[]bar', 'strikethrough', 'insertparagraph', 'inserttext'],
['foo[]bar', 'strikethrough', 'insertunorderedlist'],
['foo[]bar', 'strikethrough', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'strikethrough', 'justifycenter'],
['foo[]bar', 'strikethrough', 'justifycenter', 'inserttext'],
['foo[]bar', 'strikethrough', 'justifyfull'],
['foo[]bar', 'strikethrough', 'justifyfull', 'inserttext'],
['foo[]bar', 'strikethrough', 'justifyleft'],
['foo[]bar', 'strikethrough', 'justifyleft', 'inserttext'],
['foo[]bar', 'strikethrough', 'justifyright'],
['foo[]bar', 'strikethrough', 'justifyright', 'inserttext'],
['foo[]bar', 'strikethrough', 'outdent'],
['foo[]bar', 'strikethrough', 'outdent', 'inserttext'],
['foo[]bar', 'subscript', 'inserttext'],
['foo[]bar', 'subscript', 'delete'],
['foo[]bar', 'subscript', 'delete', 'inserttext'],
['foo[]bar', 'subscript', 'formatblock'],
['foo[]bar', 'subscript', 'formatblock', 'inserttext'],
['foo[]bar', 'subscript', 'forwarddelete'],
['foo[]bar', 'subscript', 'forwarddelete', 'inserttext'],
['foo[]bar', 'subscript', 'indent'],
['foo[]bar', 'subscript', 'indent', 'inserttext'],
['foo[]bar', 'subscript', 'inserthorizontalrule'],
['foo[]bar', 'subscript', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'subscript', 'inserthtml'],
['foo[]bar', 'subscript', 'inserthtml', 'inserttext'],
['foo[]bar', 'subscript', 'insertimage'],
['foo[]bar', 'subscript', 'insertimage', 'inserttext'],
['foo[]bar', 'subscript', 'insertlinebreak'],
['foo[]bar', 'subscript', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'subscript', 'insertorderedlist'],
['foo[]bar', 'subscript', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'subscript', 'insertparagraph'],
['foo[]bar', 'subscript', 'insertparagraph', 'inserttext'],
['foo[]bar', 'subscript', 'insertunorderedlist'],
['foo[]bar', 'subscript', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'subscript', 'justifycenter'],
['foo[]bar', 'subscript', 'justifycenter', 'inserttext'],
['foo[]bar', 'subscript', 'justifyfull'],
['foo[]bar', 'subscript', 'justifyfull', 'inserttext'],
['foo[]bar', 'subscript', 'justifyleft'],
['foo[]bar', 'subscript', 'justifyleft', 'inserttext'],
['foo[]bar', 'subscript', 'justifyright'],
['foo[]bar', 'subscript', 'justifyright', 'inserttext'],
['foo[]bar', 'subscript', 'outdent'],
['foo[]bar', 'subscript', 'outdent', 'inserttext'],
['foo[]bar', 'superscript', 'inserttext'],
['foo[]bar', 'superscript', 'delete'],
['foo[]bar', 'superscript', 'delete', 'inserttext'],
['foo[]bar', 'superscript', 'formatblock'],
['foo[]bar', 'superscript', 'formatblock', 'inserttext'],
['foo[]bar', 'superscript', 'forwarddelete'],
['foo[]bar', 'superscript', 'forwarddelete', 'inserttext'],
['foo[]bar', 'superscript', 'indent'],
['foo[]bar', 'superscript', 'indent', 'inserttext'],
['foo[]bar', 'superscript', 'inserthorizontalrule'],
['foo[]bar', 'superscript', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'superscript', 'inserthtml'],
['foo[]bar', 'superscript', 'inserthtml', 'inserttext'],
['foo[]bar', 'superscript', 'insertimage'],
['foo[]bar', 'superscript', 'insertimage', 'inserttext'],
['foo[]bar', 'superscript', 'insertlinebreak'],
['foo[]bar', 'superscript', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'superscript', 'insertorderedlist'],
['foo[]bar', 'superscript', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'superscript', 'insertparagraph'],
['foo[]bar', 'superscript', 'insertparagraph', 'inserttext'],
['foo[]bar', 'superscript', 'insertunorderedlist'],
['foo[]bar', 'superscript', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'superscript', 'justifycenter'],
['foo[]bar', 'superscript', 'justifycenter', 'inserttext'],
['foo[]bar', 'superscript', 'justifyfull'],
['foo[]bar', 'superscript', 'justifyfull', 'inserttext'],
['foo[]bar', 'superscript', 'justifyleft'],
['foo[]bar', 'superscript', 'justifyleft', 'inserttext'],
['foo[]bar', 'superscript', 'justifyright'],
['foo[]bar', 'superscript', 'justifyright', 'inserttext'],
['foo[]bar', 'superscript', 'outdent'],
['foo[]bar', 'superscript', 'outdent', 'inserttext'],
['foo[]bar', 'underline', 'inserttext'],
['foo[]bar', 'underline', 'delete'],
['foo[]bar', 'underline', 'delete', 'inserttext'],
['foo[]bar', 'underline', 'formatblock'],
['foo[]bar', 'underline', 'formatblock', 'inserttext'],
['foo[]bar', 'underline', 'forwarddelete'],
['foo[]bar', 'underline', 'forwarddelete', 'inserttext'],
['foo[]bar', 'underline', 'indent'],
['foo[]bar', 'underline', 'indent', 'inserttext'],
['foo[]bar', 'underline', 'inserthorizontalrule'],
['foo[]bar', 'underline', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'underline', 'inserthtml'],
['foo[]bar', 'underline', 'inserthtml', 'inserttext'],
['foo[]bar', 'underline', 'insertimage'],
['foo[]bar', 'underline', 'insertimage', 'inserttext'],
['foo[]bar', 'underline', 'insertlinebreak'],
['foo[]bar', 'underline', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'underline', 'insertorderedlist'],
['foo[]bar', 'underline', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'underline', 'insertparagraph'],
['foo[]bar', 'underline', 'insertparagraph', 'inserttext'],
['foo[]bar', 'underline', 'insertunorderedlist'],
['foo[]bar', 'underline', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'underline', 'justifycenter'],
['foo[]bar', 'underline', 'justifycenter', 'inserttext'],
['foo[]bar', 'underline', 'justifyfull'],
['foo[]bar', 'underline', 'justifyfull', 'inserttext'],
['foo[]bar', 'underline', 'justifyleft'],
['foo[]bar', 'underline', 'justifyleft', 'inserttext'],
['foo[]bar', 'underline', 'justifyright'],
['foo[]bar', 'underline', 'justifyright', 'inserttext'],
['foo[]bar', 'underline', 'outdent'],
['foo[]bar', 'underline', 'outdent', 'inserttext'],
// Insertion-affecting value. Test that insertText works right, and
// test that various block commands preserve (or don't preserve) the
// value.
['foo[]bar', 'backcolor', 'inserttext'],
['foo[]bar', 'backcolor', 'delete'],
['foo[]bar', 'backcolor', 'delete', 'inserttext'],
['foo[]bar', 'backcolor', 'formatblock'],
['foo[]bar', 'backcolor', 'formatblock', 'inserttext'],
['foo[]bar', 'backcolor', 'forwarddelete'],
['foo[]bar', 'backcolor', 'forwarddelete', 'inserttext'],
['foo[]bar', 'backcolor', 'indent'],
['foo[]bar', 'backcolor', 'indent', 'inserttext'],
['foo[]bar', 'backcolor', 'inserthorizontalrule'],
['foo[]bar', 'backcolor', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'backcolor', 'inserthtml'],
['foo[]bar', 'backcolor', 'inserthtml', 'inserttext'],
['foo[]bar', 'backcolor', 'insertimage'],
['foo[]bar', 'backcolor', 'insertimage', 'inserttext'],
['foo[]bar', 'backcolor', 'insertlinebreak'],
['foo[]bar', 'backcolor', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'backcolor', 'insertorderedlist'],
['foo[]bar', 'backcolor', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'backcolor', 'insertparagraph'],
['foo[]bar', 'backcolor', 'insertparagraph', 'inserttext'],
['foo[]bar', 'backcolor', 'insertunorderedlist'],
['foo[]bar', 'backcolor', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'backcolor', 'justifycenter'],
['foo[]bar', 'backcolor', 'justifycenter', 'inserttext'],
['foo[]bar', 'backcolor', 'justifyfull'],
['foo[]bar', 'backcolor', 'justifyfull', 'inserttext'],
['foo[]bar', 'backcolor', 'justifyleft'],
['foo[]bar', 'backcolor', 'justifyleft', 'inserttext'],
['foo[]bar', 'backcolor', 'justifyright'],
['foo[]bar', 'backcolor', 'justifyright', 'inserttext'],
['foo[]bar', 'backcolor', 'outdent'],
['foo[]bar', 'backcolor', 'outdent', 'inserttext'],
['foo[]bar', 'createlink', 'inserttext'],
['foo[]bar', 'createlink', 'delete'],
['foo[]bar', 'createlink', 'delete', 'inserttext'],
['foo[]bar', 'createlink', 'formatblock'],
['foo[]bar', 'createlink', 'formatblock', 'inserttext'],
['foo[]bar', 'createlink', 'forwarddelete'],
['foo[]bar', 'createlink', 'forwarddelete', 'inserttext'],
['foo[]bar', 'createlink', 'indent'],
['foo[]bar', 'createlink', 'indent', 'inserttext'],
['foo[]bar', 'createlink', 'inserthorizontalrule'],
['foo[]bar', 'createlink', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'createlink', 'inserthtml'],
['foo[]bar', 'createlink', 'inserthtml', 'inserttext'],
['foo[]bar', 'createlink', 'insertimage'],
['foo[]bar', 'createlink', 'insertimage', 'inserttext'],
['foo[]bar', 'createlink', 'insertlinebreak'],
['foo[]bar', 'createlink', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'createlink', 'insertorderedlist'],
['foo[]bar', 'createlink', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'createlink', 'insertparagraph'],
['foo[]bar', 'createlink', 'insertparagraph', 'inserttext'],
['foo[]bar', 'createlink', 'insertunorderedlist'],
['foo[]bar', 'createlink', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'createlink', 'justifycenter'],
['foo[]bar', 'createlink', 'justifycenter', 'inserttext'],
['foo[]bar', 'createlink', 'justifyfull'],
['foo[]bar', 'createlink', 'justifyfull', 'inserttext'],
['foo[]bar', 'createlink', 'justifyleft'],
['foo[]bar', 'createlink', 'justifyleft', 'inserttext'],
['foo[]bar', 'createlink', 'justifyright'],
['foo[]bar', 'createlink', 'justifyright', 'inserttext'],
['foo[]bar', 'createlink', 'outdent'],
['foo[]bar', 'createlink', 'outdent', 'inserttext'],
['foo[]bar', 'fontname', 'inserttext'],
['foo[]bar', 'fontname', 'delete'],
['foo[]bar', 'fontname', 'delete', 'inserttext'],
['foo[]bar', 'fontname', 'formatblock'],
['foo[]bar', 'fontname', 'formatblock', 'inserttext'],
['foo[]bar', 'fontname', 'forwarddelete'],
['foo[]bar', 'fontname', 'forwarddelete', 'inserttext'],
['foo[]bar', 'fontname', 'indent'],
['foo[]bar', 'fontname', 'indent', 'inserttext'],
['foo[]bar', 'fontname', 'inserthorizontalrule'],
['foo[]bar', 'fontname', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'fontname', 'inserthtml'],
['foo[]bar', 'fontname', 'inserthtml', 'inserttext'],
['foo[]bar', 'fontname', 'insertimage'],
['foo[]bar', 'fontname', 'insertimage', 'inserttext'],
['foo[]bar', 'fontname', 'insertlinebreak'],
['foo[]bar', 'fontname', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'fontname', 'insertorderedlist'],
['foo[]bar', 'fontname', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'fontname', 'insertparagraph'],
['foo[]bar', 'fontname', 'insertparagraph', 'inserttext'],
['foo[]bar', 'fontname', 'insertunorderedlist'],
['foo[]bar', 'fontname', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'fontname', 'justifycenter'],
['foo[]bar', 'fontname', 'justifycenter', 'inserttext'],
['foo[]bar', 'fontname', 'justifyfull'],
['foo[]bar', 'fontname', 'justifyfull', 'inserttext'],
['foo[]bar', 'fontname', 'justifyleft'],
['foo[]bar', 'fontname', 'justifyleft', 'inserttext'],
['foo[]bar', 'fontname', 'justifyright'],
['foo[]bar', 'fontname', 'justifyright', 'inserttext'],
['foo[]bar', 'fontname', 'outdent'],
['foo[]bar', 'fontname', 'outdent', 'inserttext'],
['foo[]bar', 'fontsize', 'inserttext'],
['foo[]bar', 'fontsize', 'delete'],
['foo[]bar', 'fontsize', 'delete', 'inserttext'],
['foo[]bar', 'fontsize', 'formatblock'],
['foo[]bar', 'fontsize', 'formatblock', 'inserttext'],
['foo[]bar', 'fontsize', 'forwarddelete'],
['foo[]bar', 'fontsize', 'forwarddelete', 'inserttext'],
['foo[]bar', 'fontsize', 'indent'],
['foo[]bar', 'fontsize', 'indent', 'inserttext'],
['foo[]bar', 'fontsize', 'inserthorizontalrule'],
['foo[]bar', 'fontsize', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'fontsize', 'inserthtml'],
['foo[]bar', 'fontsize', 'inserthtml', 'inserttext'],
['foo[]bar', 'fontsize', 'insertimage'],
['foo[]bar', 'fontsize', 'insertimage', 'inserttext'],
['foo[]bar', 'fontsize', 'insertlinebreak'],
['foo[]bar', 'fontsize', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'fontsize', 'insertorderedlist'],
['foo[]bar', 'fontsize', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'fontsize', 'insertparagraph'],
['foo[]bar', 'fontsize', 'insertparagraph', 'inserttext'],
['foo[]bar', 'fontsize', 'insertunorderedlist'],
['foo[]bar', 'fontsize', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'fontsize', 'justifycenter'],
['foo[]bar', 'fontsize', 'justifycenter', 'inserttext'],
['foo[]bar', 'fontsize', 'justifyfull'],
['foo[]bar', 'fontsize', 'justifyfull', 'inserttext'],
['foo[]bar', 'fontsize', 'justifyleft'],
['foo[]bar', 'fontsize', 'justifyleft', 'inserttext'],
['foo[]bar', 'fontsize', 'justifyright'],
['foo[]bar', 'fontsize', 'justifyright', 'inserttext'],
['foo[]bar', 'fontsize', 'outdent'],
['foo[]bar', 'fontsize', 'outdent', 'inserttext'],
['foo[]bar', 'forecolor', 'inserttext'],
['foo[]bar', 'forecolor', 'delete'],
['foo[]bar', 'forecolor', 'delete', 'inserttext'],
['foo[]bar', 'forecolor', 'formatblock'],
['foo[]bar', 'forecolor', 'formatblock', 'inserttext'],
['foo[]bar', 'forecolor', 'forwarddelete'],
['foo[]bar', 'forecolor', 'forwarddelete', 'inserttext'],
['foo[]bar', 'forecolor', 'indent'],
['foo[]bar', 'forecolor', 'indent', 'inserttext'],
['foo[]bar', 'forecolor', 'inserthorizontalrule'],
['foo[]bar', 'forecolor', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'forecolor', 'inserthtml'],
['foo[]bar', 'forecolor', 'inserthtml', 'inserttext'],
['foo[]bar', 'forecolor', 'insertimage'],
['foo[]bar', 'forecolor', 'insertimage', 'inserttext'],
['foo[]bar', 'forecolor', 'insertlinebreak'],
['foo[]bar', 'forecolor', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'forecolor', 'insertorderedlist'],
['foo[]bar', 'forecolor', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'forecolor', 'insertparagraph'],
['foo[]bar', 'forecolor', 'insertparagraph', 'inserttext'],
['foo[]bar', 'forecolor', 'insertunorderedlist'],
['foo[]bar', 'forecolor', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'forecolor', 'justifycenter'],
['foo[]bar', 'forecolor', 'justifycenter', 'inserttext'],
['foo[]bar', 'forecolor', 'justifyfull'],
['foo[]bar', 'forecolor', 'justifyfull', 'inserttext'],
['foo[]bar', 'forecolor', 'justifyleft'],
['foo[]bar', 'forecolor', 'justifyleft', 'inserttext'],
['foo[]bar', 'forecolor', 'justifyright'],
['foo[]bar', 'forecolor', 'justifyright', 'inserttext'],
['foo[]bar', 'forecolor', 'outdent'],
['foo[]bar', 'forecolor', 'outdent', 'inserttext'],
['foo[]bar', 'hilitecolor', 'inserttext'],
['foo[]bar', 'hilitecolor', 'delete'],
['foo[]bar', 'hilitecolor', 'delete', 'inserttext'],
['foo[]bar', 'hilitecolor', 'formatblock'],
['foo[]bar', 'hilitecolor', 'formatblock', 'inserttext'],
['foo[]bar', 'hilitecolor', 'forwarddelete'],
['foo[]bar', 'hilitecolor', 'forwarddelete', 'inserttext'],
['foo[]bar', 'hilitecolor', 'indent'],
['foo[]bar', 'hilitecolor', 'indent', 'inserttext'],
['foo[]bar', 'hilitecolor', 'inserthorizontalrule'],
['foo[]bar', 'hilitecolor', 'inserthorizontalrule', 'inserttext'],
['foo[]bar', 'hilitecolor', 'inserthtml'],
['foo[]bar', 'hilitecolor', 'inserthtml', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertimage'],
['foo[]bar', 'hilitecolor', 'insertimage', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertlinebreak'],
['foo[]bar', 'hilitecolor', 'insertlinebreak', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertorderedlist'],
['foo[]bar', 'hilitecolor', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertparagraph'],
['foo[]bar', 'hilitecolor', 'insertparagraph', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertunorderedlist'],
['foo[]bar', 'hilitecolor', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'hilitecolor', 'justifycenter'],
['foo[]bar', 'hilitecolor', 'justifycenter', 'inserttext'],
['foo[]bar', 'hilitecolor', 'justifyfull'],
['foo[]bar', 'hilitecolor', 'justifyfull', 'inserttext'],
['foo[]bar', 'hilitecolor', 'justifyleft'],
['foo[]bar', 'hilitecolor', 'justifyleft', 'inserttext'],
['foo[]bar', 'hilitecolor', 'justifyright'],
['foo[]bar', 'hilitecolor', 'justifyright', 'inserttext'],
['foo[]bar', 'hilitecolor', 'outdent'],
['foo[]bar', 'hilitecolor', 'outdent', 'inserttext'],
// Test things that interfere with each other
['foo[]bar', 'superscript', 'subscript', 'inserttext'],
['foo[]bar', 'subscript', 'superscript', 'inserttext'],
['foo[]bar', 'createlink', ['forecolor', '#0000FF'], 'inserttext'],
['foo[]bar', ['forecolor', '#0000FF'], 'createlink', 'inserttext'],
['foo[]bar', 'createlink', ['forecolor', 'blue'], 'inserttext'],
['foo[]bar', ['forecolor', 'blue'], 'createlink', 'inserttext'],
['foo[]bar', 'createlink', ['forecolor', 'brown'], 'inserttext'],
['foo[]bar', ['forecolor', 'brown'], 'createlink', 'inserttext'],
['foo[]bar', 'createlink', ['forecolor', 'black'], 'inserttext'],
['foo[]bar', ['forecolor', 'black'], 'createlink', 'inserttext'],
['foo[]bar', 'createlink', 'underline', 'inserttext'],
['foo[]bar', 'underline', 'createlink', 'inserttext'],
['foo[]bar', 'createlink', 'underline', 'underline', 'inserttext'],
['foo[]bar', 'underline', 'underline', 'createlink', 'inserttext'],
['foo[]bar', 'subscript', ['fontsize', '2'], 'inserttext'],
['foo[]bar', ['fontsize', '2'], 'subscript', 'inserttext'],
['foo[]bar', 'subscript', ['fontsize', '3'], 'inserttext'],
['foo[]bar', ['fontsize', '3'], 'subscript', 'inserttext'],
['foo[]bar', ['hilitecolor', 'aqua'], ['backcolor', 'tan'], 'inserttext'],
['foo[]bar', ['backcolor', 'tan'], ['hilitecolor', 'aqua'], 'inserttext'],
// The following are all just inserttext tests that we took from there,
// but we first backspace the selected text instead of letting
// inserttext handle it. This tests that deletion correctly sets
// overrides.
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
['foo[bar] baz', 'delete', 'inserttext'],
// Now repeat but with different selections.
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['[foobar] baz', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
['foo[bar baz]', 'delete', 'inserttext'],
// https://bugs.webkit.org/show_bug.cgi?id=19702
['
[foo] ', 'delete', 'inserttext'],
],
//@}
};
tests.backcolor = tests.hilitecolor;
tests.insertlinebreak = tests.insertparagraph;
// Tests that start with "!" are believed to have bogus results and should be
// skipped until the relevant bugs are fixed.
var badTests = {};
(function(){
for (var command in tests) {
badTests[command] = [];
for (var i = 0; i < tests[command].length; i++) {
var test = tests[command][i];
if (typeof test == "string" && test[0] == "!") {
test = test.slice(1);
tests[command][i] = test;
badTests[command].push(test);
}
if (typeof test == "object" && test[0][0] == "!") {
test = [test[0].slice(1)].concat(test.slice(1));
tests[command][i] = test;
badTests[command].push(test);
}
}
}
})();
var defaultValues = {
//@{
backcolor: "#00FFFF",
createlink: "http://www.google.com/",
fontname: "sans-serif",
fontsize: "4",
forecolor: "#0000FF",
formatblock: "
",
hilitecolor: "#00FFFF",
inserthorizontalrule: "",
inserthtml: "ab
c d",
insertimage: "/img/lion.svg",
inserttext: "a",
defaultparagraphseparator: "div",
stylewithcss: "true",
usecss: "true",
};
//@}
var notes = {
//@{
fontname: 'Note that the body\'s font-family is "serif".',
};
//@}
var doubleTestingCommands = [
//@{
"backcolor",
"bold",
"fontname",
"fontsize",
"forecolor",
"italic",
"justifycenter",
"justifyfull",
"justifyleft",
"justifyright",
"strikethrough",
"stylewithcss",
"subscript",
"superscript",
"underline",
"usecss",
];
//@}
function prettyPrint(value) {
//@{
// Partly stolen from testharness.js
if (typeof value != "string") {
return String(value);
}
value = value.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"');
for (var i = 0; i < 32; i++) {
var replace = "\\";
switch (i) {
case 0: replace += "0"; break;
case 1: replace += "x01"; break;
case 2: replace += "x02"; break;
case 3: replace += "x03"; break;
case 4: replace += "x04"; break;
case 5: replace += "x05"; break;
case 6: replace += "x06"; break;
case 7: replace += "x07"; break;
case 8: replace += "b"; break;
case 9: replace += "t"; break;
case 10: replace += "n"; break;
case 11: replace += "v"; break;
case 12: replace += "f"; break;
case 13: replace += "r"; break;
case 14: replace += "x0e"; break;
case 15: replace += "x0f"; break;
case 16: replace += "x10"; break;
case 17: replace += "x11"; break;
case 18: replace += "x12"; break;
case 19: replace += "x13"; break;
case 20: replace += "x14"; break;
case 21: replace += "x15"; break;
case 22: replace += "x16"; break;
case 23: replace += "x17"; break;
case 24: replace += "x18"; break;
case 25: replace += "x19"; break;
case 26: replace += "x1a"; break;
case 27: replace += "x1b"; break;
case 28: replace += "x1c"; break;
case 29: replace += "x1d"; break;
case 30: replace += "x1e"; break;
case 31: replace += "x1f"; break;
}
value = value.replace(new RegExp(String.fromCharCode(i), "g"), replace);
}
return '"' + value + '"';
}
//@}
function doSetup(selector, idx) {
//@{
var table = document.querySelectorAll(selector)[idx];
var tr = document.createElement("tr");
table.firstChild.appendChild(tr);
tr.className = (tr.className + " active").trim();
return tr;
}
//@}
function queryOutputHelper(beforeIndeterm, beforeState, beforeValue,
afterIndeterm, afterState, afterValue,
command, value) {
//@{
var frag = document.createDocumentFragment();
var beforeDiv = document.createElement("div");
var afterDiv = document.createElement("div");
frag.appendChild(beforeDiv);
frag.appendChild(afterDiv);
beforeDiv.className = afterDiv.className = "extra-results";
beforeDiv.textContent = "Before: ";
afterDiv.textContent = "After: ";
beforeDiv.appendChild(document.createElement("span"));
afterDiv.appendChild(document.createElement("span"));
if ("indeterm" in commands[command]) {
// We only know it has to be either true or false.
if (beforeIndeterm !== true && beforeIndeterm !== false) {
beforeDiv.lastChild.className = "bad-result";
}
} else {
// It always has to be false.
beforeDiv.lastChild.className = beforeIndeterm === false
? "good-result"
: "bad-result";
}
// After running the command, indeterminate must always be false, except if
// it's an exception, or if it's insert*list and the state was true to
// begin with. And we can't help strikethrough/underline.
if ((/^insert(un)?orderedlist$/.test(command) && beforeState)
|| command == "strikethrough"
|| command == "underline") {
if (afterIndeterm !== true && afterIndeterm !== false) {
afterDiv.lastChild.className = "bad-result";
}
} else {
afterDiv.lastChild.className =
afterIndeterm === false
? "good-result"
: "bad-result";
}
beforeDiv.lastChild.textContent = "indeterm " + prettyPrint(beforeIndeterm);
afterDiv.lastChild.textContent = "indeterm " + prettyPrint(afterIndeterm);
beforeDiv.appendChild(document.createTextNode(", "));
afterDiv.appendChild(document.createTextNode(", "));
beforeDiv.appendChild(document.createElement("span"));
afterDiv.appendChild(document.createElement("span"));
if (/^insert(un)?orderedlist$/.test(command)) {
// If the before state is true, the after state could be either true or
// false. But if the before state is false, the after state has to be
// true.
if (beforeState !== true && beforeState !== false) {
beforeDiv.lastChild.className = "bad-result";
}
if (!beforeState) {
afterDiv.lastChild.className = afterState === true
? "good-result"
: "bad-result";
} else if (afterState !== true && afterState !== false) {
afterDiv.lastChild.className = "bad-result";
}
} else if (/^justify(center|full|left|right)$/.test(command)) {
// We don't know about the before state, but the after state is always
// supposed to be true.
if (beforeState !== true && beforeState !== false) {
beforeDiv.lastChild.className = "bad-result";
}
afterDiv.lastChild.className = afterState === true
? "good-result"
: "bad-result";
} else if (command == "strikethrough" || command == "underline") {
// The only thing we can say is the before/after states need to be
// either true or false.
if (beforeState !== true && beforeState !== false) {
beforeDiv.lastChild.className = "bad-result";
}
if (afterState !== true && afterState !== false) {
afterDiv.lastChild.className = "bad-result";
}
} else {
// The general rule is it must flip the state, unless there's no state
// defined, in which case it should always be false.
beforeDiv.lastChild.className =
afterDiv.lastChild.className =
("state" in commands[command] && typeof beforeState == "boolean" && typeof afterState == "boolean" && beforeState === !afterState)
|| (!("state" in commands[command]) && beforeState === false && afterState === false)
? "good-result"
: "bad-result";
}
beforeDiv.lastChild.textContent = "state " + prettyPrint(beforeState);
afterDiv.lastChild.textContent = "state " + prettyPrint(afterState);
beforeDiv.appendChild(document.createTextNode(", "));
afterDiv.appendChild(document.createTextNode(", "));
beforeDiv.appendChild(document.createElement("span"));
afterDiv.appendChild(document.createElement("span"));
// Direct equality comparison doesn't make sense in a bunch of cases.
if (command == "backcolor" || command == "forecolor" || command == "hilitecolor") {
if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
value = "#" + value;
}
} else if (command == "fontsize") {
value = normalizeFontSize(value);
if (value !== null) {
value = String(cssSizeToLegacy(value));
}
} else if (command == "formatblock") {
value = value.replace(/^<(.*)>$/, "$1").toLowerCase();
} else if (command == "defaultparagraphseparator") {
value = value.toLowerCase();
if (value != "p" && value != "div") {
value = "";
}
}
if (((command == "backcolor" || command == "forecolor" || command == "hilitecolor") && value.toLowerCase() == "currentcolor")
|| (command == "fontsize" && value === null)
|| (command == "formatblock" && formattableBlockNames.indexOf(value.replace(/^<(.*)>$/, "$1").trim()) == -1)
|| (command == "defaultparagraphseparator" && value == "")) {
afterDiv.lastChild.className = beforeValue === afterValue
? "good-result"
: "bad-result";
} else if (/^justify(center|full|left|right)$/.test(command)) {
// We know there are only four correct values beforehand, and afterward
// the value has to be the one we set.
if (!/^(center|justify|left|right)$/.test(beforeValue)) {
beforeDiv.lastChild.className = "bad-result";
}
var expectedValue = command == "justifyfull"
? "justify"
: command.replace("justify", "");
afterDiv.lastChild.className = afterValue === expectedValue
? "good-result"
: "bad-result";
} else if (!("value" in commands[command])) {
// If it's not defined we want "".
beforeDiv.lastChild.className = beforeValue === ""
? "good-result"
: "bad-result";
afterDiv.lastChild.className = afterValue === ""
? "good-result"
: "bad-result";
} else {
// And in all other cases, the value afterwards has to be the one we
// set.
afterDiv.lastChild.className =
areEquivalentValues(command, afterValue, value)
? "good-result"
: "bad-result";
}
beforeDiv.lastChild.textContent = "value " + prettyPrint(beforeValue);
afterDiv.lastChild.textContent = "value " + prettyPrint(afterValue);
return frag;
}
//@}
function normalizeTest(command, test, styleWithCss) {
//@{
// Our standard format for test processing is:
// [input HTML,
// [command1, value1, optional_name_mod],
// [command2, value2, optional_name_mod], ...]
// Where `optional_name_mod` is an optionally-specified string used when
// generating test names (necessary to ensure uniqueness for command
// sequences that use the same command multiple times). This format is
// verbose, so we actually use three different formats in the tests and
// multiTests arrays:
//
// 1) Plain string giving the input HTML. The command is implicit from the
// key of the tests array. If the command takes values, the value is given
// by defaultValues, otherwise it's "". Has to be converted to
// [input HTML, [command, value].
//
// 2) Two-element array [value, input HTML]. Has to be converted to
// [input HTML, [command, value]].
//
// 3) An element of multiTests. This just has to have values filled in.
//
// Optionally, a styleWithCss argument can be passed, either true or false.
// If it is, we'll prepend a styleWithCss invocation.
if (command == "multitest") {
if (typeof test == "string") {
test = JSON.parse(test);
}
for (var i = 1; i < test.length; i++) {
if (typeof test[i] == "string"
&& test[i] in defaultValues) {
test[i] = [test[i], defaultValues[test[i]]];
} else if (typeof test[i] == "string") {
test[i] = [test[i], ""];
}
}
return test;
}
if (typeof test == "string") {
if (command in defaultValues) {
test = [test, [command, defaultValues[command]]];
} else {
test = [test, [command, ""]];
}
} else if (test.length == 2) {
test = [test[1], [command, String(test[0])]];
}
if (styleWithCss !== undefined) {
test.splice(1, 0, ["stylewithcss", String(styleWithCss)]);
}
return test;
}
//@}
function doInputCell(tr, test, command) {
//@{
var testHtml = test[0];
var msg = null;
if (command in defaultValues) {
// Single command with a value, possibly with a styleWithCss stuck
// before. We don't need to specify the command itself, since this
// presumably isn't in multiTests, so the command is already given by
// the section header.
msg = 'value: ' + prettyPrint(test[test.length - 1][1]);
} else if (command == "multitest") {
// Uses a different input format
msg = JSON.stringify(test);
}
var inputCell = document.createElement("td");
inputCell.innerHTML = "
";
inputCell.firstChild.innerHTML = testHtml;
inputCell.lastChild.textContent = inputCell.firstChild.innerHTML;
if (msg !== null) {
inputCell.lastChild.textContent += " (" + msg + ")";
}
tr.appendChild(inputCell);
}
//@}
function doSpecCell(tr, test, command) {
//@{
var specCell = document.createElement("td");
tr.appendChild(specCell);
try {
var points = setupCell(specCell, test[0]);
var range = document.createRange();
range.setStart(points[0], points[1]);
range.setEnd(points[2], points[3]);
// The points might be backwards
if (range.collapsed) {
range.setEnd(points[0], points[1]);
}
specCell.firstChild.contentEditable = "true";
specCell.firstChild.spellcheck = false;
if (command != "multitest") {
try { var beforeIndeterm = myQueryCommandIndeterm(command, range) }
catch(e) { beforeIndeterm = "Exception" }
try { var beforeState = myQueryCommandState(command, range) }
catch(e) { beforeState = "Exception" }
try { var beforeValue = myQueryCommandValue(command, range) }
catch(e) { beforeValue = "Exception" }
}
for (var i = 1; i < test.length; i++) {
myExecCommand(test[i][0], false, test[i][1], range);
}
if (command != "multitest") {
try { var afterIndeterm = myQueryCommandIndeterm(command, range) }
catch(e) { afterIndeterm = "Exception" }
try { var afterState = myQueryCommandState(command, range) }
catch(e) { afterState = "Exception" }
try { var afterValue = myQueryCommandValue(command, range) }
catch(e) { afterValue = "Exception" }
}
specCell.firstChild.contentEditable = "inherit";
specCell.firstChild.removeAttribute("spellcheck");
var compareDiv1 = specCell.firstChild.cloneNode(true);
// Now do various sanity checks, and throw if they're violated. First
// just count children:
if (specCell.childNodes.length != 2) {
throw "The cell didn't have two children. Did something spill outside the test div?";
}
// Now verify that the DOM serializes.
compareDiv1.normalize();
var compareDiv2 = compareDiv1.cloneNode(false);
compareDiv2.innerHTML = compareDiv1.innerHTML;
// Oddly, IE9 sometimes produces two nodes that return true for
// isEqualNode but have different innerHTML (omitting closing tags vs.
// not).
if (!compareDiv1.isEqualNode(compareDiv2)
&& compareDiv1.innerHTML != compareDiv2.innerHTML) {
throw "DOM does not round-trip through serialization! "
+ compareDiv1.innerHTML + " vs. " + compareDiv2.innerHTML;
}
if (!compareDiv1.isEqualNode(compareDiv2)) {
throw "DOM does not round-trip through serialization (although innerHTML is the same)! "
+ compareDiv1.innerHTML;
}
// Check for attributes
if (specCell.firstChild.attributes.length) {
throw "Wrapper div has attributes! " +
specCell.innerHTML.replace(/
<\/div>$/, "");
}
// Final sanity check: make sure everything isAllowedChild() of its
// parent.
getDescendants(specCell.firstChild).forEach(function(descendant) {
if (!isAllowedChild(descendant, descendant.parentNode)) {
throw "Something here is not an allowed child of its parent: " + descendant;
}
});
addBrackets(range);
specCell.lastChild.textContent = specCell.firstChild.innerHTML;
if (command != "multitest") {
specCell.lastChild.appendChild(queryOutputHelper(
beforeIndeterm, beforeState, beforeValue,
afterIndeterm, afterState, afterValue,
command, test[test.length - 1][1]));
if (specCell.querySelector(".bad-result")) {
specCell.parentNode.className = "alert";
}
}
} catch (e) {
specCell.firstChild.contentEditable = "inherit";
specCell.firstChild.removeAttribute("spellcheck");
specCell.lastChild.textContent = "Exception: " + formatException(e);
specCell.parentNode.className = "alert";
specCell.lastChild.className = "alert";
// Don't bother comparing to localStorage, this is always wrong no
// matter what.
return;
}
if (command != "multitest") {
// Old storage format
var key = "execcommand-" + command
+ "-" + (test.length == 2 || test[1][1] == "false" ? "0" : "1")
+ "-" + tr.firstChild.lastChild.textContent;
} else {
var key = "execcommand-" + JSON.stringify(test);
}
// Use getItem() instead of direct property access to work around Firefox
// bug: https://bugzilla.mozilla.org/show_bug.cgi?id=532062
var oldValue = localStorage.getItem(key);
var newValue = specCell.lastChild.firstChild.textContent;
// Ignore differences between {} and [].
if (oldValue === null
|| oldValue.replace("{}", "[]") !== newValue.replace("{}", "[]")) {
specCell.parentNode.className = "alert";
var alertDiv = document.createElement("div");
specCell.lastChild.appendChild(alertDiv);
alertDiv.className = "alert";
if (oldValue === null) {
alertDiv.textContent = "Newly added test result";
} else if (oldValue.replace(/[\[\]{}]/g, "") == newValue.replace(/[\[\]{}]/g, "")) {
alertDiv.textContent = "Last run produced a different selection: " + oldValue;
} else {
alertDiv.textContent = "Last run produced different markup: " + oldValue;
}
var button = document.createElement("button");
alertDiv.appendChild(button);
button.textContent = "Store new result";
button.className = "store-new-result";
button.onclick = (function(key, val, alertDiv) { return function() {
localStorage[key] = val;
// Make it easier to do mass updates, and also to jump to the next
// new result
var buttons = document.getElementsByClassName("store-new-result");
for (var i = 0; i < buttons.length; i++) {
if (isDescendant(buttons[i], alertDiv)
&& i + 1 < buttons.length) {
buttons[i + 1].focus();
break;
}
}
var td = alertDiv;
while (td.tagName != "TD") {
td = td.parentNode;
}
alertDiv.parentNode.removeChild(alertDiv);
if (!td.querySelector(".alert")) {
td.parentNode.className = (" " + td.parentNode.className + " ")
.replace(/ alert /g, "")
.replace(/^ | $/g, "");
}
} })(key, newValue, alertDiv);
}
}
//@}
function browserCellException(e, testDiv, browserCell) {
//@{
if (testDiv) {
testDiv.contenteditable = "inherit";
testDiv.removeAttribute("spellcheck");
}
browserCell.lastChild.className = "alert";
browserCell.lastChild.textContent = "Exception: " + formatException(e);
if (testDiv && testDiv.parentNode != browserCell) {
browserCell.insertBefore(testDiv, browserCell.firstChild);
}
}
//@}
function formatException(e) {
//@{
if (typeof e == "object" && "stack" in e) {
return e + " (stack: " + e.stack + ")";
}
return String(e);
}
//@}
function doSameCell(tr) {
//@{
tr.className = (" " + tr.className + " ").replace(" active ", "").trim();
if (tr.className == "") {
tr.removeAttribute("class");
}
var sameCell = document.createElement("td");
if (!document.querySelector("#browser-checkbox").checked) {
sameCell.className = "maybe";
sameCell.textContent = "?";
} else {
var exception = false;
try {
// Ad hoc normalization to avoid basically spurious mismatches. For
// now this includes ignoring where the selection goes.
var normalizedSpecCell = tr.childNodes[1].lastChild.firstChild.textContent
.replace(/[[\]{}]/g, "")
.replace(/ style="margin: 0 0 0 40px; border: none; padding: 0px;"/g, '')
.replace(/ style="margin-right: 0px;" dir="ltr"/g, '')
.replace(/ style="margin-left: 0px;" dir="rtl"/g, '')
.replace(/ style="margin-(left|right): 40px;"/g, '')
.replace(/: /g, ":")
.replace(/;? ?"/g, '"')
.replace(/<(\/?)strong/g, '<$1b')
.replace(/<(\/?)strike/g, '<$1s')
.replace(/<(\/?)em/g, '<$1i')
.replace(/#[0-9a-fA-F]{6}/g, function(match) { return match.toUpperCase(); });
var normalizedBrowserCell = tr.childNodes[2].lastChild.firstChild.textContent
.replace(/[[\]{}]/g, "")
.replace(/ style="margin: 0 0 0 40px; border: none; padding: 0px;"/g, '')
.replace(/ style="margin-right: 0px;" dir="ltr"/g, '')
.replace(/ style="margin-left: 0px;" dir="rtl"/g, '')
.replace(/ style="margin-(left|right): 40px;"/g, '')
.replace(/: /g, ":")
.replace(/;? ?"/g, '"')
.replace(/<(\/?)strong/g, '<$1b')
.replace(/<(\/?)strike/g, '<$1s')
.replace(/<(\/?)em/g, '<$1i')
.replace(/#[0-9a-fA-F]{6}/g, function(match) { return match.toUpperCase(); })
.replace(/ size="2" width="100%"/g, '');
if (navigator.userAgent.indexOf("MSIE") != -1) {
// IE produces
instead of , so let's
// translate all s to s.
normalizedSpecCell = normalizedSpecCell
.replace(/<(\/?)span/g, '<$1font');
normalizedBrowserCell = normalizedBrowserCell
.replace(/<(\/?)span/g, '<$1font');
}
} catch (e) {
exception = true;
}
if (!exception && normalizedSpecCell == normalizedBrowserCell) {
sameCell.className = "yes";
sameCell.textContent = "\u2713";
} else {
sameCell.className = "no";
sameCell.textContent = "\u2717";
}
}
tr.appendChild(sameCell);
for (var i = 0; i <= 2; i++) {
// Insert so IE doesn't stretch the screen. This is considerably
// more complicated than it has to be, thanks to Firefox's lack of
// support for outerHTML.
var div = tr.childNodes[i].lastChild;
if (div.firstChild) {
var text = div.firstChild.textContent;
div.removeChild(div.firstChild);
div.insertBefore(document.createElement("div"), div.firstChild);
div.firstChild.innerHTML = text
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/</g, "<");
while (div.firstChild.hasChildNodes()) {
div.insertBefore(div.firstChild.lastChild, div.firstChild.nextSibling);
}
div.removeChild(div.firstChild);
}
// Add position: absolute span to not affect vertical layout
getDescendants(tr.childNodes[i].firstChild)
.filter(function(node) {
return node.nodeType == Node.TEXT_NODE
&& /^(\{\}?|\})$/.test(node.data);
}).forEach(function(node) {
var span = document.createElement("span");
span.style.position = "absolute";
span.textContent = node.data;
node.parentNode.insertBefore(span, node);
node.parentNode.removeChild(node);
});
}
}
//@}
function doTearDown(command) {
//@{
getSelection().removeAllRanges();
}
//@}
function setupCell(cell, html) {
//@{
cell.innerHTML = "
";
return setupDiv(cell.firstChild, html);
}
//@}
function setupDiv(node, html) {
//@{
// A variety of checks to avoid simple errors. Not foolproof, of course.
var re = /\{|\[|data-start/g;
var markers = [];
var marker;
while (marker = re.exec(html)) {
markers.push(marker);
}
if (markers.length != 1) {
throw "Need exactly one start marker ([ or { or data-start), found " + markers.length;
}
var re = /\}|\]|data-end/g;
var markers = [];
var marker;
while (marker = re.exec(html)) {
markers.push(marker);
}
if (markers.length != 1) {
throw "Need exactly one end marker (] or } or data-end), found " + markers.length;
}
node.innerHTML = html;
var startNode, startOffset, endNode, endOffset;
// For braces that don't lie inside text nodes, we can't just set
// innerHTML, because that might disturb the DOM. For instance, if the
// brace is right before a , it could get moved outside the table
// entirely, which messes everything up pretty badly. So we instead
// allow using data attributes: data-start and data-end on the start and
// end nodes, with a numeric value indicating the offset. This format
// doesn't allow the parent div to be a start or end node, but in that case
// you can always use the curly braces.
if (node.querySelector("[data-start]")) {
startNode = node.querySelector("[data-start]");
startOffset = startNode.getAttribute("data-start");
startNode.removeAttribute("data-start");
}
if (node.querySelector("[data-end]")) {
endNode = node.querySelector("[data-end]");
endOffset = endNode.getAttribute("data-end");
endNode.removeAttribute("data-end");
}
var cur = node;
while (true) {
if (!cur || (cur != node && !(cur.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINS))) {
break;
}
if (cur.nodeType != Node.TEXT_NODE) {
cur = nextNode(cur);
continue;
}
var data = cur.data.replace(/\]/g, "");
var startIdx = data.indexOf("[");
data = cur.data.replace(/\[/g, "");
var endIdx = data.indexOf("]");
cur.data = cur.data.replace(/[\[\]]/g, "");
if (startIdx != -1) {
startNode = cur;
startOffset = startIdx;
}
if (endIdx != -1) {
endNode = cur;
endOffset = endIdx;
}
// These are only legal as the first or last
data = cur.data.replace(/\}/g, "");
var elStartIdx = data.indexOf("{");
data = cur.data.replace(/\{/g, "");
var elEndIdx = data.indexOf("}");
if (elStartIdx == 0) {
startNode = cur.parentNode;
startOffset = getNodeIndex(cur);
} else if (elStartIdx != -1) {
startNode = cur.parentNode;
startOffset = getNodeIndex(cur) + 1;
}
if (elEndIdx == 0) {
endNode = cur.parentNode;
endOffset = getNodeIndex(cur);
} else if (elEndIdx != -1) {
endNode = cur.parentNode;
endOffset = getNodeIndex(cur) + 1;
}
cur.data = cur.data.replace(/[{}]/g, "");
if (!cur.data.length) {
if (cur == startNode || cur == endNode) {
throw "You put a square bracket where there was no text node . . .";
}
var oldCur = cur;
cur = nextNode(cur);
oldCur.parentNode.removeChild(oldCur);
} else {
cur = nextNode(cur);
}
}
return [startNode, startOffset, endNode, endOffset];
}
//@}
function setSelection(startNode, startOffset, endNode, endOffset) {
//@{
if (navigator.userAgent.indexOf("Opera") != -1) {
// Yes, browser sniffing is evil, but I can't be bothered to debug
// Opera.
var range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
if (range.collapsed) {
range.setEnd(startNode, startOffset);
}
getSelection().removeAllRanges();
getSelection().addRange(range);
} else if ("extend" in getSelection()) {
// WebKit behaves unreasonably for collapse(), so do that manually.
/*
var range = document.createRange();
range.setStart(startNode, startOffset);
getSelection().removeAllRanges();
getSelection().addRange(range);
*/
getSelection().collapse(startNode, startOffset);
getSelection().extend(endNode, endOffset);
} else {
// IE9. Selections have no direction, so we just make the selection
// always forwards.
var range;
if (getSelection().rangeCount) {
range = getSelection().getRangeAt(0);
} else {
range = document.createRange();
}
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
if (range.collapsed) {
// Phooey, we got them backwards.
range.setEnd(startNode, startOffset);
}
if (!getSelection().rangeCount) {
getSelection().addRange(range);
}
}
}
//@}
/**
* Add brackets at the start and end points of the given range, so that they're
* visible.
*/
function addBrackets(range) {
//@{
// Handle the collapsed case specially, to avoid confusingly getting the
// markers backwards in some cases
if (range.startContainer.nodeType == Node.TEXT_NODE
|| range.startContainer.nodeType == Node.COMMENT_NODE) {
if (range.collapsed) {
range.startContainer.insertData(range.startOffset, "[]");
} else {
range.startContainer.insertData(range.startOffset, "[");
}
} else {
var marker = range.collapsed ? "{}" : "{";
if (range.startOffset != range.startContainer.childNodes.length
&& range.startContainer.childNodes[range.startOffset].nodeType == Node.TEXT_NODE) {
range.startContainer.childNodes[range.startOffset].insertData(0, marker);
} else if (range.startOffset != 0
&& range.startContainer.childNodes[range.startOffset - 1].nodeType == Node.TEXT_NODE) {
range.startContainer.childNodes[range.startOffset - 1].appendData(marker);
} else {
// Seems to serialize as I'd want even for tables . . . IE doesn't
// allow undefined to be passed as the second argument (it throws
// an exception), so we have to explicitly check the number of
// children and pass null.
range.startContainer.insertBefore(document.createTextNode(marker),
range.startContainer.childNodes.length == range.startOffset
? null
: range.startContainer.childNodes[range.startOffset]);
}
}
if (range.collapsed) {
return;
}
if (range.endContainer.nodeType == Node.TEXT_NODE
|| range.endContainer.nodeType == Node.COMMENT_NODE) {
range.endContainer.insertData(range.endOffset, "]");
} else {
if (range.endOffset != range.endContainer.childNodes.length
&& range.endContainer.childNodes[range.endOffset].nodeType == Node.TEXT_NODE) {
range.endContainer.childNodes[range.endOffset].insertData(0, "}");
} else if (range.endOffset != 0
&& range.endContainer.childNodes[range.endOffset - 1].nodeType == Node.TEXT_NODE) {
range.endContainer.childNodes[range.endOffset - 1].appendData("}");
} else {
range.endContainer.insertBefore(document.createTextNode("}"),
range.endContainer.childNodes.length == range.endOffset
? null
: range.endContainer.childNodes[range.endOffset]);
}
}
}
//@}
function normalizeSerializedStyle(wrapper) {
//@{
// Inline CSS attribute serialization has terrible interop, so we fix
// things up a bit to avoid spurious mismatches. This needs to be removed
// once CSSOM defines this stuff properly, but for now there's just no
// standard for any of it. This only normalizes descendants of wrapper,
// not wrapper itself.
[].forEach.call(wrapper.querySelectorAll("[style]"), function(node) {
if (node.style.color != "") {
var newColor = normalizeColor(node.style.color);
node.style.color = "";
node.style.color = newColor;
}
if (node.style.backgroundColor != "") {
var newBackgroundColor = normalizeColor(node.style.backgroundColor);
node.style.backgroundColor = "";
node.style.backgroundColor = newBackgroundColor;
}
node.setAttribute("style", node.getAttribute("style")
// Random spacing differences
.replace(/; ?$/, "")
.replace(/: /g, ":")
// Gecko likes "transparent"
.replace(/transparent/g, "rgba(0, 0, 0, 0)")
// WebKit likes to look overly precise
.replace(/, 0.496094\)/g, ", 0.5)")
// Gecko converts anything with full alpha to "transparent" which
// then becomes "rgba(0, 0, 0, 0)", so we have to make other
// browsers match
.replace(/rgba\([0-9]+, [0-9]+, [0-9]+, 0\)/g, "rgba(0, 0, 0, 0)")
);
});
}
//@}
/**
* Input is in the following format:
* [input HTML,
* array of commands,
* expected output HTML,
* array of expected execCommand() return values,
* object of expected indeterm/state/value].
* The array of commands is [[command, value, optionalDesc], [command, value,
* optionalDesc], ...]. optionalDesc is appended to the description of the
* test in the generated test name.
*
* The
* array of expected execCommand() return values is [true|false, true|false,
* ...], where the indices match those in the array of commands. The
* indeterm/state/value object is of the form
* {command: [expected indeterm before, expected state before,
* expected value before, expected indeterm after,
* expected state after, expected value after],
* command: ... }
* null for any of the last six entries means an INVALID_ACCESS_ERR must be
* raised.
*/
function runConformanceTest(browserTest) {
//@{
document.getElementById("test-container").innerHTML = "
test";
var testName = JSON.stringify(browserTest[1]) + " " + format_value(browserTest[0]);
var testDiv = document.querySelector("div[contenteditable]");
var originalRootElement, newRootElement;
var exception = null;
var expectedExecCommandReturnValues = browserTest[3];
var expectedQueryResults = browserTest[4];
var actualQueryResults = {};
var actualQueryExceptions = {};
var subtestName;
try {
var points = setupDiv(testDiv, browserTest[0]);
var range = document.createRange();
range.setStart(points[0], points[1]);
range.setEnd(points[2], points[3]);
// The points might be backwards
if (range.collapsed) {
range.setEnd(points[0], points[1]);
}
getSelection().removeAllRanges();
getSelection().addRange(range);
var originalRootElement = document.documentElement.cloneNode(true);
originalRootElement.querySelector("[contenteditable]").parentNode
.removeChild(originalRootElement.querySelector("[contenteditable]"));
originalRootElement.querySelector("#log").parentNode
.removeChild(originalRootElement.querySelector("#log"));
for (var command in expectedQueryResults) {
var results = [];
var exceptions = {};
try { results[0] = document.queryCommandIndeterm(command) }
catch(e) { exceptions[0] = e }
try { results[1] = document.queryCommandState(command) }
catch(e) { exceptions[1] = e }
try { results[2] = document.queryCommandValue(command) }
catch(e) { exceptions[2] = e }
actualQueryResults[command] = results;
actualQueryExceptions[command] = exceptions;
}
} catch(e) {
exception = e;
}
for (var i = 0; i < browserTest[1].length; i++) {
subtestName = testName + ": execCommand(" +
format_value(browserTest[1][i][0]) + ", false, " +
format_value(browserTest[1][i][1]) + ") " +
(browserTest[1][i][2] ? browserTest[1][i][2] + " " : "") +
"return value"
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
assert_equals(document.execCommand(browserTest[1][i][0], false, browserTest[1][i][1]),
expectedExecCommandReturnValues[i]);
}, subtestName);
}
if (exception === null) {
try {
for (var command in expectedQueryResults) {
var results = actualQueryResults[command];
var exceptions = actualQueryExceptions[command];
try { results[3] = document.queryCommandIndeterm(command) }
catch(e) { exceptions[3] = e }
try { results[4] = document.queryCommandState(command) }
catch(e) { exceptions[4] = e }
try { results[5] = document.queryCommandValue(command) }
catch(e) { exceptions[5] = e }
}
var newRootElement = document.documentElement.cloneNode(true);
newRootElement.querySelector("[contenteditable]").parentNode
.removeChild(newRootElement.querySelector("[contenteditable]"));
newRootElement.querySelector("#log").parentNode
.removeChild(newRootElement.querySelector("#log"));
normalizeSerializedStyle(testDiv);
} catch(e) {
exception = e;
}
}
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
// Now test for modifications to non-editable content. First just
// count children:
assert_equals(testDiv.parentNode.childNodes.length, 2,
"The parent div must have two children. Did something spill outside the test div?");
// Check for attributes
assert_equals(testDiv.attributes.length, 1,
'Wrapper div must have only one attribute (
), but has more (' +
formatStartTag(testDiv) + ")");
assert_equals(document.body.attributes.length, 0,
"Body element must have no attributes (), but has more (" +
formatStartTag(document.body) + ")");
// Check that in general, nothing outside the test div was modified.
// TODO: Less verbose error reporting, the way some of the range tests
// do?
assert_equals(newRootElement.innerHTML, originalRootElement.innerHTML,
"Everything outside the editable div must be unchanged, but some change did occur");
}, testName + " checks for modifications to non-editable content");
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
if (Array.isArray(browserTest[2])) {
var expectedInnerHTMLArray = [];
browserTest[2].forEach(function (expectedInnerHTML) {
expectedInnerHTMLArray.push(expectedInnerHTML.replace(/[\[\]{}]/g, ""));
});
assert_in_array(testDiv.innerHTML,
expectedInnerHTMLArray,
"Unexpected innerHTML (after normalizing inline style)");
} else {
assert_equals(testDiv.innerHTML,
browserTest[2].replace(/[\[\]{}]/g, ""),
"Unexpected innerHTML (after normalizing inline style)");
}
}, testName + " compare innerHTML");
for (var command in expectedQueryResults) {
var descriptions = [
'queryCommandIndeterm("' + command + '") before',
'queryCommandState("' + command + '") before',
'queryCommandValue("' + command + '") before',
'queryCommandIndeterm("' + command + '") after',
'queryCommandState("' + command + '") after',
'queryCommandValue("' + command + '") after',
];
for (var i = 0; i < 6; i++) {
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
if (expectedQueryResults[command][i] === null) {
// Some ad hoc tests to verify that we have a real
// DOMException. FIXME: This should be made more rigorous,
// with clear steps specified for checking that something
// is really a DOMException.
assert_true(i in actualQueryExceptions[command],
"An exception must be thrown in this case");
var e = actualQueryExceptions[command][i];
assert_equals(typeof e, "object",
"typeof thrown object");
assert_idl_attribute(e, "code",
"Thrown object must be a DOMException");
assert_idl_attribute(e, "INVALID_ACCESS_ERR",
"Thrown object must be a DOMException");
assert_equals(e.code, e.INVALID_ACCESS_ERR,
"Thrown object must be an INVALID_ACCESS_ERR, so its .code and .INVALID_ACCESS_ERR attributes must be equal");
} else if ((i == 2 || i == 5)
&& (command == "backcolor" || command == "forecolor" || command == "hilitecolor")
&& typeof actualQueryResults[command][i] == "string") {
assert_false(i in actualQueryExceptions[command],
"An exception must not be thrown in this case");
// We don't return the format that the color should be in:
// that's up to CSSOM. Thus we normalize before comparing.
assert_equals(normalizeColor(actualQueryResults[command][i]),
expectedQueryResults[command][i],
"Wrong result returned (after color normalization)");
} else {
assert_false(i in actualQueryExceptions[command],
"An exception must not be thrown in this case");
assert_equals(actualQueryResults[command][i],
expectedQueryResults[command][i],
"Wrong result returned");
}
}, testName + " " + descriptions[i]);
}
}
// Silly Firefox
document.body.removeAttribute("bgcolor");
}
//@}
/**
* Return a string like ''.
*/
function formatStartTag(el) {
//@{
var ret = "<" + el.tagName.toLowerCase();
for (var i = 0; i < el.attributes.length; i++) {
ret += " " + el.attributes[i].name + '="';
ret += el.attributes[i].value.replace(/\&/g, "&")
.replace(/"/g, """);
ret += '"';
}
return ret + ">";
}
//@}
// vim: foldmarker=@{,@} foldmethod=marker