2016-12-25 15:41:57 +01:00
|
|
|
/**
|
2017-02-12 16:25:20 +01:00
|
|
|
* Codex Editor Paste module
|
2016-12-25 15:41:57 +01:00
|
|
|
*
|
2017-02-12 16:25:20 +01:00
|
|
|
* @author Codex Team
|
2017-02-26 11:22:21 +01:00
|
|
|
* @version 1.1.1
|
2016-12-25 15:41:57 +01:00
|
|
|
*/
|
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
module.exports = function (paste) {
|
|
|
|
|
|
|
|
let editor = codex.editor;
|
|
|
|
|
|
|
|
var patterns = [];
|
|
|
|
|
|
|
|
paste.prepare = function () {
|
|
|
|
|
|
|
|
var tools = editor.tools;
|
|
|
|
|
|
|
|
for (var tool in tools) {
|
2017-02-02 14:58:05 +01:00
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tools[tool].renderOnPastePatterns.map(function (pattern) {
|
|
|
|
|
2017-02-26 11:22:21 +01:00
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
patterns.push(pattern);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
|
|
};
|
2017-02-02 14:58:05 +01:00
|
|
|
|
2016-12-25 15:41:57 +01:00
|
|
|
/**
|
|
|
|
* Saves data
|
|
|
|
* @param event
|
|
|
|
*/
|
2017-02-12 16:25:20 +01:00
|
|
|
paste.pasted = function (event) {
|
2016-12-25 15:41:57 +01:00
|
|
|
|
|
|
|
var clipBoardData = event.clipboardData || window.clipboardData,
|
|
|
|
content = clipBoardData.getData('Text');
|
|
|
|
|
2017-01-26 01:47:19 +01:00
|
|
|
var result = analize(content);
|
2017-01-18 16:12:50 +01:00
|
|
|
|
|
|
|
if (result) {
|
2017-02-12 16:25:20 +01:00
|
|
|
|
2017-01-18 16:12:50 +01:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopImmediatePropagation();
|
2017-02-12 16:25:20 +01:00
|
|
|
|
2017-01-18 16:12:50 +01:00
|
|
|
}
|
2017-02-12 16:25:20 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
|
2017-01-26 00:55:40 +01:00
|
|
|
};
|
2016-12-25 15:41:57 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Analizes pated string and calls necessary method
|
|
|
|
*/
|
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
var analize = function (string) {
|
2016-12-25 15:41:57 +01:00
|
|
|
|
2017-02-02 14:58:05 +01:00
|
|
|
var result = false,
|
|
|
|
content = editor.content.currentNode,
|
|
|
|
plugin = content.dataset.tool;
|
2016-12-25 15:41:57 +01:00
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
patterns.map( function (pattern) {
|
2017-02-02 14:58:05 +01:00
|
|
|
|
2017-02-23 11:32:41 +01:00
|
|
|
var execArray = pattern.regex.exec(string),
|
|
|
|
match = execArray && execArray[0];
|
|
|
|
|
|
|
|
if ( match && match === string.trim()) {
|
2017-02-02 14:58:05 +01:00
|
|
|
|
|
|
|
/** current block is not empty */
|
|
|
|
if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {
|
|
|
|
|
|
|
|
pasteToNewBlock_();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
pattern.callback(string, pattern);
|
2017-01-26 01:47:19 +01:00
|
|
|
result = true;
|
2017-02-12 16:25:20 +01:00
|
|
|
|
2017-01-12 14:56:06 +01:00
|
|
|
}
|
2017-02-12 16:25:20 +01:00
|
|
|
|
2017-01-26 01:47:19 +01:00
|
|
|
});
|
2016-12-25 15:41:57 +01:00
|
|
|
|
2017-01-26 01:47:19 +01:00
|
|
|
return result;
|
2016-12-25 15:41:57 +01:00
|
|
|
|
2017-01-26 01:47:19 +01:00
|
|
|
};
|
2017-01-11 16:48:57 +01:00
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
var pasteToNewBlock_ = function () {
|
2017-02-02 14:58:05 +01:00
|
|
|
|
|
|
|
/** Create new initial block */
|
|
|
|
editor.content.insertBlock({
|
|
|
|
|
|
|
|
type : editor.settings.initialBlockPlugin,
|
|
|
|
block : editor.tools[editor.settings.initialBlockPlugin].render({
|
|
|
|
text : ''
|
|
|
|
})
|
|
|
|
|
2017-02-02 15:13:05 +01:00
|
|
|
}, false);
|
2017-02-02 14:58:05 +01:00
|
|
|
|
|
|
|
};
|
2017-01-26 00:55:40 +01:00
|
|
|
|
2017-04-24 01:26:08 +02:00
|
|
|
/**
|
|
|
|
* This method prevents default behaviour.
|
|
|
|
*
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
paste.blockPasteCallback = function (event) {
|
|
|
|
|
|
|
|
|
|
|
|
if (!needsToHandlePasteEvent(event.target)) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-04-24 02:08:03 +02:00
|
|
|
/** Prevent default behaviour */
|
|
|
|
event.preventDefault();
|
|
|
|
|
2017-04-24 01:26:08 +02:00
|
|
|
/** get html pasted data - dirty data */
|
|
|
|
var htmlData = event.clipboardData.getData('text/html'),
|
|
|
|
plainData = event.clipboardData.getData('text/plain');
|
|
|
|
|
|
|
|
/** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/
|
|
|
|
var paragraphs = editor.draw.node('DIV', '', {}),
|
|
|
|
cleanData,
|
|
|
|
wrappedData;
|
|
|
|
|
|
|
|
/** Create fragment, that we paste to range after proccesing */
|
|
|
|
cleanData = editor.sanitizer.clean(htmlData);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We wrap pasted text with <p> tags to split it logically
|
|
|
|
* @type {string}
|
|
|
|
*/
|
|
|
|
wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData);
|
|
|
|
paragraphs.innerHTML = wrappedData;
|
|
|
|
|
|
|
|
/**
|
2017-04-24 09:23:48 +02:00
|
|
|
* If there only one paragraph, just insert in at the caret location
|
2017-04-24 01:26:08 +02:00
|
|
|
*/
|
|
|
|
if (paragraphs.childNodes.length == 1) {
|
|
|
|
|
2017-04-24 09:23:48 +02:00
|
|
|
emulateUserAgentBehaviour(paragraphs.firstChild);
|
2017-04-24 01:26:08 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
insertPastedParagraphs(paragraphs.childNodes);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if we should handle paste event on block
|
|
|
|
* @param block
|
|
|
|
*
|
|
|
|
* @return {boolean}
|
|
|
|
*/
|
|
|
|
var needsToHandlePasteEvent = function (block) {
|
|
|
|
|
|
|
|
/** If area is input or textarea then allow default behaviour */
|
|
|
|
if ( editor.core.isNativeInput(block) ) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
var editableParent = editor.content.getEditableParent(block);
|
|
|
|
|
|
|
|
/** Allow paste when event target placed in Editable element */
|
|
|
|
if (!editableParent) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2017-04-24 12:49:57 +02:00
|
|
|
/**
|
|
|
|
* Inserts new initial plugin blocks with data in paragraphs
|
|
|
|
*
|
|
|
|
* @param {Array} paragraphs - array of paragraphs (<p></p>) whit content, that should be inserted
|
|
|
|
*/
|
2017-04-24 01:26:08 +02:00
|
|
|
var insertPastedParagraphs = function (paragraphs) {
|
|
|
|
|
2017-04-24 19:34:40 +02:00
|
|
|
var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin,
|
|
|
|
currentNode = editor.content.currentNode;
|
2017-04-24 01:26:08 +02:00
|
|
|
|
|
|
|
|
2017-04-24 18:46:03 +02:00
|
|
|
paragraphs.forEach(function (paragraph) {
|
2017-04-24 01:26:08 +02:00
|
|
|
|
2017-04-24 18:46:03 +02:00
|
|
|
/** Don't allow empty paragraphs */
|
|
|
|
if (editor.core.isBlockEmpty(paragraph)) {
|
|
|
|
|
|
|
|
return;
|
2017-04-24 01:26:08 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
editor.content.insertBlock({
|
|
|
|
type : NEW_BLOCK_TYPE,
|
|
|
|
block : editor.tools[NEW_BLOCK_TYPE].render({
|
|
|
|
text : paragraph.innerHTML
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
editor.caret.inputIndex++;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1);
|
|
|
|
|
|
|
|
|
2017-04-24 19:34:40 +02:00
|
|
|
/**
|
|
|
|
* If there was no data in working node, remove it
|
|
|
|
*/
|
|
|
|
if (editor.core.isBlockEmpty(currentNode)) {
|
|
|
|
|
|
|
|
currentNode.remove();
|
|
|
|
editor.ui.saveInputs();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-24 01:26:08 +02:00
|
|
|
};
|
|
|
|
|
2017-04-24 09:23:48 +02:00
|
|
|
/**
|
|
|
|
* Inserts node content at the caret position
|
2017-04-24 12:49:57 +02:00
|
|
|
*
|
|
|
|
* @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location
|
2017-04-24 09:23:48 +02:00
|
|
|
*/
|
|
|
|
var emulateUserAgentBehaviour = function (node) {
|
|
|
|
|
|
|
|
var newNode;
|
|
|
|
|
|
|
|
if (node.childElementCount) {
|
|
|
|
|
2017-04-24 12:06:50 +02:00
|
|
|
newNode = document.createDocumentFragment();
|
|
|
|
|
|
|
|
node.childNodes.forEach(function (current) {
|
|
|
|
|
2017-04-24 12:49:57 +02:00
|
|
|
if (!editor.core.isDomNode(current) && current.data.trim() === '') {
|
2017-04-24 12:06:50 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
newNode.appendChild(current.cloneNode(true));
|
|
|
|
|
|
|
|
});
|
2017-04-24 09:23:48 +02:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
newNode = document.createTextNode(node.textContent);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
editor.caret.insertNode(newNode);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2017-04-24 01:26:08 +02:00
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
return paste;
|
2017-01-12 14:56:06 +01:00
|
|
|
|
2017-02-12 16:25:20 +01:00
|
|
|
}({});
|