From 767cf626b07b29b597c34d886b3d29048773c2db Mon Sep 17 00:00:00 2001 From: Mark Dermanov Date: Thu, 17 Dec 2015 00:36:19 +0300 Subject: [PATCH 1/8] allows select editable content throuth all editor shows add buttons block on 'tab' key press in one line with editing node #11 #12 --- ce_interface.js | 116 +++++++++++++++++++++++++++++++++++------------- editor.css | 31 ++++++++++--- 2 files changed, 110 insertions(+), 37 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index b089129d..0deeb4e7 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -55,15 +55,17 @@ ce.prototype.makeInterface = function () { var wrapper = this.make.editorWrapper(), firstNode = this.make.textNode('Lorem ipsum dolor sit amet, consectetur adipisicing elit. Porro quia nihil repellendus aut cupiditate reprehenderit sapiente magnam nobis doloremque eaque! Sint nobis assumenda nisi ducimus minima illo tenetur, cumque facilis.' ), - toolbar = this.make.toolbar(); + toolbar = this.make.toolbar(), + editableWrapper; this.wrapper = wrapper; + this.editableWrapper = editableWrapper = wrapper.getElementsByClassName("ce_content")[0]; this.toolbar = toolbar; this.toolbarButtons = this.make.toolbarButtons(this.allTools, this.settings.tools); /** Add first node and tool bar*/ - wrapper.appendChild(firstNode); + editableWrapper.appendChild(firstNode); wrapper.appendChild(toolbar); /** Insert Editor after initial textarea. Hide textarea */ @@ -78,13 +80,23 @@ ce.prototype.makeInterface = function () { */ ce.prototype.bindEvents = function () { - var _this = this; + var _this = this, + selectedNodeClass = "selected"; /** All keydowns on Window */ - window.addEventListener('keydown', function (event) { + document.addEventListener('keydown', function (event) { _this.globalKeydownCallback(event); }, false ); + + /** All blur on Window */ + document.addEventListener('focus', function (event) { + // check if currently focused in contenteditable element + if ("BODY" == event.target.tagName) return; + + event.target.classList.add(selectedNodeClass) + }, false ); + }; /** @@ -92,16 +104,35 @@ ce.prototype.bindEvents = function () { * todo depending on node type */ ce.prototype.focusNode = function (node) { + debugger + //if (node.classList.contains('ce_node_content')) node.focus(); + //else { + // var contentEditable = node.getElementsByClassName('ce_node_content'); + // contentEditable.length && contentEditable[0].focus(); + //} - var contentEditable = node.getElementsByClassName('ce_node_content'); - contentEditable.length && contentEditable[0].focus(); + node.focus(); + if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") { + var range = document.createRange(); + range.selectNodeContents(node); + range.collapse(false); + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } else if (typeof document.body.createTextRange != "undefined") { + var textRange = document.body.createTextRange(); + textRange.moveToElementText(node); + textRange.collapse(false); + textRange.select(); + } }; /** * All window keydowns handles here */ ce.prototype.globalKeydownCallback = function (event) { + console.log("keydown", event); switch (event.keyCode){ case this.key.TAB : this.tabKeyPressed(event); break; // TAB @@ -118,11 +149,19 @@ ce.prototype.tabKeyPressed = function(event) { // check if currently focused in contenteditable element if ("BODY" == event.target.tagName) return; - var toolbar = event.target.parentNode.nextSibling, + var toolbar = event.target.nextSibling, _this = this; toolbar.appendChild(this.toolbarButtons); + + var sel = window.getSelection(); + var curNode = sel.anchorNode.tagName ? sel.anchorNode : sel.focusNode.parentElement; + + //debugger + var posTop = + toolbar.style.top = curNode.offsetTop + "px"; + // repair buttons animation - just add css class async setTimeout(function () { @@ -130,7 +169,7 @@ ce.prototype.tabKeyPressed = function(event) { toolbar.className += ' ' + _this.BUTTONS_TOGGLED_CLASSNANE; _this.toolbarOpened = true; } else { - toolbar.className = toolbar.className.replace(_this.BUTTONS_TOGGLED_CLASSNANE, ''); + toolbar.className = toolbar.className.replace(' ' + _this.BUTTONS_TOGGLED_CLASSNANE, ''); _this.toolbarOpened = false } @@ -145,33 +184,37 @@ ce.prototype.tabKeyPressed = function(event) { */ ce.prototype.enterKeyPressed = function(event) { - if (event.shiftKey){ - document.execCommand('insertHTML', false, '

'); - } else { - var newNode = this.make.textNode(), - toolbar = this.make.toolbar(); + var _this = this; - /** Add node */ - this.wrapper.insertBefore(newNode, event.target.parentNode.nextSibling); + //if (event.shiftKey){ + // document.execCommand('insertHTML', false, '

'); + //} else { + // var newNode = this.make.textNode(), + // toolbar = this.make.toolbar(); + // + // var sel = window.getSelection(); + // var curNode = sel.focusNode.parentElement; + // + // /** Add node */ + // this.editableWrapper.insertBefore(newNode, curNode.nextSibling); + // + // /** Add toolbar to node */ + // //this.editableWrapper.insertBefore(toolbar, newNode); + // + // /** Set auto focus */ + // setTimeout(function () { + // + // _this.focusNode(newNode); + // }); + //} - /** Add toolbar to node */ - this.wrapper.insertBefore(toolbar, newNode); - - /** Set auto focus */ - var contentEditable = newNode.getElementsByClassName('ce_node_content'); - contentEditable.length && contentEditable[0].focus(); - } - - event.preventDefault(); + //event.preventDefault(); }; /** * Creates HTML elements */ ce.prototype.make = function () { - - var _this = this; - /** Empty toolbar with toggler */ function toolbar () { @@ -224,19 +267,30 @@ ce.prototype.make = function () { */ function textNode (content){ - var node = document.createElement('div'); + var node = document.createElement('p'); - node.className += 'node'; - node.innerHTML = '

' + (content || '') + '

'; + //node.setAttribute("tabindex", 0); + + node.classList.add("node"); + node.classList.add("ce_node_content"); + node.setAttribute("contenteditable", "true"); + + node.innerHTML = content || ''; return node; } function editorWrapper () { - var wrapper = document.createElement('div'); + var wrapper = document.createElement('div'), + editable_wrapper = document.createElement('div'); + + + editable_wrapper.className += 'ce_content'; + editable_wrapper.setAttribute("contenteditable", "true"); wrapper.className += 'codex_editor'; + wrapper.appendChild(editable_wrapper); return wrapper; } diff --git a/editor.css b/editor.css index b03455c9..d5cc5ace 100644 --- a/editor.css +++ b/editor.css @@ -90,15 +90,26 @@ .codex_editor .add_buttons{ color: #3b4352; font-size: 16px; - margin-left: -42px; - margin-top: -50px; - margin-bottom: -25px; - position: relative; + /* margin-left: -42px; */ + /* margin-top: -50px; */ + /* margin-bottom: -25px; */ + position: absolute; + /* visibility: hidden; */ + opacity: 0; + transition: opacity .15s ease-in-out; + top: 0; + left: -35px; + white-space: nowrap; } +.codex_editor .node.selected + .add_buttons{visibility:visible;} + .add_buttons .buttons { position: absolute; - top: 3px; + top: 1px; + background: wheat; + padding: 2px; + border-radius: 3px; } .codex_editor .add_buttons button:hover, .codex_editor .add_buttons .focused{ @@ -113,6 +124,7 @@ .codex_editor .buttons_toggled{ background: #fff; z-index: 10; + opacity: 1; } .codex_editor .buttons_toggled button{ opacity: 1; @@ -137,6 +149,13 @@ /** Typography styles */ .codex_editor p{ - margin: 30px 0; + padding: 5px 0; font-size: 17px; + margin: 0; + min-height: 20px; +} + +.codex_editor {position: relative;} + +.codex_editor .ce_content { } \ No newline at end of file From 3e17243f17836ada8f27998bd41a3401a2b65842 Mon Sep 17 00:00:00 2001 From: Mark Dermanov Date: Fri, 18 Dec 2015 01:41:36 +0300 Subject: [PATCH 2/8] toolBar key controlling #9 show on hover near node show on tab move focus to next btn by pressing tab again move focus to prev btn by pressing tab+shift move focus prev/next by pressing arrow buttons TODO: process enter press on selected btn TODO: open toolBar by mouseClick (has troubles with it, need discus) TODO: process mouse click on any btn TODO: code refactoring :) its only transitional status. don't be don't be a cruel --- ce_interface.js | 205 +++++++++++++++++++++++++++++++++++++++++------- editor.css | 16 ++++ example.html | 2 +- 3 files changed, 193 insertions(+), 30 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index 0deeb4e7..62dbc145 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -45,7 +45,7 @@ ce.prototype.BUTTONS_TOGGLED_CLASSNANE = 'buttons_toggled'; ce.prototype.toolbarOpened = false; // Key event constants -ce.prototype.key = { TAB: 9, ENTER: 13, BACKSPACE: 8, DELETE: 46, DOWN: 40, SPACE: 32, ESC: 27, CTRL: 17, META: 91, SHIFT: 16, ALT: 18 }; +ce.prototype.key = { TAB: 9, ENTER: 13, BACKSPACE: 8, DELETE: 46, SPACE: 32, ESC: 27, CTRL: 17, META: 91, SHIFT: 16, ALT: 18, LEFT: 37, UP: 38, DOWN: 40, RIGHT: 39 }; /** * Editor interface drawing @@ -64,6 +64,9 @@ ce.prototype.makeInterface = function () { this.toolbarButtons = this.make.toolbarButtons(this.allTools, this.settings.tools); + toolbar.appendChild(this.toolbarButtons); + + /** Add first node and tool bar*/ editableWrapper.appendChild(firstNode); wrapper.appendChild(toolbar); @@ -90,11 +93,69 @@ ce.prototype.bindEvents = function () { /** All blur on Window */ - document.addEventListener('focus', function (event) { + document.addEventListener('mouseover', function (event) { // check if currently focused in contenteditable element - if ("BODY" == event.target.tagName) return; + //if ("BODY" == event.target.tagName) return; - event.target.classList.add(selectedNodeClass) + //event.target.classList.add(selectedNodeClass) + + var sender = event.target + + if (sender.classList.contains("node") && !_this.toolbar.isOpened) { + console.log("hover", sender); + var toolbar = _this.toolbar; + + + toolbar.style.top = sender.offsetTop + "px"; + + // repair buttons animation - just add css class async + //setTimeout(function () { + toolbar.classList.add("show"); + + //}); + } + }, false ); + + /** All blur on Window */ + document.addEventListener('mouseout', function (event) { + // check if currently focused in contenteditable element + //if ("BODY" == event.target.tagName) return; + + //event.target.classList.add(selectedNodeClass) + + var sender = event.target + + // + //var sel = window.getSelection(); + //var curSelectedNode = sel.anchorNode.tagName ? sel.anchorNode : sel.focusNode.parentElement; + + if (!_this.toolbar.isOpened) { + //if (sender.classList.contains("node")) { + //debugger + //if (!curSelectedNode.isEqualNode(sender) && !_this.toolbarButtons.isEqualNode(sender)) { + //debugger + console.log("mouseout", sender); + var toolbar = _this.toolbar; + // + // + //toolbar.style.top = sender.offsetTop + "px"; + + // repair buttons animation - just add css class async + //setTimeout(function () { + toolbar.classList.remove("show"); + //toolbar.classList.remove(_this.BUTTONS_TOGGLED_CLASSNANE); + + //if (_this.focusedToolbarBtn) { + // //console.log("has focused btn", _this.focusedToolbarBtn) + // + // _this.focusedToolbarBtn.classList.remove("focused") + // _this.focusedToolbarBtn = false; + // + // event.preventDefault(); + // return + //} + //}); + } }, false ); }; @@ -104,7 +165,8 @@ ce.prototype.bindEvents = function () { * todo depending on node type */ ce.prototype.focusNode = function (node) { - debugger + //debugger + //if (node.classList.contains('ce_node_content')) node.focus(); //else { // var contentEditable = node.getElementsByClassName('ce_node_content'); @@ -134,11 +196,52 @@ ce.prototype.focusNode = function (node) { ce.prototype.globalKeydownCallback = function (event) { console.log("keydown", event); - switch (event.keyCode){ - case this.key.TAB : this.tabKeyPressed(event); break; // TAB - case this.key.ENTER : this.enterKeyPressed(event); break; // Enter + var _this = this; + + // TODO process key navigation on toolBar then its opened + if (this.toolbar.isOpened) { + if (event.which == this.key.LEFT || event.which == this.key.UP || event.which == this.key.DOWN || event.which == this.key.RIGHT) { + this.moveToolBarButtonFocus(event.which == this.key.LEFT || event.which == this.key.UP ) + + event.preventDefault(); + //return + } else if (event.which == this.key.ENTER) { + // TODO process seleceted toolBtn + //insert new node or change type of current? + //and close toolbar + + // TODO do the same by mouse clicking on any toolbar btn + + event.preventDefault(); + } else if (event.which != this.key.TAB && event.which != this.key.SHIFT) { + + var toolbar = this.toolbar; + + toolbar.isOpened = false; + this.focusedToolbarBtn.classList.remove("focused"); + this.focusedToolbarBtn = false; + + // repair buttons animation - just add css class async + setTimeout(function () { + toolbar.classList.remove("show"); + toolbar.classList.remove(_this.BUTTONS_TOGGLED_CLASSNANE); + }); + + //event.preventDefault(); + //return + } + } + if (event.which == this.key.TAB) + this.tabKeyPressed(event) + + // + //switch (event.keyCode){ + // case this.key.TAB : this.tabKeyPressed(event); break; // TAB + // case this.key.ENTER : this.enterKeyPressed(event); break; // Enter + //} + }; /** @@ -149,42 +252,86 @@ ce.prototype.tabKeyPressed = function(event) { // check if currently focused in contenteditable element if ("BODY" == event.target.tagName) return; - var toolbar = event.target.nextSibling, - _this = this; + var _this = this; - toolbar.appendChild(this.toolbarButtons); + var toolbar = this.toolbar; + if (!toolbar.isOpened) { + var sel = window.getSelection(); + var curNode = sel.anchorNode.tagName ? sel.anchorNode : sel.focusNode.parentElement; - var sel = window.getSelection(); - var curNode = sel.anchorNode.tagName ? sel.anchorNode : sel.focusNode.parentElement; + toolbar.style.top = curNode.offsetTop + "px"; - //debugger - var posTop = - toolbar.style.top = curNode.offsetTop + "px"; - - // repair buttons animation - just add css class async - setTimeout(function () { - - if ( !toolbar.className.includes(_this.BUTTONS_TOGGLED_CLASSNANE) ){ - toolbar.className += ' ' + _this.BUTTONS_TOGGLED_CLASSNANE; - _this.toolbarOpened = true; - } else { - toolbar.className = toolbar.className.replace(' ' + _this.BUTTONS_TOGGLED_CLASSNANE, ''); - _this.toolbarOpened = false + if (!toolbar.classList.contains(_this.BUTTONS_TOGGLED_CLASSNANE)) { + // repair buttons animation - just add css class async + setTimeout(function () { + toolbar.classList.add(_this.BUTTONS_TOGGLED_CLASSNANE) + toolbar.isOpened = true; + }); } - }); + } + + // + this.moveToolBarButtonFocus(event.shiftKey); event.preventDefault(); - }; +/* +* +* */ +ce.prototype.moveToolBarButtonFocus = function(focusPrev){ + var allButtons = this.toolbarButtons; + + var focusedQuery = allButtons.getElementsByClassName("focused");//[0] || allButtons.firstChild; + var focused; + +//debugger + console.log("focusing", focusedQuery) + if (focusedQuery.length > 0) { + focused = focusedQuery[0] + + focused.classList.remove("focused") + + if (focusPrev) focused = focused.previousSibling; + else focused = focused.nextSibling; + + if (!focused) { + if (focusPrev) focused = allButtons.lastChild; + else focused = allButtons.firstChild; + } + + focused.classList.add("focused") + } else { + focused = allButtons.firstChild; + + + focused.classList.add("focused") + } + + this.focusedToolbarBtn = focused; + + //return !!focused; +} + /** * Handle Enter key. Adds new Node; */ ce.prototype.enterKeyPressed = function(event) { - var _this = this; + //var _this = this; + + + if (this.toolbar.isOpened) { + console.log("has focused btn", this.focusedToolbarBtn) + + event.preventDefault(); + return + } + + this.toolbar.classList.remove("show") + this.toolbar.classList.remove(this.BUTTONS_TOGGLED_CLASSNANE) //if (event.shiftKey){ // document.execCommand('insertHTML', false, '

'); diff --git a/editor.css b/editor.css index d5cc5ace..cd3e1812 100644 --- a/editor.css +++ b/editor.css @@ -102,6 +102,13 @@ white-space: nowrap; } +.add_buttons.show { + background: #fff; + z-index: 10; + opacity: 1; +} +.add_buttons.show .buttons {display:none;} + .codex_editor .node.selected + .add_buttons{visibility:visible;} .add_buttons .buttons { @@ -110,6 +117,7 @@ background: wheat; padding: 2px; border-radius: 3px; + display: none; } .codex_editor .add_buttons button:hover, .codex_editor .add_buttons .focused{ @@ -137,6 +145,7 @@ font-size: 23px; color: #387ff5; transition: transform 100ms ease-in; + cursor: pointer; } .codex_editor .toggler .buttons { @@ -147,6 +156,13 @@ transform: rotate(45deg); } +.codex_editor .buttons_toggled .buttons{ + display: inline; +} + + + + /** Typography styles */ .codex_editor p{ padding: 5px 0; diff --git a/example.html b/example.html index 3e57bf74..db2a80d2 100644 --- a/example.html +++ b/example.html @@ -58,7 +58,7 @@ /** Document is ready */ ready(function() { window.cEditor = new ce({ - tools : ['header', 'picture'] + tools : ['header', 'list', 'picture'] }); }) From ed4fda465129d33575a9141b15153b4e82ac906e Mon Sep 17 00:00:00 2001 From: Mark Dermanov Date: Fri, 25 Dec 2015 17:06:43 +0300 Subject: [PATCH 3/8] add header --- ce_interface.js | 117 +++++++++++++++++++++++++++++++++++++----------- example.html | 2 +- 2 files changed, 92 insertions(+), 27 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index 62dbc145..5e51968b 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -3,6 +3,13 @@ * @author Savchenko Peter (vk.com/specc) */ + /* + * TODO + * выделение нескольких блоков и нажатие энтера - вместо замены новой стро + * + * */ + + var ce = function(settings) { this.resultTextarea = document.getElementById("codex_editor"); @@ -210,9 +217,56 @@ ce.prototype.globalKeydownCallback = function (event) { //insert new node or change type of current? //and close toolbar + //debugger + var btnType = this.focusedToolbarBtn.dataset["type"]; + + switch (btnType){ + + case "header": + // TODO insertHeader() + + // TODO make.HeaderNode() + var header = document.createElement("h2"); + + header.classList.add("node"); + header.dataset["type"] = "header"; + + var curNode = this.getFocusedNode(); + + header.textContent = curNode.textContent; + curNode.textContent = ""; + + // insert before, if curNode is paragraph or header or some other text-editable node + if (curNode.dataset["type"] == "text") + curNode.parentNode.insertBefore(header, curNode); + // else insert header node after + else + curNode.parentNode.insertBefore(header, curNode.nextSibling); + + this.focusNode(header); + + break; + + } + + // TODO closeToolar() + var toolbar = this.toolbar; + + toolbar.isOpened = false; + this.focusedToolbarBtn.classList.remove("focused"); + this.focusedToolbarBtn = false; + + // repair buttons animation - just add css class async + setTimeout(function () { + toolbar.classList.remove("show"); + toolbar.classList.remove(_this.BUTTONS_TOGGLED_CLASSNANE); + }); + // TODO do the same by mouse clicking on any toolbar btn event.preventDefault(); + return + } else if (event.which != this.key.TAB && event.which != this.key.SHIFT) { var toolbar = this.toolbar; @@ -237,13 +291,22 @@ ce.prototype.globalKeydownCallback = function (event) { this.tabKeyPressed(event) // - //switch (event.keyCode){ - // case this.key.TAB : this.tabKeyPressed(event); break; // TAB - // case this.key.ENTER : this.enterKeyPressed(event); break; // Enter - //} + switch (event.keyCode){ + //case this.key.TAB : this.tabKeyPressed(event); break; // TAB + case this.key.ENTER : this.enterKeyPressed.call(_this, event); break; // Enter + } }; +/** +* Returns node which is currently focused +*/ +ce.prototype.getFocusedNode = function(focusPrev){ + var sel = window.getSelection(); + return sel.anchorNode.tagName ? sel.anchorNode : sel.focusNode.parentElement; +} + + /** * */ @@ -320,7 +383,7 @@ ce.prototype.moveToolBarButtonFocus = function(focusPrev){ */ ce.prototype.enterKeyPressed = function(event) { - //var _this = this; + var _this = this; if (this.toolbar.isOpened) { @@ -330,29 +393,32 @@ ce.prototype.enterKeyPressed = function(event) { return } - this.toolbar.classList.remove("show") - this.toolbar.classList.remove(this.BUTTONS_TOGGLED_CLASSNANE) //if (event.shiftKey){ // document.execCommand('insertHTML', false, '

