[whatwg] [editing] HTML Editing APIs specification ready for implementer feedback

Aryeh Gregor Simetrical+w3c at gmail.com
Thu Jul 28 13:17:34 PDT 2011

Thanks to both of you for the feedback!

On Wed, Jul 27, 2011 at 7:51 PM, Ryosuke Niwa <rniwa at webkit.org> wrote:
> WebKit treats any font-weight above or equal to 600 as bold because that's
> what user sees, and boldness is a binary concept in execCommand; Firefox 5
> appears to do the same.

Yes, bold is not a big problem.  If you look at "the bold command"
section, it explicitly defines the values "bold", "600", "700", "800",
or "900" as corresponding to "on", so it's simple string comparison.
The bigger problem is things like colors and sizes, where there are
lots of units that are related in complicated ways.

What I'd really like to do is have CSSOM define a reliable way of
uniquely serializing CSS values, and then say that two values are
equal if they serialize to the same thing.  But I guess for now I
should just make up my own definition.  For most things it's pretty
straightforward in principle, but it still needs to be specced.

> WebKit compares colors in rgb/rgba format; e.g. red is first parsed as
> rgb(255, 0, 0).  Firefox 5 seems to does the same as well.

Yeah, that's the obvious way to do it.  If I have to write the
definition for this, I guess I'll just say two CSS colors are equal if
their R/G/B/A channels are all equal.

> WebKit compares font sizes in legacy font size used in font element;
> See CSSStyleSelector::legacyFontSize or legacyFontSizeFromCSSValue in
> EditingStyle.cpp

I more or less reverse-engineered that to define
queryCommandValue("fontSize") -- translate the computed font-size to
pixels, then round to the nearest corresponding legacy font size.
Other browsers do different things that are less useful.  But there
are cases when I want to compare CSS values for equality more
precisely.  For instance, per spec, if you have

<span style=font-size:large>foo[bar]baz</span>

and run execCommand("fontSize", false, "4"), it does nothing.  WebKit
seems to break up the span and add a new span or font element, but
this adds extra clutter.  However, if you have

<span style=font-size:18px>foo[bar]baz</span>

then the spec says to break up the span, because 18px != large, even
though queryCommandValue() says the same thing for both.

> Throwing SYNTAX_ERR might cause a backward compatibility issue because the
> UAs don't throw an error now.  We can probably throwing console messages
> first to give authors some grace period to transition.

Yeah, this was a bad idea.  The only case where anyone throws
exceptions for bad values is Opera with formatBlock.  I've removed


Don't know why I added it in the first place.

> For font element vs. span with style issue, we could add another boolean
> flag that forces UAs to toggle font-element; i.e. add StyleWithFont command.

I guess.

> 3.2: Prefix "webkit-" doesn't seem natural given all editing commands use
> Camel case.  Maybe Ms, Gecko, WebKit and Opera?  e.g. WebKitFontSizeDelta.
>  But again this might cause a backward compatibility because we do implement
> few editing commands that are not in the spec and they are not prefixed.

I copied this from HTML5, and I think at least Opera has some commands
with this syntax, but you're right it doesn't make much sense.  I've
changed it: http://aryeh.name/gitweb.cgi?p=editing;a=commitdiff;h=e9369d6c

> 3.3: The return value of queryCommandEnable depends on beforecut,
> beforecopy, and beforepaste events and selection state in WebKit; WebKit
> returns false if default actions are prevented in those events or selection
> is not a range.  Firefox 5 appears to do the same for selection but doesn't
> seem to fire beforecut, beforecopy, and beforepaste.

How does WebKit know if those events will be prevented or not, without
running the handlers?  If the page runs queryCommandEnabled(), nothing
actually happened, so surely WebKit doesn't fire any events?  Also,
are you only talking about the cut/copy/paste commands, or other
commands too?

On Thu, Jul 28, 2011 at 7:06 AM, Michael A. Puls II
<shadow2531 at gmail.com> wrote:
> At the end of section 4, there's:
>> the state of insertOrderedList and insertOrderedList might be true both
>> before and after calling
> Is one of those supposed to be insertUnorderedList?

