mirror of
https://github.com/codex-team/editor.js
synced 2024-06-17 13:15:20 +02:00
Merge branch 'master' into quotes
# Conflicts: # example.html
This commit is contained in:
commit
6b69d1f325
173
codex-editor.js
173
codex-editor.js
|
@ -24,13 +24,13 @@ var cEditor = (function (cEditor) {
|
|||
blockSettings : null,
|
||||
toolbarButtons : {}, // { type : DomEl, ... }
|
||||
redactor : null,
|
||||
}
|
||||
};
|
||||
|
||||
// Current editor state
|
||||
cEditor.state = {
|
||||
html : '',
|
||||
blocks : []
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialization
|
||||
|
@ -53,7 +53,7 @@ var cEditor = (function (cEditor) {
|
|||
.then(this.renderer.makeBlocksFromData)
|
||||
.catch(function (error) {
|
||||
cEditor.core.log('Initialization failed with error: %o', 'warn', error);
|
||||
})
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
@ -92,7 +92,7 @@ cEditor.core = {
|
|||
|
||||
cEditor.nodes.textarea = document.getElementById(userSettings.textareaId || cEditor.settings.textareaId);
|
||||
|
||||
if (typeof cEditor.nodes.textarea == undefined || cEditor.nodes.textarea == null) {
|
||||
if (typeof cEditor.nodes.textarea === undefined || cEditor.nodes.textarea === null) {
|
||||
reject(Error("Textarea wasn't found by ID: #" + userSettings.textareaId));
|
||||
} else {
|
||||
resolve();
|
||||
|
@ -153,7 +153,7 @@ cEditor.core = {
|
|||
return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -304,11 +304,11 @@ cEditor.renderer = {
|
|||
return {
|
||||
type : pluginName,
|
||||
block : block
|
||||
}
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Methods for saving HTML blocks to JSON object
|
||||
|
@ -324,7 +324,7 @@ cEditor.saver = {
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -532,7 +532,7 @@ cEditor.callback = {
|
|||
cEditor.toolbar.toolClicked(event);
|
||||
cEditor.toolbar.close();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
@ -556,7 +556,16 @@ cEditor.callback = {
|
|||
|
||||
redactorClicked : function (event) {
|
||||
|
||||
cEditor.content.workingNodeChanged();
|
||||
if ( cEditor.parser.isFirstLevelBlock(event.target) ) {
|
||||
|
||||
/** If clicked on editor first-level block, set event target*/
|
||||
cEditor.content.workingNodeChanged(event.target);
|
||||
|
||||
} else {
|
||||
|
||||
/** Otherwise get current node from selection */
|
||||
cEditor.content.workingNodeChanged();
|
||||
}
|
||||
|
||||
cEditor.toolbar.move();
|
||||
|
||||
|
@ -653,35 +662,49 @@ cEditor.callback = {
|
|||
/** Founded contentEditable element doesn't have childs */
|
||||
if (focusedNode.childNodes.length === 0)
|
||||
{
|
||||
cEditor.caret.setToNextBlock(block);
|
||||
cEditor.caret.setToNextBlock(focusedNode);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find deepest child node
|
||||
* Iterate child nodes and find LAST DEEPEST node
|
||||
* We need to check caret positon (it must be at the end)
|
||||
* @param focusedNodeIndex is index of childnode by length
|
||||
* @param focusedTextNode is Text node founded by DFS algorithm
|
||||
* Do nothing when caret doesn not reaches the end of last child
|
||||
*/
|
||||
var focusedTextNode = '',
|
||||
focusedNodeIndex = cEditor.caret.focusedNodeIndex + 1;
|
||||
var caretInLastChild = false,
|
||||
caretAtTheEndOfText = false;
|
||||
|
||||
if (focusedNodeHolder.childNodes){
|
||||
/** Looking from the END of node */
|
||||
focusedTextNode = cEditor.content.getDeepestTextNodeFromPosition(focusedNodeHolder, focusedNodeHolder.childNodes.length);
|
||||
var editableElement = focusedNode.querySelector('[contenteditable]'),
|
||||
lastChild,
|
||||
deepestTextnode;
|
||||
|
||||
if (!editableElement) {
|
||||
cEditor.core.log('Can not find editable element in current block: %o', 'warn', focusedNode);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop transition when caret is not at the end of Text node
|
||||
* When we click "DOWN" or "RIGHT", caret moves to the end of node.
|
||||
* We should check caret position before we transmit/switch the block.
|
||||
*/
|
||||
if ( block.childNodes.length != focusedNodeIndex || focusedTextNode.length != selection.anchorOffset) {
|
||||
lastChild = editableElement.childNodes[editableElement.childNodes.length - 1 ];
|
||||
|
||||
if (cEditor.core.isDomNode(lastChild)) {
|
||||
|
||||
deepestTextnode = cEditor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length);
|
||||
|
||||
} else {
|
||||
|
||||
deepestTextnode = lastChild;
|
||||
|
||||
}
|
||||
|
||||
caretInLastChild = selection.anchorNode == deepestTextnode;
|
||||
caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset;
|
||||
|
||||
console.log("каретка в последнем узле: %o", caretInLastChild);
|
||||
console.log("каретка в конце последнего узла: %o", caretAtTheEndOfText);
|
||||
|
||||
if ( !caretInLastChild || !caretAtTheEndOfText ) {
|
||||
cEditor.core.log('arrow [down|right] : caret does not reached the end');
|
||||
return false;
|
||||
}
|
||||
|
||||
cEditor.caret.setToNextBlock(block);
|
||||
cEditor.caret.setToNextBlock(focusedNode);
|
||||
|
||||
},
|
||||
|
||||
|
@ -754,8 +777,8 @@ cEditor.callback = {
|
|||
* First we check, if caret is at the end of last node and offset is legth of text node
|
||||
* focusedNodeIndex + 1, because that we compare non-arrays index.
|
||||
*/
|
||||
if ( currentNode.length === cEditor.caret.offset
|
||||
&& parentOfFocusedNode.childNodes.length == cEditor.caret.focusedNodeIndex + 1) {
|
||||
if ( currentNode.length === cEditor.caret.offset &&
|
||||
parentOfFocusedNode.childNodes.length == cEditor.caret.focusedNodeIndex + 1) {
|
||||
|
||||
/** Prevent <div></div> creation */
|
||||
event.preventDefault();
|
||||
|
@ -852,17 +875,26 @@ cEditor.content = {
|
|||
var selection = window.getSelection(),
|
||||
focused;
|
||||
|
||||
if (selection.anchorNode != null) {
|
||||
if (selection.anchorNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( selection.anchorNode.nodeType == cEditor.core.nodeTypes.TAG ) {
|
||||
focused = selection.anchorNode;
|
||||
} else {
|
||||
focused = selection.focusNode.parentElement;
|
||||
}
|
||||
if ( selection.anchorNode.nodeType == cEditor.core.nodeTypes.TAG ) {
|
||||
focused = selection.anchorNode;
|
||||
} else {
|
||||
focused = selection.focusNode.parentElement;
|
||||
}
|
||||
|
||||
if ( !cEditor.parser.isFirstLevelBlock(focused) ) {
|
||||
focused = focused.parentElement;
|
||||
|
||||
/** Iterate with parent nodes to find first-level*/
|
||||
var parent = focused.parentNode;
|
||||
|
||||
while (parent && !cEditor.parser.isFirstLevelBlock(parent)){
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
|
||||
focused = parent;
|
||||
}
|
||||
|
||||
if (focused != cEditor.nodes.redactor){
|
||||
|
@ -878,7 +910,13 @@ cEditor.content = {
|
|||
*/
|
||||
workingNodeChanged : function (setCurrent) {
|
||||
|
||||
this.currentNode = setCurrent || this.getNodeFocused();
|
||||
var nodeWithSelection = this.getNodeFocused();
|
||||
|
||||
if (!setCurrent && !nodeWithSelection) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentNode = setCurrent || nodeWithSelection;
|
||||
|
||||
},
|
||||
|
||||
|
@ -920,16 +958,23 @@ cEditor.content = {
|
|||
|
||||
},
|
||||
|
||||
insertBlock : function(newBlock, blockType) {
|
||||
/**
|
||||
* Inserts new block to redactor
|
||||
* Wrapps block into a DIV with BLOCK_CLASSNAME class
|
||||
*/
|
||||
insertBlock : function(newBlockContent, blockType) {
|
||||
|
||||
var workingNode = cEditor.content.currentNode;
|
||||
var workingBlock = cEditor.content.currentNode,
|
||||
newBlock = cEditor.draw.block('DIV');
|
||||
|
||||
newBlock.classList.add(cEditor.ui.BLOCK_CLASSNAME);
|
||||
newBlock.dataset.type = blockType;
|
||||
|
||||
if (workingNode) {
|
||||
newBlock.appendChild(newBlockContent);
|
||||
|
||||
cEditor.core.insertAfter(workingNode, newBlock);
|
||||
if (workingBlock) {
|
||||
|
||||
cEditor.core.insertAfter(workingBlock, newBlock);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -1074,7 +1119,7 @@ cEditor.content = {
|
|||
/** Text is empty. We should remove this child from node before we start DFS
|
||||
* decrease the quantity of childs.
|
||||
*/
|
||||
if (text == '') {
|
||||
if (text === '') {
|
||||
|
||||
block.removeChild(node);
|
||||
position--;
|
||||
|
@ -1121,7 +1166,7 @@ cEditor.content = {
|
|||
return block;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
cEditor.caret = {
|
||||
|
||||
|
@ -1144,11 +1189,18 @@ cEditor.caret = {
|
|||
*/
|
||||
save : function() {
|
||||
|
||||
var selection = window.getSelection();
|
||||
var parentElement = selection.anchorNode,
|
||||
previousElement = selection.anchorNode.previousSibling,
|
||||
var selection = window.getSelection(),
|
||||
parentElement,
|
||||
previousElement,
|
||||
nodeIndex = 0;
|
||||
|
||||
if (!selection.anchorNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
parentElement = selection.anchorNode;
|
||||
previousElement = selection.anchorNode.previousSibling;
|
||||
|
||||
/**
|
||||
* We get index of node which is child of #BLOCK_CLASSNAME.
|
||||
* if selected node is not below the block container, we get the closest TAG which is below #BLOCK_CLASSNAME
|
||||
|
@ -1165,7 +1217,7 @@ cEditor.caret = {
|
|||
}
|
||||
|
||||
/** Counting index of focused node */
|
||||
while (previousElement != null) {
|
||||
while (previousElement !== null) {
|
||||
|
||||
nodeIndex ++;
|
||||
previousElement = previousElement.previousSibling;
|
||||
|
@ -1228,14 +1280,25 @@ cEditor.caret = {
|
|||
*/
|
||||
setToNextBlock : function(block) {
|
||||
|
||||
cEditor.caret.offset = 0;
|
||||
cEditor.caret.focusedNodeIndex = 0;
|
||||
|
||||
var nextBlock = block.nextSibling,
|
||||
nextBlockEditableElement;
|
||||
|
||||
console.log("nextBlock: %o", nextBlock);
|
||||
|
||||
nextBlockEditableElement = nextBlock.querySelector('[contenteditable], [contenteditable="true"]');
|
||||
|
||||
console.log("nextBlockEditableElement: %o", nextBlockEditableElement);
|
||||
|
||||
|
||||
if ( !block.nextSibling ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cEditor.caret.offset = 0;
|
||||
cEditor.caret.focusedNodeIndex = 0;
|
||||
|
||||
cEditor.caret.set(block.nextSibling, 0, 0);
|
||||
cEditor.caret.set(nextBlockEditableElement, 0, 0);
|
||||
cEditor.content.workingNodeChanged(block.nextSibling);
|
||||
},
|
||||
|
||||
|
@ -1688,7 +1751,7 @@ cEditor.parser = {
|
|||
isFirstLevelBlock : function (node) {
|
||||
|
||||
return node.nodeType == cEditor.core.nodeTypes.TAG &&
|
||||
cEditor.settings.blockTags.indexOf(node.tagName) !== -1;
|
||||
node.classList.contains(cEditor.ui.BLOCK_CLASSNAME);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1797,7 +1860,7 @@ cEditor.draw = {
|
|||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -1846,7 +1909,7 @@ var paragraphTool = {
|
|||
*/
|
||||
make : function (data) {
|
||||
|
||||
var tag = document.createElement('P');
|
||||
var tag = document.createElement('DIV');
|
||||
|
||||
if (data && data.text) {
|
||||
tag.innerHTML = data.text;
|
||||
|
@ -1996,7 +2059,7 @@ var headerTool = {
|
|||
selectTypeButton;
|
||||
|
||||
/** Add holder classname */
|
||||
holder.className = 'ce_plugin_header--settings'
|
||||
holder.className = 'ce_plugin_header--settings';
|
||||
|
||||
/** Add settings helper caption */
|
||||
caption.textContent = 'Настройки заголовка';
|
||||
|
|
|
@ -75,7 +75,6 @@
|
|||
.ce_redactor {
|
||||
position: relative;
|
||||
outline: none;
|
||||
background: #FCFCFC;
|
||||
padding: 1px 0;
|
||||
}
|
||||
|
||||
|
@ -184,13 +183,14 @@
|
|||
|
||||
.ce_redactor .ce_block{
|
||||
padding: 10px;
|
||||
margin: -1px;
|
||||
border: 1px dotted #ccc;
|
||||
/*margin: -1px;*/
|
||||
/*border: 1px dotted #ccc;*/
|
||||
background: #fff;
|
||||
outline: none;
|
||||
}
|
||||
.ce_redactor .ce_block:focus{
|
||||
box-shadow: inset 0 0 0px 2px rgba(148, 158, 191, 0.05);
|
||||
background: #fbfbfb;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
|
|
10
example.html
10
example.html
|
@ -20,8 +20,11 @@
|
|||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
<<<<<<< HEAD
|
||||
<link rel="stylesheet" href="plugins/ceditor-tool-link.css" />
|
||||
<link rel="stylesheet" href="plugins/ceditor-tool-quote/ceditor-tool-quote.css" />
|
||||
=======
|
||||
>>>>>>> master
|
||||
</head>
|
||||
<body style="padding: 100px">
|
||||
|
||||
|
@ -268,4 +271,11 @@
|
|||
</script>
|
||||
|
||||
<script src="plugins/ceditor-tool-link.js"></script>
|
||||
<<<<<<< HEAD
|
||||
<script src="plugins/ceditor-tool-quote/ceditor-tool-quote.js"></script>
|
||||
=======
|
||||
<link rel="stylesheet" href="plugins/ceditor-tool-link.css" />
|
||||
|
||||
<script src="plugins/images/plugin.js"></script>
|
||||
<link rel="stylesheet" href="plugins/images/plugin.css" />
|
||||
>>>>>>> master
|
||||
|
|
22
plugins/images/plugin.css
Normal file
22
plugins/images/plugin.css
Normal file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Image plugin for codex-editor
|
||||
* @author CodeX Team <team@ifmo.su>
|
||||
*
|
||||
* @version 0.0.1
|
||||
*/
|
||||
.ce-plugin-image__holder{
|
||||
background: #FEFEFE;
|
||||
border: 2px dashed #E8EBF5;
|
||||
border-radius: 55px;
|
||||
margin: 30px 0;
|
||||
padding: 30px 40px;
|
||||
white-space: nowrap;
|
||||
color: #A5ABBC;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.ce-plugin-image__button{
|
||||
float: right;
|
||||
font-family: "codex_editor";
|
||||
font-size: 1.5em;
|
||||
color: #8990AA;
|
||||
}
|
75
plugins/images/plugin.js
Normal file
75
plugins/images/plugin.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* Image plugin for codex-editor
|
||||
* @author CodeX Team <team@ifmo.su>
|
||||
*
|
||||
* @version 0.0.1
|
||||
*/
|
||||
var ceImage = {
|
||||
|
||||
make : function ( data ) {
|
||||
|
||||
var holder = ceImage.ui.holder(),
|
||||
uploadButton = ceImage.ui.uploadButton();
|
||||
|
||||
holder.textContent = 'Past image URL or file';
|
||||
holder.appendChild(uploadButton);
|
||||
|
||||
holder.contentEditable = true;
|
||||
|
||||
return holder;
|
||||
|
||||
},
|
||||
|
||||
render : function( data ){
|
||||
|
||||
return this.make(data);
|
||||
|
||||
},
|
||||
|
||||
/** */
|
||||
save : function ( block ){
|
||||
|
||||
},
|
||||
|
||||
ui : {
|
||||
|
||||
holder : function(){
|
||||
|
||||
var element = document.createElement('DIV');
|
||||
|
||||
element.classList.add('ce-plugin-image__holder');
|
||||
|
||||
return element;
|
||||
|
||||
},
|
||||
|
||||
uploadButton : function(){
|
||||
|
||||
var button = document.createElement('SPAN');
|
||||
|
||||
button.classList.add('ce-plugin-image__button');
|
||||
|
||||
button.innerHTML = '<i class="ce-icon-picture"></i>';
|
||||
|
||||
return button;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Add plugin it to redactor tools
|
||||
*/
|
||||
cEditor.tools.image = {
|
||||
|
||||
type : 'image',
|
||||
iconClassname : 'ce-icon-picture',
|
||||
make : ceImage.make,
|
||||
render : ceImage.render,
|
||||
save : ceImage.save
|
||||
|
||||
};
|
Loading…
Reference in a new issue