'); //} else { - // var newNode = this.make.textNode(), - // toolbar = this.make.toolbar(); - // - // var sel = window.getSelection(); - // var curNode = sel.focusNode.parentElement; - // - // /** Add node */ - // this.editableWrapper.insertBefore(newNode, curNode.nextSibling); - // - // /** Add toolbar to node */ - // //this.editableWrapper.insertBefore(toolbar, newNode); - // - // /** Set auto focus */ - // setTimeout(function () { - // - // _this.focusNode(newNode); - // }); + + var sel = window.getSelection(); + var curNode = this.getFocusedNode(); + + + if (curNode.dataset["type"] == "header") { + var newNode = this.make.textNode(); + + /** Add node */ + this.editableWrapper.insertBefore(newNode, curNode.nextSibling); + + /** Set auto focus */ + setTimeout(function () { + + _this.focusNode(newNode); + }); + + event.preventDefault(); + return; + } + + //} //event.preventDefault(); @@ -419,8 +485,7 @@ ce.prototype.make = function () { //node.setAttribute("tabindex", 0); node.classList.add("node"); - node.classList.add("ce_node_content"); - node.setAttribute("contenteditable", "true"); + node.dataset["type"] = "text"; node.innerHTML = content || ''; diff --git a/example.html b/example.html index db2a80d2..6e85d83e 100644 --- a/example.html +++ b/example.html @@ -58,7 +58,7 @@ /** Document is ready */ ready(function() { window.cEditor = new ce({ - tools : ['header', 'list', 'picture'] + tools : ['header'] }); }) From 908508584fa4cd4b47e48571453d7cfec5aff28b Mon Sep 17 00:00:00 2001 From: Mark Dermanov Date: Tue, 29 Dec 2015 21:44:32 +0300 Subject: [PATCH 4/8] start export and import --- ce_interface.js | 67 ++++++++++++++++++++++++++++++++++++++++++++++--- example.html | 6 ++++- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index 5e51968b..53697541 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -35,6 +35,7 @@ var ce = function(settings) { /** Bind all events */ this.bindEvents(); + }; // All posible tools @@ -80,11 +81,40 @@ ce.prototype.makeInterface = function () { /** Insert Editor after initial textarea. Hide textarea */ this.resultTextarea.parentNode.insertBefore(wrapper, this.resultTextarea.nextSibling); - this.resultTextarea.hidden = true; + //this.resultTextarea.hidden = true; this.focusNode(firstNode); }; + +/* + * Экспорт разметки в итоговый текстареа + * пока по кнопке "экспорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) + * */ +ce.prototype.exportHtml = function () { + console.log("export"); + + this.resultTextarea.innerHTML = this.editableWrapper.innerHTML; + + return false; +}; + + +/* + * Импорт разметки из итоговой текстареа + * пока по кнопке "импорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) + * */ +ce.prototype.importHtml = function () { + console.log("importHtml"); + + //this.resultTextarea.innerHTML = this.editableWrapper.innerHTML; + + + return false; +}; + + + /** * All events binds in one place */ @@ -93,6 +123,24 @@ ce.prototype.bindEvents = function () { var _this = this, selectedNodeClass = "selected"; + /* + * Экспорт разметки в итоговый текстареа + * пока по кнопке "экспорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) + * */ + document.getElementById("export_html").addEventListener('click', function () { + _this.exportHtml.apply(_this) + }); + + + /* + * Импорт разметки из итоговой текстареа + * пока по кнопке "импорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) + * */ + document.getElementById("import_html").addEventListener('click', function () { + _this.importHtml.apply(_this) + }); + + /** All keydowns on Window */ document.addEventListener('keydown', function (event) { _this.globalKeydownCallback(event); @@ -106,7 +154,7 @@ ce.prototype.bindEvents = function () { //event.target.classList.add(selectedNodeClass) - var sender = event.target + var sender = event.target; if (sender.classList.contains("node") && !_this.toolbar.isOpened) { console.log("hover", sender); @@ -197,6 +245,17 @@ ce.prototype.focusNode = function (node) { } }; +/* +* +* */ +ce.prototype.isTextSelected = function(){ + + //var sel = window.getSelection(); + //debugger + + return !!window.getSelection().toString() +} + /** * All window keydowns handles here */ @@ -213,6 +272,8 @@ ce.prototype.globalKeydownCallback = function (event) { event.preventDefault(); //return } else if (event.which == this.key.ENTER) { + + // TODO process seleceted toolBtn //insert new node or change type of current? //and close toolbar @@ -402,7 +463,7 @@ ce.prototype.enterKeyPressed = function(event) { var curNode = this.getFocusedNode(); - if (curNode.dataset["type"] == "header") { + if (curNode.dataset["type"] == "header" && !this.isTextSelected()) { var newNode = this.make.textNode(); /** Add node */ diff --git a/example.html b/example.html index 6e85d83e..ebf2ecd2 100644 --- a/example.html +++ b/example.html @@ -10,9 +10,13 @@

