mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-09-03 22:30:51 +08:00
Add paste from word base
This commit is contained in:
parent
eebd28631e
commit
7013be6825
10
package-lock.json
generated
10
package-lock.json
generated
@ -90,6 +90,16 @@
|
|||||||
"@ckeditor/ckeditor5-undo": "^11.0.5"
|
"@ckeditor/ckeditor5-undo": "^11.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@ckeditor/ckeditor5-paste-from-office": {
|
||||||
|
"version": "11.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-11.1.0.tgz",
|
||||||
|
"integrity": "sha512-LcXmJSlr0fzi+hccdyTnHuKh/K9nWV5OiuWqcOpX3IucczSYzGgykG4MUZVlBLv1mkP0AsjJ1oSPGXCkVkgJkg==",
|
||||||
|
"requires": {
|
||||||
|
"@ckeditor/ckeditor5-clipboard": "^12.0.2",
|
||||||
|
"@ckeditor/ckeditor5-core": "^12.3.0",
|
||||||
|
"@ckeditor/ckeditor5-engine": "^14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@ckeditor/ckeditor5-typing": {
|
"@ckeditor/ckeditor5-typing": {
|
||||||
"version": "12.2.0",
|
"version": "12.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-12.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-12.2.0.tgz",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"@ckeditor/ckeditor5-clipboard": "^12.0.2",
|
"@ckeditor/ckeditor5-clipboard": "^12.0.2",
|
||||||
"@ckeditor/ckeditor5-core": "^12.3.0",
|
"@ckeditor/ckeditor5-core": "^12.3.0",
|
||||||
"@ckeditor/ckeditor5-engine": "^14.0.0",
|
"@ckeditor/ckeditor5-engine": "^14.0.0",
|
||||||
|
"@ckeditor/ckeditor5-paste-from-office": "^11.1.0",
|
||||||
"@ckeditor/ckeditor5-ui": "^14.0.0",
|
"@ckeditor/ckeditor5-ui": "^14.0.0",
|
||||||
"@ckeditor/ckeditor5-undo": "^11.0.5",
|
"@ckeditor/ckeditor5-undo": "^11.0.5",
|
||||||
"@ckeditor/ckeditor5-utils": "^14.0.0",
|
"@ckeditor/ckeditor5-utils": "^14.0.0",
|
||||||
|
@ -4,10 +4,11 @@ import Widget from '@ckeditor/ckeditor5-widget/src/widget';
|
|||||||
import MathUI from './mathui';
|
import MathUI from './mathui';
|
||||||
import MathEditing from './mathediting';
|
import MathEditing from './mathediting';
|
||||||
import AutoMath from './automath';
|
import AutoMath from './automath';
|
||||||
|
import MathPasteFromOffice from './mathpastefromoffice';
|
||||||
|
|
||||||
export default class Math extends Plugin {
|
export default class Math extends Plugin {
|
||||||
static get requires() {
|
static get requires() {
|
||||||
return [ MathEditing, MathUI, Widget, AutoMath ];
|
return [ MathEditing, MathUI, Widget, AutoMath, MathPasteFromOffice ];
|
||||||
}
|
}
|
||||||
|
|
||||||
static get pluginName() {
|
static get pluginName() {
|
||||||
|
263
src/mathpastefromoffice.js
Normal file
263
src/mathpastefromoffice.js
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
|
||||||
|
import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
|
||||||
|
import UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';
|
||||||
|
import Matcher from '@ckeditor/ckeditor5-engine/src/view/matcher';
|
||||||
|
// import Element from '@ckeditor/ckeditor5-engine/src/view/element';
|
||||||
|
import { normalizeSpacing, normalizeSpacerunSpans } from '@ckeditor/ckeditor5-paste-from-office/src/filters/space';
|
||||||
|
|
||||||
|
const BULLET_REGEXP = /(<span style=['"]mso-list:((.||\r?\n)*?)Ignore['"]>((.|\r?\n)*?)<\/span>)/g;
|
||||||
|
|
||||||
|
export default class MathPasteFromOffice extends Plugin {
|
||||||
|
static get pluginName() {
|
||||||
|
return 'MathPasteFromOffice';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get requires() {
|
||||||
|
return [ Clipboard ];
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const editor = this.editor;
|
||||||
|
|
||||||
|
editor.plugins.get( 'Clipboard' ).on(
|
||||||
|
'inputTransformation',
|
||||||
|
( evt, data ) => {
|
||||||
|
console.log( 'isTransformedWithPasteFromOffice', data.isTransformedWithPasteFromOffice ); // eslint-disable-line
|
||||||
|
console.log( data.content ); // eslint-disable-line
|
||||||
|
|
||||||
|
if ( data.isTransformedWithMathPasteFromOffice ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !data.isTransformedWithPasteFromOffice ) {
|
||||||
|
console.warn( 'Paste from office must be set before this' );// eslint-disable-line
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const domParser = new DOMParser(); // eslint-disable-line
|
||||||
|
|
||||||
|
/*
|
||||||
|
console.log(htmlString); // eslint-disable-line
|
||||||
|
const { body } = parseHtml( htmlString );
|
||||||
|
console.log(body); // eslint-disable-line
|
||||||
|
*/
|
||||||
|
|
||||||
|
const plainString = data.dataTransfer.getData( 'text/plain' );
|
||||||
|
const lines = plainString.split( /\r?\n/ ); // split by new lines
|
||||||
|
if ( lines.length > 1 ) {
|
||||||
|
lines.pop(); // Remove last new line
|
||||||
|
}
|
||||||
|
// console.log(plainString); // eslint-disable-line
|
||||||
|
|
||||||
|
const htmlMimeType = 'text/html';
|
||||||
|
let htmlString = data.dataTransfer.getData( htmlMimeType );
|
||||||
|
// console.log(htmlString); // eslint-disable-line
|
||||||
|
|
||||||
|
htmlString = htmlString.replace( /<!--\[if gte vml 1]>/g, '' );
|
||||||
|
htmlString = htmlString.replace( BULLET_REGEXP, '' );
|
||||||
|
|
||||||
|
const normalizedHtml = normalizeSpacing( cleanContentAfterBody( htmlString ) );
|
||||||
|
const htmlDocument = domParser.parseFromString( normalizedHtml, htmlMimeType );
|
||||||
|
normalizeSpacerunSpans( htmlDocument );
|
||||||
|
|
||||||
|
// const htmlDocument = domParser.parseFromString( htmlString, htmlMimeType );
|
||||||
|
// console.log(htmlDocument); // eslint-disable-line
|
||||||
|
|
||||||
|
const parts = htmlDocument.body.children;
|
||||||
|
|
||||||
|
// console.log(parts); // eslint-disable-line
|
||||||
|
|
||||||
|
const partsByLines = [];
|
||||||
|
|
||||||
|
for ( let i = 0; i < parts.length; i++ ) {
|
||||||
|
const part = parts[ i ];
|
||||||
|
if ( part.tagName.toLowerCase() === 'table' ) {
|
||||||
|
// console.log(part); // eslint-disable-line
|
||||||
|
const table = part;
|
||||||
|
const rows = table.getElementsByTagName( 'tr' );
|
||||||
|
for ( let j = 0; j < rows.length; j++ ) {
|
||||||
|
const row = rows[ j ];
|
||||||
|
partsByLines.push( row );
|
||||||
|
}
|
||||||
|
// console.log(rows); // eslint-disable-line
|
||||||
|
} else {
|
||||||
|
partsByLines.push( part );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(lines); // eslint-disable-line
|
||||||
|
// console.log(parts); // eslint-disable-line
|
||||||
|
// console.log(lines.length, partsByLines.length); // eslint-disable-line
|
||||||
|
|
||||||
|
if ( lines.length === partsByLines.length ) {
|
||||||
|
for ( let i = 0; i < partsByLines.length; i++ ) {
|
||||||
|
const part = partsByLines[ i ];
|
||||||
|
const line = lines[ i ];
|
||||||
|
|
||||||
|
const nodes = part.childNodes;
|
||||||
|
// console.log( nodes ); // eslint-disable-line
|
||||||
|
|
||||||
|
let lineFromNode = '';
|
||||||
|
let equationCounter = 0;
|
||||||
|
for ( let j = 0; j < nodes.length; j++ ) {
|
||||||
|
const node = nodes[ j ];
|
||||||
|
// If node is comment
|
||||||
|
const commentType = Node.COMMENT_NODE; // eslint-disable-line
|
||||||
|
if ( node.nodeType === commentType ) {
|
||||||
|
const commentNode = node;
|
||||||
|
// console.log( comment ); // eslint-disable-line
|
||||||
|
const comment = commentNode.textContent;
|
||||||
|
// console.log(comment); // eslint-disable-line
|
||||||
|
if ( comment.match( /\[if gte msEquation 12]>/g ) ) {
|
||||||
|
equationCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE ) { // eslint-disable-line
|
||||||
|
// console.log( node.nodeType, node.textContent ); // eslint-disable-line
|
||||||
|
lineFromNode += node.textContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if don't have any equation
|
||||||
|
if ( equationCounter === 0 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const equations = collectEquations( line, lineFromNode, equationCounter );
|
||||||
|
// console.log( part, equations ); // eslint-disable-line
|
||||||
|
|
||||||
|
const images = part.getElementsByTagName( 'img' );
|
||||||
|
// console.log( images ); // eslint-disable-line
|
||||||
|
for ( let j = 0; j < images.length; j++ ) {
|
||||||
|
const img = images[ j ];
|
||||||
|
// console.log( img.src ); // eslint-disable-line
|
||||||
|
|
||||||
|
const mathtex = document.createElement( 'span' ); // eslint-disable-line
|
||||||
|
mathtex.classList.add( 'math-tex' );
|
||||||
|
mathtex.innerHTML = '\\[' + equations[ j ] + '\\]';
|
||||||
|
|
||||||
|
const parent = img.parentNode;
|
||||||
|
parent.replaceChild( mathtex, img );
|
||||||
|
|
||||||
|
// console.log( parent ); // eslint-disable-line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const writer = new UpcastWriter();
|
||||||
|
const documentFragment = data.content;
|
||||||
|
const itemLikeElements = findAllItemLikeElements( documentFragment, writer );
|
||||||
|
console.log( itemLikeElements ); // eslint-disable-line
|
||||||
|
|
||||||
|
if ( !itemLikeElements.length ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemLikeElements.forEach( ( itemLikeElement, i ) => {
|
||||||
|
console.log( i, itemLikeElement, itemLikeElement.element ); // eslint-disable-line
|
||||||
|
// const item = new Element( 'span' );
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
console.warn( 'Lines length is wrong', lines.length + ' !== ' + partsByLines.length ); // eslint-disable-line
|
||||||
|
}
|
||||||
|
|
||||||
|
data.isTransformedWithMathPasteFromOffice = true;
|
||||||
|
},
|
||||||
|
{ priority: 'high' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectEquations( line, lineFromNode, equationCounter ) {
|
||||||
|
const equations = [];
|
||||||
|
let equation = '';
|
||||||
|
let charCounter = 0;
|
||||||
|
let newEquation = true;
|
||||||
|
|
||||||
|
// Replace all spaces to non breaking spaces. (Cannot be in equation)
|
||||||
|
let lineFiltered = line;
|
||||||
|
lineFiltered = lineFiltered.replace( / /g, ' ' );
|
||||||
|
lineFiltered = lineFiltered.trim();
|
||||||
|
|
||||||
|
// Remove '\ ' chars
|
||||||
|
lineFiltered = lineFiltered.replace( /\\ /g, '' ); // Remove all extra spaces.
|
||||||
|
|
||||||
|
// Try remove all spaces in equation
|
||||||
|
lineFiltered = lineFiltered.replace( /{(?=.*?)(?=\\+).*?}/g, match => {
|
||||||
|
return match.replace( /\s+/g, '' );
|
||||||
|
} ); // Remove all extra spaces.
|
||||||
|
lineFiltered = lineFiltered.replace( /\s/g, '\u00A0' ); // Replcae all spaces to non breaking spaces
|
||||||
|
|
||||||
|
let lineFromNodeFiltered = lineFromNode;
|
||||||
|
lineFromNodeFiltered = lineFromNodeFiltered.replace( /\r?\n|\r/g, ' ' ); // Line break is same as space
|
||||||
|
lineFromNodeFiltered = lineFromNodeFiltered.replace( / /g, ' ' );
|
||||||
|
lineFromNodeFiltered = lineFromNodeFiltered.trim();
|
||||||
|
lineFromNodeFiltered = lineFromNodeFiltered.replace( /\s/g, '\u00A0' ); // Replcae all spaces to non breaking spaces
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
// console.log( '%c' + lineFiltered + ' %c' + lineFromNodeFiltered + ' %c', 'color:green', 'color:red','color:white' );
|
||||||
|
|
||||||
|
// Let check line char by char
|
||||||
|
for ( let j = 0; j < lineFiltered.length; j++ ) {
|
||||||
|
const charFromLine = lineFiltered.charAt( j );
|
||||||
|
// console.log( charFromLine, lineFiltered.charCodeAt( j ) ); // eslint-disable-line
|
||||||
|
const charFromNode = lineFromNodeFiltered.charAt( j - charCounter );
|
||||||
|
// Jump to next iteration if same char
|
||||||
|
// console.log( charFromLine, charFromNode ); // eslint-disable-line
|
||||||
|
if ( charFromLine === charFromNode ) {
|
||||||
|
if ( !newEquation ) {
|
||||||
|
equations.push( equation.trim() );
|
||||||
|
equation = '';
|
||||||
|
newEquation = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
equation += charFromLine;
|
||||||
|
charCounter++;
|
||||||
|
if ( newEquation ) {
|
||||||
|
newEquation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add last one
|
||||||
|
if ( !newEquation ) {
|
||||||
|
equations.push( equation.trim() );
|
||||||
|
equation = '';
|
||||||
|
newEquation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( equations.length !== equationCounter ) {
|
||||||
|
console.warn( 'Couldn\'t parse all equations' ); // eslint-disable-line
|
||||||
|
}
|
||||||
|
|
||||||
|
return equations;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanContentAfterBody( htmlString ) {
|
||||||
|
const regexp = /<\/body>(.*?)(<\/html>|$)/;
|
||||||
|
const match = htmlString.match( regexp );
|
||||||
|
|
||||||
|
if ( match && match[ 1 ] ) {
|
||||||
|
htmlString = htmlString.slice( 0, match.index ) + htmlString.slice( match.index ).replace( match[ 1 ], '' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findAllItemLikeElements( documentFragment, writer ) {
|
||||||
|
const range = writer.createRangeIn( documentFragment );
|
||||||
|
|
||||||
|
// Matcher for finding list-like elements.
|
||||||
|
const itemLikeElementsMatcher = new Matcher( {
|
||||||
|
name: /^img$/
|
||||||
|
} );
|
||||||
|
|
||||||
|
const itemLikeElements = [];
|
||||||
|
|
||||||
|
for ( const value of range ) {
|
||||||
|
if ( value.type === 'elementStart' && itemLikeElementsMatcher.match( value.item ) ) {
|
||||||
|
itemLikeElements.push( value.item );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemLikeElements;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user