@@ -39,7 +39,7 @@ import { addEvent } from './utils/event';
3939import Logger from '@/Logger' ;
4040import { handleFileUploadCallback } from '@/utils/file' ;
4141import { createElement } from './utils/dom' ;
42- import { longTextReg , base64Reg , imgDrawioXmlReg , createUrlReg } from './utils/regexp' ;
42+ import { longTextReg , base64Reg , imgDrawioXmlReg , createUrlReg , pasteWrapperReg } from './utils/regexp' ;
4343import { handleNewlineIndentList } from './utils/autoindent' ;
4444
4545/**
@@ -153,6 +153,17 @@ export default class Editor {
153153 if ( this . $cherry . status . editor === 'hide' ) {
154154 return ;
155155 }
156+ this . formatBigData2Mark ( pasteWrapperReg , 'cm-url paste-wrapper' , ( target , oneSearch ) => {
157+ const whole = oneSearch [ 0 ] ?? '' ;
158+ const id = oneSearch [ 1 ] ?? '' ;
159+ const bigString = oneSearch [ 2 ] ?? '' ;
160+ const targetChFrom = target . ch ;
161+ const targetChTo = targetChFrom + whole . length ;
162+ const targetLine = target . line ;
163+ const begin = { line : targetLine , ch : targetChFrom } ;
164+ const end = { line : targetLine , ch : targetChTo } ;
165+ return { bigString, begin, end, id } ;
166+ } ) ;
156167 this . formatBigData2Mark ( base64Reg , 'cm-url base64' ) ;
157168 this . formatBigData2Mark ( imgDrawioXmlReg , 'cm-url drawio' ) ;
158169 this . formatBigData2Mark ( longTextReg , 'cm-url long-text' ) ;
@@ -168,8 +179,22 @@ export default class Editor {
168179 * 把大字符串变成省略号
169180 * @param {* } reg 正则
170181 * @param {* } className 利用codemirror的MarkText生成的新元素的class
182+ * @param {function } getBeginEnd 获取begin和end的函数
171183 */
172- formatBigData2Mark = ( reg , className ) => {
184+ formatBigData2Mark = (
185+ reg ,
186+ className ,
187+ getBeginEnd = ( target , oneSearch ) => {
188+ const bigString = oneSearch [ 2 ] ?? '' ;
189+ const targetChFrom = target . ch + oneSearch [ 1 ] ?. length ;
190+ const targetChTo = targetChFrom + bigString . length ;
191+ const targetLine = target . line ;
192+ const begin = { line : targetLine , ch : targetChFrom } ;
193+ const end = { line : targetLine , ch : targetChTo } ;
194+ const id = '' ;
195+ return { bigString, begin, end, id } ;
196+ } ,
197+ ) => {
173198 const codemirror = this . editor ;
174199 const searcher = codemirror . getSearchCursor ( reg ) ;
175200
@@ -179,17 +204,12 @@ export default class Editor {
179204 if ( ! target ) {
180205 continue ;
181206 }
182- const bigString = oneSearch [ 2 ] ?? '' ;
183- const targetChFrom = target . ch + oneSearch [ 1 ] ?. length ;
184- const targetChTo = targetChFrom + bigString . length ;
185- const targetLine = target . line ;
186- const begin = { line : targetLine , ch : targetChFrom } ;
187- const end = { line : targetLine , ch : targetChTo } ;
207+ const { bigString, begin, end, id } = getBeginEnd ( target , oneSearch ) ;
188208 // 如果所在区域已经有mark了,则不再增加mark
189209 if ( codemirror . findMarks ( begin , end ) . length > 0 ) {
190210 continue ;
191211 }
192- const newSpan = createElement ( 'span' , `cm-string ${ className } ` , { title : bigString } ) ;
212+ const newSpan = createElement ( 'span' , `cm-string ${ className } ` , { title : bigString , 'data-id' : id } ) ;
193213 newSpan . textContent = bigString ;
194214 codemirror . markText ( begin , end , { replacedWith : newSpan , atomic : true } ) ;
195215 }
@@ -285,32 +305,72 @@ export default class Editor {
285305 /**
286306 *
287307 * @param {ClipboardEvent } e
288- * @param {CodeMirror.Editor } codemirror
289308 */
290- onPaste ( e , codemirror ) {
309+ onPaste ( e ) {
291310 let { clipboardData } = e ;
292- if ( clipboardData ) {
293- this . handlePaste ( e , clipboardData , codemirror ) ;
294- } else {
311+ if ( ! clipboardData ) {
295312 ( { clipboardData } = window ) ;
296- this . handlePaste ( e , clipboardData , codemirror ) ;
313+ }
314+ const needHandlePaste = this . handleThirdPaste ( e , clipboardData ) ;
315+ if ( needHandlePaste ) {
316+ this . handlePaste ( e , clipboardData ) ;
317+ }
318+ }
319+
320+ onPasteCallback ( { html, htmlText, mdText } ) {
321+ // @ts -ignore
322+ const { randomId, _this } = this ;
323+ const allMarks = _this . editor . getAllMarks ( ) ;
324+ for ( let i = 0 ; i < allMarks . length ; i ++ ) {
325+ const mark = allMarks [ i ] ;
326+ const span = mark . widgetNode . querySelector ( `.paste-wrapper[data-id="${ randomId } "]` ) ;
327+ if ( span ) {
328+ const { from, to } = mark . find ( ) ;
329+ mark . clear ( ) ;
330+ _this . editor . setSelection ( from , to ) ;
331+ if ( mdText ) {
332+ _this . editor . replaceSelection ( mdText , 'end' ) ;
333+ } else {
334+ _this . formatHtml2MdWhenPaste ( null , html , htmlText ) ;
335+ }
336+ break ;
337+ }
297338 }
298339 }
299340
341+ /**
342+ * 调用第三方的粘贴回调
343+ * @returns {boolean } true: 需要继续处理粘贴内容,false: 不需要继续处理粘贴内容
344+ */
345+ handleThirdPaste ( event , clipboardData ) {
346+ // 生成一个随机id,用于有可能的异步回调
347+ const randomId = `cherry-paste-${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } ${ new Date ( ) . getTime ( ) } ` ;
348+ const onPasteRet = this . $cherry . options . callback . onPaste (
349+ clipboardData ,
350+ this . $cherry ,
351+ this . onPasteCallback . bind ( { randomId, _this : this } ) ,
352+ ) ;
353+ if ( onPasteRet !== false && typeof onPasteRet === 'string' ) {
354+ event . preventDefault ( ) ;
355+ // 是否命中语法糖
356+ if ( / ^ < < [ \s \S ] + > > $ / . test ( onPasteRet ) ) {
357+ const newText = `{{${ randomId } |${ onPasteRet . replace ( / ^ < < ( [ \s \S ] + ) > > $ / , ( whole , $1 ) => `<<${ $1 . replace ( / [ < > ] / g, '' ) } >>` ) } }}` ;
358+ this . editor . replaceSelection ( newText ) ;
359+ } else {
360+ this . editor . replaceSelection ( onPasteRet , 'around' ) ;
361+ }
362+ return false ;
363+ }
364+ return true ;
365+ }
366+
300367 /**
301368 *
302369 * @param {ClipboardEvent } event
303370 * @param {ClipboardEvent['clipboardData'] } clipboardData
304- * @param {CodeMirror.Editor } codemirror
305371 * @returns {boolean | void }
306372 */
307- handlePaste ( event , clipboardData , codemirror ) {
308- const onPasteRet = this . $cherry . options . callback . onPaste ( clipboardData , this . $cherry ) ;
309- if ( onPasteRet !== false && typeof onPasteRet === 'string' ) {
310- event . preventDefault ( ) ;
311- codemirror . replaceSelection ( onPasteRet ) ;
312- return ;
313- }
373+ handlePaste ( event , clipboardData ) {
314374 let html = clipboardData . getData ( 'Text/Html' ) ;
315375 const { items } = clipboardData ;
316376
@@ -331,7 +391,6 @@ export default class Editor {
331391 ) {
332392 html = '' ;
333393 }
334- const codemirrorDoc = codemirror . getDoc ( ) ;
335394 this . fileUploadCount = 0 ;
336395 // 只要有html内容,就不处理剪切板里的其他内容,这么做的后果是粘贴excel内容时,只会粘贴html内容,不会把excel对应的截图粘进来
337396 for ( let i = 0 ; ! html && i < items . length ; i ++ ) {
@@ -346,14 +405,14 @@ export default class Editor {
346405 return ;
347406 }
348407 const mdStr = `${ this . fileUploadCount > 1 ? '\n' : '' } ${ handleFileUploadCallback ( url , params , file ) } ` ;
349- codemirrorDoc . replaceSelection ( mdStr ) ;
408+ this . editor . replaceSelection ( mdStr , 'end' ) ;
350409 // if (this.pasterHtml) {
351410 // // 如果同时粘贴了html内容和文件内容,则在文件上传完成后强制让光标处于非选中状态,以防止自动选中的html内容被文件内容替换掉
352411 // const { line, ch } = codemirror.getCursor();
353412 // codemirror.setSelection({ line, ch }, { line, ch });
354- // codemirrorDoc .replaceSelection(mdStr, 'end');
413+ // this.editor .replaceSelection(mdStr, 'end');
355414 // } else {
356- // codemirrorDoc .replaceSelection(mdStr);
415+ // this.editor .replaceSelection(mdStr);
357416 // }
358417 } ) ;
359418 event . preventDefault ( ) ;
@@ -365,23 +424,22 @@ export default class Editor {
365424 if ( ! html || ! this . options . convertWhenPaste ) {
366425 return true ;
367426 }
427+ this . formatHtml2MdWhenPaste ( event , html , htmlText ) ;
428+ }
368429
430+ formatHtml2MdWhenPaste ( event , html , htmlText ) {
369431 let divObj = document . createElement ( 'DIV' ) ;
370432 divObj . innerHTML = html ;
371- html = divObj . innerHTML ;
372- const mdText = htmlParser . run ( html ) ;
433+ const mdText = htmlParser . run ( divObj . innerHTML ) ;
373434 if ( typeof mdText === 'string' && mdText . trim ( ) . length > 0 ) {
374- const range = codemirror . listSelections ( ) ;
375- if ( codemirror . getSelections ( ) . length <= 1 && range [ 0 ] && range [ 0 ] . anchor ) {
376- const currentCursor = { } ;
377- currentCursor . line = range [ 0 ] . anchor . line ;
378- currentCursor . ch = range [ 0 ] . anchor . ch ;
379- codemirrorDoc . replaceSelection ( mdText ) ;
380- pasteHelper . showSwitchBtnAfterPasteHtml ( this . $cherry , currentCursor , codemirror , htmlText , mdText ) ;
435+ const range = this . editor . listSelections ( ) ;
436+ if ( this . editor . getSelections ( ) . length <= 1 && range [ 0 ] && range [ 0 ] . anchor ) {
437+ this . editor . replaceSelection ( mdText , 'around' ) ;
438+ pasteHelper . showSwitchBtnAfterPasteHtml ( this . $cherry . locale , this . editor , htmlText , mdText ) ;
381439 } else {
382- codemirrorDoc . replaceSelection ( mdText ) ;
440+ this . editor . replaceSelection ( mdText , 'around' ) ;
383441 }
384- event . preventDefault ( ) ;
442+ event && event . preventDefault ( ) ;
385443 }
386444 divObj = null ;
387445 }
@@ -505,7 +563,7 @@ export default class Editor {
505563 } ) ;
506564
507565 editor . on ( 'paste' , ( codemirror , evt ) => {
508- this . options . onPaste . call ( this , evt , codemirror ) ;
566+ this . options . onPaste . call ( this , evt ) ;
509567 } ) ;
510568
511569 if ( this . options . autoScrollByCursor ) {
@@ -537,7 +595,7 @@ export default class Editor {
537595 const mdStr = handleFileUploadCallback ( url , params , file ) ;
538596 // 当批量上传文件时,每个被插入的文件中间需要加个换行,但单个上传文件的时候不需要加换行
539597 const insertValue = i > 0 ? `\n${ mdStr } ` : `${ mdStr } ` ;
540- codemirror . replaceSelection ( insertValue ) ;
598+ codemirror . replaceSelection ( insertValue , 'end' ) ;
541599 this . dealSpecialWords ( ) ;
542600 } ) ;
543601 }
0 commit comments