mirror of
https://github.com/codex-team/editor.js
synced 2024-06-26 09:20:07 +02:00
BlockManager
This commit is contained in:
parent
b83bd752f9
commit
bf83f41cc2
|
@ -73,6 +73,7 @@
|
|||
"XMLHttpRequest": true,
|
||||
"ActiveXObject": true,
|
||||
"RegExp": true,
|
||||
"Node": true
|
||||
"Node": true,
|
||||
"Proxy": true
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -17,8 +17,8 @@
|
|||
|
||||
</body>
|
||||
|
||||
<!--<script src="plugins/paragraph/paragraph.js?v=100"></script>-->
|
||||
<!--<link rel="stylesheet" href="plugins/paragraph/paragraph.css">-->
|
||||
<script src="plugins/paragraph/paragraph.js?v=100"></script>
|
||||
<link rel="stylesheet" href="plugins/paragraph/paragraph.css">
|
||||
|
||||
<!--<script src="plugins/header/header.js"></script>-->
|
||||
<!--<link rel="stylesheet" href="plugins/header/header.css">-->
|
||||
|
@ -71,26 +71,25 @@
|
|||
displayInToolbox : true,
|
||||
enableLineBreaks : true
|
||||
}
|
||||
},
|
||||
data: {
|
||||
items: [
|
||||
{
|
||||
type : 'paragraph',
|
||||
data : {
|
||||
text : 'Привет от CodeX'
|
||||
}
|
||||
},
|
||||
{
|
||||
type : 'paragraph',
|
||||
data : {
|
||||
text : 'Пишите нам на team@ifmo.su'
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
console.log(editor);
|
||||
|
||||
var items = [
|
||||
{
|
||||
type : 'paragraph',
|
||||
data : {
|
||||
text : 'Привет от CodeX'
|
||||
}
|
||||
},
|
||||
{
|
||||
type : 'paragraph',
|
||||
data : {
|
||||
text : 'Пишите нам на team@ifmo.su'
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
// var editor2 = new CodexEditor({
|
||||
// holderId : 'cdx',
|
||||
// initialBlock: 'header'
|
||||
|
|
|
@ -243,6 +243,7 @@ module.exports = class CodexEditor {
|
|||
return Promise.resolve()
|
||||
.then(prepareDecorator(this.moduleInstances.ui))
|
||||
.then(prepareDecorator(this.moduleInstances.Tools))
|
||||
.then(prepareDecorator(this.moduleInstances.BlockManager))
|
||||
|
||||
.catch(function (error) {
|
||||
|
||||
|
|
63
src/components/block.js
Normal file
63
src/components/block.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
*
|
||||
* @class Block
|
||||
* @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool
|
||||
*
|
||||
* @property {Tool} tool — current block tool (Paragraph, for example)
|
||||
* @property {Object} CSS — block`s css classes
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import $ from './dom';
|
||||
|
||||
export default class Block {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {Object} tool — current block plugin`s instance
|
||||
*/
|
||||
constructor(tool) {
|
||||
|
||||
this.tool = tool;
|
||||
|
||||
this.CSS = {
|
||||
wrapper: 'ce-block',
|
||||
content: 'ce-block__content'
|
||||
};
|
||||
|
||||
this._html = this._compose();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Make default block wrappers and put tool`s content there
|
||||
*
|
||||
* @returns {HTMLDivElement}
|
||||
* @private
|
||||
*/
|
||||
_compose() {
|
||||
|
||||
let wrapper = $.make('div', this.CSS.wrapper),
|
||||
content = $.make('div', this.CSS.content);
|
||||
|
||||
content.appendChild(this.tool.html);
|
||||
wrapper.appendChild(content);
|
||||
|
||||
return wrapper;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block`s HTML
|
||||
*
|
||||
* @returns {HTMLDivElement}
|
||||
*/
|
||||
get html() {
|
||||
|
||||
return this._html;
|
||||
|
||||
}
|
||||
|
||||
}
|
344
src/components/modules/blockManager.js
Normal file
344
src/components/modules/blockManager.js
Normal file
|
@ -0,0 +1,344 @@
|
|||
/**
|
||||
* @class BlockManager
|
||||
* @classdesc Manage editor`s blocks storage and appearance
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
import Block from '../block';
|
||||
|
||||
module.exports = class BlockManager {
|
||||
|
||||
/**
|
||||
* Module key name
|
||||
* @returns {string}
|
||||
*/
|
||||
static get name() {
|
||||
|
||||
return 'BlockManager';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {EditorConfig} config
|
||||
*/
|
||||
constructor({ config }) {
|
||||
|
||||
this.config = config;
|
||||
this.Editor = null;
|
||||
this._blocks = null;
|
||||
this._currentBlcokIndex = -1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Editor modules setting
|
||||
*
|
||||
* @param Editor
|
||||
*/
|
||||
set state(Editor) {
|
||||
|
||||
this.Editor = Editor;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called after Editor.ui preparation
|
||||
* Define this._blocks property
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
prepare() {
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
||||
let blocks = new Blocks(this.Editor.ui.nodes.redactor);
|
||||
|
||||
/**
|
||||
* We need to use Proxy to overload set/get [] operator.
|
||||
* So we can use array-like syntax to access blocks
|
||||
*
|
||||
* @example
|
||||
* this._blocks[0] = new Block(...);
|
||||
*
|
||||
* block = this._blocks[0];
|
||||
*
|
||||
* @todo proxy the enumerate method
|
||||
*
|
||||
* @type {Proxy}
|
||||
* @private
|
||||
*/
|
||||
this._blocks = new Proxy(blocks, {
|
||||
set: Blocks.set,
|
||||
get: Blocks.get
|
||||
});
|
||||
|
||||
resolve();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert new block into _blocks
|
||||
*
|
||||
* @param {String} toolName — plugin name
|
||||
* @param {Object} data — plugin data
|
||||
*/
|
||||
insert(toolName, data) {
|
||||
|
||||
let toolInstance = this.Editor.Tools.construct(toolName, data),
|
||||
block = new Block(toolInstance);
|
||||
|
||||
this._blocks[++this._currentBlcokIndex] = block;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Block instance by html element
|
||||
*
|
||||
* @todo get first level block before searching
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* @returns {Block}
|
||||
*/
|
||||
getBlock(element) {
|
||||
|
||||
let nodes = Array.prototype.slice.call(this._blocks.workingArea.children),
|
||||
index = nodes.indexOf(element);
|
||||
|
||||
if (index >= 0) {
|
||||
|
||||
return this._blocks[index];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current Block instance
|
||||
*/
|
||||
get currentBlock() {
|
||||
|
||||
return this._blocks.workingArea.children[this._currentBlcokIndex];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get working html element
|
||||
*/
|
||||
get currentNode() {
|
||||
|
||||
return this._blocks.workingArea.children[this._currentBlcokIndex];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set _currentBlockIndex to passed block
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
set currentNode(element) {
|
||||
|
||||
let nodes = Array.prototype.slice.call(this._blocks.workingArea.children);
|
||||
|
||||
this._currentBlcokIndex = nodes.indexOf(element);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of Block instances
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
get blocks() {
|
||||
|
||||
return this._blocks.array;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Blocks
|
||||
* @classdesc Class to work with Block instances array
|
||||
*
|
||||
* @private
|
||||
*
|
||||
* @property {HTMLElement} workingArea — editor`s working node
|
||||
*
|
||||
*/
|
||||
class Blocks {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {HTMLElement} workingArea — editor`s working node
|
||||
*/
|
||||
constructor(workingArea) {
|
||||
|
||||
this._blocks = [];
|
||||
this.workingArea = workingArea;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Push back new Block
|
||||
*
|
||||
* @param {Block} block
|
||||
*/
|
||||
push(block) {
|
||||
|
||||
this._blocks.push(block);
|
||||
this.workingArea.appendChild(block.html);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert new Block at passed index
|
||||
*
|
||||
* @param {Number} index — index to insert Block
|
||||
* @param {Block} block — Block to insert
|
||||
*/
|
||||
insert(index, block) {
|
||||
|
||||
if (!this.length) {
|
||||
|
||||
this.push(block);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (index > this.length) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
this._blocks[index] = block;
|
||||
|
||||
if (index > 0) {
|
||||
|
||||
let previousBlock = this._blocks[index - 1];
|
||||
|
||||
previousBlock.html.insertAdjacentElement('afterend', block.html);
|
||||
|
||||
} else {
|
||||
|
||||
let nextBlock = this._blocks[index + 1];
|
||||
|
||||
nextBlock.html.insertAdjacentElement('beforebegin', block.html);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert Block after passed target
|
||||
*
|
||||
* @todo decide if this method is necessary
|
||||
*
|
||||
* @param {Block} targetBlock — target after wich Block should be inserted
|
||||
* @param {Block} newBlock — Block to insert
|
||||
*/
|
||||
insertAfter(targetBlock, newBlock) {
|
||||
|
||||
let index = this._blocks.indexOf(targetBlock);
|
||||
|
||||
this.insert(index + 1, newBlock);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Block by index
|
||||
*
|
||||
* @param {Number} index — Block index
|
||||
* @returns {Block}
|
||||
*/
|
||||
get(index) {
|
||||
|
||||
return this._blocks[index];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return index of passed Block
|
||||
*
|
||||
* @param {Block} block
|
||||
* @returns {Number}
|
||||
*/
|
||||
indexOf(block) {
|
||||
|
||||
return this._blocks.indexOf(block);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length of Block instances array
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
get length() {
|
||||
|
||||
return this._blocks.length;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Block instances array
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
get array() {
|
||||
|
||||
return this._blocks;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy trap to implement array-like setter
|
||||
*
|
||||
* @example
|
||||
* blocks[0] = new Block(...)
|
||||
*
|
||||
* @param {Blocks} instance — Blocks instance
|
||||
* @param {Number|String} index — block index
|
||||
* @param {Block} block — Block to set
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
static set(instance, index, block) {
|
||||
|
||||
if (isNaN(Number(index))) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
instance.insert(index, block);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy trap to implement array-like getter
|
||||
*
|
||||
* @param {Blocks} instance — Blocks instance
|
||||
* @param {Number|String} index — Block index
|
||||
* @returns {Block|*}
|
||||
*/
|
||||
static get(instance, index) {
|
||||
|
||||
if (isNaN(Number(index))) {
|
||||
|
||||
return instance[index];
|
||||
|
||||
}
|
||||
|
||||
return instance.get(index);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -66,11 +66,7 @@ module.exports = class Renderer {
|
|||
let tool = item.type,
|
||||
data = item.data;
|
||||
|
||||
let instance = this.Editor.Tools.construct(tool, data),
|
||||
index = this.Editor.Content.insertBlock(instance.html);
|
||||
|
||||
|
||||
this.Editor.Tools.add(instance, index);
|
||||
this.Editor.BlockManager.insert(tool, data);
|
||||
|
||||
return Promise.resolve();
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* @todo update according to current API
|
||||
*
|
||||
* @typedef {Object} Tool
|
||||
* @property render
|
||||
* @property save
|
||||
|
@ -100,8 +102,6 @@ module.exports = class Tools {
|
|||
this.toolsAvailable = {};
|
||||
this.toolsUnavailable = {};
|
||||
|
||||
this._list = [];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,6 +215,9 @@ module.exports = class Tools {
|
|||
*
|
||||
* @param {String} tool — tool name
|
||||
* @param {Object} data — initial data
|
||||
*
|
||||
* @todo throw exceptions if tool doesnt exist
|
||||
*
|
||||
*/
|
||||
construct(tool, data) {
|
||||
|
||||
|
@ -227,32 +230,4 @@ module.exports = class Tools {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert tool instance for private list
|
||||
*
|
||||
* @param {Object} instance — tool instance
|
||||
* @param {Number} index — tool index
|
||||
*/
|
||||
add(instance, index) {
|
||||
|
||||
this._list[index] = instance;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tool instance by html element
|
||||
*
|
||||
* @param el
|
||||
* @returns {*}
|
||||
*/
|
||||
getByElement(el) {
|
||||
|
||||
let index = el.dataset.toolId;
|
||||
|
||||
if (!index) return null;
|
||||
|
||||
return this._list[index];
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue