your new best friend
Laurent Perrin @l_perrin
Front — frontapp.com
your old pal
no formatting
resize sucks
This support only refers to basic editing capability, implementations vary significantly on how certain elements can be edited.
[contenteditable=true]:empty::before {
content: attr(placeholder);
display: inline;
color: ui-dimmed-color;
font-weight: 300;
}
https://developer.mozilla.org/en-US/docs/Web/API/document.execCommand#Commands
Nope… we need to track the current selection and inspect the DOM to see what style lies under the cursor.
http://stackoverflow.com/questions/7781963/js-get-array-of-all-selected-nodes-in-contenteditable-div
function getSelectedNodes() {
var nodes = getAllSelectedNodes(),
editorNode = getEditor();
// ignore if the user's selection is not in the editor
var allInEditor = nodes.every(function (node) {
return editorNode.find(node).length > 0;
});
return allInEditor ? nodes : [];
}
Make sure everything is in the editor
// styles can nested
function nodeHasParent(node, style, root) {
if (!node || node === root)
return false;
if (node.nodeName === style)
return true;
return nodeHasParent(node.parentNode, style, root);
}
Styles can be nested
function selectionChanged() {
var nodes = getSelectedNodes(),
editorNode = getEditor();
var state = {bold: false, italic: false, underline: false, fontSize: 12};
if (nodes.length === 0)
return;
state.bold = nodes.every(function (node) {
return nodeHasParent(node, 'B', editorNode);
});
state.italic = nodes.every(function (node) {
return nodeHasParent(node, 'I', editorNode);
});
state.underline = nodes.every(function (node) {
return nodeHasParent(node, 'U', editorNode);
});
// now do something with state…
}
$document.on('selectionchange', selectionChanged);
function saveSelection() {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount)
savedSelection = sel.getRangeAt(0);
}
function restoreSelection() {
if (!savedSelection)
return;
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(savedSelection);
savedSelection = null;
}
// capture on mousedown so it happens before "blur"
$('.toolbar button').on('mousedown', saveSelection);
$('#prompt-url button.btn-primary').click(function () {
var url = $('#prompt-url input').val();
if (url) {
var link = '<a href="' + encodeURI(url) + '">' + url + '</a>';
// restore the position of the cursor
$('[contenteditable=true').focus();
restoreSelection();
document.execCommand('insertHTML', false, link);
}
});
yes!
The actual size depends on the browser
var fontSizes = {1: 10, 2: 12, 3: 14, 4: 18, 5: 24, 6: 32, 7: 48};
function forceFontSize(editor, size) {
// execCommand inserts <font size="4"> which appears way too small in Safari
// http://stackoverflow.com/questions/5868295/document-execcommand-fontsize-in-pixels
var fontElements = document.getElementsByTagName('font'),
targetSize = fontSizes[size] + 'px';
size = size.toString();
for (var i = 0, len = fontElements.length; i < len; ++i) {
if (fontElements[i].size === size) {
fontElements[i].removeAttribute('size');
fontElements[i].style.fontSize = targetSize;
}
}
}
Solution: crawl the DOM to use explicity CSS instead.
And sanitize your inputs!
CTO Front — frontapp.com
@l_perrin
https://github.com/lperrin/talk-contenteditable