Styling contentEditable lists (<li>) with font family, font size and color
I am looking for a way to create style lists so that they use the formatting set by the user when editing in the contentEditable element. In particular, I want to be able to style the number / brand in the same way as the rest of the <li> .
From the test I did, the browser never erases the <li> tags directly (which actually controls the number / marker style), but always puts the <font> (or <span> if StyleWithCSS ) as the first child node, using it for formatting. I already tried several ideas to get around this, but did not find success:
1. Apply styles to <li> programmatically
Here I tried listening to "DOMNodeInserted", and when the <li> was inserted into the DOM, I requested the current fontName , fontSize and foreColor and applied them as an inline style on <li> .
textarea.addEventListener('DOMNodeInserted', function (evt) { if (evt.target.nodeName === 'LI') { evt.target.style.color = queryCommandValue('foreColor'); evt.target.style.fontFamily = queryCommandValue('fontName'); evt.target.style.fontSize = queryCommandValue('fontSize'); } }, false); Even so, as soon as you start typing in the list, the browser tries to be smart and erases the styles from the <li> by putting them in the <font> (or <span> ) tag :(
2. Create a rule for the styles you want to insert in the StyleSheet
Based on the attempt above, instead of writing inline styles, I created a rule for them, gave the identifier <li> node and entered this rule into the stylesheet. Now the rule will define the <li> style, and I could use CSSOM to constantly update any specific <li> styles.
This seemed to work very well (with some bugs that needed to be resolved), however it completely broke the content stacks contentEditable. Since the undo command is bound only to textContent and other formatting commands, there is no way to βundoβ the styles that you set in the stylesheet. (At least not very intuitively, I thought about how this can be done ...)
3. Keep track of <li> attribute changes and save them
For this attempt, I used the recently available MutationObserver http://www.w3.org/TR/dom/#mutationobserve r , available at DOM level 4. This observer can monitor for changes in the node attributes that will be passed back to the MutationRecord. It can even hold previous attribute values, including style values, so I could find out what was deleted and reapply it.
var observer = new WebKitMutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.target.nodeName === 'LI') { ... } }) }); observer.observe(document, { attributes: true, subtree: true, attributeOldValue: true }); It still suffers from a lack of cancellation support. You will undo other formatting changes, but <li> retain their styles.
Any new ideas? Only modern browser solutions are also welcome. I know that I could format my own HTML for use in lists, but I'm trying to figure out if this can be done using the standard insertOrderedList and insertUnorderedList that use real list tags.
** Update November 7, 2012 **
It doesn't seem like anyone else has solved this, here is a JSFiddle example to see what I am describing: http://jsfiddle.net/8LyZR/ . Just try changing the styles of bulleted or numbered lists.
For the project I'm working on, we use our own build of WebKit, so we were able to fix it with our own change, but I hope there is a way (or there will be a way) to do this directly with HTML / CSS / JS.
Here are some interesting CSS tricks. http://jsfiddle.net/GZ3cv/
It mainly relies on placing psuedo-element :before on inline tags (which will be stripped of styles), and then tries to position it on top of the original list of markers / numbers.
I cannot decide if I will name this solution, as it can become impractical with all the various combinations of nested / embedded tags (font, u, b, span, i).
But just by playing with the font, size, color, and list controls, it looks like it can mimic what you are looking for, with some obvious careful tweaking.
I'm curious if this technique is believable or just ridiculous :) Just drop it there ..