mirror of
https://github.com/codex-team/editor.js
synced 2024-06-06 16:02:50 +02:00
Prepare plugins (#148)
* prepare plugins improvements * prepare plugins asyncronically * update version * restore data from cache when plugin is unavailable * added comments to the complicated solution * new module tools.js for methods working with plugins * remove ArrayOfCachedData * build updated * remove trash
This commit is contained in:
parent
8f9844ff83
commit
f5314dfab6
|
@ -39,8 +39,8 @@
|
||||||
"no-trailing-spaces": 2,
|
"no-trailing-spaces": 2,
|
||||||
"no-mixed-spaces-and-tabs": 2,
|
"no-mixed-spaces-and-tabs": 2,
|
||||||
"padded-blocks": [2, "always"],
|
"padded-blocks": [2, "always"],
|
||||||
"space-before-blocks": 2,
|
"space-before-blocks": 1,
|
||||||
"space-before-function-paren": [2, {
|
"space-before-function-paren": [1, {
|
||||||
"anonymous": "always",
|
"anonymous": "always",
|
||||||
"named": "never"
|
"named": "never"
|
||||||
}],
|
}],
|
||||||
|
@ -63,6 +63,7 @@
|
||||||
"module": true,
|
"module": true,
|
||||||
"require": true,
|
"require": true,
|
||||||
"window": true,
|
"window": true,
|
||||||
|
"console" : true,
|
||||||
"codex": true,
|
"codex": true,
|
||||||
"VERSION" : true,
|
"VERSION" : true,
|
||||||
"Promise" : true,
|
"Promise" : true,
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
min-height: 350px;
|
min-height: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.ce-block__content a {
|
.ce-block__content a {
|
||||||
color: #186baa;
|
color: #186baa;
|
||||||
}
|
}
|
||||||
|
@ -390,6 +389,16 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cdx-unavailable-block {
|
||||||
|
display: block;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 80px;
|
||||||
|
background-color: #fff7f7;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #ce5f5f;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typographycs
|
* Typographycs
|
||||||
*/
|
*/
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
9
codex.js
9
codex.js
|
@ -14,6 +14,7 @@ module.exports = (function (editor) {
|
||||||
var init = function () {
|
var init = function () {
|
||||||
|
|
||||||
editor.core = require('./modules/core');
|
editor.core = require('./modules/core');
|
||||||
|
editor.tools = require('./modules/tools');
|
||||||
editor.ui = require('./modules/ui');
|
editor.ui = require('./modules/ui');
|
||||||
editor.transport = require('./modules/transport');
|
editor.transport = require('./modules/transport');
|
||||||
editor.renderer = require('./modules/renderer');
|
editor.renderer = require('./modules/renderer');
|
||||||
|
@ -75,9 +76,9 @@ module.exports = (function (editor) {
|
||||||
* Output state
|
* Output state
|
||||||
*/
|
*/
|
||||||
editor.state = {
|
editor.state = {
|
||||||
jsonOutput: [],
|
jsonOutput : [],
|
||||||
blocks : [],
|
blocks : [],
|
||||||
inputs : []
|
inputs : []
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,7 +128,7 @@ module.exports = (function (editor) {
|
||||||
.then(editor.ui.make)
|
.then(editor.ui.make)
|
||||||
.then(editor.ui.addTools)
|
.then(editor.ui.addTools)
|
||||||
.then(editor.ui.bindEvents)
|
.then(editor.ui.bindEvents)
|
||||||
.then(editor.ui.preparePlugins)
|
.then(editor.tools.prepare)
|
||||||
.then(editor.transport.prepare)
|
.then(editor.transport.prepare)
|
||||||
.then(editor.renderer.makeBlocksFromData)
|
.then(editor.renderer.makeBlocksFromData)
|
||||||
.then(editor.ui.saveInputs)
|
.then(editor.ui.saveInputs)
|
||||||
|
|
31
example.html
31
example.html
|
@ -176,8 +176,35 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data : {
|
data : {
|
||||||
items: [],
|
// items: [
|
||||||
count: 0
|
// {
|
||||||
|
// type : 'paragraph',
|
||||||
|
// data : {
|
||||||
|
// text : 'Привет от CodeX'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type : 'tweet',
|
||||||
|
// data : {
|
||||||
|
// "media" : true,
|
||||||
|
// "conversation" : false,
|
||||||
|
// "user" : null,
|
||||||
|
// "id" : 12312312312,
|
||||||
|
// "text" : null,
|
||||||
|
// "created_at" : null,
|
||||||
|
// "status_url" : 'ertertert',
|
||||||
|
// "caption" : null
|
||||||
|
// },
|
||||||
|
// cover : false
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type : 'paragraph',
|
||||||
|
// data : {
|
||||||
|
// text : 'Пишите нам на team@ifmo.su'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// count: 2
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -130,6 +130,17 @@ module.exports = (function (core) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks passed object for emptiness
|
||||||
|
* @require ES5 - Object.keys
|
||||||
|
* @param {object}
|
||||||
|
*/
|
||||||
|
core.isEmpty = function ( obj ) {
|
||||||
|
|
||||||
|
return Object.keys(obj).length === 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Native Ajax
|
* Native Ajax
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -311,6 +311,19 @@ module.exports = (function (draw) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unavailable plugin block
|
||||||
|
*/
|
||||||
|
draw.unavailableBlock = function () {
|
||||||
|
|
||||||
|
var wrapper = document.createElement('DIV');
|
||||||
|
|
||||||
|
wrapper.classList.add('cdx-unavailable-block');
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
return draw;
|
return draw;
|
||||||
|
|
||||||
})({});
|
})({});
|
|
@ -17,7 +17,7 @@ module.exports = (function (renderer) {
|
||||||
/**
|
/**
|
||||||
* If redactor is empty, add first paragraph to start writing
|
* If redactor is empty, add first paragraph to start writing
|
||||||
*/
|
*/
|
||||||
if (!editor.state.blocks.items.length) {
|
if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {
|
||||||
|
|
||||||
editor.ui.addInitialBlock();
|
editor.ui.addInitialBlock();
|
||||||
return;
|
return;
|
||||||
|
@ -121,7 +121,10 @@ module.exports = (function (renderer) {
|
||||||
|
|
||||||
return Promise.resolve().then(function () {
|
return Promise.resolve().then(function () {
|
||||||
|
|
||||||
return blocksList[index];
|
return {
|
||||||
|
tool : blocksList[index],
|
||||||
|
position : index
|
||||||
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,19 +135,22 @@ module.exports = (function (renderer) {
|
||||||
*
|
*
|
||||||
* @uses render method of each plugin
|
* @uses render method of each plugin
|
||||||
*
|
*
|
||||||
* @param {object} blockData looks like
|
* @param {Object} toolData.tool
|
||||||
* { header : {
|
* { header : {
|
||||||
* text: '',
|
* text: '',
|
||||||
* type: 'H3', ...
|
* type: 'H3', ...
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* @return {object} with type and Element
|
* @param {Number} toolData.position - index in input-blocks array
|
||||||
|
* @return {Object} with type and Element
|
||||||
*/
|
*/
|
||||||
renderer.createBlockFromData = function (blockData) {
|
renderer.createBlockFromData = function ( toolData ) {
|
||||||
|
|
||||||
/** New parser */
|
/** New parser */
|
||||||
var pluginName = blockData.type,
|
var block,
|
||||||
cover = blockData.cover;
|
tool = toolData.tool,
|
||||||
|
pluginName = tool.type,
|
||||||
|
cover = tool.cover;
|
||||||
|
|
||||||
/** Get first key of object that stores plugin name */
|
/** Get first key of object that stores plugin name */
|
||||||
// for (var pluginName in blockData) break;
|
// for (var pluginName in blockData) break;
|
||||||
|
@ -163,8 +169,23 @@ module.exports = (function (renderer) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** New Parser */
|
if ( editor.tools[pluginName].available === false ) {
|
||||||
var block = editor.tools[pluginName].render(blockData.data);
|
|
||||||
|
block = editor.draw.unavailableBlock();
|
||||||
|
|
||||||
|
block.innerHTML = editor.tools[pluginName].loadingMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saver will extract data from initial block data by position in array
|
||||||
|
*/
|
||||||
|
block.dataset.inputPosition = toolData.position;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/** New Parser */
|
||||||
|
block = editor.tools[pluginName].render(tool.data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** is first-level block stretched */
|
/** is first-level block stretched */
|
||||||
var stretched = editor.tools[pluginName].isStretched || false;
|
var stretched = editor.tools[pluginName].isStretched || false;
|
||||||
|
|
|
@ -105,29 +105,45 @@ module.exports = (function (saver) {
|
||||||
/** Result saver */
|
/** Result saver */
|
||||||
var blockContent = block.childNodes[0],
|
var blockContent = block.childNodes[0],
|
||||||
pluginsContent = blockContent.childNodes[0],
|
pluginsContent = blockContent.childNodes[0],
|
||||||
savedData = editor.tools[pluginName].save(pluginsContent),
|
savedData,
|
||||||
output;
|
position,
|
||||||
|
output,
|
||||||
|
coverFlag = false;
|
||||||
|
|
||||||
|
/** If plugin wasn't available then return data from cache */
|
||||||
|
if ( editor.tools[pluginName].available === false ) {
|
||||||
|
|
||||||
|
position = pluginsContent.dataset.inputPosition;
|
||||||
|
|
||||||
|
savedData = codex.editor.state.blocks.items[position].data;
|
||||||
|
coverFlag = codex.editor.state.blocks.items[position].cover;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
savedData = editor.tools[pluginName].save(pluginsContent);
|
||||||
|
coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);
|
||||||
|
|
||||||
|
if (editor.tools[pluginName].validate) {
|
||||||
|
|
||||||
|
var result = editor.tools[pluginName].validate(savedData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not allow invalid data
|
||||||
|
*/
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
type: pluginName,
|
type: pluginName,
|
||||||
data: savedData
|
data: savedData
|
||||||
};
|
};
|
||||||
|
|
||||||
if (editor.tools[pluginName].validate) {
|
|
||||||
|
|
||||||
var result = editor.tools[pluginName].validate(savedData);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not allow invalid data
|
|
||||||
*/
|
|
||||||
if (!result)
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Marks Blocks that will be in main page */
|
/** Marks Blocks that will be in main page */
|
||||||
output.cover = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);
|
output.cover = coverFlag;
|
||||||
|
|
||||||
editor.state.jsonOutput.push(output);
|
editor.state.jsonOutput.push(output);
|
||||||
|
|
||||||
|
|
144
modules/tools.js
Normal file
144
modules/tools.js
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
/**
|
||||||
|
* Module working with plugins
|
||||||
|
*/
|
||||||
|
module.exports = (function () {
|
||||||
|
|
||||||
|
let editor = codex.editor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize plugins before using
|
||||||
|
* Ex. Load scripts or call some internal methods
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
function prepare() {
|
||||||
|
|
||||||
|
return new Promise(function (resolve_, reject_) {
|
||||||
|
|
||||||
|
Promise.resolve()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose a sequence of plugins that requires preparation
|
||||||
|
*/
|
||||||
|
.then(function () {
|
||||||
|
|
||||||
|
let pluginsRequiresPreparation = [],
|
||||||
|
allPlugins = editor.tools;
|
||||||
|
|
||||||
|
for ( let pluginName in allPlugins ) {
|
||||||
|
|
||||||
|
let plugin = allPlugins[pluginName];
|
||||||
|
|
||||||
|
if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginsRequiresPreparation.push(plugin);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return pluginsRequiresPreparation;
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Wait plugins while they prepares */
|
||||||
|
.then(waitAllPluginsPreparation_)
|
||||||
|
|
||||||
|
.then(function () {
|
||||||
|
|
||||||
|
editor.core.log('Plugins loaded', 'info');
|
||||||
|
resolve_();
|
||||||
|
|
||||||
|
}).catch(function (error) {
|
||||||
|
|
||||||
|
reject_(error);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {array} plugins - list of tools that requires preparation
|
||||||
|
* @return {Promise} resolved while all plugins will be ready or failed
|
||||||
|
*/
|
||||||
|
function waitAllPluginsPreparation_(plugins) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @calls allPluginsProcessed__ when all plugins prepared or failed
|
||||||
|
*/
|
||||||
|
return new Promise (function (allPluginsProcessed__) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pluck each element from queue
|
||||||
|
* First, send resolved Promise as previous value
|
||||||
|
* Each plugins "prepare" method returns a Promise, that's why
|
||||||
|
* reduce current element will not be able to continue while can't get
|
||||||
|
* a resolved Promise
|
||||||
|
*
|
||||||
|
* If last plugin is "prepared" then go to the next stage of initialization
|
||||||
|
*/
|
||||||
|
plugins.reduce(function (previousValue, plugin, iteration) {
|
||||||
|
|
||||||
|
return previousValue.then(function () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait till plugins prepared
|
||||||
|
* @calls pluginIsReady__ when plugin is ready or failed
|
||||||
|
*/
|
||||||
|
return new Promise ( function (pluginIsReady__) {
|
||||||
|
|
||||||
|
callPluginsPrepareMethod_( plugin )
|
||||||
|
|
||||||
|
.then( pluginIsReady__ )
|
||||||
|
.then( function () {
|
||||||
|
|
||||||
|
plugin.available = true;
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.catch(function (error) {
|
||||||
|
|
||||||
|
editor.core.log(`Plugin «${plugin.type}» was not loaded. Preparation failed because %o`, 'warn', error);
|
||||||
|
plugin.available = false;
|
||||||
|
plugin.loadingMessage = error;
|
||||||
|
|
||||||
|
/** Go ahead even some plugin has problems */
|
||||||
|
pluginIsReady__();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(function () {
|
||||||
|
|
||||||
|
/** If last plugin has problems then just ignore and continue */
|
||||||
|
if (iteration == plugins.length - 1) {
|
||||||
|
|
||||||
|
allPluginsProcessed__();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}, Promise.resolve() );
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var callPluginsPrepareMethod_ = function (plugin) {
|
||||||
|
|
||||||
|
return plugin.prepare( plugin.config || {} );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
prepare: prepare
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
|
@ -309,44 +309,6 @@ module.exports = (function (ui) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize plugins before using
|
|
||||||
* Ex. Load scripts or call some internal methods
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
ui.preparePlugins = function () {
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
|
|
||||||
let pluginName,
|
|
||||||
plugin;
|
|
||||||
|
|
||||||
for ( pluginName in editor.tools ) {
|
|
||||||
|
|
||||||
plugin = editor.tools[pluginName];
|
|
||||||
|
|
||||||
if (typeof plugin.prepare != 'function') {
|
|
||||||
|
|
||||||
continue;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.prepare(plugin.config || {}).then(function () {
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
|
|
||||||
}).catch(function (error) {
|
|
||||||
|
|
||||||
reject(error);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
ui.addBlockHandlers = function (block) {
|
ui.addBlockHandlers = function (block) {
|
||||||
|
|
||||||
if (!block) return;
|
if (!block) return;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "codex.editor",
|
"name": "codex.editor",
|
||||||
"version": "1.4.1",
|
"version": "1.4.3",
|
||||||
"description": "Codex Editor. Native JS, based on API and Open Source",
|
"description": "Codex Editor. Native JS, based on API and Open Source",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -63,7 +63,12 @@ module.exports = {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/** Минифицируем CSS и JS */
|
/** Минифицируем CSS и JS */
|
||||||
new webpack.optimize.UglifyJsPlugin(),
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
|
/** Disable warning messages. Cant disable uglify for 3rd party libs such as html-janitor */
|
||||||
|
compress: {
|
||||||
|
warnings: false
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
/** Block biuld if errors found */
|
/** Block biuld if errors found */
|
||||||
new webpack.NoErrorsPlugin(),
|
new webpack.NoErrorsPlugin(),
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue