$(function() {
+ var BLOCKS = [
+ {name: 'code', tag: 'PRE', klass: 'screen'},
+ {name: 'figure', tag: 'DIV', subtag: true, klass: 'figure'},
+ {name: 'note', tag: 'DIV', subtag: true, klass: 'note'},
+ ];
+ function get_contenteditable_subnode(node) {
+ if (node === null) return null;
+ if (node.parentNode.contentEditable === 'true') return node;
+ return get_contenteditable_subnode(node.parentNode);
+ }
+ function get_active_block(node) {
+ var main_node = get_contenteditable_subnode(node);
+ if (main_node === null) return null;
+ for (const block of BLOCKS) {
+ if (main_node.tagName === block.tag && main_node.classList.contains(block.klass))
+ return block;
+ }
+ return null;
+ }
+
$('div[contenteditable]').on('input', function(event) {
if (event.originalEvent.inputType == "insertParagraph") {
var sel = document.getSelection();
}
return true;
});
- $('div[contenteditable]').on('keyup', function(event) {
- var sel = document.getSelection();
- if ((sel.anchorNode instanceof Element && (
- (sel.anchorOffset == 0 && sel.isCollapsed) || // first line
- (sel.anchorNode.tagName === 'PRE'))) ||
- (sel.anchorNode.parentNode.tagName === 'PRE')) {
- // start of line
- show_block_style_popup();
- } else {
- hide_block_style_popup();
- }
- return true;
- });
+ $('div[contenteditable]').on('keyup click', update_block_style_popup);
$('#save').on('click', function() {
var text = $('div[contenteditable]')[0].innerHTML;
var block_style_popup = null;
function block_style() {
- var action = $(this).data('action');
- var class_name = null;
- if (action == 'code') {
- action = 'pre';
- class_name = 'screen';
- if ($(this).hasClass('on')) { // toggle off
- action = 'p';
- class_name = null;
- }
- }
- document.execCommand('formatBlock', false, action);
var sel = window.getSelection();
- if (class_name) {
- $(sel.anchorNode).addClass(class_name);
+ var current_anchor = sel.anchorNode;
+ if (this.classList.contains('on')) { // toggle off
+ if (this.action_block.subtag) {
+ // unwrap
+ var main_node = get_contenteditable_subnode(current_anchor);
+ $(current_anchor).detach().insertAfter(main_node);
+ } else {
+ document.execCommand('formatBlock', false, 'p');
+ current_anchor = sel.anchorNode;
+ }
+ } else {
+ action = this.action_block.subtag || this.action_block.tag;
+ if (this.action_block.subtag) {
+ // enclose current tag into a new parent;
+ var new_parent = document.createElement(this.action_block.tag);
+ new_parent.className = this.action_block.klass;
+ $(current_anchor).wrap(new_parent);
+ } else {
+ document.execCommand('formatBlock', false, this.action_block.tag);
+ sel.anchorNode.className = this.action_block.klass;
+ current_anchor = sel.anchorNode;
+ }
}
var range = document.createRange();
- range.setStart(sel.anchorNode, 0);
+ range.setStart(current_anchor, 0);
sel.removeAllRanges();
sel.addRange(range);
+ update_block_style_popup();
}
- function show_block_style_popup() {
+ function update_block_style_popup() {
+ var sel = window.getSelection();
+ if (! ((sel.anchorNode instanceof Element && (sel.anchorOffset == 0 && sel.isCollapsed)) || get_active_block(sel.anchorNode))) {
+ if (block_style_popup) {
+ $(block_style_popup).hide();
+ }
+ return true;
+ }
if (block_style_popup === null) {
- block_style_popup = $(
- '<div class="style-popup">' +
- '<button data-action="code">code</button>' +
- '</div>');
+ block_style_popup = $('<div class="block-style-popup"></div>');
+ for (const block of BLOCKS) {
+ var button = document.createElement('button');
+ button.action_block = block;
+ button.dataset.action = block.name;
+ button.textContent = block.name;
+ block_style_popup.append(button);
+ }
block_style_popup.hide();
- block_style_popup.insertAfter($('.actions'));
+ block_style_popup.insertAfter(document.body);
block_style_popup.find('button').on('click', block_style);
}
block_style_popup.css('position', 'absolute');
- var sel = window.getSelection();
- var anchor = sel.anchorNode;
- if (anchor instanceof Text) {
- anchor = anchor.parentNode;
- }
- if (anchor.tagName === "PRE") {
- block_style_popup.find('[data-action=code]').addClass('on');
+ var block = get_active_block(sel.anchorNode);
+ block_style_popup.find('button').removeClass('on');
+ if (block) {
+ block_style_popup.find('[data-action=' + block.name + ']').addClass('on');
+ block_style_popup.addClass('selected');
} else {
- block_style_popup.find('[data-action=code]').removeClass('on');
+ block_style_popup.removeClass('selected');
}
+ var anchor = get_contenteditable_subnode(sel.anchorNode);
var pos = $(anchor).offset();
block_style_popup.css('top', pos.top - 33);
block_style_popup.css('left', pos.left);
block_style_popup.show();
- }
- function hide_block_style_popup() {
- if (block_style_popup) {
- $(block_style_popup).hide();
- }
+ return true;
}
var style_popup = null;
function show_style_popup(sel) {
if (style_popup === null) {
- style_popup = $('<div class="style-popup short">' +
+ style_popup = $('<div class="inline-style-popup">' +
'<button data-action="italic"><i>i</i></button>' +
'<button data-action="bold"><b>b</b></button>' +
'<button data-action="code">#</button>' +