Yeah, thanks.  Fixed:


> At the beginning of section 5, there's:
>> An editing host is a node that is either an Element with a contenteditable
>> attribute set to the true state, or the Element child of a Document whose
>> designMode is enabled.
> What does "Element child" refer to specifically in the latter? Is it the
> HTML body element or is that implementation-specific?

It just means what the literal words imply: any Element that is the
child of a Document whose designMode is enabled.  The Nodes model
implies that any Document will always have either zero or one child
that's an Element.  If one exists, it will be returned by
document.documentElement.  For HTML documents, the Element child of a
Document is generally <html>, although you could change it with DOM
manipulation if you really wanted.

(I noticed that the word "child" wasn't linked here, and I fixed that,
although I don't think that's what caused your confusion.)

> Still in section 5:
>> A collapsed line break is a br that begins a line box which has nothing
>> else in it, and therefore has zero height.
>> An extraneous line break is a br that has no visual effect, in that
>> removing it from the DOM would not change layout, except that a br that is
>> the sole child of an li is not extraneous.
>> Is this a good definition at all?
> Don't really have much opinion on the names or the definition.
> Which one refers to a <br> that acts like a placeholder for a line (so the
> line is selectable) where the <br> disappears once the user starts editing
> that line or closes the paragraph?

That would be "collapsed block prop", which is admittedly a terrible
term whose definition is confusing.  I added a note to clarify what
the intent is:


> At the end of section 5:
>> When the user agent is instructed to run a particular method, it must
>> follow the steps defined for that method in the appropriate specification,
>> not act as though the method had actually been called from JavaScript. In
>> particular, if the author has overridden the method with a custom method,
>> the standard method must be run rather than the custom one.
> Is this saying that doing something like:
> HTMLDocument.prototype.execCommand = function(a, b, c) {
>    // stuff
> };
> , will have no effect or should throw an error or something?

It's saying that even if the author does that, when the spec says to
do execCommand("foo"), it has to use the real implementation and not
the author-overridden one.  For instance, I often say things like "Let
replacement element be the result of calling createElement(new name)
on the ownerDocument of element", so this means that even if you
replace createElement(), it will still act like it called the original
unreplaced one.  DOM Range uses similar terminology.  An alternative
approach would be to make sure there are unambiguous ways of saying
the same thing in prose, but that doesn't scale well in my experience.

I tried to clarify:


Does that seem better?

> If so, is this just matching what browsers do now or just something you
> think is a good thing to prevent?

This is what browsers do now.  I'm just clarifying what the spec
means, not requiring specific author-visible behavior.

> I pretty much translate that as:
> var replacementElement = document.createElement("differentTagName");
> parent.insertBefore(replacementElement, element);
> for (var i = 0; i < element.attributes.length; ++i) {
>    replacementElement.setAttribute(element.attributes[i].name,
> element.attributes[i].value);
> }
> while (element.hasChildNodes()) {
>    replacementElement.appendChild(element.removeChild(element.lastChild));
> }
> parent.removeChild(element);
> That seems to be removing attributes and nodes from one element and
> appending them to another while they're both being displayed in the parent.

Essentially, yes, but you missed the "preserving ranges" part.  You
can see my implementation here:


Note that browsers don't repaint until the event loop spins, so the
intermediate state here should never be visible to the user.  Opera
currently repaints sometimes event between event loop spins, but
that's probably a bug, and anyway I doubt they'll repaint in the
middle of an execCommand() execution.

> Do you intend for that to be strictly done like that or is doing it a
> different way (like copying to the replacementElement in the DOM and then
> doing a replace) allowed as long as it gives the same end result? Or, will
> that mess up the range preservation?

The way I've currently specced it, it has to be done in that order or
else the "preserving ranges" part won't work.  It would be possible
for me to rework that if necessary.  UAs can always do whatever they
want as long as the results are black-box identical, of course.

More information about the whatwg mailing list