mirror of
https://github.com/codex-team/editor.js
synced 2024-06-28 10:20:29 +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
335
codex-editor.js
335
codex-editor.js
|
@ -8,7 +8,7 @@ var cEditor = (function (cEditor) {
|
||||||
|
|
||||||
// Default settings
|
// Default settings
|
||||||
cEditor.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',
|
textareaId : 'codex-editor',
|
||||||
|
|
||||||
// First-level tags viewing as separated blocks. Other'll be inserted as child
|
// First-level tags viewing as separated blocks. Other'll be inserted as child
|
||||||
|
@ -166,8 +166,6 @@ cEditor.renderer = {
|
||||||
*/
|
*/
|
||||||
makeBlocksFromData : function (argument) {
|
makeBlocksFromData : function (argument) {
|
||||||
|
|
||||||
console.info('renderer makeBlocksFromData');
|
|
||||||
|
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
|
|
||||||
/** First, get JSON from state */
|
/** First, get JSON from state */
|
||||||
|
@ -180,7 +178,7 @@ cEditor.renderer = {
|
||||||
|
|
||||||
/** Write log if something goes wrong */
|
/** Write log if something goes wrong */
|
||||||
.catch(function(error) {
|
.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) {
|
appendBlocks : function (data) {
|
||||||
|
|
||||||
console.info('renderer appendBlocks %o', data);
|
var blocks = data.items;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тут надо создать очередь по аналогии с parser.appendNodesToRedactor,
|
* Sequence of one-by-one blocks appending
|
||||||
* которая будет асинхронно парсить блоки с помощью метода render у каждого плагина
|
* 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
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -808,11 +914,29 @@ cEditor.content = {
|
||||||
|
|
||||||
var workingNode = cEditor.content.currentNode;
|
var workingNode = cEditor.content.currentNode;
|
||||||
|
|
||||||
el.classList.add(cEditor.ui.BLOCK_CLASSNAME);
|
newBlock.classList.add(cEditor.ui.BLOCK_CLASSNAME);
|
||||||
newBlock.dataset.type = blockType;
|
newBlock.dataset.type = blockType;
|
||||||
|
|
||||||
|
|
||||||
|
if (workingNode) {
|
||||||
|
|
||||||
cEditor.core.insertAfter(workingNode, newBlock);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @deprecated with replaceBlock()
|
* @deprecated with replaceBlock()
|
||||||
|
@ -1169,11 +1293,13 @@ cEditor.toolbar = {
|
||||||
leaf : function(){
|
leaf : function(){
|
||||||
|
|
||||||
var currentTool = this.current,
|
var currentTool = this.current,
|
||||||
tools = cEditor.settings.tools,
|
// tools = cEditor.settings.tools,
|
||||||
|
tools = Object.keys(cEditor.tools),
|
||||||
barButtons = cEditor.nodes.toolbarButtons,
|
barButtons = cEditor.nodes.toolbarButtons,
|
||||||
nextToolIndex,
|
nextToolIndex,
|
||||||
toolToSelect;
|
toolToSelect;
|
||||||
|
|
||||||
|
// console.log(tools);
|
||||||
if ( !currentTool ) {
|
if ( !currentTool ) {
|
||||||
|
|
||||||
/** Get first tool from object*/
|
/** Get first tool from object*/
|
||||||
|
@ -1544,75 +1670,9 @@ cEditor.parser = {
|
||||||
|
|
||||||
cEditor.tools = {
|
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
|
* 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
|
* Example of making plugin
|
||||||
|
@ -1756,17 +1882,63 @@ var headerTool = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make initial header block
|
* Make initial header block
|
||||||
|
* @param {object} JSON to with block data
|
||||||
* @return {Element} element to append
|
* @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(),
|
append : headerTool.makeBlockToAppend(),
|
||||||
appendCallback : headerTool.appendCallback,
|
appendCallback : headerTool.appendCallback,
|
||||||
settings : headerTool.makeSettings(),
|
settings : headerTool.makeSettings(),
|
||||||
|
render : headerTool.render,
|
||||||
|
save : headerTool.save
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -124,7 +124,9 @@
|
||||||
{
|
{
|
||||||
quote : {
|
quote : {
|
||||||
type : 'simple',
|
type : 'simple',
|
||||||
text : 'git — распределенная система контроля версий файлов.<br> «Распределенная» значит, что каждый репозиторий содержит всю историю изменений, и из него можно развернуть полноценную рабочую копию проекта.'
|
text : 'git — распределенная система контроля версий файлов.<br> «Распределенная» значит, что каждый репозиторий содержит всю историю изменений, и из него можно развернуть полноценную рабочую копию проекта.',
|
||||||
|
photo : '',
|
||||||
|
author : 'sss',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
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