CodeX Editor

+ + +
+
- +
From 2d748485b56c72e4d10d4ffe1cdaed0c75f4c769 Mon Sep 17 00:00:00 2001 From: Mark Dermanov Date: Tue, 29 Dec 2015 23:18:32 +0300 Subject: [PATCH 5/8] remove garbage --- ce_interface.js | 163 ++++++++++-------------------------------------- 1 file changed, 34 insertions(+), 129 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index 53697541..d095d981 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -92,9 +92,7 @@ ce.prototype.makeInterface = function () { * пока по кнопке "экспорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) * */ ce.prototype.exportHtml = function () { - console.log("export"); - - this.resultTextarea.innerHTML = this.editableWrapper.innerHTML; + this.resultTextarea.value = this.editableWrapper.innerHTML; return false; }; @@ -105,16 +103,12 @@ ce.prototype.exportHtml = function () { * пока по кнопке "импорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) * */ ce.prototype.importHtml = function () { - console.log("importHtml"); - - //this.resultTextarea.innerHTML = this.editableWrapper.innerHTML; - + this.editableWrapper.innerHTML = this.resultTextarea.value; return false; }; - /** * All events binds in one place */ @@ -124,7 +118,7 @@ ce.prototype.bindEvents = function () { selectedNodeClass = "selected"; /* - * Экспорт разметки в итоговый текстареа + * Экспорт разметки в итоговый textarea * пока по кнопке "экспорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) * */ document.getElementById("export_html").addEventListener('click', function () { @@ -133,7 +127,7 @@ ce.prototype.bindEvents = function () { /* - * Импорт разметки из итоговой текстареа + * Импорт разметки из итоговой textarea * пока по кнопке "импорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) * */ document.getElementById("import_html").addEventListener('click', function () { @@ -149,67 +143,26 @@ ce.prototype.bindEvents = function () { /** All blur on Window */ document.addEventListener('mouseover', function (event) { - // check if currently focused in contenteditable element - //if ("BODY" == event.target.tagName) return; - - //event.target.classList.add(selectedNodeClass) - var sender = event.target; if (sender.classList.contains("node") && !_this.toolbar.isOpened) { - console.log("hover", sender); var toolbar = _this.toolbar; - toolbar.style.top = sender.offsetTop + "px"; - // repair buttons animation - just add css class async - //setTimeout(function () { - toolbar.classList.add("show"); - - //}); + toolbar.classList.add("show"); } }, false ); + /** All blur on Window */ document.addEventListener('mouseout', function (event) { - // check if currently focused in contenteditable element - //if ("BODY" == event.target.tagName) return; - - //event.target.classList.add(selectedNodeClass) - var sender = event.target - // - //var sel = window.getSelection(); - //var curSelectedNode = sel.anchorNode.tagName ? sel.anchorNode : sel.focusNode.parentElement; - if (!_this.toolbar.isOpened) { - //if (sender.classList.contains("node")) { - //debugger - //if (!curSelectedNode.isEqualNode(sender) && !_this.toolbarButtons.isEqualNode(sender)) { - //debugger - console.log("mouseout", sender); var toolbar = _this.toolbar; - // - // - //toolbar.style.top = sender.offsetTop + "px"; - // repair buttons animation - just add css class async - //setTimeout(function () { - toolbar.classList.remove("show"); - //toolbar.classList.remove(_this.BUTTONS_TOGGLED_CLASSNANE); - - //if (_this.focusedToolbarBtn) { - // //console.log("has focused btn", _this.focusedToolbarBtn) - // - // _this.focusedToolbarBtn.classList.remove("focused") - // _this.focusedToolbarBtn = false; - // - // event.preventDefault(); - // return - //} - //}); + toolbar.classList.remove("show"); } }, false ); @@ -220,15 +173,8 @@ ce.prototype.bindEvents = function () { * todo depending on node type */ ce.prototype.focusNode = function (node) { - //debugger - - //if (node.classList.contains('ce_node_content')) node.focus(); - //else { - // var contentEditable = node.getElementsByClassName('ce_node_content'); - // contentEditable.length && contentEditable[0].focus(); - //} - node.focus(); + if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") { var range = document.createRange(); range.selectNodeContents(node); @@ -246,15 +192,11 @@ ce.prototype.focusNode = function (node) { }; /* -* +* Определяет, есть ли выделенный текст * */ ce.prototype.isTextSelected = function(){ - - //var sel = window.getSelection(); - //debugger - return !!window.getSelection().toString() -} +}; /** * All window keydowns handles here @@ -362,10 +304,10 @@ ce.prototype.globalKeydownCallback = function (event) { /** * Returns node which is currently focused */ -ce.prototype.getFocusedNode = function(focusPrev){ +ce.prototype.getFocusedNode = function(){ var sel = window.getSelection(); return sel.anchorNode.tagName ? sel.anchorNode : sel.focusNode.parentElement; -} +}; /** @@ -402,21 +344,19 @@ ce.prototype.tabKeyPressed = function(event) { event.preventDefault(); }; -/* -* +/** +* Перемещает фокус на следующую кнопку в панеле добавления (плюс) * */ ce.prototype.moveToolBarButtonFocus = function(focusPrev){ var allButtons = this.toolbarButtons; - var focusedQuery = allButtons.getElementsByClassName("focused");//[0] || allButtons.firstChild; + var focusedQuery = allButtons.getElementsByClassName("focused"); var focused; -//debugger - console.log("focusing", focusedQuery) if (focusedQuery.length > 0) { - focused = focusedQuery[0] + focused = focusedQuery[0]; - focused.classList.remove("focused") + focused.classList.remove("focused"); if (focusPrev) focused = focused.previousSibling; else focused = focused.nextSibling; @@ -426,18 +366,15 @@ ce.prototype.moveToolBarButtonFocus = function(focusPrev){ else focused = allButtons.firstChild; } - focused.classList.add("focused") + focused.classList.add("focused"); } else { focused = allButtons.firstChild; - - focused.classList.add("focused") + focused.classList.add("focused"); } this.focusedToolbarBtn = focused; - - //return !!focused; -} +}; /** * Handle Enter key. Adds new Node; @@ -446,7 +383,6 @@ ce.prototype.enterKeyPressed = function(event) { var _this = this; - if (this.toolbar.isOpened) { console.log("has focused btn", this.focusedToolbarBtn) @@ -454,35 +390,25 @@ ce.prototype.enterKeyPressed = function(event) { return } - - //if (event.shiftKey){ - // document.execCommand('insertHTML', false, '

'); - //} else { - - var sel = window.getSelection(); - var curNode = this.getFocusedNode(); + var sel = window.getSelection(); + var curNode = this.getFocusedNode(); - if (curNode.dataset["type"] == "header" && !this.isTextSelected()) { - var newNode = this.make.textNode(); + if (curNode.dataset["type"] == "header" && !this.isTextSelected()) { + var newNode = this.make.textNode(); - /** Add node */ - this.editableWrapper.insertBefore(newNode, curNode.nextSibling); + /** Add node */ + this.editableWrapper.insertBefore(newNode, curNode.nextSibling); - /** Set auto focus */ - setTimeout(function () { + /** Set auto focus */ + setTimeout(function () { - _this.focusNode(newNode); - }); + _this.focusNode(newNode); + }); - event.preventDefault(); - return; - } - - - //} - - //event.preventDefault(); + event.preventDefault(); + return; + } }; /** @@ -543,8 +469,6 @@ ce.prototype.make = function () { var node = document.createElement('p'); - //node.setAttribute("tabindex", 0); - node.classList.add("node"); node.dataset["type"] = "text"; @@ -578,23 +502,4 @@ ce.prototype.make = function () { return new ceMake(); -}(); - - - - - -/** -* Polyfilling ECMAScript 6 method String.includes -* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#Browser_compatibility -*/ -if ( !String.prototype.includes ) { - - String.prototype.includes = function() { - - 'use strict'; - - return String.prototype.indexOf.apply(this, arguments) !== -1; - - }; -} \ No newline at end of file +}(); \ No newline at end of file From 3b546ad32202b5354c7cec8b2bb0bcc399a46f63 Mon Sep 17 00:00:00 2001 From: Markus3295 Date: Wed, 30 Dec 2015 00:41:19 +0300 Subject: [PATCH 6/8] =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=8F=D0=B4=D0=BE=D0=BA?= =?UTF-8?q?=20=D0=B2=20=D0=BA=D0=BE=D0=B4=D0=B5.=20=D1=8D=D0=BA=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=82/=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82?= =?UTF-8?q?=20=D1=81=D0=BE=D0=B4=D0=B5=D1=80=D0=B6=D0=B8=D0=BC=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=8D=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82=20=D0=B8=20?= =?UTF-8?q?=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82=20=D0=BF=D0=BE=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=B2=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D0=BE=D0=BC=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=D0=B5=20=D0=BF=D0=BE=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B8=D0=BA=D1=83=20=D0=BD=D0=B0=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D1=82=D0=B2=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20textarea?= =?UTF-8?q?=20=D1=81=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D0=BE=D0=B9=20=D0=B8?= =?UTF-8?q?=D0=B4=D0=B5=D1=82=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20-?= =?UTF-8?q?=20=D1=82=D0=B0=20=D0=B6=D0=B5=20=D1=81=D0=B0=D0=BC=D0=B0=D1=8F?= =?UTF-8?q?,=20=D1=87=D1=82=D0=BE=20=D0=BF=D1=80=D0=B8=20=D0=B8=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8,=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=BE=20=D0=B2=D0=B8?= =?UTF-8?q?=D0=B4=D0=B8=D0=BC=D0=B0=D1=8F=20=D0=BD=D0=B0=D0=B4=D0=BE=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D1=83=D0=BC=D0=B0=D1=82=D1=8C,=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B3=D0=B4=20=D0=B4=D0=B5=D0=BB=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=B8=D0=B9=20=D1=8D=D1=81=D0=BA=D0=BF=D0=BE=D1=80?= =?UTF-8?q?=D1=82=20=D0=B2=20textarea?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ce_interface.js | 295 +++++++++++++++++++++++++++--------------------- editor.css | 2 +- 2 files changed, 169 insertions(+), 128 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index d095d981..70d28b4b 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -141,33 +141,50 @@ ce.prototype.bindEvents = function () { }, false ); - /** All blur on Window */ + /** All mouseover on Window */ document.addEventListener('mouseover', function (event) { - var sender = event.target; - - if (sender.classList.contains("node") && !_this.toolbar.isOpened) { - var toolbar = _this.toolbar; - - toolbar.style.top = sender.offsetTop + "px"; - - toolbar.classList.add("show"); - } + _this.globalMouseOverCallback(event); }, false ); - /** All blur on Window */ + /** All mouseout on Window */ document.addEventListener('mouseout', function (event) { - var sender = event.target - - if (!_this.toolbar.isOpened) { - var toolbar = _this.toolbar; - - toolbar.classList.remove("show"); - } + _this.globalMouseOutCallback(event); }, false ); }; + +/** + * All window mouseover handles here +*/ +ce.prototype.globalMouseOverCallback = function (event) { + var sender = event.target; + + if (sender.classList.contains("node") && !this.toolbar.isOpened) { + var toolbar = this.toolbar; + + toolbar.style.top = sender.offsetTop + "px"; + + toolbar.classList.add("show"); + } +}; + + +/** + * All window mouseout handles here +*/ +ce.prototype.globalMouseOutCallback = function (event) { + var sender = event.target; + + if (!this.toolbar.isOpened) { + var toolbar = this.toolbar; + + toolbar.classList.remove("show"); + } +}; + + /** * Sets focus to node conteneditable child * todo depending on node type @@ -198,109 +215,77 @@ ce.prototype.isTextSelected = function(){ return !!window.getSelection().toString() }; +/* +* Определяет, относится ли нажатая кнопка к навигационным +* */ +ce.prototype.isNavigationKey = function(keyCode){ + return keyCode == this.key.LEFT || keyCode == this.key.UP || keyCode == this.key.DOWN || keyCode == this.key.RIGHT +}; + /** * All window keydowns handles here */ ce.prototype.globalKeydownCallback = function (event) { - console.log("keydown", event); - var _this = this; - - // TODO process key navigation on toolBar then its opened - if (this.toolbar.isOpened) { - if (event.which == this.key.LEFT || event.which == this.key.UP || event.which == this.key.DOWN || event.which == this.key.RIGHT) { - this.moveToolBarButtonFocus(event.which == this.key.LEFT || event.which == this.key.UP ) - - event.preventDefault(); - //return - } else if (event.which == this.key.ENTER) { - - - // TODO process seleceted toolBtn - //insert new node or change type of current? - //and close toolbar - - //debugger - var btnType = this.focusedToolbarBtn.dataset["type"]; - - switch (btnType){ - - case "header": - // TODO insertHeader() - - // TODO make.HeaderNode() - var header = document.createElement("h2"); - - header.classList.add("node"); - header.dataset["type"] = "header"; - - var curNode = this.getFocusedNode(); - - header.textContent = curNode.textContent; - curNode.textContent = ""; - - // insert before, if curNode is paragraph or header or some other text-editable node - if (curNode.dataset["type"] == "text") - curNode.parentNode.insertBefore(header, curNode); - // else insert header node after - else - curNode.parentNode.insertBefore(header, curNode.nextSibling); - - this.focusNode(header); - - break; - - } - - // TODO closeToolar() - var toolbar = this.toolbar; - - toolbar.isOpened = false; - this.focusedToolbarBtn.classList.remove("focused"); - this.focusedToolbarBtn = false; - - // repair buttons animation - just add css class async - setTimeout(function () { - toolbar.classList.remove("show"); - toolbar.classList.remove(_this.BUTTONS_TOGGLED_CLASSNANE); - }); - - // TODO do the same by mouse clicking on any toolbar btn - - event.preventDefault(); - return - - } else if (event.which != this.key.TAB && event.which != this.key.SHIFT) { - - var toolbar = this.toolbar; - - toolbar.isOpened = false; - this.focusedToolbarBtn.classList.remove("focused"); - this.focusedToolbarBtn = false; - - // repair buttons animation - just add css class async - setTimeout(function () { - toolbar.classList.remove("show"); - toolbar.classList.remove(_this.BUTTONS_TOGGLED_CLASSNANE); - }); - - //event.preventDefault(); - //return - } - - } - - if (event.which == this.key.TAB) - this.tabKeyPressed(event) + /** + * Обработка клавиш на панеле добавления + */ + this.processToolBarKeyPressed(event); // switch (event.keyCode){ - //case this.key.TAB : this.tabKeyPressed(event); break; // TAB - case this.key.ENTER : this.enterKeyPressed.call(_this, event); break; // Enter + case this.key.TAB : this.tabKeyPressed(event); break; // TAB + case this.key.ENTER : this.enterKeyPressed(event); break; // Enter } }; + +/** +* Обрабатывает нажатие клавиш при открытой панеле добавления +*/ +ce.prototype.processToolBarKeyPressed = function(event){ + if (this.toolbar.isOpened) { + + if (this.isNavigationKey(event.which)) { + + this.moveToolBarButtonFocus(event.which == this.key.LEFT || event.which == this.key.UP ); + + event.preventDefault(); + + } else if (event.which == this.key.ENTER) { + // will process later + } else if (event.which != this.key.TAB && event.which != this.key.SHIFT) { + + this.closeToolBar(); + + } + + } +}; + + + +/** +* Closes tool bar (plus btn) +*/ +ce.prototype.closeToolBar = function(){ + var _this = this, + toolbar = this.toolbar; + + toolbar.isOpened = false; + this.focusedToolbarBtn.classList.remove("focused"); + this.focusedToolbarBtn = false; + + // repair buttons animation - just add css class async + setTimeout(function () { + toolbar.classList.remove("show"); + toolbar.classList.remove(_this.BUTTONS_TOGGLED_CLASSNANE); + }); +}; + + + /** * Returns node which is currently focused */ @@ -381,33 +366,73 @@ ce.prototype.moveToolBarButtonFocus = function(focusPrev){ */ ce.prototype.enterKeyPressed = function(event) { - var _this = this; + var _this = this, + curNode = this.getFocusedNode(); + /* + * обработка выбранной кнопки тулбара + * */ if (this.toolbar.isOpened) { - console.log("has focused btn", this.focusedToolbarBtn) + + switch ( this.focusedToolbarBtn.dataset["type"] ){ + + case "header": + var header = this.make.headerNode(); + + if (curNode.textContent){ + + header.textContent = curNode.textContent; + curNode.textContent = ""; + + // insert before, if curNode is paragraph or header or some other text-editable node + if (curNode.dataset["type"] == "text"){ + curNode.parentNode.insertBefore(header, curNode); + curNode.remove(); + } + // else insert header node after + else + curNode.parentNode.insertBefore(header, curNode.nextSibling); + + } else { + + curNode.parentNode.insertBefore(header, curNode); + curNode.remove(); + + } + + this.focusNode(header); + + break; + + } + + this.closeToolBar(); + + // TODO do the same by mouse clicking on any toolbar btn event.preventDefault(); - return + } + /* + * Перехват создания нового параграфа при нахождении в заголовке. + * По-умолчанию создается просто div. + * */ + else { - var sel = window.getSelection(); - var curNode = this.getFocusedNode(); + if (curNode.dataset["type"] == "header" && !this.isTextSelected()) { + var newNode = this.make.textNode(); + /** Add node */ + this.editableWrapper.insertBefore(newNode, curNode.nextSibling); - if (curNode.dataset["type"] == "header" && !this.isTextSelected()) { - var newNode = this.make.textNode(); + /** Set auto focus */ + setTimeout(function () { - /** Add node */ - this.editableWrapper.insertBefore(newNode, curNode.nextSibling); + _this.focusNode(newNode); + }); - /** Set auto focus */ - setTimeout(function () { - - _this.focusNode(newNode); - }); - - event.preventDefault(); - return; + event.preventDefault(); + } } }; @@ -477,6 +502,21 @@ ce.prototype.make = function () { return node; } + /** + * Header node + */ + function headerNode (content){ + + var node = document.createElement('h2'); + + node.classList.add("node"); + node.dataset["type"] = "header"; + + node.innerHTML = content || ''; + + return node; + } + function editorWrapper () { var wrapper = document.createElement('div'), @@ -496,8 +536,9 @@ ce.prototype.make = function () { this.toolbar = toolbar; this.toolbarButtons = toolbarButtons; this.toolbarButton = toolbarButton; - this.textNode = textNode; this.editorWrapper = editorWrapper; + this.textNode = textNode; + this.headerNode = headerNode; }; return new ceMake(); diff --git a/editor.css b/editor.css index cd3e1812..1e1d29a1 100644 --- a/editor.css +++ b/editor.css @@ -85,6 +85,7 @@ .codex_editor .node{ position: relative; z-index: 5; + min-height: 20px; } .codex_editor .add_buttons{ @@ -168,7 +169,6 @@ padding: 5px 0; font-size: 17px; margin: 0; - min-height: 20px; } .codex_editor {position: relative;} From 54d51f42d2e76721f1f935f776ba4cf9df3789ca Mon Sep 17 00:00:00 2001 From: Mark Dermanov Date: Sat, 2 Jan 2016 00:01:37 +0300 Subject: [PATCH 7/8] auto import textarea content to editor on init --- ce_interface.js | 75 +++++++++++++++++++++++++++++++++++++++++-------- example.html | 19 +++++++++++-- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index 70d28b4b..2dcf3224 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -32,6 +32,13 @@ var ce = function(settings) { /** Making a wrapper and interface */ this.makeInterface(); + + /* + * Импорт содержимого textarea в редактор + * */ + this.importHtml(); + + /** Bind all events */ this.bindEvents(); @@ -98,14 +105,67 @@ ce.prototype.exportHtml = function () { }; -/* +/** * Импорт разметки из итоговой текстареа * пока по кнопке "импорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) + * + * TODO + * 1) удалить лишние узлы, работа с которыми не предполагается в рамках редактора + * 2) удалить скрипты, стили + * 3) поочищать содержимое узлов от мусора - должен остаться только текст, теги форматирования (жирность и тд) и переносы строк (или их тоже убираем?) * */ ce.prototype.importHtml = function () { - this.editableWrapper.innerHTML = this.resultTextarea.value; + var node, body, i, nodeType, tmp; + + /* + * Парсим содержимое textarea. + * Создаем новый документ, получаем указатель на контенейр body. + * */ + tmp = new DOMParser().parseFromString( this.resultTextarea.value, "text/html" ); + body = tmp.getElementsByTagName("body")[0]; + + /* + * Обходим корневые узлы. Проставляем им класс и тип узла. + * */ + for(i = 0; i < body.children.length; i++){ + node = body.children.item(i); + + if (!node.classList.contains("node")) + node.classList.add("node"); + + + switch (node.tagName){ + case "P" : + nodeType = "text"; + break; + + case "H1" : + case "H2" : + case "H3" : + case "H4" : + case "H5" : + case "H6" : + nodeType = "header"; + break; + + case "UL" : + nodeType = "list"; + break; + + case "IMG" : + nodeType = "picture"; + break; + + case "CODE" : + nodeType = "code"; + break; + } + + node.dataset["type"] = nodeType; + } + + this.editableWrapper.innerHTML = body.innerHTML; - return false; }; @@ -126,15 +186,6 @@ ce.prototype.bindEvents = function () { }); - /* - * Импорт разметки из итоговой textarea - * пока по кнопке "импорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) - * */ - document.getElementById("import_html").addEventListener('click', function () { - _this.importHtml.apply(_this) - }); - - /** All keydowns on Window */ document.addEventListener('keydown', function (event) { _this.globalKeydownCallback(event); diff --git a/example.html b/example.html index ebf2ecd2..13ed9f46 100644 --- a/example.html +++ b/example.html @@ -11,12 +11,27 @@

CodeX Editor

-

- +
From ba12890a6199fe53fd1f2007dba6c2e82fe28d58 Mon Sep 17 00:00:00 2001 From: Mark Dermanov Date: Sat, 2 Jan 2016 00:12:06 +0300 Subject: [PATCH 8/8] export editor content to result textarea by click on "save" button save button must have a special ID "codex_editor_export_btn" closes #5 and closes old tasks #11 #9 #3 #12 #7 --- ce_interface.js | 12 ++++++------ example.html | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ce_interface.js b/ce_interface.js index 2dcf3224..3760bc71 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -42,7 +42,6 @@ var ce = function(settings) { /** Bind all events */ this.bindEvents(); - }; // All posible tools @@ -88,7 +87,7 @@ ce.prototype.makeInterface = function () { /** Insert Editor after initial textarea. Hide textarea */ this.resultTextarea.parentNode.insertBefore(wrapper, this.resultTextarea.nextSibling); - //this.resultTextarea.hidden = true; + this.resultTextarea.hidden = true; this.focusNode(firstNode); }; @@ -99,7 +98,8 @@ ce.prototype.makeInterface = function () { * пока по кнопке "экспорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) * */ ce.prototype.exportHtml = function () { - this.resultTextarea.value = this.editableWrapper.innerHTML; + this.resultTextarea.innerHTML = this.editableWrapper.innerHTML; + this.resultTextarea.value = this.editableWrapper.innerHTML; return false; }; @@ -178,10 +178,10 @@ ce.prototype.bindEvents = function () { selectedNodeClass = "selected"; /* - * Экспорт разметки в итоговый textarea - * пока по кнопке "экспорт", потом можно сделать на каждое изменение в редакторе (надо ли это?) + * Экспорт разметки в итоговый textarea по нажатию на кнопку "сохранить". + * Кнопка сохранения должна иметь, так же как и textarea, особенный ID. * */ - document.getElementById("export_html").addEventListener('click', function () { + document.getElementById("codex_editor_export_btn").addEventListener('click', function () { _this.exportHtml.apply(_this) }); diff --git a/example.html b/example.html index 13ed9f46..18040ed8 100644 --- a/example.html +++ b/example.html @@ -10,7 +10,7 @@

CodeX Editor

- +