Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Переход курсора на следующий и предыдущий блоки при нажатии на кнопки вверх/вниз #32

Merged
merged 16 commits into from
Jun 10, 2016
323 changes: 233 additions & 90 deletions codex-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,7 @@ cEditor.ui = {

block.addEventListener('keydown', function(event) {

cEditor.caret.save();
cEditor.callback.blockTransition(event, block);
cEditor.callback.blockKeydown(event, block);

}, false);

Expand Down Expand Up @@ -368,25 +367,129 @@ cEditor.callback = {

},

blockTransition : function(event, block) {
blockKeydown : function(event, block) {

switch (event.keyCode){

case cEditor.core.keys.DOWN:
case cEditor.core.keys.RIGHT:
cEditor.callback.blockRightOrDownArrowPressed(block);
break;

case cEditor.core.keys.UP:
case cEditor.core.keys.LEFT:
cEditor.callback.blockLeftOrUpArrowPressed(block);
break;

}

},

if (event.keyCode == cEditor.core.keys.DOWN || event.keyCode == cEditor.core.keys.RIGHT ) {
/**
* RIGHT or DOWN keydowns on block
*/
blockRightOrDownArrowPressed : function (block) {

if ( block.nextSibling == null )
return ;
var selection = window.getSelection(),
focusedNode = selection.anchorNode,
focusedNodeHolder;

cEditor.caret.setToNextBlock( block );
/** Check for caret exists */
if (!focusedNode){
return false;
}

else if (event.keyCode == cEditor.core.keys.UP || event.keyCode == cEditor.core.keys.LEFT ) {
while (focusedNode.className != 'ce_block') {

if ( block.previousSibling == null )
return ;
focusedNodeHolder = focusedNode.parentNode;
focusedNode = focusedNodeHolder;
}

cEditor.caret.setToPreviousBlock( block );
/** TAG is focused and node doesn't have childs */
if (focusedNode.childNodes.length === 0)
{
cEditor.caret.setToNextBlock(block);
return;
}

/**
* Find deepest child node
* Iterate child nodes and find LAST and DEEPEST node (
* We need it to check caret positon (it must be at the end)
*/
var focusedTextNode = '';

if (focusedNodeHolder.childNodes){
/** Looking from the END of node */
focusedTextNode = cEditor.content.getDeepestTextNodeFromPosition(focusedNodeHolder, focusedNodeHolder.childNodes.length);
}

/**
* Stop transition when caret is not at the end of Text node
* When we click "DOWN", caret moves to the end of node.
* We should check check caret position before we transmit/switch the block.
*/
if ( focusedTextNode.length != selection.anchorOffset ) {
return false;
}

cEditor.caret.setToNextBlock(block);

},

/**
* LEFT or UP keydowns on block
*/
blockLeftOrUpArrowPressed : function (block) {

var selection = window.getSelection(),
focusedNode = selection.anchorNode,
focusedNodeHolder;

/** Check for caret exists */
if (!focusedNode){
return false;
}

/** Looking for parent contentEditable block */
while (focusedNode.className != 'ce_block') {

focusedNodeHolder = focusedNode.parentNode;
focusedNode = focusedNodeHolder;
}

/** TAG is focused and node doesn't have childs */
if (focusedNode.childNodes.length === 0)
{
cEditor.caret.setToPreviousBlock(block);
return;
}

/**
* Find deepest child node
* Iterate child nodes and find LAST and DEEPEST node (
* We need it to check caret positon (it must be at the end)
*/
var focusedTextNode = '';

if (focusedNodeHolder.childNodes){
/** Looking from the END of node */
focusedTextNode = cEditor.content.getDeepestTextNodeFromPosition(focusedNodeHolder, 0);
}

/**
* Stop transition when caret is not at the end of Text node
* When we click "DOWN", caret moves to the end of node.
* We should check check caret position before we transmit/switch the block.
*/
if ( selection.anchorOffset !== 0) {
return false;
}

cEditor.caret.setToPreviousBlock(block);

}

};


Expand Down Expand Up @@ -521,6 +624,75 @@ cEditor.content = {
cEditor.caret.set(nodeCreated);
},


/**
* Iterates between child noted and looking for #text node on deepest level
* @param {Element} block - node where find
* @param {int} postiton - starting postion
* Example: childNodex.length to find from the end
* or 0 to find from the start
* @return {TextNode} block
* @uses DFS
*/
getDeepestTextNodeFromPosition : function (block, position) {

/**
* Clear Block from empty and useless spaces with trim.
* Such nodes we should remove
*/
var index,
blockChilds = block.childNodes;

for(index = 0; index < blockChilds.length; index++)
{
var node = blockChilds[index];

if (node.nodeType == cEditor.core.nodeTypes.TEXT) {

text = node.textContent.trim();

if (text == '') {

block.removeChild(node);
position--;
}
}
}
/** Setting default position when we deleted all empty nodes */
if ( position < 0 )
position = 1;

var looking_from_start = false;

/** For looking from START */
if (position === 0) {
looking_from_start = true;
position = 1;
}

while ( position ) {

/** @todo comment */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

напиши тут полноценный комментарий, пока не забыли

if ( looking_from_start ) {
block = block.childNodes[0];
} else {
block = block.childNodes[position-1];
}

if ( block.nodeType == cEditor.core.nodeTypes.TAG ){

position = block.childNodes.length;

} else if (block.nodeType == cEditor.core.nodeTypes.TEXT ){

position = 0;
}

}

return block;
}

}

cEditor.caret = {
Expand Down Expand Up @@ -561,118 +733,89 @@ cEditor.caret = {
},

/**
* Creates Documnt Range and sets caret to the NodeElement.
* @param {Element} NodeElement - Changed Node.
* Creates Documnt Range and sets caret to the element.
* @uses caret.save — if you need to save caret position
* @param {Element} el - Changed Node.
* @todo remove saving positon
* @todo - Check nodeToSet for type: if TAG -> look for nearest TextNode
*/
set : function(NodeElement) {
set : function( el , index, offset) {

var nodeIndex = this.focusedNodeIndex || 0,
caretOffset = this.offset || 0,
childs = NodeElement.childNodes,
nodeChild = childs[nodeIndex];
offset = offset || this.offset || 0;
index = index || this.focusedNodeIndex || 0;

var range = document.createRange();
var childs = el.childNodes,
nodeToSet;

if ( NodeElement.childNodes.length == 0 ) {
if ( childs.length === 0 ) {

nodeToSet = el;
offset = 0;

} else {

nodeChild = NodeElement;
caretOffset = 0;
nodeToSet = childs[index];

}

var range = document.createRange(),
var range = document.createRange(),
selection = window.getSelection();

setTimeout(function() {

range.setStart(nodeChild, caretOffset);
range.setEnd(nodeChild, caretOffset);
range.setStart(nodeToSet, offset);
range.setEnd(nodeToSet, offset);

selection.removeAllRanges();
selection.addRange(range);

}, 50);
}, 100);
},

/**
* @param {Element} - block element where we should find caret position
*/
get : function (el) {

},

/**
* @param {Element} block - element from which we take next block
*/
setToNextBlock : function(block) {

var selection = window.getSelection(),
focusedElement = selection.anchorNode.parentNode;

/** Stop transition when caret is not at the end of Text node
* When we click "DOWN", caret moves to the end of node.
* We should check check caret position before we transmit/switch the block.
*/
if ( !block.nextSibling ) {
return false;
}

if ( cEditor.caret.offset != selection.anchorNode.length
&& typeof( selection.anchorNode.length ) != 'undefined') {
cEditor.caret.save();
return ;
cEditor.caret.offset = 0;
cEditor.caret.focusedNodeIndex = 0;

}
cEditor.caret.set(block.nextSibling, 0, 0);

console.log(block);

var el = block;

console.log(block.childNodes.length);
// while ( block.)

// /* Setting Caret to the first child of next node */
// else if ( selection.focusNode.length == cEditor.caret.Offset ) {
//
// /** Firstchild of block */
// cEditor.caret.offset = 0;
// cEditor.caret.focusedNodeIndex = 0;
//
// cEditor.caret.set(block.nextSibling);
//
// } else {
//
// /** Firstchild of block */
// cEditor.caret.offset = 0;
// cEditor.caret.focusedNodeIndex = 0;
// cEditor.caret.set(block.nextSibling);
// }
},

setToPreviousBlock : function(block) {

var selection = window.getSelection(),
focusedElement = selection.anchorNode.parentNode;

/** Stop transition when caret is not at the beggining of Text node
* When we click "UP", caret moves to the end of node.
* We should check check caret position before we transmit/switch the block.
*/

if ( cEditor.caret.offset != 0
&& typeof( selection.anchorNode.length ) != 'undefined') {

cEditor.caret.save();
return ;

if ( !block.previousSibling ) {
return false;
}

/* Setting Caret to the first child of previous node */
else if ( selection.anchorOffset == 0
&& cEditor.caret.focusedNodeIndex == 0
&& typeof( block.previousSibling.childNodes.length ) != 'undefined') {

cEditor.caret.focusedNodeIndex = (block.previousSibling.childNodes.length == 0) ? 0 : block.previousSibling.childNodes.length - 1;
cEditor.caret.offset = (block.previousSibling.childNodes.length == 0) ? 0 : block.previousSibling.childNodes[cEditor.caret.focusedNodeIndex].length;
var lastChildOfPreiviousBlockIndex = block.previousSibling.childNodes.length;
var theEndOfPrevieousBlockLastNode = 0;

cEditor.caret.set(block.previousSibling);

} else {

cEditor.caret.offset = 0;
cEditor.caret.focusedNodeIndex = 0;

cEditor.caret.set(block.previousSibling);
/** Index in childs Array */
if (lastChildOfPreiviousBlockIndex !== 0) {
lastChildOfPreiviousBlockIndex--;
}

if (block.previousSibling.childNodes.length !== 0) {
theEndOfPrevieousBlockLastNode = block.previousSibling.childNodes[lastChildOfPreiviousBlockIndex].length;
}
cEditor.caret.offset = theEndOfPrevieousBlockLastNode;
cEditor.caret.focusedNodeIndex = lastChildOfPreiviousBlockIndex;

cEditor.caret.set(block.previousSibling, lastChildOfPreiviousBlockIndex , theEndOfPrevieousBlockLastNode);
},
};

Expand Down