== Research on execCommand() users == vBulletin (http://www.vbulletin.com/forum/clientscript/vbulletin_textedit.js): * Link given now actually goes to a copy of CKEditor, since they realized rolling their own editor wasn't a good idea. This applies more to older versions. * Lots and lots and lots of browser sniffing. Only appears to support IE, Firefox, Opera. * Forces CSS mode off: if (is_moz) this.editdoc.execCommand('useCSS', false, true); * Wraps insertLink to unlink the selection first * Wraps various commands to insert HTML at the end of the document if there's no selection, instead of (I guess) doing nothing * Consistently uses getRangeAt(0) to get the corresponding range, as though it assumes that's the active range; in fact the affected range will be the last one, typically, not the first, if there are multiple ranges. Also uses addRange() as though it will change the selection instead of expanding it. This combination seems likely to cause some bugs in Firefox. They mostly use their own add_range() function as a Selection.selectAllChildren() workalike, but in at least one place they use straight addRange(), probably by mistake. * Assumes all nodes are either element or text, in at least one place * Goes to some trouble to do insertImage but then add attributes; maybe this is worth natively supporting somehow? Something like insertNode? (Or does that already exist?) * Constantly calls a function check_focus(), which mostly just does this.editwin.focus(). This is most likely because some commands fail gratuitously if the document isn't focused? Need to look into it. * When doing queryCommandValue('fontname'), special-cases the empty string by replacing it with this.editdoc.body.style.fontFamily. Similar for fontsize. * Has an entire function whose description is "Function to translate the output from queryCommandState('forecolor') into something useful", which handles not only the empty string and null, but also translates rgb() syntax to #xxxxxx syntax ("translate_silly_hex()"). This one seems to be used only for setting id's, though. * Sets p { margin: 0 } somewhere for the editable document, presumably to account for IE and Opera. jwysiwyg (https://github.com/akzhan/jwysiwyg): * Browser-sniffs "IE" vs. "W3C" by going down standards-compliant code-paths if (window.getSelection). jwysiwyg++. (Mostly.) * Assumes window.getSelection evaluates to boolean false if there is no selection. I'm about 98% sure this is wrong. But it just means the codepath is always missed, which is harmless. * Also goes to some lengths to insert an image with attributes. It does insertImage with a src of "#jwysiwyg#", then effectively does querySelector("img[src=#jwysiwyg#]") to find it, except it uses a home-made getElementByAttributeValue method. * Also assumes getSelection().getRangeAt(0) will always return the current selection's range. * Works around lack of insertHTML support in IE by using insertImage, finding the image as described above, and replacing it with the desired HTML . . . (uses browser-sniffing instead of feature-detection, bad jwysiwyg). * Throws in focus() calls for IE. Maybe IE doesn't work right if stuff isn't focused? * removeFormat doesn't remove headings, so it optionally removes headings when its internal formatting thing is called . . . using execCommand("formatBlock", false, "

"). ??? * Has an option to replace

with

. Wonder how well this works. * Turns styleWithCSS/useCSS off in Mozilla (although perhaps buggily). CKEditor (http://ckeditor.com): Spent a while trying to figure it out, gave up. Way too much abstraction for me to figure out. I'm not sure if they use execCommand() at all. TinyMCE (http://tinymce.moxiecode.com/): * Big, complicated project, unlike vBulletin and jwysiwyg. No way I'll be able to even skim all of it. * Always forces styleWithCSS to false * "Text formatter engine class. This class is used to apply formats like bold, italic, font size etc to the current selection or specific nodes. This engine was build to replace the browsers default formatting logic for execCommand due to it's inconsistant and buggy behavior." Not much more to see here, it seems. == List requirements == *

  1. foo
  2. [bar]
  3. baz
* insertOrderedList:
  1. foo
bar
  1. baz
* insertUnorderedList:
  1. foo
  1. baz
* indent:
  1. foo
    1. bar
  2. baz
* outdent:
  1. foo
bar
  1. baz
*
  1. foo
[bar] * insertOrderedList:
  1. foo
  2. bar
*
  1. [foo]
    bar
  2. baz
* insertOrderedList: foo
bar
  1. baz
* insertUnorderedList:
  1. baz
* indent:
    1. foo
      bar
  1. baz
* outdent: foo
bar
  1. baz
*
  1. foo
    [bar]
  2. baz
* Same behavior as last case. *
  1. foo
    1. [bar]
    2. baz
  2. quz
* insertOrderedList:
  1. foo
  2. bar
    1. baz
  3. quz
* insertUnorderedList:
  1. foo
    • bar
    1. baz
  2. quz
* indent:
  1. foo
      1. bar
    1. baz
  2. quz
* outdent:
  1. foo
  2. bar
    1. baz
  3. quz
*
  1. foo
    • [bar]
    • baz
  2. quz
* insertOrderedList:
  1. foo
    1. bar
    • baz
  2. quz
* insertUnorderedList:
  1. foo
  2. bar
    • baz
  3. quz
* indent:
  1. foo
      • bar
    • baz
  2. quz
* outdent:
  1. foo
  2. bar
    • baz
  3. quz
*
  1. foo
  2. [bar]
    1. baz
  3. quz
* insertOrderedList:
  1. foo
bar
    1. baz
  1. quz
* insertUnorderedList:
  1. foo
    1. baz
  1. quz
* indent:
  1. foo
    1. bar
      1. baz
    2. quz
    * outdent:
    1. foo
    bar
      1. baz
    1. quz