mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-09-02 21:42:15 +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-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": {
|
||||
"version": "12.2.0",
|
||||
"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-core": "^12.3.0",
|
||||
"@ckeditor/ckeditor5-engine": "^14.0.0",
|
||||
"@ckeditor/ckeditor5-paste-from-office": "^11.1.0",
|
||||
"@ckeditor/ckeditor5-ui": "^14.0.0",
|
||||
"@ckeditor/ckeditor5-undo": "^11.0.5",
|
||||
"@ckeditor/ckeditor5-utils": "^14.0.0",
|
||||
|
@ -4,10 +4,11 @@ import Widget from '@ckeditor/ckeditor5-widget/src/widget';
|
||||
import MathUI from './mathui';
|
||||
import MathEditing from './mathediting';
|
||||
import AutoMath from './automath';
|
||||
import MathPasteFromOffice from './mathpastefromoffice';
|
||||
|
||||
export default class Math extends Plugin {
|
||||
static get requires() {
|
||||
return [ MathEditing, MathUI, Widget, AutoMath ];
|
||||
return [ MathEditing, MathUI, Widget, AutoMath, MathPasteFromOffice ];
|
||||
}
|
||||
|
||||
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