CKEditor5从Word复制粘贴列表功能失效求助
CKEditor5 从Word复制粘贴编号列表时缩进子内容丢失格式的修复
问题详情
集成CKEditor5后,从Word复制带缩进的编号列表,粘贴后缩进的子内容丢失格式。
复制的原内容:
1.Dfgdfgdfg Dfgdfgdfgdf 2.Dfgdfgdfg kjdfhgjdfhghdfhjg Dfgjhdfjhgjdhfghkjdhfghdfjg dfjjhg dfjgh dfjhj gh dfhdgf 3.Dfgdfgjhdfj 4.Dfgdfgdf 5.Dfgdfgdfg 6.Dfgdfgdf
粘贴后效果:
1.Dfgdfgdfg Dfgdfgdfgdf 2.Dfgdfgdfg kjdfhgjdfhghdfhjg Dfgjhdfjhgjdhfghkjdhfghdfjg dfjjhg dfjgh dfjhj gh dfhdgf hjdgf 3.Dfgdfgjhdfj 4.Dfgdfgdf 5.Dfgdfgdfg 6.Dfgdfgdf
尝试自定义clipboardInput事件和HTML转换函数未生效,使用免费版本,需修复列表复制粘贴功能,原尝试代码如下:
DecoupledEditor .create( document.querySelector( '.editor' ), { // Editor configuration. link: { addTargetToExternalLinks: true, defaultProtocol: 'https://', allowedProtocols: [ 'https'], decorators: { addTargetToExternalLinks: { mode: 'automatic', callback: url => /^(https?:)?\/\//.test( url ), attributes: { target: '_blank', rel: 'noopener noreferrer' } } } }, } ) .then( editor => { window.editor = editor; // Set a custom container for the toolbar. document.querySelector( '.document-editor__toolbar' ).appendChild( editor.ui.view.toolbar.element ); document.querySelector( '.ck-toolbar' ).classList.add( 'ck-reset_all' ); // Assuming editor is already initialized editor.editing.view.document.on('clipboardInput', (evt, data) => { const htmlData = data.dataTransfer.getData('text/html'); if (htmlData) { // Manipulate the HTML structure to properly integrate text into lists const processedHtml = integrateTextIntoLists(htmlData); const viewFragment = editor.data.htmlProcessor.toView(processedHtml); const modelFragment = editor.data.toModel(viewFragment); // Insert the transformed content editor.model.change(writer => { editor.model.insertContent(modelFragment, editor.model.document.selection); }); // Stop the default processing to use our custom transformation evt.stop(); } }); } ) .catch( handleSampleError ); function handleSampleError( error ) { const issueUrl = 'https://github.com/ckeditor/ckeditor5/issues'; const message = [ 'Oops, something went wrong!', `Please, report the following error on ${ issueUrl } with the build id "m7gmbfwakd12-rztuvf3ew3ra" and the error stack trace:` ].join( '\n' ); console.error( message ); console.error( error ); } function integrateTextIntoLists(html) { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); // Handle incorrect list item integration const lists = doc.querySelectorAll('ol, ul'); lists.forEach(list => { let lastLi = list.lastElementChild; // Track the last <li> element // This is the node immediately following the current list let followingNode = list.nextSibling; while (followingNode) { const nextFollowingNode = followingNode.nextSibling; if (followingNode.nodeType === Node.ELEMENT_NODE && (followingNode.tagName === 'P' || followingNode.tagName === 'SPAN')) { // Move the node inside the last <li> if it's a <p> or <span> if (lastLi) { lastLi.appendChild(followingNode); } else { // If no <li> exists, create one lastLi = document.createElement('li'); lastLi.appendChild(followingNode); list.appendChild(lastLi); } } else { break; // Stop if the next node is not a <p> or <span> } followingNode = nextFollowingNode; } }); return new XMLSerializer().serializeToString(doc); }
修复方案
核心思路
从Word复制的内容,HTML结构会把编号和缩进子内容拆分为独立段落,而纯文本保留了完整的编号和缩进层级。改用纯文本解析,识别编号行和缩进行,构建正确的有序列表结构。
修改后的完整代码
DecoupledEditor .create( document.querySelector( '.editor' ), { link: { addTargetToExternalLinks: true, defaultProtocol: 'https://', allowedProtocols: [ 'https'], decorators: { addTargetToExternalLinks: { mode: 'automatic', callback: url => /^(https?:)?\/\//.test( url ), attributes: { target: '_blank', rel: 'noopener noreferrer' } } } }, } ) .then( editor => { window.editor = editor; document.querySelector( '.document-editor__toolbar' ).appendChild( editor.ui.view.toolbar.element ); document.querySelector( '.ck-toolbar' ).classList.add( 'ck-reset_all' ); editor.editing.view.document.on('clipboardInput', (evt, data) => { const textData = data.dataTransfer.getData('text/plain'); if (textData) { const processedHtml = convertTextToProperList(textData); const viewFragment = editor.data.htmlProcessor.toView(processedHtml); const modelFragment = editor.data.toModel(viewFragment); editor.model.change(writer => { editor.model.insertContent(modelFragment, editor.model.document.selection); }); evt.stop(); } }); } ) .catch( handleSampleError ); function handleSampleError( error ) { const issueUrl = 'https://github.com/ckeditor/ckeditor5/issues'; const message = [ 'Oops, something went wrong!', `Please, report the following error on ${ issueUrl } with the build id "m7gmbfwakd12-rztuvf3ew3ra" and the error stack trace:` ].join( '\n' ); console.error( message ); console.error( error ); } function convertTextToProperList(text) { const lines = text.split('\n').filter(line => line.trim() !== ''); const ol = document.createElement('ol'); let currentLi = null; lines.forEach(line => { // 匹配以数字+点开头的编号行 if (/^\d+\./.test(line.trim())) { currentLi = document.createElement('li'); // 移除编号前缀,保留内容 const content = line.replace(/^\d+\.\s*/, '').trim(); currentLi.textContent = content; ol.appendChild(currentLi); } else if (currentLi && line.trim()) { // 缩进行添加到当前列表项,用<br>保持换行 const br = document.createElement('br'); currentLi.appendChild(br); currentLi.appendChild(document.createTextNode(line.trim())); } }); return ol.outerHTML; }
关键说明
- 优先处理纯文本:Word复制的纯文本保留了清晰的编号和缩进关系,比HTML更易解析
- 编号行识别:通过正则
/^\d+\./匹配编号开头的行,创建新的<li>元素 - 缩进行合并:将后续缩进的文本添加到当前
<li>中,用<br>维持换行格式 - 构建标准
<ol>结构:确保CKEditor能正确识别为有序列表
内容的提问来源于stack exchange,提问作者Eduardo perez
相关产品推荐
相关产品推荐

