mirror of
https://github.com/codex-team/editor.js
synced 2024-06-16 04:35:50 +02:00
Renderer sequence, Render and Save example, (#53)
* Renderer sequence, Render and Save example, * move render method close to the save * fixed bugs and parapraph plugin added * result JSON example * upd * upd * cEditor tools cleared default methods * upd
This commit is contained in:
parent
34eb871bb0
commit
b93942a820
345
codex-editor.js
345
codex-editor.js
|
@ -8,7 +8,7 @@ var cEditor = (function (cEditor) {
|
|||
|
||||
// Default settings
|
||||
cEditor.settings = {
|
||||
tools : ['header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],
|
||||
tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],
|
||||
textareaId : 'codex-editor',
|
||||
|
||||
// First-level tags viewing as separated blocks. Other'll be inserted as child
|
||||
|
@ -27,7 +27,7 @@ var cEditor = (function (cEditor) {
|
|||
}
|
||||
|
||||
// Current editor state
|
||||
cEditor.state = {
|
||||
cEditor.state = {
|
||||
html : '',
|
||||
blocks : []
|
||||
}
|
||||
|
@ -166,8 +166,6 @@ cEditor.renderer = {
|
|||
*/
|
||||
makeBlocksFromData : function (argument) {
|
||||
|
||||
console.info('renderer makeBlocksFromData');
|
||||
|
||||
Promise.resolve()
|
||||
|
||||
/** First, get JSON from state */
|
||||
|
@ -177,12 +175,12 @@ cEditor.renderer = {
|
|||
|
||||
/** Then, start to iterate they */
|
||||
.then(cEditor.renderer.appendBlocks)
|
||||
|
||||
|
||||
/** Write log if something goes wrong */
|
||||
.catch(function(error) {
|
||||
cEditor.core.log('Error while parsing JSON: %o', 'warn', error);
|
||||
cEditor.core.log('Error while parsing JSON: %o', 'error', error);
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -192,12 +190,120 @@ cEditor.renderer = {
|
|||
*/
|
||||
appendBlocks : function (data) {
|
||||
|
||||
console.info('renderer appendBlocks %o', data);
|
||||
var blocks = data.items;
|
||||
|
||||
/**
|
||||
* Тут надо создать очередь по аналогии с parser.appendNodesToRedactor,
|
||||
* которая будет асинхронно парсить блоки с помощью метода render у каждого плагина
|
||||
* Sequence of one-by-one blocks appending
|
||||
* Uses to save blocks order after async-handler
|
||||
*/
|
||||
var nodeSequence = Promise.resolve();
|
||||
|
||||
for (var index = 0; index < blocks.length ; index++ ) {
|
||||
|
||||
/** Add node to sequence at specified index */
|
||||
cEditor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Append node at specified index
|
||||
*/
|
||||
appendNodeAtIndex : function (nodeSequence, blocks, index) {
|
||||
|
||||
/** We need to append node to sequence */
|
||||
nodeSequence
|
||||
|
||||
/** first, get node async-aware */
|
||||
.then(function() {
|
||||
|
||||
return cEditor.renderer.getNodeAsync(blocks , index);
|
||||
|
||||
})
|
||||
|
||||
/**
|
||||
* second, compose editor-block from JSON object
|
||||
*/
|
||||
.then(cEditor.renderer.createBlockFromData)
|
||||
|
||||
/**
|
||||
* now insert block to redactor
|
||||
*/
|
||||
.then(function(blockData){
|
||||
|
||||
/**
|
||||
* blockData has 'block' and 'type' information
|
||||
*/
|
||||
cEditor.content.insertBlock(blockData.block, blockData.type);
|
||||
|
||||
/** Pass created block to next step */
|
||||
return blockData.block;
|
||||
|
||||
})
|
||||
|
||||
/**
|
||||
* add handlers to new block
|
||||
*/
|
||||
.then(cEditor.ui.addBlockHandlers)
|
||||
|
||||
/** Log if something wrong with node */
|
||||
.catch(function(error) {
|
||||
cEditor.core.log('Node skipped while parsing because %o', 'error', error);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Asynchronously returns block data from blocksList by index
|
||||
* @return Promise to node
|
||||
*/
|
||||
getNodeAsync : function (blocksList, index) {
|
||||
|
||||
return Promise.resolve().then(function() {
|
||||
|
||||
return blocksList[index];
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates editor block by JSON-data
|
||||
*
|
||||
* @uses render method of each plugin
|
||||
*
|
||||
* @param {object} blockData looks like
|
||||
* { header : {
|
||||
* text: '',
|
||||
* type: 'H3', ...
|
||||
* }
|
||||
* }
|
||||
* @return {object} with type and Element
|
||||
*/
|
||||
createBlockFromData : function (blockData) {
|
||||
|
||||
/** Get first key of object that stores plugin name */
|
||||
for (var pluginName in blockData) break;
|
||||
|
||||
/** Check for plugin existance */
|
||||
if (!cEditor.tools[pluginName]) {
|
||||
throw Error(`Plugin «${pluginName}» not found`);
|
||||
}
|
||||
|
||||
/** Check for plugin having render method */
|
||||
if (typeof cEditor.tools[pluginName].render != 'function') {
|
||||
|
||||
throw Error(`Plugin «${pluginName}» must have «render» method`);
|
||||
}
|
||||
|
||||
/** Fire the render method with data */
|
||||
var block = cEditor.tools[pluginName].render(blockData[pluginName]);
|
||||
|
||||
/** Retrun type and block */
|
||||
return {
|
||||
type : pluginName,
|
||||
block : block
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
@ -214,7 +320,7 @@ cEditor.saver = {
|
|||
saveBlocks : function (argument) {
|
||||
|
||||
console.info('saver saveBlocks');
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -808,10 +914,28 @@ cEditor.content = {
|
|||
|
||||
var workingNode = cEditor.content.currentNode;
|
||||
|
||||
el.classList.add(cEditor.ui.BLOCK_CLASSNAME);
|
||||
newBlock.classList.add(cEditor.ui.BLOCK_CLASSNAME);
|
||||
newBlock.dataset.type = blockType;
|
||||
|
||||
cEditor.core.insertAfter(workingNode, newBlock);
|
||||
|
||||
if (workingNode) {
|
||||
|
||||
cEditor.core.insertAfter(workingNode, newBlock);
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* If redactor is empty, append as first child
|
||||
*/
|
||||
cEditor.nodes.redactor.appendChild(newBlock);
|
||||
|
||||
/**
|
||||
* Set new node as current
|
||||
*/
|
||||
cEditor.content.workingNodeChanged(newBlock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
},
|
||||
/**
|
||||
|
@ -1169,11 +1293,13 @@ cEditor.toolbar = {
|
|||
leaf : function(){
|
||||
|
||||
var currentTool = this.current,
|
||||
tools = cEditor.settings.tools,
|
||||
// tools = cEditor.settings.tools,
|
||||
tools = Object.keys(cEditor.tools),
|
||||
barButtons = cEditor.nodes.toolbarButtons,
|
||||
nextToolIndex,
|
||||
toolToSelect;
|
||||
|
||||
// console.log(tools);
|
||||
if ( !currentTool ) {
|
||||
|
||||
/** Get first tool from object*/
|
||||
|
@ -1544,75 +1670,9 @@ cEditor.parser = {
|
|||
|
||||
cEditor.tools = {
|
||||
|
||||
paragraph : {
|
||||
|
||||
type : 'paragraph',
|
||||
iconClassname : 'ce-icon-paragraph',
|
||||
append : document.createElement('P'),
|
||||
appendCallback : function () {
|
||||
console.log('paragraph added');
|
||||
},
|
||||
settings : null,
|
||||
|
||||
},
|
||||
|
||||
/*quote : {
|
||||
|
||||
type : 'quote',
|
||||
iconClassname : 'ce-icon-quote',
|
||||
append : document.createElement('BLOCKQUOTE'),
|
||||
appendCallback : function () {
|
||||
console.log('quote added');
|
||||
},
|
||||
settings : null,
|
||||
|
||||
},*/
|
||||
|
||||
code : {
|
||||
|
||||
type : 'code',
|
||||
iconClassname : 'ce-icon-code',
|
||||
append : document.createElement('CODE'),
|
||||
appendCallback : function () {
|
||||
console.log('code added');
|
||||
},
|
||||
settings : null,
|
||||
|
||||
},
|
||||
|
||||
list : {
|
||||
|
||||
type : 'list',
|
||||
iconClassname : 'ce-icon-list-bullet',
|
||||
append : document.createElement('LI'),
|
||||
appendCallback : function () {
|
||||
console.log('code added');
|
||||
},
|
||||
settings : null,
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates HTML elements
|
||||
*/
|
||||
|
@ -1747,6 +1807,72 @@ cEditor.draw = {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Paragraph Plugin\
|
||||
* Creates P tag and adds content to this tag
|
||||
*/
|
||||
var paragraphTool = {
|
||||
|
||||
/**
|
||||
* Make initial header block
|
||||
* @param {object} JSON to with block data
|
||||
* @return {Element} element to append
|
||||
*/
|
||||
makeBlockToAppend : function (data) {
|
||||
|
||||
var tag = document.createElement('P');
|
||||
|
||||
if (data && data.text) {
|
||||
tag.innerHTML = data.text;
|
||||
}
|
||||
|
||||
tag.contentEditable = true;
|
||||
|
||||
return tag;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to render HTML block from JSON
|
||||
*/
|
||||
render : function (data) {
|
||||
|
||||
return paragraphTool.makeBlockToAppend(data);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to extract JSON data from HTML block
|
||||
*/
|
||||
save : function (block){
|
||||
|
||||
var data = {
|
||||
text : null
|
||||
};
|
||||
|
||||
data.text = blockData.textContent;
|
||||
|
||||
return data;
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Now plugin is ready.
|
||||
* Add it to redactor tools
|
||||
*/
|
||||
cEditor.tools.paragraph = {
|
||||
|
||||
type : 'paragraph',
|
||||
iconClassname : 'ce-icon-paragraph',
|
||||
append : paragraphTool.makeBlockToAppend(),
|
||||
appendCallback : null,
|
||||
settings : null,
|
||||
render : paragraphTool.render,
|
||||
save : paragraphTool.save
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Example of making plugin
|
||||
|
@ -1756,17 +1882,63 @@ var headerTool = {
|
|||
|
||||
/**
|
||||
* Make initial header block
|
||||
* @param {object} JSON to with block data
|
||||
* @return {Element} element to append
|
||||
*/
|
||||
makeBlockToAppend : function () {
|
||||
makeBlockToAppend : function (data) {
|
||||
|
||||
var el = document.createElement('H2');
|
||||
var availableTypes = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'],
|
||||
tag;
|
||||
|
||||
el.contentEditable = 'true';
|
||||
if (data && data.type && availableTypes.includes(data.type)) {
|
||||
|
||||
cEditor.ui.addBlockHandlers(el);
|
||||
tag = document.createElement( data.type );
|
||||
|
||||
return el;
|
||||
/**
|
||||
* Save header type in data-attr.
|
||||
* We need it in save method to extract type from HTML to JSON
|
||||
*/
|
||||
tag.dataset.headerData = data.type;
|
||||
|
||||
} else {
|
||||
|
||||
tag = document.createElement( 'H2' );
|
||||
|
||||
}
|
||||
|
||||
if (data && data.text) {
|
||||
tag.textContent = data.text;
|
||||
}
|
||||
|
||||
tag.contentEditable = true;
|
||||
|
||||
return tag;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to render HTML block from JSON
|
||||
*/
|
||||
render : function (data) {
|
||||
|
||||
return headerTool.makeBlockToAppend(data);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to extract JSON data from HTML block
|
||||
*/
|
||||
save : function (block){
|
||||
|
||||
var data = {
|
||||
type : null,
|
||||
text : null
|
||||
};
|
||||
|
||||
data.type = blockData.dataset.headerData;
|
||||
data.text = blockData.textContent;
|
||||
|
||||
return data;
|
||||
|
||||
},
|
||||
|
||||
|
@ -1863,7 +2035,6 @@ var headerTool = {
|
|||
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1877,5 +2048,7 @@ cEditor.tools.header = {
|
|||
append : headerTool.makeBlockToAppend(),
|
||||
appendCallback : headerTool.appendCallback,
|
||||
settings : headerTool.makeSettings(),
|
||||
render : headerTool.render,
|
||||
save : headerTool.save
|
||||
|
||||
};
|
||||
|
|
26
example.html
26
example.html
File diff suppressed because one or more lines are too long
116
result-sample.json
Normal file
116
result-sample.json
Normal file
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
"data":[
|
||||
{
|
||||
"type":"text",
|
||||
"data":{
|
||||
"text":"<p>It's a text. It can be with <a href=\"http:\/\/tj.local\/redirect?url=http%3A%2F%2Fya.ru\" target=\"_blank\">link<\/a>. And <b>bold<\/b> and <i>italic.<\/i><\/p><p>We can use br here.<\/p><p>and paragraphs<\/p>",
|
||||
"format":"html",
|
||||
"introText":"<<<same>>>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"heading_styled",
|
||||
"data":{
|
||||
"text":"Header",
|
||||
"format":"html",
|
||||
"heading-styles":"h2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"heading_styled",
|
||||
"data":{
|
||||
"text":"little header",
|
||||
"format":"html",
|
||||
"heading-styles":"h4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"link_embed",
|
||||
"data":{
|
||||
"title":"",
|
||||
"description":"",
|
||||
"image":"",
|
||||
"url":"https:\/\/new.vk.com\/feed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"image_extended",
|
||||
"data":{
|
||||
"background":false,
|
||||
"border":false,
|
||||
"isstretch":false,
|
||||
"file":{
|
||||
"url":"https:\/\/static39.cmtt.ru\/club\/66\/13\/cb\/3165d72648b97e.jpg",
|
||||
"bigUrl":"https:\/\/static35.cmtt.ru\/club\/66\/88\/1b\/d990e3f617eb9b.jpg",
|
||||
"width":1200,
|
||||
"height":750,
|
||||
"additionalData":"null"
|
||||
},
|
||||
"caption":"It's a caption. It will have b, i and a tags in future",
|
||||
"cover":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"gallery",
|
||||
"data":{
|
||||
"background":false,
|
||||
"border":false,
|
||||
"isstretch":false,
|
||||
"files":[
|
||||
{
|
||||
"url":"https:\/\/static39.cmtt.ru\/club\/7c\/f1\/ed\/6b139e871d1bce.jpg",
|
||||
"bigUrl":"https:\/\/static36.cmtt.ru\/club\/4b\/40\/e8\/8c7e9d6941948c.jpg",
|
||||
"width":1080,
|
||||
"height":1080,
|
||||
"caption":"caption1"
|
||||
},
|
||||
{
|
||||
"url":"https:\/\/static35.cmtt.ru\/club\/e7\/ec\/6b\/c43f8f0f694341.jpg",
|
||||
"bigUrl":"https:\/\/static35.cmtt.ru\/club\/53\/b2\/d2\/a633e11246a1bb.jpg",
|
||||
"width":1200,
|
||||
"height":1200,
|
||||
"caption":"caption2"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"video_extended",
|
||||
"data":{
|
||||
"source":"youtube",
|
||||
"remote_id":"SqmAjcAPBpA",
|
||||
"thumbnailUrl":"http:\/\/tj.local\/preview\/youtube\/SqmAjcAPBpA",
|
||||
"time":0,
|
||||
"width":800,
|
||||
"height":450
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"quote_styled",
|
||||
"data":{
|
||||
"text":"<p>Quote <a href=\"http:\/\/tj.local\/redirect?url=http%3A%2F%2Fya.ru\" target=\"_blank\">text<\/a><\/p><p>Bold <i>etc<\/i><\/p>",
|
||||
"format":"html",
|
||||
"cite":"Author",
|
||||
"size":"small"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type":"tweet",
|
||||
"data":{
|
||||
"media":true,
|
||||
"conversation":false,
|
||||
"user":{
|
||||
"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1817165982\/nikita-likhachev-512_normal.jpg",
|
||||
"profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1817165982\/nikita-likhachev-512_normal.jpg",
|
||||
"screen_name":"Niketas",
|
||||
"name":"Никита Лихачёв"
|
||||
},
|
||||
"id":747793978511101953,
|
||||
"text":"ВНИМАНИЕ ЧИТАТЬ ВСЕМ НЕ ДАЙ БОГ ПРОПУСТИТЕ НУ ИЛИ ХОТЯ БЫ КЛИКНИ И ПОДОЖДИ 15 СЕКУНД https:\/\/t.co\/iWyOHf4xr2",
|
||||
"created_at":"Tue Jun 28 14:09:12 +0000 2016",
|
||||
"status_url":"https:\/\/twitter.com\/Niketas\/status\/747793978511101953",
|
||||
"caption":"Caption"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue