mirror of
https://github.com/codex-team/editor.js
synced 2024-06-03 06:22:39 +02:00
updated youtube plugin
This commit is contained in:
parent
065540a782
commit
fbbccaa350
49
.eslintrc
Normal file
49
.eslintrc
Normal file
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"rules": {
|
||||
|
||||
"arrow-spacing": [2, { "before": true, "after": true }],
|
||||
|
||||
/** Variables */
|
||||
"no-catch-shadow": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-label-var": 2,
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-shadow": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-undef": 2,
|
||||
"no-unused-vars": 2,
|
||||
|
||||
/** Style */
|
||||
"array-bracket-spacing": [2, "never", {
|
||||
"singleValue": true,
|
||||
"objectsInArrays": true,
|
||||
"arraysInArrays": true
|
||||
}],
|
||||
"quotes": [2, "single", "avoid-escape"],
|
||||
"eqeqeq": 0,
|
||||
"brace-style": [2, "stroustrup"],
|
||||
"comma-spacing": [2, { "before": false, "after": true }],
|
||||
"comma-style": [2, "last"],
|
||||
"eol-last": 0,
|
||||
"no-nested-ternary": 1,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"padded-blocks": [2, "never"],
|
||||
"space-before-blocks": 2,
|
||||
"space-before-function-paren": [2, { "anonymous": "always", "named": "never" }],
|
||||
"spaced-comment": [2, "always", {
|
||||
"exceptions": ["-", "+"],
|
||||
"markers": ["=", "!"]
|
||||
}],
|
||||
"semi": [2, "always"],
|
||||
"indent": [2, 4, { "SwitchCase": 1 }],
|
||||
"camelcase": [2, { "properties": "always" }],
|
||||
"newline-after-var": [1, "always"]
|
||||
},
|
||||
"globals":{
|
||||
"document": true,
|
||||
"require": true,
|
||||
"module": true,
|
||||
"codex": true
|
||||
}
|
||||
}
|
|
@ -16,6 +16,10 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.codex-editor .hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Working zone - redactor
|
||||
*/
|
||||
|
|
878
codex-editor.js
878
codex-editor.js
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -1,12 +1,14 @@
|
|||
/**
|
||||
*
|
||||
* Codex Editor
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0.6
|
||||
* @version 1.2.5
|
||||
*/
|
||||
|
||||
var codex = (function(codex){
|
||||
|
||||
var init = function() {
|
||||
|
||||
codex.core = require('./modules/core');
|
||||
codex.ui = require('./modules/ui');
|
||||
codex.transport = require('./modules/transport');
|
||||
|
@ -22,6 +24,8 @@ var codex = (function(codex){
|
|||
codex.parser = require('./modules/parser');
|
||||
};
|
||||
|
||||
codex.version = VERSION;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
|
|
14
example.html
14
example.html
|
@ -10,8 +10,8 @@
|
|||
|
||||
</body>
|
||||
|
||||
<script src="./codex-editor.js?v=11"></script>
|
||||
<link rel="stylesheet" href="./codex-editor.css?v=11">
|
||||
<script src="./codex-editor.js?v=108"></script>
|
||||
<link rel="stylesheet" href="./codex-editor.css?v=11000">
|
||||
|
||||
<link rel="stylesheet" href="codex-editor.css">
|
||||
|
||||
|
@ -51,6 +51,8 @@
|
|||
<script>
|
||||
codex.start({
|
||||
textareaId : "codex_area",
|
||||
initialBlockPlugin : 'paragraph',
|
||||
uploadImagesUrl : '/hull',
|
||||
tools : {
|
||||
paragraph: {
|
||||
type: 'paragraph',
|
||||
|
@ -61,7 +63,8 @@
|
|||
render: paragraphTool.render,
|
||||
save: paragraphTool.save,
|
||||
enableLineBreaks: false,
|
||||
allowedToPaste: true
|
||||
allowedToPaste: true,
|
||||
handleTagOnPaste : ['P']
|
||||
},
|
||||
paste: {
|
||||
type: 'paste',
|
||||
|
@ -84,7 +87,8 @@
|
|||
settings: headerTool.makeSettings(),
|
||||
render: headerTool.render,
|
||||
save: headerTool.save,
|
||||
displayInToolbox: true
|
||||
displayInToolbox: true,
|
||||
handleTagOnPaste : ['H1', 'H2', 'H3', 'H4', 'H5', 'H6']
|
||||
},
|
||||
code: {
|
||||
type: 'code',
|
||||
|
@ -151,7 +155,6 @@
|
|||
settings: null,
|
||||
render: instagramTool.reneder,
|
||||
save: instagramTool.save,
|
||||
displayInToolbox: false,
|
||||
enableLineBreaks: false,
|
||||
allowedToPaste: false
|
||||
},
|
||||
|
@ -164,7 +167,6 @@
|
|||
settings: null,
|
||||
render: twitterTool.render,
|
||||
save: twitterTool.save,
|
||||
displayInToolbox: false,
|
||||
enableLineBreaks: false,
|
||||
allowedToPaste: false
|
||||
},
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
/**
|
||||
* Codex Editor callbacks module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.2.5
|
||||
*/
|
||||
|
||||
var callbacks = (function(callbacks) {
|
||||
|
||||
callbacks.redactorSyncTimeout = null;
|
||||
|
||||
callbacks.globalKeydown = function(event){
|
||||
switch (event.keyCode){
|
||||
case codex.core.keys.TAB : codex.callback.tabKeyPressed(event); break;
|
||||
case codex.core.keys.ENTER : codex.callback.enterKeyPressed(event); break;
|
||||
case codex.core.keys.ESC : codex.callback.escapeKeyPressed(event); break;
|
||||
default : codex.callback.defaultKeyPressed(event); break;
|
||||
}
|
||||
};
|
||||
|
||||
callbacks.redactorKeyDown = function(event) {
|
||||
switch (event.keyCode){
|
||||
case codex.core.keys.TAB : codex.callback.tabKeyPressed(event); break;
|
||||
case codex.core.keys.ENTER : codex.callback.enterKeyPressedOnRedactorZone(event); break;
|
||||
case codex.core.keys.ESC : codex.callback.escapeKeyPressed(event); break;
|
||||
default : codex.callback.defaultKeyPressed(event); break;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -35,17 +48,9 @@ var callbacks = (function(callbacks) {
|
|||
event.preventDefault();
|
||||
};
|
||||
|
||||
/**
|
||||
* ENTER key handler
|
||||
* Makes new paragraph block
|
||||
*/
|
||||
callbacks.enterKeyPressed = function(event){
|
||||
callbacks.enterKeyPressed = function(event) {
|
||||
|
||||
/** Set current node */
|
||||
var firstLevelBlocksArea = codex.callback.clickedOnFirstLevelBlockArea();
|
||||
|
||||
if (firstLevelBlocksArea) {
|
||||
event.preventDefault();
|
||||
if (codex.content.editorAreaHightlighted) {
|
||||
|
||||
/**
|
||||
* it means that we lose input index, saved index before is not correct
|
||||
|
@ -54,8 +59,14 @@ var callbacks = (function(callbacks) {
|
|||
codex.caret.inputIndex = -1;
|
||||
|
||||
codex.callback.enterPressedOnBlock();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ENTER key handler
|
||||
* Makes new paragraph block
|
||||
*/
|
||||
callbacks.enterKeyPressedOnRedactorZone = function(event){
|
||||
|
||||
if (event.target.contentEditable == 'true') {
|
||||
|
||||
|
@ -83,7 +94,7 @@ var callbacks = (function(callbacks) {
|
|||
var enableLineBreaks = codex.tools[tool].enableLineBreaks;
|
||||
|
||||
/** This type of block creates when enter is pressed */
|
||||
var NEW_BLOCK_TYPE = 'paragraph';
|
||||
var NEW_BLOCK_TYPE = codex.settings.initialBlockPlugin;
|
||||
|
||||
/**
|
||||
* When toolbar is opened, select tool instead of making new paragraph
|
||||
|
@ -96,6 +107,12 @@ var callbacks = (function(callbacks) {
|
|||
|
||||
codex.toolbar.close();
|
||||
|
||||
/**
|
||||
* Stop other listeners callback executions
|
||||
*/
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
@ -217,6 +234,8 @@ var callbacks = (function(callbacks) {
|
|||
|
||||
callbacks.redactorClicked = function (event) {
|
||||
|
||||
callbacks.markWhenClickedOnFirstLevelBlockArea();
|
||||
|
||||
codex.content.workingNodeChanged(event.target);
|
||||
|
||||
codex.ui.saveInputs();
|
||||
|
@ -252,14 +271,14 @@ var callbacks = (function(callbacks) {
|
|||
}
|
||||
|
||||
/** If input is empty, then we set caret to the last input */
|
||||
if (codex.state.inputs.length && codex.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == 'paragraph') {
|
||||
if (codex.state.inputs.length && codex.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == codex.settings.initialBlockPlugin) {
|
||||
|
||||
codex.caret.setToBlock(indexOfLastInput);
|
||||
|
||||
} else {
|
||||
|
||||
/** Create new input when caret clicked in redactors area */
|
||||
var NEW_BLOCK_TYPE = 'paragraph';
|
||||
var NEW_BLOCK_TYPE = codex.settings.initialBlockPlugin;
|
||||
|
||||
codex.content.insertBlock({
|
||||
type : NEW_BLOCK_TYPE,
|
||||
|
@ -318,7 +337,7 @@ var callbacks = (function(callbacks) {
|
|||
var currentNodeType = codex.content.currentNode.dataset.tool;
|
||||
|
||||
/** Mark current block*/
|
||||
if (currentNodeType != 'paragraph' || !inputIsEmpty) {
|
||||
if (currentNodeType != codex.settings.initialBlockPlugin || !inputIsEmpty) {
|
||||
|
||||
codex.content.markBlock();
|
||||
|
||||
|
@ -333,16 +352,15 @@ var callbacks = (function(callbacks) {
|
|||
* Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always
|
||||
* specifies to the first-level block. Other cases we just ignore.
|
||||
*/
|
||||
callbacks.clickedOnFirstLevelBlockArea = function() {
|
||||
callbacks.markWhenClickedOnFirstLevelBlockArea = function() {
|
||||
|
||||
var selection = window.getSelection(),
|
||||
anchorNode = selection.anchorNode,
|
||||
flag = false;
|
||||
|
||||
|
||||
if (selection.rangeCount == 0) {
|
||||
|
||||
return true;
|
||||
codex.content.editorAreaHightlighted = true;
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -368,7 +386,7 @@ var callbacks = (function(callbacks) {
|
|||
}
|
||||
|
||||
/** If editable element founded, flag is "TRUE", Therefore we return "FALSE" */
|
||||
return flag ? false : true;
|
||||
codex.content.editorAreaHightlighted = flag ? false : true;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -597,7 +615,7 @@ var callbacks = (function(callbacks) {
|
|||
*/
|
||||
callbacks.enterPressedOnBlock = function (event) {
|
||||
|
||||
var NEW_BLOCK_TYPE = 'paragraph';
|
||||
var NEW_BLOCK_TYPE = codex.settings.initialBlockPlugin;
|
||||
|
||||
codex.content.insertBlock({
|
||||
type : NEW_BLOCK_TYPE,
|
||||
|
@ -690,6 +708,11 @@ var callbacks = (function(callbacks) {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
callbacks.blockPaste = function(event) {
|
||||
|
||||
var currentInputIndex = codex.caret.getCurrentInputIndex(),
|
||||
|
@ -699,11 +722,15 @@ var callbacks = (function(callbacks) {
|
|||
|
||||
codex.content.sanitize(node);
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
}, 10);
|
||||
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
};
|
||||
|
||||
callbacks._blockPaste = function(event) {
|
||||
callbacks.blockPasteViaSanitize = function(event) {
|
||||
|
||||
var currentInputIndex = codex.caret.getCurrentInputIndex();
|
||||
|
||||
|
@ -715,7 +742,12 @@ var callbacks = (function(callbacks) {
|
|||
/**
|
||||
* configuration of the observer:
|
||||
*/
|
||||
var config = { attributes: true, childList: true, characterData: false };
|
||||
var config = {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: false,
|
||||
subtree : true
|
||||
};
|
||||
|
||||
// pass in the target node, as well as the observer options
|
||||
observer.observe(codex.state.inputs[currentInputIndex], config);
|
||||
|
@ -725,7 +757,19 @@ var callbacks = (function(callbacks) {
|
|||
* Sends all mutations to paste handler
|
||||
*/
|
||||
callbacks.handlePasteEvents = function(mutations) {
|
||||
mutations.forEach(codex.content.paste);
|
||||
|
||||
var self = this;
|
||||
|
||||
/**
|
||||
* Calling function with context of this function.
|
||||
* Also, we should sanitize pasted or changed data one time and ignore
|
||||
* changings which makes sanitize method.
|
||||
* For that, we need to send Context, MutationObserver.__proto__ that contains
|
||||
* observer disconnect method.
|
||||
*/
|
||||
mutations.forEach(function(mutation) {
|
||||
codex.content.paste.call(self, mutation);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor Caret Module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
var caret = (function(caret) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,49 @@
|
|||
/**
|
||||
* Codex Editor Content Module
|
||||
* Works with DOM
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.3.1
|
||||
*/
|
||||
|
||||
var janitor = require('html-janitor');
|
||||
|
||||
|
||||
/**
|
||||
* Default settings for sane.
|
||||
* @uses html-janitor
|
||||
*/
|
||||
var Config = {
|
||||
|
||||
tags: {
|
||||
p: {},
|
||||
a: {
|
||||
href: true,
|
||||
target: '_blank',
|
||||
rel: 'nofollow'
|
||||
},
|
||||
i: {},
|
||||
b: {},
|
||||
strong: {},
|
||||
em: {},
|
||||
span: {}
|
||||
}
|
||||
};
|
||||
|
||||
var content = (function(content) {
|
||||
|
||||
/**
|
||||
* Links to current active block
|
||||
* @type {null | Element}
|
||||
*/
|
||||
content.currentNode = null;
|
||||
|
||||
/**
|
||||
* clicked in redactor area
|
||||
* @type {null | Boolean}
|
||||
*/
|
||||
content.editorAreaHightlighted = null;
|
||||
|
||||
/**
|
||||
* Synchronizes redactor with original textarea
|
||||
*/
|
||||
|
@ -251,6 +293,12 @@ var content = (function(content) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Block is inserted, wait for new click that defined focusing on editors area
|
||||
* @type {boolean}
|
||||
*/
|
||||
content.editorAreaHightlighted = false;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -456,7 +504,7 @@ var content = (function(content) {
|
|||
newNode = newNode.innerHTML;
|
||||
|
||||
/** This type of block creates when enter is pressed */
|
||||
var NEW_BLOCK_TYPE = 'paragraph';
|
||||
var NEW_BLOCK_TYPE = codex.settings.initialBlockPlugin;
|
||||
|
||||
/**
|
||||
* Make new paragraph with text after caret
|
||||
|
@ -509,7 +557,7 @@ var content = (function(content) {
|
|||
tool = workingNode.dataset.tool;
|
||||
|
||||
if (codex.tools[tool].allowedToPaste) {
|
||||
codex.content.sanitize(mutation.addedNodes);
|
||||
codex.content.sanitize.call(this, mutation.addedNodes);
|
||||
} else {
|
||||
codex.content.pasteTextContent(mutation.addedNodes);
|
||||
}
|
||||
|
@ -524,8 +572,18 @@ var content = (function(content) {
|
|||
*/
|
||||
content.pasteTextContent = function(nodes) {
|
||||
|
||||
var node = nodes[0],
|
||||
var node = nodes[0],
|
||||
textNode;
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.nodeType == codex.core.nodeTypes.TEXT) {
|
||||
textNode = document.createTextNode(node);
|
||||
} else {
|
||||
textNode = document.createTextNode(node.textContent);
|
||||
}
|
||||
|
||||
if (codex.core.isDomNode(node)) {
|
||||
node.parentNode.replaceChild(textNode, node);
|
||||
|
@ -537,7 +595,7 @@ var content = (function(content) {
|
|||
*
|
||||
* Sanitizes HTML content
|
||||
* @param {Element} target - inserted element
|
||||
* @uses DFS function for deep searching
|
||||
* @uses Sanitize library html-janitor
|
||||
*/
|
||||
content.sanitize = function(target) {
|
||||
|
||||
|
@ -545,85 +603,60 @@ var content = (function(content) {
|
|||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < target.childNodes.length; i++) {
|
||||
this.dfs(target.childNodes[i]);
|
||||
}
|
||||
};
|
||||
var node = target[0];
|
||||
|
||||
/**
|
||||
* Clears styles
|
||||
* @param {Element|Text}
|
||||
*/
|
||||
content.clearStyles = function(target) {
|
||||
|
||||
var href,
|
||||
newNode = null,
|
||||
blockTags = ['P', 'BLOCKQUOTE', 'UL', 'CODE', 'OL', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DIV', 'PRE', 'HEADER', 'SECTION'],
|
||||
allowedTags = ['P', 'B', 'I', 'A', 'U', 'BR'],
|
||||
needReplace = !allowedTags.includes(target.tagName),
|
||||
isDisplayedAsBlock = blockTags.includes(target.tagName);
|
||||
|
||||
if (!codex.core.isDomNode(target)){
|
||||
return target;
|
||||
}
|
||||
|
||||
if (!target.parentNode){
|
||||
return target;
|
||||
}
|
||||
|
||||
if (needReplace) {
|
||||
|
||||
if (isDisplayedAsBlock) {
|
||||
|
||||
newNode = document.createElement('P');
|
||||
newNode.innerHTML = target.innerHTML;
|
||||
target.parentNode.replaceChild(newNode, target);
|
||||
target = newNode;
|
||||
|
||||
} else {
|
||||
|
||||
newNode = document.createTextNode(` ${target.textContent} `);
|
||||
newNode.textContent = newNode.textContent.replace(/\s{2,}/g, ' ');
|
||||
target.parentNode.replaceChild(newNode, target);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** keep href attributes of tag A */
|
||||
if (target.tagName == 'A') {
|
||||
href = target.getAttribute('href');
|
||||
}
|
||||
|
||||
/** Remove all tags */
|
||||
while(target.attributes.length > 0) {
|
||||
target.removeAttribute(target.attributes[0].name);
|
||||
}
|
||||
|
||||
/** return href */
|
||||
if (href) {
|
||||
target.setAttribute('href', href);
|
||||
}
|
||||
|
||||
return target;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Depth-first search Algorithm
|
||||
* returns all childs
|
||||
* @param {Element}
|
||||
*/
|
||||
content.dfs = function(el) {
|
||||
|
||||
if (!codex.core.isDomNode(el))
|
||||
if (!node) {
|
||||
return;
|
||||
|
||||
var sanitized = this.clearStyles(el);
|
||||
|
||||
for(var i = 0; i < sanitized.childNodes.length; i++) {
|
||||
this.dfs(sanitized.childNodes[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect Observer
|
||||
* hierarchy of function calls inherits context of observer
|
||||
*/
|
||||
this.disconnect();
|
||||
|
||||
/**
|
||||
* Don't sanitize text node
|
||||
*/
|
||||
if (node.nodeType == codex.core.nodeTypes.TEXT) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear dirty content
|
||||
*/
|
||||
var sanitizer = new janitor(Config),
|
||||
clear = sanitizer.clean(node.outerHTML);
|
||||
|
||||
var div = codex.draw.node('DIV', [], { innerHTML: clear });
|
||||
node.replaceWith(div.childNodes[0]);
|
||||
|
||||
// for (i = 0; i < clearHTML.childNodes.length; i++) {
|
||||
//
|
||||
// var tag = clearHTML.childNodes[i],
|
||||
// blockType = null;
|
||||
//
|
||||
// for (tool in codex.tools) {
|
||||
//
|
||||
// var handleTags = codex.tools[tool].handleTagOnPaste;
|
||||
//
|
||||
// if (!handleTags) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// if (handleTags.indexOf(tag.tagName) !== -1) {
|
||||
// blockType = codex.tools[tool];
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// if (blockType) {
|
||||
// codex.parser.insertPastedContent(blockType, tag);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
return content;
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor Core
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.1.2
|
||||
*/
|
||||
|
||||
var core = (function(core) {
|
||||
|
||||
/**
|
||||
|
@ -20,6 +27,14 @@ var core = (function(core) {
|
|||
codex.state.blocks = userSettings.data;
|
||||
}
|
||||
|
||||
if (userSettings.initialBlockPlugin) {
|
||||
codex.settings.initialBlockPlugin = userSettings.initialBlockPlugin;
|
||||
}
|
||||
|
||||
if (userSettings.uploadImagesUrl) {
|
||||
codex.settings.uploadImagesUrl = userSettings.uploadImagesUrl;
|
||||
}
|
||||
|
||||
codex.nodes.textarea = document.getElementById(userSettings.textareaId || codex.settings.textareaId);
|
||||
|
||||
if (typeof codex.nodes.textarea === undefined || codex.nodes.textarea === null) {
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor Draw module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0.
|
||||
*/
|
||||
|
||||
var draw = (function(draw) {
|
||||
|
||||
/**
|
||||
|
@ -153,7 +160,7 @@ var draw = (function(draw) {
|
|||
div.classList.add('ce-settings_default');
|
||||
|
||||
return div;
|
||||
},
|
||||
};
|
||||
|
||||
draw.pluginsSettings = function() {
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor Notification Module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
var notifications = (function(notifications) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,237 +1,21 @@
|
|||
/**
|
||||
* Codex Editor Parser Module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.1
|
||||
*/
|
||||
|
||||
var parser = (function(parser) {
|
||||
|
||||
/**
|
||||
* Splits content by `\n` and returns blocks
|
||||
*/
|
||||
parser.getSeparatedTextFromContent = function(content) {
|
||||
return content.split('\n');
|
||||
};
|
||||
|
||||
/** inserting text */
|
||||
parser.insertPastedContent = function(content) {
|
||||
|
||||
var blocks = this.getSeparatedTextFromContent(content),
|
||||
i,
|
||||
inputIndex = cEditor.caret.getCurrentInputIndex(),
|
||||
textNode,
|
||||
parsedTextContent;
|
||||
|
||||
for(i = 0; i < blocks.length; i++) {
|
||||
|
||||
blocks[i].trim();
|
||||
|
||||
if (blocks[i]) {
|
||||
var data = cEditor.draw.pluginsRender('paragraph', blocks[i]);
|
||||
cEditor.content.insertBlock(data);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously parses textarea input string to HTML editor blocks
|
||||
*/
|
||||
parser.parseTextareaContent = function () {
|
||||
|
||||
var initialContent = cEditor.nodes.textarea.value;
|
||||
|
||||
if ( initialContent.trim().length === 0 ) return true;
|
||||
|
||||
|
||||
cEditor.parser
|
||||
|
||||
/** Get child nodes async-aware */
|
||||
.getNodesFromString(initialContent)
|
||||
|
||||
/** Then append nodes to the redactor */
|
||||
.then(cEditor.parser.appendNodesToRedactor)
|
||||
|
||||
/** Write log if something goes wrong */
|
||||
.catch(function(error) {
|
||||
cEditor.core.log('Error while parsing content: %o', 'warn', error);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses string to nodeList
|
||||
* @param string inputString
|
||||
* @return Primise -> nodeList
|
||||
*/
|
||||
parser.getNodesFromString = function (inputString) {
|
||||
|
||||
return Promise.resolve().then(function() {
|
||||
|
||||
var contentHolder = document.createElement('div');
|
||||
|
||||
contentHolder.innerHTML = inputString;
|
||||
|
||||
/**
|
||||
* Returning childNodes will include:
|
||||
* - Elements (html-tags),
|
||||
* - Texts (empty-spaces or non-wrapped strings )
|
||||
* - Comments and other
|
||||
*/
|
||||
return contentHolder.childNodes;
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends nodes to the redactor
|
||||
* @param nodeList nodes - list for nodes to append
|
||||
*/
|
||||
parser.appendNodesToRedactor = function(nodes) {
|
||||
|
||||
/**
|
||||
* Sequence of one-by-one nodes appending
|
||||
* Uses to save blocks order after async-handler
|
||||
*/
|
||||
var nodeSequence = Promise.resolve();
|
||||
|
||||
|
||||
for (var index = 0; index < nodes.length ; index++ ) {
|
||||
|
||||
/** Add node to sequence at specified index */
|
||||
cEditor.parser.appendNodeAtIndex(nodeSequence, nodes, index);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Append node at specified index
|
||||
*/
|
||||
parser.appendNodeAtIndex = function (nodeSequence, nodes, index) {
|
||||
|
||||
/** We need to append node to sequence */
|
||||
nodeSequence
|
||||
|
||||
/** first, get node async-aware */
|
||||
.then(function() {
|
||||
|
||||
return cEditor.parser.getNodeAsync(nodes , index);
|
||||
parser.insertPastedContent = function(blockType, tag) {
|
||||
|
||||
codex.content.insertBlock({
|
||||
type : blockType.type,
|
||||
block : blockType.render({
|
||||
text : tag.innerHTML
|
||||
})
|
||||
|
||||
/**
|
||||
* second, compose editor-block from node
|
||||
* and append it to redactor
|
||||
*/
|
||||
.then(function(node){
|
||||
|
||||
var block = cEditor.parser.createBlockByDomNode(node);
|
||||
|
||||
if ( cEditor.core.isDomNode(block) ) {
|
||||
|
||||
block.contentEditable = "true";
|
||||
|
||||
/** Mark node as redactor block*/
|
||||
block.classList.add('ce-block');
|
||||
|
||||
/** Append block to the redactor */
|
||||
cEditor.nodes.redactor.appendChild(block);
|
||||
|
||||
/** Save block to the cEditor.state array */
|
||||
cEditor.state.blocks.push(block);
|
||||
|
||||
return block;
|
||||
|
||||
}
|
||||
return null;
|
||||
})
|
||||
|
||||
.then(cEditor.ui.addBlockHandlers)
|
||||
|
||||
/** Log if something wrong with node */
|
||||
.catch(function(error) {
|
||||
cEditor.core.log('Node skipped while parsing because %o', 'warn', error);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously returns node from nodeList by index
|
||||
* @return Promise to node
|
||||
*/
|
||||
parser.getNodeAsync = function (nodeList, index) {
|
||||
|
||||
return Promise.resolve().then(function() {
|
||||
|
||||
return nodeList.item(index);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates editor block by DOM node
|
||||
*
|
||||
* First-level blocks (see cEditor.settings.blockTags) saves as-is,
|
||||
* other wrapps with <p>-tag
|
||||
*
|
||||
* @param DOMnode node
|
||||
* @return First-level node (paragraph)
|
||||
*/
|
||||
parser.createBlockByDomNode = function (node) {
|
||||
|
||||
/** First level nodes already appears as blocks */
|
||||
if ( cEditor.parser.isFirstLevelBlock(node) ){
|
||||
|
||||
/** Save plugin type in data-type */
|
||||
node = this.storeBlockType(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/** Other nodes wraps into parent block (paragraph-tag) */
|
||||
var parentBlock,
|
||||
nodeContent = node.textContent.trim(),
|
||||
isPlainTextNode = node.nodeType != cEditor.core.nodeTypes.TAG;
|
||||
|
||||
|
||||
/** Skip empty textNodes with space-symbols */
|
||||
if (isPlainTextNode && !nodeContent.length) return null;
|
||||
|
||||
/** Make <p> tag */
|
||||
parentBlock = cEditor.draw.block('P');
|
||||
|
||||
if (isPlainTextNode){
|
||||
parentBlock.textContent = nodeContent.replace(/(\s){2,}/, '$1'); // remove double spaces
|
||||
} else {
|
||||
parentBlock.appendChild(node);
|
||||
}
|
||||
|
||||
/** Save plugin type in data-type */
|
||||
parentBlock = this.storeBlockType(parentBlock);
|
||||
|
||||
return parentBlock;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* It's a crutch
|
||||
* - - - - - - -
|
||||
* We need block type stored as data-attr
|
||||
* Now supports only simple blocks : P, HEADER, QUOTE, CODE
|
||||
* Remove it after updating parser module for the block-oriented structure:
|
||||
* - each block must have stored type
|
||||
* @param {Element} node
|
||||
*/
|
||||
parser.storeBlockType = function (node) {
|
||||
|
||||
switch (node.tagName) {
|
||||
case 'P' : node.dataset.tool = 'paragraph'; break;
|
||||
case 'H1':
|
||||
case 'H2':
|
||||
case 'H3':
|
||||
case 'H4':
|
||||
case 'H5':
|
||||
case 'H6': node.dataset.tool = 'header'; break;
|
||||
case 'BLOCKQUOTE': node.dataset.tool = 'quote'; break;
|
||||
case 'CODE': node.dataset.tool = 'code'; break;
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor Renderer Module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
var renderer = (function(renderer) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor Saver
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
var saver = (function(saver) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
/**
|
||||
* Inline toolbar
|
||||
*
|
||||
* Contains from tools:
|
||||
* Bold, Italic, Underline and Anchor
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
var inline = (function(inline) {
|
||||
|
||||
inline.init = function() {
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
/**
|
||||
* Codex Editor toolbar module
|
||||
*
|
||||
* Contains:
|
||||
* - Inline toolbox
|
||||
* - Toolbox within plus button
|
||||
* - Settings section
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
var toolbar = (function(toolbar) {
|
||||
|
||||
toolbar.init = function() {
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
/**
|
||||
* Codex Editor toolbox
|
||||
*
|
||||
* All tools be able to appended here
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
var toolbox = (function(toolbox) {
|
||||
|
||||
toolbox.init = function() {
|
||||
toolbox.init = function () {
|
||||
|
||||
require('./toolbar');
|
||||
|
||||
};
|
||||
|
||||
toolbox.opened = false;
|
||||
|
@ -11,7 +21,9 @@ var toolbox = (function(toolbox) {
|
|||
|
||||
/** Close setting if toolbox is opened */
|
||||
if (codex.toolbar.settings.opened) {
|
||||
|
||||
codex.toolbar.settings.close();
|
||||
|
||||
}
|
||||
|
||||
/** display toolbox */
|
||||
|
@ -50,8 +62,14 @@ var toolbox = (function(toolbox) {
|
|||
|
||||
/** Count toolbox hidden tools */
|
||||
for( var tool in codex.tools ) {
|
||||
if (!codex.tools[tool].displayInToolbox)
|
||||
|
||||
if (!codex.tools[tool].displayInToolbox) {
|
||||
|
||||
hiddenToolsAmount ++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if ( !currentTool ) {
|
||||
|
@ -73,7 +91,9 @@ var toolbox = (function(toolbox) {
|
|||
for( var tool in codex.tools ) {
|
||||
|
||||
if (codex.tools[tool].displayInToolbox){
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
nextToolIndex ++;
|
||||
|
@ -123,6 +143,7 @@ var toolbox = (function(toolbox) {
|
|||
UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 &&
|
||||
workingNode.textContent.trim() === ''
|
||||
){
|
||||
|
||||
/** Replace current block */
|
||||
codex.content.switchBlock(workingNode, newBlockContent, tool.type);
|
||||
|
||||
|
@ -140,7 +161,9 @@ var toolbox = (function(toolbox) {
|
|||
appendCallback = tool.appendCallback;
|
||||
|
||||
if (appendCallback && typeof appendCallback == 'function') {
|
||||
|
||||
appendCallback.call(event);
|
||||
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor tools
|
||||
* This tools will be appended in toolbox
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
var tools = (function(tools) {
|
||||
|
||||
return tools;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Codex.Editor Transport Module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0.0
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
var transport = (function(transport){
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Codex Editor UI module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.1
|
||||
*/
|
||||
|
||||
var ui = (function(ui){
|
||||
|
||||
/**
|
||||
|
@ -10,30 +17,30 @@ var ui = (function(ui){
|
|||
*/
|
||||
BLOCK_CLASSNAME : 'ce-block',
|
||||
|
||||
/**
|
||||
* @const {String} wrapper for plugins content
|
||||
*/
|
||||
BLOCK_CONTENT : 'ce-block__content',
|
||||
/**
|
||||
* @const {String} wrapper for plugins content
|
||||
*/
|
||||
BLOCK_CONTENT : 'ce-block__content',
|
||||
|
||||
/**
|
||||
* @const {String} BLOCK_STRETCHED - makes block stretched
|
||||
*/
|
||||
BLOCK_STRETCHED : 'ce-block--stretched',
|
||||
/**
|
||||
* @const {String} BLOCK_STRETCHED - makes block stretched
|
||||
*/
|
||||
BLOCK_STRETCHED : 'ce-block--stretched',
|
||||
|
||||
/**
|
||||
* @const {String} BLOCK_HIGHLIGHTED - adds background
|
||||
*/
|
||||
BLOCK_HIGHLIGHTED : 'ce-block--focused',
|
||||
/**
|
||||
* @const {String} BLOCK_HIGHLIGHTED - adds background
|
||||
*/
|
||||
BLOCK_HIGHLIGHTED : 'ce-block--focused',
|
||||
|
||||
/**
|
||||
* @const {String} - highlights covered blocks
|
||||
*/
|
||||
BLOCK_IN_FEED_MODE : 'ce-block--feed-mode',
|
||||
/**
|
||||
* @const {String} - highlights covered blocks
|
||||
*/
|
||||
BLOCK_IN_FEED_MODE : 'ce-block--feed-mode',
|
||||
|
||||
/**
|
||||
* @const {String} - for all default settings
|
||||
*/
|
||||
SETTINGS_ITEM : 'ce-settings__item'
|
||||
/**
|
||||
* @const {String} - for all default settings
|
||||
*/
|
||||
SETTINGS_ITEM : 'ce-settings__item'
|
||||
|
||||
};
|
||||
|
||||
|
@ -257,7 +264,10 @@ var ui = (function(ui){
|
|||
}, false );
|
||||
|
||||
/** All keydowns on Document */
|
||||
codex.nodes.redactor.addEventListener('keydown', codex.callback.globalKeydown, false );
|
||||
document.addEventListener('keydown', codex.callback.globalKeydown, false );
|
||||
|
||||
/** All keydowns on Redactor zone */
|
||||
codex.nodes.redactor.addEventListener('keydown', codex.callback.redactorKeyDown, false);
|
||||
|
||||
/** All keydowns on Document */
|
||||
document.addEventListener('keyup', codex.callback.globalKeyup, false );
|
||||
|
@ -302,7 +312,7 @@ var ui = (function(ui){
|
|||
|
||||
codex.tools[tool].prepare();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ui.addBlockHandlers = function(block) {
|
||||
|
||||
|
@ -317,9 +327,25 @@ var ui = (function(ui){
|
|||
|
||||
/**
|
||||
* Pasting content from another source
|
||||
* We have two type of sanitization
|
||||
* First - uses deep-first search algorithm to get sub nodes,
|
||||
* sanitizes whole Block_content and replaces cleared nodes
|
||||
* This method is deprecated
|
||||
* Method is used in codex.callback.blockPaste(event)
|
||||
*
|
||||
* Secont - uses Mutation observer.
|
||||
* Observer "observe" DOM changes and send changings to callback.
|
||||
* Callback gets changed node, not whole Block_content.
|
||||
* Inserted or changed node, which we've gotten have been cleared and replaced with diry node
|
||||
*
|
||||
* Method is used in codex.callback.blockPasteViaSanitize(event)
|
||||
*
|
||||
* @uses html-janitor
|
||||
* @example codex.callback.blockPasteViaSanitize(event), the second method.
|
||||
*
|
||||
*/
|
||||
block.addEventListener('paste', function (event) {
|
||||
codex.callback.blockPaste(event);
|
||||
codex.callback.blockPasteViaSanitize(event);
|
||||
}, false);
|
||||
|
||||
block.addEventListener('mouseup', function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "codex.editor",
|
||||
"version": "1.0.0",
|
||||
"version": "1.2.8",
|
||||
"description": "Codex Editor. Native JS, based on API and Open Source",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
@ -17,7 +17,11 @@
|
|||
"babel-polyfill": "^6.20.0",
|
||||
"babel-runtime": "^6.20.0",
|
||||
"css-loader": "^0.26.1",
|
||||
"eslint": "^3.12.2",
|
||||
"eslint-loader": "^1.6.1",
|
||||
"extract-text-webpack-plugin": "^1.0.1",
|
||||
"html-janitor": "^2.0.2",
|
||||
"path": "^0.12.7",
|
||||
"webpack": "^1.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ var headerTool = {
|
|||
tag.textContent = data.text;
|
||||
}
|
||||
|
||||
if (!tag.dataset.headerData) {
|
||||
tag.dataset.headerData = 'H2';
|
||||
}
|
||||
|
||||
tag.classList.add('ce-header');
|
||||
tag.setAttribute('data-placeholder', 'Heading');
|
||||
tag.contentEditable = true;
|
||||
|
|
|
@ -6,9 +6,24 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
var pkg = require('./package.json');
|
||||
var path = require('path');
|
||||
|
||||
/**
|
||||
* Environment
|
||||
* @type {any}
|
||||
*/
|
||||
const NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
var webpack = require('webpack');
|
||||
var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
|
||||
const VERSION = process.env.VERSION || pkg.version;
|
||||
|
||||
var versioning = VERSION.split('.');
|
||||
|
||||
/**
|
||||
* Plugins for bundle
|
||||
* @type {webpack}
|
||||
*/
|
||||
var webpack = require('webpack');
|
||||
var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
|
||||
|
@ -30,8 +45,9 @@ module.exports = {
|
|||
devtool: NODE_ENV == 'development' ? "source-map" : null,
|
||||
|
||||
resolve : {
|
||||
fallback: path.join(__dirname, "node_modules"),
|
||||
modulesDirectories : ['./node_modules', './modules'],
|
||||
extensions : ['', '.js']
|
||||
extensions : ['', '.js', '.json']
|
||||
},
|
||||
|
||||
resolveLoader : {
|
||||
|
@ -42,9 +58,15 @@ module.exports = {
|
|||
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
NODE_ENV: JSON.stringify(NODE_ENV)
|
||||
NODE_ENV: JSON.stringify(NODE_ENV),
|
||||
VERSION: JSON.stringify(VERSION),
|
||||
MAJOR: parseInt(versioning[0]),
|
||||
MINOR: versioning[1],
|
||||
BUILD: versioning[2]
|
||||
}),
|
||||
|
||||
new webpack.EnvironmentPlugin('VERSION', pkg.version),
|
||||
|
||||
new webpack.ProvidePlugin({
|
||||
_ : 'lodash'
|
||||
})
|
||||
|
@ -60,6 +82,16 @@ module.exports = {
|
|||
presets: [__dirname + '/node_modules/babel-preset-es2015']
|
||||
}
|
||||
},
|
||||
{
|
||||
test : /\.js$/,
|
||||
loader: 'eslint-loader',
|
||||
exclude: /(node_modules)/
|
||||
},
|
||||
{
|
||||
test: /node_modules\/entities\/.*\.json$/,
|
||||
include : /(node_modules)/,
|
||||
loader: 'json'
|
||||
},
|
||||
{
|
||||
test : /\.css$/,
|
||||
exclude: /(node_modules)/,
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue