mirror of
https://github.com/codex-team/editor.js
synced 2024-06-26 09:20:07 +02:00
Merge branch 'master' into release.1.6.0
This commit is contained in:
commit
37a51c3faf
|
@ -112,6 +112,7 @@
|
|||
margin-right: 17px;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
7
codex.js
7
codex.js
|
@ -28,7 +28,6 @@ module.exports = (function (editor) {
|
|||
editor.notifications = require('./modules/notifications');
|
||||
editor.parser = require('./modules/parser');
|
||||
editor.sanitizer = require('./modules/sanitizer');
|
||||
editor.anchors = require('./modules/anchors');
|
||||
editor.listeners = require('./modules/listeners');
|
||||
editor.destroyer = require('./modules/destroyer');
|
||||
editor.paste = require('./modules/paste');
|
||||
|
@ -37,13 +36,11 @@ module.exports = (function (editor) {
|
|||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* holds initial settings
|
||||
*/
|
||||
editor.settings = {
|
||||
tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],
|
||||
textareaId: 'codex-editor',
|
||||
uploadImagesUrl: '/editor/transport/',
|
||||
|
||||
// Type of block showing on empty editor
|
||||
initialBlockPlugin: 'paragraph'
|
||||
|
@ -129,9 +126,7 @@ module.exports = (function (editor) {
|
|||
editor.core.prepare(userSettings)
|
||||
|
||||
// If all ok, make UI, bind events and parse initial-content
|
||||
.then(editor.ui.make)
|
||||
.then(editor.ui.addTools)
|
||||
.then(editor.ui.bindEvents)
|
||||
.then(editor.ui.prepare)
|
||||
.then(editor.tools.prepare)
|
||||
.then(editor.paste.prepare)
|
||||
.then(editor.transport.prepare)
|
||||
|
|
35
example.html
35
example.html
|
@ -51,6 +51,9 @@
|
|||
<script src="plugins/embed/embed.js"></script>
|
||||
<link rel="stylesheet" href="plugins/embed/embed.css">
|
||||
|
||||
<script src="plugins/raw/raw.js"></script>
|
||||
<link rel="stylesheet" href="plugins/raw/raw.css">
|
||||
|
||||
<script>
|
||||
codex.editor.start({
|
||||
holderId : "codex-editor",
|
||||
|
@ -68,8 +71,8 @@
|
|||
showInlineToolbar: true,
|
||||
allowRenderOnPaste: true
|
||||
},
|
||||
heading_styled: {
|
||||
type: 'heading_styled',
|
||||
header: {
|
||||
type: 'header',
|
||||
iconClassname: 'ce-icon-header',
|
||||
appendCallback: header.appendCallback,
|
||||
makeSettings: header.makeSettings,
|
||||
|
@ -120,8 +123,8 @@
|
|||
enableLineBreaks: true,
|
||||
allowedToPaste: true,
|
||||
},
|
||||
quote_styled: {
|
||||
type: 'quote_styled',
|
||||
quote: {
|
||||
type: 'quote',
|
||||
iconClassname: 'ce-icon-quote',
|
||||
makeSettings: quote.makeSettings,
|
||||
prepare: quote.prepare,
|
||||
|
@ -151,14 +154,15 @@
|
|||
displayInToolbox: true,
|
||||
renderOnPastePatterns: image.pastePatterns,
|
||||
config: {
|
||||
uploadUrl : '/club/fetch'
|
||||
uploadImage : '/writing/uploadImage',
|
||||
uploadFromUrl : '/club/fetch'
|
||||
}
|
||||
},
|
||||
instagram: {
|
||||
type: 'instagram',
|
||||
iconClassname: 'ce-icon-instagram',
|
||||
prepare: instagram.prepare,
|
||||
render: instagram.reneder,
|
||||
render: instagram.render,
|
||||
validate: instagram.validate,
|
||||
save: instagram.save,
|
||||
destroy: instagram.destroy,
|
||||
|
@ -186,6 +190,17 @@
|
|||
destroy: embed.destroy,
|
||||
validate: embed.validate,
|
||||
renderOnPastePatterns: embed.pastePatterns,
|
||||
},
|
||||
raw: {
|
||||
type: 'raw',
|
||||
displayInToolbox: true,
|
||||
iconClassname: 'raw-plugin-icon',
|
||||
render: rawPlugin.render,
|
||||
save: rawPlugin.save,
|
||||
validate: rawPlugin.validate,
|
||||
destroy: rawPlugin.destroy,
|
||||
enableLineBreaks: true,
|
||||
allowPasteHTML: true
|
||||
}
|
||||
},
|
||||
data : {
|
||||
|
@ -200,20 +215,18 @@
|
|||
type : 'paragraph',
|
||||
data : {
|
||||
text : 'Пишите нам на team@ifmo.su'
|
||||
},
|
||||
anchor: 'Update',
|
||||
}
|
||||
},
|
||||
{
|
||||
type : 'list',
|
||||
data : {
|
||||
type : 'OL',
|
||||
items : [1,3,4]
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
count: 3
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -1,47 +1,91 @@
|
|||
/**
|
||||
* Codex Editor callbacks module
|
||||
* @module Codex Editor Callbacks module
|
||||
* @description Module works with editor added Elements
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.3.7
|
||||
* @version 1.3.12
|
||||
*/
|
||||
|
||||
module.exports = (function (callbacks) {
|
||||
|
||||
let editor = codex.editor;
|
||||
|
||||
/**
|
||||
* used by UI module
|
||||
* @description Routes all keydowns on document
|
||||
* @param {Object} event
|
||||
*/
|
||||
callbacks.globalKeydown = function (event) {
|
||||
|
||||
switch (event.keyCode) {
|
||||
case editor.core.keys.ENTER : editor.callback.enterKeyPressed(event); break;
|
||||
case editor.core.keys.ENTER : enterKeyPressed_(event); break;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* used by UI module
|
||||
* @description Routes all keydowns on redactors area
|
||||
* @param {Object} event
|
||||
*/
|
||||
callbacks.redactorKeyDown = function (event) {
|
||||
|
||||
switch (event.keyCode) {
|
||||
case editor.core.keys.TAB : editor.callback.tabKeyPressed(event); break;
|
||||
case editor.core.keys.ENTER : editor.callback.enterKeyPressedOnRedactorZone(event); break;
|
||||
case editor.core.keys.ESC : editor.callback.escapeKeyPressed(event); break;
|
||||
default : editor.callback.defaultKeyPressed(event); break;
|
||||
case editor.core.keys.TAB : tabKeyPressedOnRedactorsZone_(event); break;
|
||||
case editor.core.keys.ENTER : enterKeyPressedOnRedactorsZone_(event); break;
|
||||
case editor.core.keys.ESC : escapeKeyPressedOnRedactorsZone_(event); break;
|
||||
default : defaultKeyPressedOnRedactorsZone_(event); break;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* used by UI module
|
||||
* @description Routes all keyup events
|
||||
* @param {Object} event
|
||||
*/
|
||||
callbacks.globalKeyup = function (event) {
|
||||
|
||||
switch (event.keyCode) {
|
||||
case editor.core.keys.UP :
|
||||
case editor.core.keys.LEFT :
|
||||
case editor.core.keys.RIGHT :
|
||||
case editor.core.keys.DOWN : editor.callback.arrowKeyPressed(event); break;
|
||||
case editor.core.keys.DOWN : arrowKeyPressed_(event); break;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
callbacks.tabKeyPressed = function (event) {
|
||||
/**
|
||||
* @param {Object} event
|
||||
* @private
|
||||
*
|
||||
* Handles behaviour when tab pressed
|
||||
* @description if Content is empty show toolbox (if it is closed) or leaf tools
|
||||
* uses Toolbars toolbox module to handle the situation
|
||||
*/
|
||||
var tabKeyPressedOnRedactorsZone_ = function (event) {
|
||||
|
||||
var blockIsEmpty = !editor.content.currentNode.textContent.trim();
|
||||
/**
|
||||
* Wait for solution. Would like to know the behaviour
|
||||
* @todo Add spaces
|
||||
*/
|
||||
event.preventDefault();
|
||||
|
||||
var nativeInputs = editor.content.currentNode.querySelectorAll('textarea, input'),
|
||||
nativeInputsAreEmpty = true,
|
||||
textContentIsEmpty = !editor.content.currentNode.textContent.trim();
|
||||
|
||||
Array.prototype.map.call(nativeInputs, function (input) {
|
||||
|
||||
if (input.type == 'textarea' || input.type == 'text') {
|
||||
|
||||
nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var blockIsEmpty = textContentIsEmpty && nativeInputsAreEmpty;
|
||||
|
||||
if (!blockIsEmpty) {
|
||||
|
||||
|
@ -65,14 +109,14 @@ module.exports = (function (callbacks) {
|
|||
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
callbacks.enterKeyPressed = function () {
|
||||
* Handles global EnterKey Press
|
||||
* @see enterPressedOnBlock_
|
||||
* @param {Object} event
|
||||
*/
|
||||
var enterKeyPressed_ = function () {
|
||||
|
||||
if (editor.content.editorAreaHightlighted) {
|
||||
|
||||
|
@ -82,17 +126,44 @@ module.exports = (function (callbacks) {
|
|||
*/
|
||||
editor.caret.inputIndex = -1;
|
||||
|
||||
editor.callback.enterPressedOnBlock();
|
||||
enterPressedOnBlock_();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* ENTER key handler
|
||||
* Makes new paragraph block
|
||||
* Callback for enter key pressing in first-level block area
|
||||
*
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*
|
||||
* @description Inserts new block with initial type from settings
|
||||
*/
|
||||
callbacks.enterKeyPressedOnRedactorZone = function (event) {
|
||||
var enterPressedOnBlock_ = function () {
|
||||
|
||||
var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;
|
||||
|
||||
editor.content.insertBlock({
|
||||
type : NEW_BLOCK_TYPE,
|
||||
block : editor.tools[NEW_BLOCK_TYPE].render()
|
||||
}, true );
|
||||
|
||||
editor.toolbar.move();
|
||||
editor.toolbar.open();
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ENTER key handler
|
||||
*
|
||||
* @param {Object} event
|
||||
* @private
|
||||
*
|
||||
* @description Makes new block with initial type from settings
|
||||
*/
|
||||
var enterKeyPressedOnRedactorsZone_ = function (event) {
|
||||
|
||||
if (event.target.contentEditable == 'true') {
|
||||
|
||||
|
@ -224,7 +295,14 @@ module.exports = (function (callbacks) {
|
|||
|
||||
};
|
||||
|
||||
callbacks.escapeKeyPressed = function (event) {
|
||||
/**
|
||||
* Escape behaviour
|
||||
* @param event
|
||||
* @private
|
||||
*
|
||||
* @description Closes toolbox and toolbar. Prevents default behaviour
|
||||
*/
|
||||
var escapeKeyPressedOnRedactorsZone_ = function (event) {
|
||||
|
||||
/** Close all toolbar */
|
||||
editor.toolbar.close();
|
||||
|
@ -237,9 +315,12 @@ module.exports = (function (callbacks) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
callbacks.arrowKeyPressed = function () {
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*
|
||||
* closes and moves toolbar
|
||||
*/
|
||||
var arrowKeyPressed_ = function (event) {
|
||||
|
||||
editor.content.workingNodeChanged();
|
||||
|
||||
|
@ -250,9 +331,13 @@ module.exports = (function (callbacks) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
callbacks.defaultKeyPressed = function () {
|
||||
* @private
|
||||
* @param {Event} event
|
||||
*
|
||||
* @description Closes all opened bars from toolbar.
|
||||
* If block is mark, clears highlightning
|
||||
*/
|
||||
var defaultKeyPressedOnRedactorsZone_ = function () {
|
||||
|
||||
editor.toolbar.close();
|
||||
|
||||
|
@ -265,20 +350,30 @@ module.exports = (function (callbacks) {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler when clicked on redactors area
|
||||
*
|
||||
* @protected
|
||||
* @param event
|
||||
*
|
||||
* @description Detects clicked area. If it is first-level block area, marks as detected and
|
||||
* on next enter press will be inserted new block
|
||||
* Otherwise, save carets position (input index) and put caret to the editable zone.
|
||||
*
|
||||
* @see detectWhenClickedOnFirstLevelBlockArea_
|
||||
*
|
||||
*/
|
||||
callbacks.redactorClicked = function (event) {
|
||||
|
||||
callbacks.detectWhenClickedOnFirstLevelBlockArea();
|
||||
detectWhenClickedOnFirstLevelBlockArea_();
|
||||
|
||||
editor.content.workingNodeChanged(event.target);
|
||||
|
||||
editor.ui.saveInputs();
|
||||
|
||||
var selectedText = editor.toolbar.inline.getSelectionText(),
|
||||
firstLevelBlock;
|
||||
|
||||
/**
|
||||
* If selection range took off, then we hide inline toolbar
|
||||
*/
|
||||
/** If selection range took off, then we hide inline toolbar */
|
||||
if (selectedText.length === 0) {
|
||||
|
||||
editor.toolbar.inline.close();
|
||||
|
@ -302,10 +397,6 @@ module.exports = (function (callbacks) {
|
|||
/** If we have any inputs */
|
||||
if (editor.state.inputs.length) {
|
||||
|
||||
/**
|
||||
* @todo Refactor
|
||||
*/
|
||||
|
||||
/** getting firstlevel parent of input */
|
||||
firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);
|
||||
|
||||
|
@ -340,26 +431,19 @@ module.exports = (function (callbacks) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Move toolbar to the right position and open
|
||||
*/
|
||||
editor.toolbar.move();
|
||||
editor.toolbar.open();
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* Move toolbar to the new position and open
|
||||
*/
|
||||
editor.toolbar.move();
|
||||
editor.toolbar.open();
|
||||
|
||||
/** Close all panels */
|
||||
editor.toolbar.settings.close();
|
||||
editor.toolbar.toolbox.close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Move toolbar and open
|
||||
*/
|
||||
editor.toolbar.move();
|
||||
editor.toolbar.open();
|
||||
|
||||
var inputIsEmpty = !editor.content.currentNode.textContent.trim(),
|
||||
currentNodeType = editor.content.currentNode.dataset.tool,
|
||||
|
@ -388,12 +472,15 @@ module.exports = (function (callbacks) {
|
|||
|
||||
/**
|
||||
* This method allows to define, is caret in contenteditable element or not.
|
||||
* Otherwise, if we get TEXT node from range container, that will means we have input index.
|
||||
*
|
||||
* @private
|
||||
*
|
||||
* @description Otherwise, if we get TEXT node from range container, that will means we have input index.
|
||||
* In this case we use default browsers behaviour (if plugin allows that) or overwritten action.
|
||||
* 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.detectWhenClickedOnFirstLevelBlockArea = function () {
|
||||
var detectWhenClickedOnFirstLevelBlockArea_ = function () {
|
||||
|
||||
var selection = window.getSelection(),
|
||||
anchorNode = selection.anchorNode,
|
||||
|
@ -437,7 +524,7 @@ module.exports = (function (callbacks) {
|
|||
}
|
||||
|
||||
/** If editable element founded, flag is "TRUE", Therefore we return "FALSE" */
|
||||
editor.content.editorAreaHightlighted = flag ? false : true;
|
||||
editor.content.editorAreaHightlighted = !flag;
|
||||
|
||||
}
|
||||
|
||||
|
@ -445,7 +532,11 @@ module.exports = (function (callbacks) {
|
|||
|
||||
/**
|
||||
* Toolbar button click handler
|
||||
* @param this - cursor to the button
|
||||
*
|
||||
* @param {Object} event - cursor to the button
|
||||
* @protected
|
||||
*
|
||||
* @description gets current tool and calls render method
|
||||
*/
|
||||
callbacks.toolbarButtonClicked = function (event) {
|
||||
|
||||
|
@ -458,7 +549,9 @@ module.exports = (function (callbacks) {
|
|||
|
||||
};
|
||||
|
||||
/** Show or Hide toolbox when plus button is clicked */
|
||||
/**
|
||||
* Show or Hide toolbox when plus button is clicked
|
||||
*/
|
||||
callbacks.plusButtonClicked = function () {
|
||||
|
||||
if (!editor.nodes.toolbox.classList.contains('opened')) {
|
||||
|
@ -475,25 +568,33 @@ module.exports = (function (callbacks) {
|
|||
|
||||
/**
|
||||
* Block handlers for KeyDown events
|
||||
*
|
||||
* @protected
|
||||
* @param {Object} event
|
||||
*
|
||||
* Handles keydowns on block
|
||||
* @see blockRightOrDownArrowPressed_
|
||||
* @see backspacePressed_
|
||||
* @see blockLeftOrUpArrowPressed_
|
||||
*/
|
||||
callbacks.blockKeydown = function (event) {
|
||||
|
||||
let block = this; // event.target input
|
||||
let block = event.target; // event.target is input
|
||||
|
||||
switch (event.keyCode) {
|
||||
|
||||
case editor.core.keys.DOWN:
|
||||
case editor.core.keys.RIGHT:
|
||||
editor.callback.blockRightOrDownArrowPressed();
|
||||
blockRightOrDownArrowPressed_(event);
|
||||
break;
|
||||
|
||||
case editor.core.keys.BACKSPACE:
|
||||
editor.callback.backspacePressed(block, event);
|
||||
backspacePressed_(block, event);
|
||||
break;
|
||||
|
||||
case editor.core.keys.UP:
|
||||
case editor.core.keys.LEFT:
|
||||
editor.callback.blockLeftOrUpArrowPressed();
|
||||
blockLeftOrUpArrowPressed_(event);
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -502,8 +603,15 @@ module.exports = (function (callbacks) {
|
|||
|
||||
/**
|
||||
* RIGHT or DOWN keydowns on block
|
||||
*
|
||||
* @param {Object} event
|
||||
* @private
|
||||
*
|
||||
* @description watches the selection and gets closest editable element.
|
||||
* Uses method getDeepestTextNodeFromPosition to get the last node of next block
|
||||
* Sets caret if it is contenteditable
|
||||
*/
|
||||
callbacks.blockRightOrDownArrowPressed = function () {
|
||||
var blockRightOrDownArrowPressed_ = function (event) {
|
||||
|
||||
var selection = window.getSelection(),
|
||||
inputs = editor.state.inputs,
|
||||
|
@ -582,8 +690,16 @@ module.exports = (function (callbacks) {
|
|||
|
||||
/**
|
||||
* LEFT or UP keydowns on block
|
||||
*
|
||||
* @param {Object} event
|
||||
* @private
|
||||
*
|
||||
* watches the selection and gets closest editable element.
|
||||
* Uses method getDeepestTextNodeFromPosition to get the last node of previous block
|
||||
* Sets caret if it is contenteditable
|
||||
*
|
||||
*/
|
||||
callbacks.blockLeftOrUpArrowPressed = function () {
|
||||
var blockLeftOrUpArrowPressed_ = function (event) {
|
||||
|
||||
var selection = window.getSelection(),
|
||||
inputs = editor.state.inputs,
|
||||
|
@ -667,30 +783,39 @@ module.exports = (function (callbacks) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Callback for enter key pressing in first-level block area
|
||||
* @param {Event} event
|
||||
* Handles backspace keydown
|
||||
*
|
||||
* @param {Element} block
|
||||
* @param {Object} event
|
||||
* @private
|
||||
*
|
||||
* @description if block is empty, delete the block and set caret to the previous block
|
||||
* If block is not empty, try to merge two blocks - current and previous
|
||||
* But it we try'n to remove first block, then we should set caret to the next block, not previous.
|
||||
* If we removed the last block, create new one
|
||||
*/
|
||||
callbacks.enterPressedOnBlock = function () {
|
||||
|
||||
var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;
|
||||
|
||||
editor.content.insertBlock({
|
||||
type : NEW_BLOCK_TYPE,
|
||||
block : editor.tools[NEW_BLOCK_TYPE].render()
|
||||
}, true );
|
||||
|
||||
editor.toolbar.move();
|
||||
editor.toolbar.open();
|
||||
|
||||
};
|
||||
|
||||
callbacks.backspacePressed = function (block, event) {
|
||||
var backspacePressed_ = function (block, event) {
|
||||
|
||||
var currentInputIndex = editor.caret.getCurrentInputIndex(),
|
||||
range,
|
||||
selectionLength,
|
||||
firstLevelBlocksCount;
|
||||
|
||||
if (isNativeInput_(event.target)) {
|
||||
|
||||
/** If input value is empty - remove block */
|
||||
if (event.target.value.trim() == '') {
|
||||
|
||||
block.remove();
|
||||
|
||||
} else {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (block.textContent.trim()) {
|
||||
|
||||
range = editor.content.getRange();
|
||||
|
@ -810,19 +935,27 @@ module.exports = (function (callbacks) {
|
|||
/**
|
||||
* This method prevents default behaviour.
|
||||
*
|
||||
* We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.
|
||||
* @param {Object} event
|
||||
* @protected
|
||||
*
|
||||
* @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.
|
||||
* Firstly, we need to memorize the caret position. We can do that by getting the range of selection.
|
||||
* After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
callbacks.blockPasteCallback = function (event) {
|
||||
|
||||
/** If area is input or textarea then allow default behaviour */
|
||||
if ( isNativeInput_(event.target) ) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/** Prevent default behaviour */
|
||||
event.preventDefault();
|
||||
|
||||
var editableParent = editor.content.getEditableParent(event.target),
|
||||
firstLevelBlock = editor.content.getFirstLevelBlock(event.target);
|
||||
currentNode = editor.content.currentNode;
|
||||
|
||||
/** Allow paste when event target placed in Editable element */
|
||||
if (!editableParent) {
|
||||
|
@ -832,7 +965,8 @@ module.exports = (function (callbacks) {
|
|||
}
|
||||
|
||||
/** get html pasted data - dirty data */
|
||||
var data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain');
|
||||
var htmlData = event.clipboardData.getData('text/html'),
|
||||
plainData = event.clipboardData.getData('text/plain');
|
||||
|
||||
/** Temporary DIV that is used to work with childs as arrays item */
|
||||
var div = editor.draw.node('DIV', '', {}),
|
||||
|
@ -843,9 +977,16 @@ module.exports = (function (callbacks) {
|
|||
/** Create fragment, that we paste to range after proccesing */
|
||||
fragment = document.createDocumentFragment();
|
||||
|
||||
cleanData = cleaner.clean(data);
|
||||
if ( htmlData.trim() != '' ) {
|
||||
|
||||
div.innerHTML = cleanData;
|
||||
cleanData = cleaner.clean(htmlData);
|
||||
div.innerHTML = cleanData;
|
||||
|
||||
} else {
|
||||
|
||||
div.innerText = plainData.toString();
|
||||
|
||||
}
|
||||
|
||||
var node, lastNode;
|
||||
|
||||
|
@ -859,7 +1000,7 @@ module.exports = (function (callbacks) {
|
|||
}
|
||||
|
||||
|
||||
if (editor.tools[firstLevelBlock.dataset.tool].allowRenderOnPaste) {
|
||||
if (editor.tools[currentNode.dataset.tool].allowRenderOnPaste) {
|
||||
|
||||
if (editor.paste.pasted(event)) return;
|
||||
|
||||
|
@ -891,6 +1032,7 @@ module.exports = (function (callbacks) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Sends all mutations to paste handler
|
||||
*/
|
||||
callbacks.handleMutationsOnPaste = function (mutations) {
|
||||
|
@ -913,9 +1055,14 @@ module.exports = (function (callbacks) {
|
|||
};
|
||||
|
||||
/**
|
||||
* used by UI module
|
||||
* Clicks on block settings button
|
||||
*
|
||||
* @param {Object} event
|
||||
* @protected
|
||||
* @description Opens toolbar settings
|
||||
*/
|
||||
callbacks.showSettingsButtonClicked = function () {
|
||||
callbacks.showSettingsButtonClicked = function (event) {
|
||||
|
||||
/**
|
||||
* Get type of current block
|
||||
|
@ -933,6 +1080,21 @@ module.exports = (function (callbacks) {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* Check block
|
||||
* @param target
|
||||
* @private
|
||||
*
|
||||
* @description Checks target is it native input
|
||||
*/
|
||||
var isNativeInput_ = function (target) {
|
||||
|
||||
var nativeInputAreas = ['INPUT', 'TEXTAREA'];
|
||||
|
||||
return (nativeInputAreas.indexOf(target.tagName) != -1);
|
||||
|
||||
};
|
||||
|
||||
return callbacks;
|
||||
|
||||
})({});
|
|
@ -49,7 +49,7 @@ module.exports = (function (caret) {
|
|||
}
|
||||
|
||||
/** If Element is INPUT */
|
||||
if (el.tagName == 'INPUT') {
|
||||
if (el.contentEditable != 'true') {
|
||||
|
||||
el.focus();
|
||||
return;
|
||||
|
|
|
@ -2,8 +2,12 @@
|
|||
* Codex Editor Content Module
|
||||
* Works with DOM
|
||||
*
|
||||
* @module Codex Editor content module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.3.11
|
||||
* @version 1.3.13
|
||||
*
|
||||
* @description Module works with Elements that have been appended to the main DOM
|
||||
*/
|
||||
|
||||
module.exports = (function (content) {
|
||||
|
@ -23,6 +27,7 @@ module.exports = (function (content) {
|
|||
content.editorAreaHightlighted = null;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Synchronizes redactor with original textarea
|
||||
*/
|
||||
content.sync = function () {
|
||||
|
@ -36,57 +41,10 @@ module.exports = (function (content) {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
content.getNodeFocused = function () {
|
||||
|
||||
var selection = window.getSelection(),
|
||||
focused;
|
||||
|
||||
if (selection.anchorNode === null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
if ( selection.anchorNode.nodeType == editor.core.nodeTypes.TAG ) {
|
||||
|
||||
focused = selection.anchorNode;
|
||||
|
||||
} else {
|
||||
|
||||
focused = selection.focusNode.parentElement;
|
||||
|
||||
}
|
||||
|
||||
if ( !editor.parser.isFirstLevelBlock(focused) ) {
|
||||
|
||||
/** Iterate with parent nodes to find first-level*/
|
||||
var parent = focused.parentNode;
|
||||
|
||||
while (parent && !editor.parser.isFirstLevelBlock(parent)) {
|
||||
|
||||
parent = parent.parentNode;
|
||||
|
||||
}
|
||||
|
||||
focused = parent;
|
||||
|
||||
}
|
||||
|
||||
if (focused != editor.nodes.redactor) {
|
||||
|
||||
return focused;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends background to the block
|
||||
*
|
||||
* @description add CSS class to highlight visually first-level block area
|
||||
*/
|
||||
content.markBlock = function () {
|
||||
|
||||
|
@ -96,6 +54,8 @@ module.exports = (function (content) {
|
|||
|
||||
/**
|
||||
* Clear background
|
||||
*
|
||||
* @description clears styles that highlights block
|
||||
*/
|
||||
content.clearMark = function () {
|
||||
|
||||
|
@ -108,10 +68,13 @@ module.exports = (function (content) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* Finds first-level block
|
||||
*
|
||||
* @param {Element} node - selected or clicked in redactors area node
|
||||
* @protected
|
||||
*
|
||||
* @description looks for first-level block.
|
||||
* gets parent while node is not first-level
|
||||
*/
|
||||
content.getFirstLevelBlock = function (node) {
|
||||
|
||||
|
@ -142,7 +105,9 @@ module.exports = (function (content) {
|
|||
/**
|
||||
* Trigger this event when working node changed
|
||||
* @param {Element} targetNode - first-level of this node will be current
|
||||
* If targetNode is first-level then we set it as current else we look for parents to find first-level
|
||||
* @protected
|
||||
*
|
||||
* @description If targetNode is first-level then we set it as current else we look for parents to find first-level
|
||||
*/
|
||||
content.workingNodeChanged = function (targetNode) {
|
||||
|
||||
|
@ -185,27 +150,6 @@ module.exports = (function (content) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is this block was in feed
|
||||
* If true, than set switched block also covered
|
||||
*/
|
||||
if (targetBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE)) {
|
||||
|
||||
newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);
|
||||
|
||||
}
|
||||
|
||||
if (targetBlock.classList.contains(editor.ui.className.BLOCK_WITH_ANCHOR)) {
|
||||
|
||||
newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving anchor
|
||||
*/
|
||||
newBlock.dataset.anchor = targetBlock.dataset.anchor;
|
||||
|
||||
/** Replacing */
|
||||
editor.nodes.redactor.replaceChild(newBlock, targetBlock);
|
||||
|
||||
|
@ -227,7 +171,7 @@ module.exports = (function (content) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @protected
|
||||
*
|
||||
* Inserts new block to redactor
|
||||
* Wrapps block into a DIV with BLOCK_CLASSNAME class
|
||||
|
@ -243,23 +187,9 @@ module.exports = (function (content) {
|
|||
var workingBlock = editor.content.currentNode,
|
||||
newBlockContent = blockData.block,
|
||||
blockType = blockData.type,
|
||||
cover = blockData.cover,
|
||||
anchor = blockData.anchor,
|
||||
isStretched = blockData.stretched;
|
||||
|
||||
var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);
|
||||
|
||||
if (cover === true) {
|
||||
|
||||
newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);
|
||||
|
||||
}
|
||||
|
||||
if (anchor) {
|
||||
|
||||
newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);
|
||||
|
||||
}
|
||||
var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched);
|
||||
|
||||
if (workingBlock) {
|
||||
|
||||
|
@ -347,7 +277,8 @@ module.exports = (function (content) {
|
|||
*/
|
||||
content.switchBlock = function (blockToReplace, newBlock, tool) {
|
||||
|
||||
var newBlockComposed = editor.content.composeNewBlock(newBlock, tool);
|
||||
tool = tool || editor.content.currentNode.dataset.tool;
|
||||
var newBlockComposed = composeNewBlock_(newBlock, tool);
|
||||
|
||||
/** Replacing */
|
||||
editor.content.replaceBlock(blockToReplace, newBlockComposed);
|
||||
|
@ -359,7 +290,8 @@ module.exports = (function (content) {
|
|||
|
||||
/**
|
||||
* Iterates between child noted and looking for #text node on deepest level
|
||||
* @private
|
||||
* @protected
|
||||
*
|
||||
* @param {Element} block - node where find
|
||||
* @param {int} postiton - starting postion
|
||||
* Example: childNodex.length to find from the end
|
||||
|
@ -451,8 +383,13 @@ module.exports = (function (content) {
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {Element} block - current plugins render
|
||||
* @param {String} tool - plugins name
|
||||
* @param {Boolean} isStretched - make stretched block or not
|
||||
*
|
||||
* @description adds necessary information to wrap new created block by first-level holder
|
||||
*/
|
||||
content.composeNewBlock = function (block, tool, isStretched, anchor) {
|
||||
var composeNewBlock_ = function (block, tool, isStretched) {
|
||||
|
||||
var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),
|
||||
blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});
|
||||
|
@ -467,13 +404,13 @@ module.exports = (function (content) {
|
|||
}
|
||||
|
||||
newBlock.dataset.tool = tool;
|
||||
newBlock.dataset.anchor = anchor || '';
|
||||
return newBlock;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns Range object of current selection
|
||||
* @protected
|
||||
*/
|
||||
content.getRange = function () {
|
||||
|
||||
|
@ -485,8 +422,12 @@ module.exports = (function (content) {
|
|||
|
||||
/**
|
||||
* Divides block in two blocks (after and before caret)
|
||||
* @private
|
||||
* @param {Int} inputIndex - target input index
|
||||
*
|
||||
* @protected
|
||||
* @param {int} inputIndex - target input index
|
||||
*
|
||||
* @description splits current input content to the separate blocks
|
||||
* When enter is pressed among the words, that text will be splited.
|
||||
*/
|
||||
content.splitBlock = function (inputIndex) {
|
||||
|
||||
|
@ -593,6 +534,12 @@ module.exports = (function (content) {
|
|||
/**
|
||||
* Merges two blocks — current and target
|
||||
* If target index is not exist, then previous will be as target
|
||||
*
|
||||
* @protected
|
||||
* @param {int} currentInputIndex
|
||||
* @param {int} targetInputIndex
|
||||
*
|
||||
* @description gets two inputs indexes and merges into one
|
||||
*/
|
||||
content.mergeBlocks = function (currentInputIndex, targetInputIndex) {
|
||||
|
||||
|
@ -621,7 +568,7 @@ module.exports = (function (content) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @deprecated
|
||||
*
|
||||
* Callback for HTML Mutations
|
||||
* @param {Array} mutation - Mutation Record
|
||||
|
@ -644,7 +591,7 @@ module.exports = (function (content) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @deprecated
|
||||
*
|
||||
* gets only text/plain content of node
|
||||
* @param {Element} target - HTML node
|
||||
|
@ -679,7 +626,7 @@ module.exports = (function (content) {
|
|||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @deprecated
|
||||
*
|
||||
* Sanitizes HTML content
|
||||
* @param {Element} target - inserted element
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Codex Editor Core
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.1.2
|
||||
* @version 1.1.3
|
||||
*/
|
||||
|
||||
module.exports = (function (core) {
|
||||
|
@ -37,12 +37,6 @@ module.exports = (function (core) {
|
|||
|
||||
}
|
||||
|
||||
if (userSettings.uploadImagesUrl) {
|
||||
|
||||
editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;
|
||||
|
||||
}
|
||||
|
||||
editor.hideToolbar = userSettings.hideToolbar;
|
||||
|
||||
editor.nodes.textarea = document.getElementById(userSettings.textareaId || editor.settings.textareaId);
|
||||
|
@ -146,9 +140,9 @@ module.exports = (function (core) {
|
|||
/**
|
||||
* Native Ajax
|
||||
*/
|
||||
core.ajax = function (data) {
|
||||
core.ajax = function (settings) {
|
||||
|
||||
if (!data || !data.url) {
|
||||
if (!settings || !settings.url) {
|
||||
|
||||
return;
|
||||
|
||||
|
@ -156,44 +150,65 @@ module.exports = (function (core) {
|
|||
|
||||
var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),
|
||||
successFunction = function () {},
|
||||
params = '',
|
||||
obj;
|
||||
encodedString,
|
||||
isFormData,
|
||||
prop;
|
||||
|
||||
data.async = true;
|
||||
data.type = data.type || 'GET';
|
||||
data.data = data.data || '';
|
||||
data['content-type'] = data['content-type'] || 'application/json; charset=utf-8';
|
||||
successFunction = data.success || successFunction ;
|
||||
settings.async = true;
|
||||
settings.type = settings.type || 'GET';
|
||||
settings.data = settings.data || '';
|
||||
settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8';
|
||||
successFunction = settings.success || successFunction ;
|
||||
|
||||
if (data.type == 'GET' && data.data) {
|
||||
if (settings.type == 'GET' && settings.data) {
|
||||
|
||||
data.url = /\?/.test(data.url) ? data.url + '&' + data.data : data.url + '?' + data.data;
|
||||
settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data;
|
||||
|
||||
} else {
|
||||
|
||||
for(obj in data.data) {
|
||||
encodedString = '';
|
||||
for(prop in settings.data) {
|
||||
|
||||
params += (obj + '=' + encodeURIComponent(data.data[obj]) + '&');
|
||||
encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (data.withCredentials) {
|
||||
if (settings.withCredentials) {
|
||||
|
||||
XMLHTTP.withCredentials = true;
|
||||
|
||||
}
|
||||
|
||||
if (data.beforeSend && typeof data.beforeSend == 'function') {
|
||||
if (settings.beforeSend && typeof settings.beforeSend == 'function') {
|
||||
|
||||
data.beforeSend.call();
|
||||
settings.beforeSend.call();
|
||||
|
||||
}
|
||||
|
||||
XMLHTTP.open( settings.type, settings.url, settings.async );
|
||||
|
||||
/**
|
||||
* If we send FormData, we need no content-type header
|
||||
*/
|
||||
isFormData = isFormData_(settings.data);
|
||||
|
||||
if (!isFormData) {
|
||||
|
||||
if (settings.type != 'POST') {
|
||||
|
||||
XMLHTTP.setRequestHeader('Content-type', settings['content-type']);
|
||||
|
||||
} else {
|
||||
|
||||
XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
XMLHTTP.open( data.type, data.url, data.async );
|
||||
XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
XMLHTTP.onreadystatechange = function () {
|
||||
|
||||
|
@ -205,7 +220,18 @@ module.exports = (function (core) {
|
|||
|
||||
};
|
||||
|
||||
XMLHTTP.send(params);
|
||||
if (isFormData) {
|
||||
|
||||
// Sending FormData
|
||||
XMLHTTP.send(settings.data);
|
||||
|
||||
} else {
|
||||
|
||||
// POST requests
|
||||
XMLHTTP.send(encodedString);
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
@ -254,6 +280,17 @@ module.exports = (function (core) {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* Function for checking is it FormData object to send.
|
||||
* @param {Object} object to check
|
||||
* @return boolean
|
||||
*/
|
||||
var isFormData_ = function (object) {
|
||||
|
||||
return object instanceof FormData;
|
||||
|
||||
};
|
||||
|
||||
return core;
|
||||
|
||||
})({});
|
|
@ -2,7 +2,7 @@
|
|||
* Codex Editor Paste module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
* @version 1.1.1
|
||||
*/
|
||||
|
||||
module.exports = function (paste) {
|
||||
|
@ -25,6 +25,7 @@ module.exports = function (paste) {
|
|||
|
||||
tools[tool].renderOnPastePatterns.map(function (pattern) {
|
||||
|
||||
|
||||
patterns.push(pattern);
|
||||
|
||||
});
|
||||
|
@ -69,7 +70,10 @@ module.exports = function (paste) {
|
|||
|
||||
patterns.map( function (pattern) {
|
||||
|
||||
if (pattern.regex.test(string)) {
|
||||
var execArray = pattern.regex.exec(string),
|
||||
match = execArray && execArray[0];
|
||||
|
||||
if ( match && match === string.trim()) {
|
||||
|
||||
/** current block is not empty */
|
||||
if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {
|
||||
|
|
|
@ -149,9 +149,7 @@ module.exports = (function (renderer) {
|
|||
/** New parser */
|
||||
var block,
|
||||
tool = toolData.tool,
|
||||
pluginName = tool.type,
|
||||
anchor = tool.anchor,
|
||||
cover = tool.cover;
|
||||
pluginName = tool.type;
|
||||
|
||||
/** Get first key of object that stores plugin name */
|
||||
// for (var pluginName in blockData) break;
|
||||
|
@ -195,9 +193,7 @@ module.exports = (function (renderer) {
|
|||
return {
|
||||
type : pluginName,
|
||||
block : block,
|
||||
stretched : stretched,
|
||||
cover : cover,
|
||||
anchor : anchor
|
||||
stretched : stretched
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -86,8 +86,7 @@ module.exports = (function (saver) {
|
|||
|
||||
saver.makeFormDataFromBlocks = function (block) {
|
||||
|
||||
var pluginName = block.dataset.tool,
|
||||
anchor = block.dataset.anchor;
|
||||
var pluginName = block.dataset.tool;
|
||||
|
||||
/** Check for plugin existance */
|
||||
if (!editor.tools[pluginName]) {
|
||||
|
@ -108,22 +107,17 @@ module.exports = (function (saver) {
|
|||
pluginsContent = blockContent.childNodes[0],
|
||||
savedData,
|
||||
position,
|
||||
output,
|
||||
coverFlag = false;
|
||||
output;
|
||||
|
||||
/** 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;
|
||||
anchor = codex.editor.state.blocks.items[position].anchor;
|
||||
|
||||
} else {
|
||||
|
||||
savedData = editor.tools[pluginName].save(pluginsContent);
|
||||
coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);
|
||||
|
||||
if (editor.tools[pluginName].validate) {
|
||||
|
||||
|
@ -141,13 +135,9 @@ module.exports = (function (saver) {
|
|||
|
||||
output = {
|
||||
type : pluginName,
|
||||
anchor : anchor,
|
||||
data : savedData
|
||||
};
|
||||
|
||||
/** Marks Blocks that will be in main page */
|
||||
output.cover = coverFlag;
|
||||
|
||||
editor.state.jsonOutput.push(output);
|
||||
|
||||
};
|
||||
|
|
|
@ -13,8 +13,6 @@ module.exports = (function (settings) {
|
|||
settings.setting = null;
|
||||
settings.actions = null;
|
||||
|
||||
settings.cover = null;
|
||||
|
||||
/**
|
||||
* Append and open settings
|
||||
*/
|
||||
|
@ -27,7 +25,7 @@ module.exports = (function (settings) {
|
|||
if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {
|
||||
|
||||
editor.core.log(`Plugin «${toolType}» has no settings`, 'warn');
|
||||
// editor.nodes.pluginSettings.innerHTML = `Плагин «${toolType}» не имеет настроек`;
|
||||
editor.nodes.pluginSettings.innerHTML = `Плагин «${toolType}» не имеет настроек`;
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -42,7 +40,6 @@ module.exports = (function (settings) {
|
|||
|
||||
/** Open settings block */
|
||||
editor.nodes.blockSettings.classList.add('opened');
|
||||
editor.toolbar.settings.addDefaultSettings();
|
||||
this.opened = true;
|
||||
|
||||
};
|
||||
|
@ -67,7 +64,6 @@ module.exports = (function (settings) {
|
|||
if ( !this.opened ) {
|
||||
|
||||
this.open(toolType);
|
||||
editor.anchors.settingsOpened(editor.content.currentNode);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -77,125 +73,6 @@ module.exports = (function (settings) {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* This function adds default core settings
|
||||
*/
|
||||
settings.addDefaultSettings = function () {
|
||||
|
||||
/** list of default settings */
|
||||
var feedModeToggler,
|
||||
anchorInput;
|
||||
|
||||
/** Clear block and append initialized settings */
|
||||
editor.nodes.defaultSettings.innerHTML = '';
|
||||
|
||||
|
||||
/** Init all default setting buttons */
|
||||
feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();
|
||||
anchorInput = editor.toolbar.settings.makeAnchorInput();
|
||||
|
||||
/**
|
||||
* Fill defaultSettings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Input for anchor for block
|
||||
*/
|
||||
editor.nodes.defaultSettings.appendChild(anchorInput);
|
||||
|
||||
/**
|
||||
* Button that enables/disables Feed-mode
|
||||
* Feed-mode means that block will be showed in articles-feed like cover
|
||||
*/
|
||||
editor.nodes.defaultSettings.appendChild(feedModeToggler);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Cover setting.
|
||||
* This tune highlights block, so that it may be used for showing target block on main page
|
||||
* Draw different setting when block is marked for main page
|
||||
* If TRUE, then we show button that removes this selection
|
||||
* Also defined setting "Click" events will be listened and have separate callbacks
|
||||
*
|
||||
* @return {Element} node/button that we place in default settings block
|
||||
*/
|
||||
settings.makeFeedModeToggler = function () {
|
||||
|
||||
var isFeedModeActivated = editor.toolbar.settings.isFeedModeActivated(),
|
||||
setting,
|
||||
data;
|
||||
|
||||
if (!isFeedModeActivated) {
|
||||
|
||||
data = {
|
||||
innerHTML : '<i class="ce-icon-newspaper"></i>Вывести в ленте'
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
data = {
|
||||
innerHTML : '<i class="ce-icon-newspaper"></i>Не выводить в ленте'
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);
|
||||
editor.listeners.add(setting, 'click', editor.toolbar.settings.updateFeedMode, false);
|
||||
|
||||
return setting;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates Feed-mode
|
||||
*/
|
||||
settings.updateFeedMode = function () {
|
||||
|
||||
var currentNode = editor.content.currentNode;
|
||||
|
||||
currentNode.classList.toggle(editor.ui.className.BLOCK_IN_FEED_MODE);
|
||||
|
||||
editor.toolbar.settings.close();
|
||||
|
||||
};
|
||||
|
||||
settings.isFeedModeActivated = function () {
|
||||
|
||||
var currentBlock = editor.content.currentNode;
|
||||
|
||||
if (currentBlock) {
|
||||
|
||||
return currentBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
settings.makeAnchorInput = function () {
|
||||
|
||||
var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),
|
||||
hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),
|
||||
anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });
|
||||
|
||||
editor.listeners.add(anchor, 'keydown', editor.anchors.keyDownOnAnchorInput );
|
||||
editor.listeners.add(anchor, 'keyup', editor.anchors.keyUpOnAnchorInput );
|
||||
editor.listeners.add(anchor, 'input', editor.anchors.anchorChanged );
|
||||
editor.listeners.add(anchor, 'blur', editor.anchors.anchorChanged );
|
||||
|
||||
anchorWrapper.appendChild(hash);
|
||||
anchorWrapper.appendChild(anchor);
|
||||
|
||||
editor.anchors.input = anchor;
|
||||
|
||||
return anchorWrapper;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Here we will draw buttons and add listeners to components
|
||||
*/
|
||||
|
|
|
@ -46,6 +46,8 @@ module.exports = (function (toolbox) {
|
|||
/** toolbox state */
|
||||
editor.toolbar.toolbox.opened = false;
|
||||
|
||||
editor.toolbar.current = null;
|
||||
|
||||
};
|
||||
|
||||
toolbox.leaf = function () {
|
||||
|
@ -75,21 +77,14 @@ module.exports = (function (toolbox) {
|
|||
|
||||
} else {
|
||||
|
||||
nextToolIndex = tools.indexOf(currentTool) + 1;
|
||||
nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;
|
||||
visibleTool = tools[nextToolIndex];
|
||||
|
||||
while (!editor.tools[visibleTool].displayInToolbox) {
|
||||
|
||||
nextToolIndex++;
|
||||
nextToolIndex = (nextToolIndex + 1) % tools.length;
|
||||
visibleTool = tools[nextToolIndex];
|
||||
|
||||
if ( nextToolIndex == tools.length ) {
|
||||
|
||||
nextToolIndex = 0;
|
||||
visibleTool = tools[nextToolIndex];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,14 +2,17 @@
|
|||
*
|
||||
* Codex.Editor Transport Module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
* @copyright 2017 Codex-Team
|
||||
* @version 1.2.0
|
||||
*/
|
||||
|
||||
module.exports = (function (transport) {
|
||||
|
||||
let editor = codex.editor;
|
||||
|
||||
/**
|
||||
* @type {null} | {DOMElement} input - keeps input element in memory
|
||||
*/
|
||||
transport.input = null;
|
||||
|
||||
/**
|
||||
|
@ -17,13 +20,14 @@ module.exports = (function (transport) {
|
|||
*/
|
||||
transport.arguments = null;
|
||||
|
||||
/**
|
||||
* Prepares input element where will be files
|
||||
*/
|
||||
transport.prepare = function () {
|
||||
|
||||
var input = document.createElement('INPUT');
|
||||
let input = editor.draw.node( 'INPUT', '', { type : 'file' } );
|
||||
|
||||
input.type = 'file';
|
||||
editor.listeners.add(input, 'change', editor.transport.fileSelected);
|
||||
|
||||
editor.transport.input = input;
|
||||
|
||||
};
|
||||
|
@ -32,10 +36,10 @@ module.exports = (function (transport) {
|
|||
transport.clearInput = function () {
|
||||
|
||||
/** Remove old input */
|
||||
this.input = null;
|
||||
transport.input = null;
|
||||
|
||||
/** Prepare new one */
|
||||
this.prepare();
|
||||
transport.prepare();
|
||||
|
||||
};
|
||||
|
||||
|
@ -46,65 +50,67 @@ module.exports = (function (transport) {
|
|||
transport.fileSelected = function () {
|
||||
|
||||
var input = this,
|
||||
i,
|
||||
files = input.files,
|
||||
formdData = new FormData();
|
||||
formData = new FormData();
|
||||
|
||||
formdData.append('files', files[0], files[0].name);
|
||||
if (editor.transport.arguments.multiple === false) {
|
||||
|
||||
editor.transport.ajax({
|
||||
data : formdData,
|
||||
formData.append('files', files[0], files[0].name);
|
||||
|
||||
} else {
|
||||
|
||||
for ( i = 0; i < files.length; i++) {
|
||||
|
||||
formData.append('files[]', files[i], files[i].name);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
editor.core.ajax({
|
||||
type : 'POST',
|
||||
data : formData,
|
||||
url : editor.transport.arguments.url,
|
||||
beforeSend : editor.transport.arguments.beforeSend,
|
||||
success : editor.transport.arguments.success,
|
||||
error : editor.transport.arguments.error
|
||||
});
|
||||
|
||||
/** Clear input */
|
||||
transport.clearInput();
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Use plugin callbacks
|
||||
* @protected
|
||||
*
|
||||
* @param {Object} args - can have :
|
||||
* @param {String} args.url - fetch URL
|
||||
* @param {Function} args.beforeSend - function calls before sending ajax
|
||||
* @param {Function} args.success - success callback
|
||||
* @param {Function} args.error - on error handler
|
||||
* @param {Boolean} args.multiple - allow select several files
|
||||
* @param {String} args.accept - adds accept attribute
|
||||
*/
|
||||
transport.selectAndUpload = function (args) {
|
||||
|
||||
this.arguments = args;
|
||||
this.input.click();
|
||||
transport.arguments = args;
|
||||
|
||||
};
|
||||
if ( args.multiple === true) {
|
||||
|
||||
/**
|
||||
* Ajax requests module
|
||||
* @todo use core.ajax
|
||||
*/
|
||||
transport.ajax = function (params) {
|
||||
transport.input.setAttribute('multiple', 'multiple');
|
||||
|
||||
var xhr = new XMLHttpRequest(),
|
||||
beforeSend = typeof params.beforeSend == 'function' ? params.beforeSend : function () {},
|
||||
success = typeof params.success == 'function' ? params.success : function () {},
|
||||
error = typeof params.error == 'function' ? params.error : function () {};
|
||||
}
|
||||
|
||||
beforeSend();
|
||||
if ( args.accept ) {
|
||||
|
||||
xhr.open('POST', editor.settings.uploadImagesUrl, true);
|
||||
transport.input.setAttribute('accept', args.accept);
|
||||
|
||||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
}
|
||||
|
||||
xhr.onload = function () {
|
||||
|
||||
if (xhr.status === 200) {
|
||||
|
||||
success(xhr.responseText);
|
||||
|
||||
} else {
|
||||
|
||||
editor.core.log('request error: %o', xhr);
|
||||
error();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
xhr.send(params.data);
|
||||
this.clearInput();
|
||||
transport.input.click();
|
||||
|
||||
};
|
||||
|
||||
|
|
233
modules/ui.js
233
modules/ui.js
|
@ -2,7 +2,7 @@
|
|||
* Codex Editor UI module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.1
|
||||
* @version 1.2.0
|
||||
*/
|
||||
|
||||
module.exports = (function (ui) {
|
||||
|
@ -34,16 +34,6 @@ module.exports = (function (ui) {
|
|||
*/
|
||||
BLOCK_HIGHLIGHTED : 'ce-block--focused',
|
||||
|
||||
/**
|
||||
* @const {String} - highlights covered blocks
|
||||
*/
|
||||
BLOCK_IN_FEED_MODE : 'ce-block--feed-mode',
|
||||
|
||||
/**
|
||||
* @const {String} - Block with anchor
|
||||
*/
|
||||
BLOCK_WITH_ANCHOR : 'ce-block--anchor',
|
||||
|
||||
/**
|
||||
* @const {String} - for all default settings
|
||||
*/
|
||||
|
@ -56,92 +46,56 @@ module.exports = (function (ui) {
|
|||
*
|
||||
* Making main interface
|
||||
*/
|
||||
ui.make = function () {
|
||||
ui.prepare = function () {
|
||||
|
||||
var wrapper,
|
||||
toolbar,
|
||||
toolbarContent,
|
||||
redactor,
|
||||
blockButtons,
|
||||
blockSettings,
|
||||
showSettingsButton,
|
||||
showTrashButton,
|
||||
toolbox,
|
||||
plusButton;
|
||||
return new Promise(function (resolve) {
|
||||
|
||||
/** Make editor wrapper */
|
||||
wrapper = editor.draw.wrapper();
|
||||
let wrapper = editor.draw.wrapper(),
|
||||
redactor = editor.draw.redactor(),
|
||||
toolbar = makeToolBar_();
|
||||
|
||||
/** Append editor wrapper after initial textarea */
|
||||
editor.core.insertAfter(editor.nodes.textarea, wrapper);
|
||||
wrapper.appendChild(toolbar);
|
||||
wrapper.appendChild(redactor);
|
||||
|
||||
/** Append block with notifications to the document */
|
||||
editor.notifications.createHolder();
|
||||
/** Save created ui-elements to static nodes state */
|
||||
editor.nodes.wrapper = wrapper;
|
||||
editor.nodes.redactor = redactor;
|
||||
|
||||
/** Make toolbar and content-editable redactor */
|
||||
toolbar = editor.draw.toolbar();
|
||||
toolbarContent = editor.draw.toolbarContent();
|
||||
plusButton = editor.draw.plusButton();
|
||||
showSettingsButton = editor.draw.settingsButton();
|
||||
showTrashButton = editor.toolbar.settings.makeRemoveBlockButton();
|
||||
blockSettings = editor.draw.blockSettings();
|
||||
blockButtons = editor.draw.blockButtons();
|
||||
toolbox = editor.draw.toolbox();
|
||||
redactor = editor.draw.redactor();
|
||||
/** Append editor wrapper with redactor zone after initial textarea */
|
||||
editor.core.insertAfter(editor.nodes.textarea, wrapper);
|
||||
|
||||
/** settings */
|
||||
var defaultSettings = editor.draw.defaultSettings(),
|
||||
pluginSettings = editor.draw.pluginsSettings();
|
||||
resolve();
|
||||
|
||||
/** Add default and plugins settings */
|
||||
blockSettings.appendChild(pluginSettings);
|
||||
blockSettings.appendChild(defaultSettings);
|
||||
})
|
||||
|
||||
/** Make blocks buttons
|
||||
* This block contains settings button and remove block button
|
||||
*/
|
||||
blockButtons.appendChild(showSettingsButton);
|
||||
blockButtons.appendChild(showTrashButton);
|
||||
blockButtons.appendChild(blockSettings);
|
||||
|
||||
/** Append plus button */
|
||||
toolbarContent.appendChild(plusButton);
|
||||
|
||||
/** Appending toolbar tools */
|
||||
toolbarContent.appendChild(toolbox);
|
||||
|
||||
/** Appending first-level block buttons */
|
||||
toolbar.appendChild(blockButtons);
|
||||
|
||||
/** Append toolbarContent to toolbar */
|
||||
toolbar.appendChild(toolbarContent);
|
||||
|
||||
wrapper.appendChild(toolbar);
|
||||
|
||||
wrapper.appendChild(redactor);
|
||||
|
||||
/** Save created ui-elements to static nodes state */
|
||||
editor.nodes.wrapper = wrapper;
|
||||
editor.nodes.toolbar = toolbar;
|
||||
editor.nodes.plusButton = plusButton;
|
||||
editor.nodes.toolbox = toolbox;
|
||||
editor.nodes.blockSettings = blockSettings;
|
||||
editor.nodes.pluginSettings = pluginSettings;
|
||||
editor.nodes.defaultSettings = defaultSettings;
|
||||
editor.nodes.showSettingsButton = showSettingsButton;
|
||||
editor.nodes.showTrashButton = showTrashButton;
|
||||
|
||||
editor.nodes.redactor = redactor;
|
||||
/** Add toolbox tools */
|
||||
.then(addTools_)
|
||||
|
||||
/** Make container for inline toolbar */
|
||||
editor.ui.makeInlineToolbar();
|
||||
.then(makeInlineToolbar_)
|
||||
|
||||
/** fill in default settings */
|
||||
editor.toolbar.settings.addDefaultSettings();
|
||||
/** Add inline toolbar tools */
|
||||
.then(addInlineToolbarTools_)
|
||||
|
||||
/** Draw wrapper for notifications */
|
||||
.then(makeNotificationHolder_)
|
||||
|
||||
/** Add eventlisteners to redactor elements */
|
||||
.then(bindEvents_)
|
||||
|
||||
.catch( function () {
|
||||
|
||||
editor.core.log("Can't draw editor interface");
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
ui.makeInlineToolbar = function () {
|
||||
/**
|
||||
* @private
|
||||
* Draws inline toolbar zone
|
||||
*/
|
||||
var makeInlineToolbar_ = function () {
|
||||
|
||||
var container = editor.draw.inlineToolbar();
|
||||
|
||||
|
@ -162,11 +116,90 @@ module.exports = (function (ui) {
|
|||
|
||||
};
|
||||
|
||||
var makeToolBar_ = function () {
|
||||
|
||||
let toolbar = editor.draw.toolbar(),
|
||||
blockButtons = makeToolbarSettings_(),
|
||||
toolbarContent = makeToolbarContent_();
|
||||
|
||||
/** Appending first-level block buttons */
|
||||
toolbar.appendChild(blockButtons);
|
||||
|
||||
/** Append toolbarContent to toolbar */
|
||||
toolbar.appendChild(toolbarContent);
|
||||
|
||||
/** Make toolbar global */
|
||||
editor.nodes.toolbar = toolbar;
|
||||
|
||||
return toolbar;
|
||||
|
||||
};
|
||||
|
||||
var makeToolbarContent_ = function () {
|
||||
|
||||
let toolbarContent = editor.draw.toolbarContent(),
|
||||
toolbox = editor.draw.toolbox(),
|
||||
plusButton = editor.draw.plusButton();
|
||||
|
||||
/** Append plus button */
|
||||
toolbarContent.appendChild(plusButton);
|
||||
|
||||
/** Appending toolbar tools */
|
||||
toolbarContent.appendChild(toolbox);
|
||||
|
||||
/** Make Toolbox and plusButton global */
|
||||
editor.nodes.toolbox = toolbox;
|
||||
editor.nodes.plusButton = plusButton;
|
||||
|
||||
return toolbarContent;
|
||||
|
||||
};
|
||||
|
||||
var makeToolbarSettings_ = function () {
|
||||
|
||||
let blockSettings = editor.draw.blockSettings(),
|
||||
blockButtons = editor.draw.blockButtons(),
|
||||
defaultSettings = editor.draw.defaultSettings(),
|
||||
showSettingsButton = editor.draw.settingsButton(),
|
||||
showTrashButton = editor.toolbar.settings.makeRemoveBlockButton(),
|
||||
pluginSettings = editor.draw.pluginsSettings();
|
||||
|
||||
/** Add default and plugins settings */
|
||||
blockSettings.appendChild(pluginSettings);
|
||||
blockSettings.appendChild(defaultSettings);
|
||||
|
||||
/**
|
||||
* Make blocks buttons
|
||||
* This block contains settings button and remove block button
|
||||
*/
|
||||
blockButtons.appendChild(showSettingsButton);
|
||||
blockButtons.appendChild(showTrashButton);
|
||||
blockButtons.appendChild(blockSettings);
|
||||
|
||||
/** Make BlockSettings, PluginSettings, DefaultSettings global */
|
||||
editor.nodes.blockSettings = blockSettings;
|
||||
editor.nodes.pluginSettings = pluginSettings;
|
||||
editor.nodes.defaultSettings = defaultSettings;
|
||||
editor.nodes.showSettingsButton = showSettingsButton;
|
||||
editor.nodes.showTrashButton = showTrashButton;
|
||||
|
||||
return blockButtons;
|
||||
|
||||
};
|
||||
|
||||
/** Draw notifications holder */
|
||||
var makeNotificationHolder_ = function () {
|
||||
|
||||
/** Append block with notifications to the document */
|
||||
editor.nodes.notifications = editor.notifications.createHolder();
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Append tools passed in editor.tools
|
||||
*/
|
||||
ui.addTools = function () {
|
||||
var addTools_ = function () {
|
||||
|
||||
var tool,
|
||||
toolName,
|
||||
|
@ -178,7 +211,7 @@ module.exports = (function (ui) {
|
|||
|
||||
editor.tools[toolName] = tool;
|
||||
|
||||
if (!tool.iconClassname) {
|
||||
if (!tool.iconClassname && tool.displayInToolbox) {
|
||||
|
||||
editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);
|
||||
continue;
|
||||
|
@ -209,15 +242,9 @@ module.exports = (function (ui) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add inline toolbar tools
|
||||
*/
|
||||
editor.ui.addInlineToolbarTools();
|
||||
|
||||
|
||||
};
|
||||
|
||||
ui.addInlineToolbarTools = function () {
|
||||
var addInlineToolbarTools_ = function () {
|
||||
|
||||
var tools = {
|
||||
|
||||
|
@ -265,7 +292,7 @@ module.exports = (function (ui) {
|
|||
* @private
|
||||
* Bind editor UI events
|
||||
*/
|
||||
ui.bindEvents = function () {
|
||||
var bindEvents_ = function () {
|
||||
|
||||
editor.core.log('ui.bindEvents fired', 'info');
|
||||
|
||||
|
@ -297,12 +324,6 @@ module.exports = (function (ui) {
|
|||
*/
|
||||
editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );
|
||||
|
||||
/**
|
||||
* @deprecated ( but now in use for syncronization );
|
||||
* Any redactor changes: keyboard input, mouse cut/paste, drag-n-drop text
|
||||
*/
|
||||
// editor.nodes.redactor.addEventListener('input', editor.callback.redactorInputEvent, false );
|
||||
|
||||
/** Bind click listeners on toolbar buttons */
|
||||
for (var button in editor.nodes.toolbarButtons) {
|
||||
|
||||
|
@ -351,8 +372,20 @@ module.exports = (function (ui) {
|
|||
|
||||
var redactor = editor.nodes.redactor;
|
||||
|
||||
editor.state.inputs = [];
|
||||
|
||||
/** Save all inputs in global variable state */
|
||||
editor.state.inputs = redactor.querySelectorAll('[contenteditable], input');
|
||||
var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');
|
||||
|
||||
Array.prototype.map.call(inputs, function (current) {
|
||||
|
||||
if (!current.type || current.type == 'text' || current.type == 'textarea') {
|
||||
|
||||
editor.state.inputs.push(current);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
.ce-code {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
border: 1px solid #ebeef3;
|
||||
border-radius: 3px;
|
||||
background: #fdfdff !important;
|
||||
|
@ -13,6 +15,9 @@
|
|||
line-height: 1.5em;
|
||||
color: #325179;
|
||||
font-size: .8em;
|
||||
|
||||
resize: vertical;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,17 +14,32 @@ var code = (function(code_plugin) {
|
|||
*/
|
||||
var make_ = function (data) {
|
||||
|
||||
var tag = codex.editor.draw.node('CODE', [baseClass], {});
|
||||
var tag = codex.editor.draw.node('TEXTAREA', [baseClass], {});
|
||||
|
||||
if (data && data.text) {
|
||||
tag.innerHTML = data.text;
|
||||
tag.value = data.text;
|
||||
}
|
||||
|
||||
tag.contentEditable = true;
|
||||
|
||||
return tag;
|
||||
};
|
||||
|
||||
/**
|
||||
* Escapes HTML chars
|
||||
*
|
||||
* @param {string} input
|
||||
* @return {string} — escaped string
|
||||
*/
|
||||
var escapeHTML_ = function (input) {
|
||||
|
||||
var div = document.createElement('DIV'),
|
||||
text = document.createTextNode(input);
|
||||
|
||||
div.appendChild(text);
|
||||
|
||||
return div.innerHTML;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to render HTML block from JSON
|
||||
*/
|
||||
|
@ -38,9 +53,12 @@ var code = (function(code_plugin) {
|
|||
*/
|
||||
code_plugin.save = function (blockContent) {
|
||||
|
||||
var data = {
|
||||
text : blockContent.innerHTML
|
||||
};
|
||||
var escaped = escapeHTML_(blockContent.value),
|
||||
data = {
|
||||
text : escaped
|
||||
};
|
||||
|
||||
|
||||
return data;
|
||||
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ var embed = function(embed_plugin){
|
|||
var methods = {
|
||||
|
||||
addInternal: function (content) {
|
||||
codex.editor.content.switchBlock(codex.editor.content.currentNode, content, 'video_extended');
|
||||
codex.editor.content.switchBlock(codex.editor.content.currentNode, content);
|
||||
|
||||
var blockContent = codex.editor.content.currentNode.childNodes[0];
|
||||
blockContent.classList.add('embed__loader');
|
||||
|
@ -48,76 +48,11 @@ var embed = function(embed_plugin){
|
|||
};
|
||||
|
||||
var services = {
|
||||
vimeo: {
|
||||
regex: /(?:http[s]?:\/\/)?(?:www.)?vimeo\.co(?:.+\/([^\/]\d+)(?:#t=[\d]+)?s?$)/,
|
||||
html: "<iframe src=\"https://player.vimeo.com/video/<%= remote_id %>?title=0&byline=0\" style=\"width:100%;\" height=\"320\" frameborder=\"0\"></iframe>",
|
||||
height: 320,
|
||||
width: 580
|
||||
|
||||
},
|
||||
youtube: {
|
||||
regex: /^.*(?:(?:youtu\.be\/)|(?:youtube\.com)\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*)(?:[\?\&]t\=(\d*)|)/,
|
||||
html: "<iframe src=\"https://www.youtube.com/embed/<%= remote_id %>\" style=\"width:100%;\" height=\"320\" frameborder=\"0\" allowfullscreen></iframe>",
|
||||
height: 320,
|
||||
width: 580
|
||||
},
|
||||
vk : {
|
||||
regex: /^https?.+vk?.com\/feed\?w=wall\d+_\d+/,
|
||||
html: "<iframe src=\"https://tjournal.ru/proxy/video/<%= remote_id %>?rel=0&showinfo=0&enablejsapi=1&autoplay=1\" width=\"580\" height=\"320\" frameborder=\"0\" allowfullscreen></iframe>"
|
||||
},
|
||||
coub: {
|
||||
regex: /https?:\/\/coub\.com\/view\/([^\/\?\&]+)/,
|
||||
html: "<iframe src=\"//coub.com/embed/<%= remote_id %>\" style=\"width:100%;\" height=\"320\" frameborder=\"0\" allowfullscreen></iframe>",
|
||||
height: 320,
|
||||
width: 580
|
||||
},
|
||||
vine: {
|
||||
regex: /https?:\/\/vine\.co\/v\/([^\/\?\&]+)/,
|
||||
html: "<iframe src=\"https://vine.co/v/<%= remote_id %>/embed/simple/\" style=\"width:100%;\" height=\"320\" frameborder=\"0\" allowfullscreen></iframe>",
|
||||
height: 320,
|
||||
width: 580
|
||||
},
|
||||
imgur: {
|
||||
regex: /https?:\/\/(?:i\.)?imgur\.com.*\/([a-zA-Z0-9]+)(?:\.gifv)?/,
|
||||
html: "<iframe allowfullscreen=\"true\" scrolling=\"no\" src=\"http://imgur.com/<%= remote_id %>/embed\" id=\"imgur-embed-iframe-pub-<%= remote_id %>\" class=\"imgur-embed-iframe-pub\" style=\"height: 500px; width: 100%; border: 1px solid #000\"></iframe>",
|
||||
height: 500,
|
||||
width: 540
|
||||
},
|
||||
gfycat: {
|
||||
regex: /https?:\/\/gfycat\.com(?:\/detail)?\/([a-zA-Z]+)/,
|
||||
html: "<iframe src='https://gfycat.com/ifr/<%= remote_id %>' frameborder='0' scrolling='no' style=\"width:100%;\" height='436' allowfullscreen ></iframe>",
|
||||
height: 436,
|
||||
width: 580
|
||||
},
|
||||
'twitch-channel': {
|
||||
regex: /https?:\/\/www.twitch.tv\/([^\/\?\&]*)/,
|
||||
html: "<iframe src=\"https://player.twitch.tv/?channel=<%= remote_id %>\" frameborder=\"0\" allowfullscreen=\"true\" scrolling=\"no\" height=\"366\" style=\"width:100%;\"></iframe>",
|
||||
height: 366,
|
||||
width: 600
|
||||
},
|
||||
'twitch-video': {
|
||||
regex: /https?:\/\/www.twitch.tv\/(?:[^\/\?\&]*\/v|videos)\/([0-9]*)/,
|
||||
html: "<iframe src=\"https://player.twitch.tv/?video=v<%= remote_id %>\" frameborder=\"0\" allowfullscreen=\"true\" scrolling=\"no\" height=\"366\" style=\"width:100%;\"></iframe>",
|
||||
height: 366,
|
||||
width: 600
|
||||
},
|
||||
'yandex-music-album': {
|
||||
regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)/,
|
||||
html: "<iframe frameborder=\"0\" style=\"border:none;width:540px;height:400px;\" style=\"width:100%;\" height=\"400\" src=\"https://music.yandex.ru/iframe/#album/<%= remote_id %>/\"></iframe>",
|
||||
height: 400,
|
||||
width: 540
|
||||
},
|
||||
'yandex-music-track': {
|
||||
regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)\/track\/([0-9]*)/,
|
||||
html: "<iframe frameborder=\"0\" style=\"border:none;width:540px;height:100px;\" style=\"width:100%;\" height=\"100\" src=\"https://music.yandex.ru/iframe/#track/<%= remote_id %>/\"></iframe>",
|
||||
height: 100,
|
||||
width: 540
|
||||
},
|
||||
'yandex-music-playlist': {
|
||||
regex: /https?:\/\/music.yandex.ru\/users\/([^\/\?\&]*)\/playlists\/([0-9]*)/,
|
||||
html: "<iframe frameborder=\"0\" style=\"border:none;width:540px;height:400px;\" width=\"540\" height=\"400\" src=\"https://music.yandex.ru/iframe/#playlist/<%= remote_id %>/show/cover/description/\"></iframe>",
|
||||
height: 400,
|
||||
width: 540
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ var header = (function(header_plugin) {
|
|||
new_header.setAttribute('data-placeholder', 'Заголовок');
|
||||
new_header.dataset.headerData = type;
|
||||
|
||||
codex.editor.content.switchBlock(old_header, new_header, 'heading_styled');
|
||||
codex.editor.content.switchBlock(old_header, new_header);
|
||||
|
||||
/** Close settings after replacing */
|
||||
codex.editor.toolbar.settings.close();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Image plugin for codex-editor
|
||||
* @author CodeX Team <team@ifmo.su>
|
||||
*
|
||||
* @version 1.2.0
|
||||
* @version 1.3.0
|
||||
*/
|
||||
var image = (function(image_plugin) {
|
||||
|
||||
|
@ -220,15 +220,19 @@ var image = (function(image_plugin) {
|
|||
*/
|
||||
var uploadButtonClicked_ = function(event) {
|
||||
|
||||
var beforeSend = uploadingCallbacks_.ByClick.beforeSend,
|
||||
var url = image_plugin.config.uploadImage,
|
||||
beforeSend = uploadingCallbacks_.ByClick.beforeSend,
|
||||
success = uploadingCallbacks_.ByClick.success,
|
||||
error = uploadingCallbacks_.ByClick.error;
|
||||
|
||||
/** Define callbacks */
|
||||
codex.editor.transport.selectAndUpload({
|
||||
beforeSend: beforeSend,
|
||||
success: success,
|
||||
error: error
|
||||
url : url,
|
||||
multiple : false,
|
||||
accept : 'image/*',
|
||||
beforeSend : beforeSend,
|
||||
success : success,
|
||||
error : error
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -272,11 +276,7 @@ var image = (function(image_plugin) {
|
|||
/**
|
||||
* Save settings in dataset
|
||||
*/
|
||||
if (img.classList.contains(elementClasses_.imageWrapperBordered)) {
|
||||
wrapper.dataset.bordered = true;
|
||||
} else {
|
||||
wrapper.dataset.bordered = false;
|
||||
}
|
||||
wrapper.dataset.bordered = img.classList.contains(elementClasses_.imageWrapperBordered);
|
||||
|
||||
setTimeout(function() {
|
||||
codex.editor.toolbar.settings.close();
|
||||
|
@ -302,15 +302,7 @@ var image = (function(image_plugin) {
|
|||
|
||||
clickedSettingsItem.classList.toggle(elementClasses_.toggled);
|
||||
|
||||
if (img.classList.contains(elementClasses_.uploadedImage.stretched)) {
|
||||
|
||||
wrapper.dataset.stretched = true;
|
||||
|
||||
} else {
|
||||
|
||||
wrapper.dataset.stretched = false;
|
||||
|
||||
}
|
||||
wrapper.dataset.stretched = img.classList.contains(elementClasses_.uploadedImage.stretched);
|
||||
|
||||
setTimeout(function() {
|
||||
codex.editor.toolbar.settings.close();
|
||||
|
@ -369,7 +361,7 @@ var image = (function(image_plugin) {
|
|||
|
||||
var newImage = make_(data);
|
||||
|
||||
codex.editor.content.switchBlock(image.holder, newImage, 'image_extended');
|
||||
codex.editor.content.switchBlock(image.holder, newImage);
|
||||
newImage.classList.add(elementClasses_.imagePreview);
|
||||
|
||||
/**
|
||||
|
@ -414,7 +406,7 @@ var image = (function(image_plugin) {
|
|||
var oldHolder = image.holder;
|
||||
var form = ui_.makeForm();
|
||||
|
||||
codex.editor.content.switchBlock(oldHolder, form, 'image_extended');
|
||||
codex.editor.content.switchBlock(oldHolder, form);
|
||||
|
||||
}
|
||||
},
|
||||
|
@ -428,9 +420,7 @@ var image = (function(image_plugin) {
|
|||
*/
|
||||
uploadImageFromUrl : function(path) {
|
||||
|
||||
var ajaxUrl = image_plugin.config.uploadUrl,
|
||||
file,
|
||||
image,
|
||||
var image,
|
||||
current = codex.editor.content.currentNode,
|
||||
beforeSend,
|
||||
success_callback;
|
||||
|
@ -479,13 +469,13 @@ var image = (function(image_plugin) {
|
|||
|
||||
var img = image.querySelector('img');
|
||||
|
||||
codex.editor.content.switchBlock(codex.editor.content.currentNode, image, 'image_extended');
|
||||
codex.editor.content.switchBlock(codex.editor.content.currentNode, image);
|
||||
|
||||
};
|
||||
|
||||
/** Preparing data for XMLHTTP */
|
||||
var data = {
|
||||
url: image_plugin.config.uploadUrl,
|
||||
url: image_plugin.config.uploadFromUrl,
|
||||
type: "POST",
|
||||
data : {
|
||||
url: path
|
||||
|
|
|
@ -8,7 +8,7 @@ var instagram = (function(instagram_plugin) {
|
|||
|
||||
render : function(content) {
|
||||
|
||||
codex.editor.content.switchBlock(codex.editor.content.currentNode, content, 'instagram');
|
||||
codex.editor.content.switchBlock(codex.editor.content.currentNode, content);
|
||||
|
||||
setTimeout(function() {
|
||||
window.instgrm.Embeds.process();
|
||||
|
@ -144,7 +144,7 @@ var instagram = (function(instagram_plugin) {
|
|||
instagram_plugin.pastePatterns = [
|
||||
{
|
||||
type: 'instagram',
|
||||
regex: /http?.+instagram.com\/p\/([a-zA-Z0-9]*)/,
|
||||
regex: /http?.+instagram.com\/p\/([a-zA-Z0-9]*)\S*/,
|
||||
callback: instagram_plugin.urlPastedCallback
|
||||
}
|
||||
];
|
||||
|
|
|
@ -74,7 +74,7 @@ var list = (function(list_plugin) {
|
|||
newEditable.innerHTML = oldEditable.innerHTML;
|
||||
newEditable.classList.add(elementClasses_.pluginWrapper);
|
||||
|
||||
codex.editor.content.switchBlock(currentBlock, newEditable, 'list');
|
||||
codex.editor.content.switchBlock(currentBlock, newEditable);
|
||||
},
|
||||
keyDown: function (e) {
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ var quote = (function(quote_plugin) {
|
|||
/* make Author contentEditable */
|
||||
author.contentEditable = 'true';
|
||||
|
||||
author.textContent = data.cite || '';
|
||||
author.innerHTML = data.cite || '';
|
||||
|
||||
/* Appending created components */
|
||||
wrapper.dataset.quoteStyle = 'withCaption';
|
||||
|
@ -200,11 +200,11 @@ var quote = (function(quote_plugin) {
|
|||
|
||||
/* make author block contentEditable */
|
||||
author.contentEditable = 'true';
|
||||
author.textContent = data.cite || '';
|
||||
author.innerHTML = data.cite || '';
|
||||
|
||||
/* Author's position and job */
|
||||
job.contentEditable = 'true';
|
||||
job.textContent = data.caption || '';
|
||||
job.innerHTML = data.caption || '';
|
||||
|
||||
var authorsWrapper = ui_.makeBlock('DIV', [elementClasses_.withPhoto.authorHolder]);
|
||||
authorsWrapper.appendChild(author);
|
||||
|
@ -234,20 +234,34 @@ var quote = (function(quote_plugin) {
|
|||
quote ;
|
||||
|
||||
/** Simple quote text placed in Blockquote tag*/
|
||||
if ( currentNode.dataset.quoteStyle == 'simple' )
|
||||
if ( currentNode.dataset.quoteStyle == 'simple' ){
|
||||
|
||||
quote = currentNode.innerHTML || '';
|
||||
else
|
||||
|
||||
} else {
|
||||
|
||||
quote = currentNode.querySelector('.' + elementClasses_.quoteText).innerHTML;
|
||||
|
||||
if (job)
|
||||
job = job.textContent || '';
|
||||
}
|
||||
|
||||
if (author)
|
||||
author = author.textContent || '';
|
||||
if (job){
|
||||
|
||||
job = job.innerHTML || '';
|
||||
|
||||
}
|
||||
|
||||
if (author){
|
||||
|
||||
author = author.innerHTML || '';
|
||||
|
||||
}
|
||||
|
||||
if (photo){
|
||||
|
||||
if (photo)
|
||||
photo = photo.dataset.bigUrl;
|
||||
|
||||
}
|
||||
|
||||
var data = {
|
||||
style : currentNode.dataset.quoteStyle,
|
||||
text : quote,
|
||||
|
|
7
plugins/raw/raw-icon-black.svg
Normal file
7
plugins/raw/raw-icon-black.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<svg class="raw-plugin-icon-svg" width="19px" height="6px" viewBox="0 0 19 6" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>RAW</title>
|
||||
<defs></defs>
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M3.17724609,0.00146484375 C4.53955078,0.00146484375 5.31298828,0.766113281 5.31298828,1.93505859 C5.31298828,2.84033203 4.75048828,3.42480469 4.22753906,3.62255859 L5.43164062,6 L4.01660156,6 L2.97509766,3.81591797 L1.98632812,3.81591797 L1.98632812,6 L0.733886719,6 L0.733886719,0.00146484375 L3.17724609,0.00146484375 Z M1.98632812,2.84912109 L2.97509766,2.84912109 C3.59912109,2.84912109 4.00341797,2.55029297 4.00341797,1.95263672 C4.00341797,1.34179688 3.5859375,1.01660156 2.99267578,1.01660156 L1.98632812,1.01660156 L1.98632812,2.84912109 Z M6.85976562,6 L5.58095703,6 L7.56728515,0.00146484375 L9.0790039,0.00146484375 L11.056543,6 L9.70302734,6 L9.26357421,4.54541016 L7.30800781,4.54541016 L6.85976562,6 Z M8.31874999,1.22753906 L8.26162109,1.22753906 L7.55849609,3.57421875 L9.01748046,3.57421875 L8.31874999,1.22753906 Z M13.7107422,6 L12.5374023,6 L10.9641601,0.00146484375 L12.3308594,0.00146484375 L13.187793,4.20263672 L13.2493164,4.20263672 L14.2820312,0.00146484375 L15.3542969,0.00146484375 L16.3914062,4.20263672 L16.4529297,4.20263672 L17.3054687,0.00146484375 L18.6677734,0.00146484375 L17.0989258,6 L15.9255859,6 L14.8445312,2.00537109 L14.7961914,2.00537109 L13.7107422,6 Z" id="RAW" fill="#000000"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
7
plugins/raw/raw-icon-white.svg
Normal file
7
plugins/raw/raw-icon-white.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<svg class="raw-plugin-icon-svg" width="19px" height="6px" viewBox="0 0 19 6" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>RAW</title>
|
||||
<defs></defs>
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M3.17724609,0.00146484375 C4.53955078,0.00146484375 5.31298828,0.766113281 5.31298828,1.93505859 C5.31298828,2.84033203 4.75048828,3.42480469 4.22753906,3.62255859 L5.43164062,6 L4.01660156,6 L2.97509766,3.81591797 L1.98632812,3.81591797 L1.98632812,6 L0.733886719,6 L0.733886719,0.00146484375 L3.17724609,0.00146484375 Z M1.98632812,2.84912109 L2.97509766,2.84912109 C3.59912109,2.84912109 4.00341797,2.55029297 4.00341797,1.95263672 C4.00341797,1.34179688 3.5859375,1.01660156 2.99267578,1.01660156 L1.98632812,1.01660156 L1.98632812,2.84912109 Z M6.85976562,6 L5.58095703,6 L7.56728515,0.00146484375 L9.0790039,0.00146484375 L11.056543,6 L9.70302734,6 L9.26357421,4.54541016 L7.30800781,4.54541016 L6.85976562,6 Z M8.31874999,1.22753906 L8.26162109,1.22753906 L7.55849609,3.57421875 L9.01748046,3.57421875 L8.31874999,1.22753906 Z M13.7107422,6 L12.5374023,6 L10.9641601,0.00146484375 L12.3308594,0.00146484375 L13.187793,4.20263672 L13.2493164,4.20263672 L14.2820312,0.00146484375 L15.3542969,0.00146484375 L16.3914062,4.20263672 L16.4529297,4.20263672 L17.3054687,0.00146484375 L18.6677734,0.00146484375 L17.0989258,6 L15.9255859,6 L14.8445312,2.00537109 L14.7961914,2.00537109 L13.7107422,6 Z" id="RAW" fill="#ffffff"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
36
plugins/raw/raw.css
Normal file
36
plugins/raw/raw.css
Normal file
|
@ -0,0 +1,36 @@
|
|||
.raw-plugin__input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
border: 0;
|
||||
background: #fdfdfd;
|
||||
box-shadow: inset 0 2px 8px rgba(23, 32, 74, 0.06);
|
||||
border-radius: 3px;
|
||||
margin: 1em auto;
|
||||
padding: 1em;
|
||||
box-sizing: border-box;
|
||||
white-space: pre;
|
||||
outline: none;
|
||||
resize: vertical;
|
||||
|
||||
font-family: 'monospace', 'monaco', 'consolas', 'courier';
|
||||
line-height: 1.7em;
|
||||
font-size: 12px;
|
||||
color: #152b48;
|
||||
overflow: auto;
|
||||
letter-spacing: 0.015em;
|
||||
}
|
||||
|
||||
.raw-plugin-icon {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 32px;
|
||||
background: url(raw-icon-black.svg) no-repeat center center;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
li:hover .raw-plugin-icon,
|
||||
.selected .raw-plugin-icon{
|
||||
background: url(raw-icon-white.svg) no-repeat center center;
|
||||
background-size: contain;
|
||||
}
|
51
plugins/raw/raw.js
Normal file
51
plugins/raw/raw.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Plugin for CodeX.Editor
|
||||
* Implements RAW-data block
|
||||
*/
|
||||
var rawPlugin = function (plugin) {
|
||||
|
||||
var editor = codex.editor;
|
||||
|
||||
plugin.render = function (data) {
|
||||
|
||||
var input = editor.draw.node('TEXTAREA', 'raw-plugin__input', {});
|
||||
|
||||
input.placeholder = 'Вставьте HTML код';
|
||||
|
||||
if (data && data.raw) {
|
||||
input.value = data.raw;
|
||||
}
|
||||
|
||||
return input;
|
||||
|
||||
};
|
||||
|
||||
plugin.save = function (block) {
|
||||
|
||||
return {
|
||||
raw: block.value
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
plugin.validate = function (data) {
|
||||
|
||||
if (data.raw.trim() === '') {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
plugin.destroy = function () {
|
||||
|
||||
rawPlugin = null;
|
||||
|
||||
};
|
||||
|
||||
return plugin;
|
||||
|
||||
}({});
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue