注意:我添加的信息似乎使注释中的分辨率得到解决。

问题:

将内容从Gutenberg外部源粘贴到古腾堡丢失了一些HTML / CSS格式。[1]古腾堡保留大多数HTML(语义)元素,但会删除CSS(样式/非语义)元素。这意味着在粘贴事件期间,诸如字体大小,文本对齐方式,文本颜色等属性均被删除。

没有问题: ,自定义HTML块等(例如Wordable,JetPack)可用于将外部内容源(例如Google Docs)转换为WP友好内容,但这绝对不是这些解决方案的问题。相反,此问题仅集中在如何以编程方式更改Gutenberg的粘贴处理行为。例如,尝试将以下HTML块粘贴到Gutenberg的段落块中:

<p style="color:red">Hello WordPress StackExchange!</p>

然后查看该段落块的HTML,您将看到:

<p>Hello WordPress StackExchange!</p>

style="color:red"已被剥离。

查看段落块

其中一个块遭受此剥离是段落块(/gutenberg/packages/block-library/src/paragraph)。该块[2]使用RichText组件(/gutenberg/packages/block-editor/rich-text)来实现其富文本编辑功能。

查看RichText组件段落块继承。此函数依次调用/rich-text/index.js函数(onPaste)。

查看粘贴处理程序

pasteHandler函数“将HTML字符串转换为已知块。剥离所有其他内容。”根据JSDoc。

此函数有五个参数:



/gutenberg/packages/blocks/src/api/raw-handling/paste-handler.js =如果是HTML格式,则要转换的源内容

pasteHandler =如果是文本格式,则要转换的源内容

HTML =是将内容粘贴为块还是内联内容到现有块中。

plainText =我们是什么标记将内容插入其中。

mode =最初,我认为这确定了是否可以使用所需的任何HTML / CSS,但似乎更受限制,AFAIK仅确定是否针对粘贴的内容(仅与切线相关)。

我们可以看到tagName是导入的(canUserUseUnfilteredHTML):

 iframeRemover 


然后从pasteHandler调用index.js

 import { 
  pasteHandler, 
  children as childrenSource, 
  getBlockTransforms, 
  findTransform, 
  isUnmodifiedDefaultBlock
 } from '@wordpress/blocks';
 


出于我们的目的,我们只对pasteHandler函数的一部分感兴趣:

 pasteHandler 


即使在这里,大部分发生的事情与我们无关 当前的问题。例如,我们不在乎删除Google Doc UID或转换Word列表。

相反,我们感兴趣的是:



> onPaste-包含对onPaste( { value, onChange, html, plainText, files } ) { ... if ( files && files.length && ! html ) { const content = pasteHandler( { HTML: filePasteHandler( files), mode: 'BLOCKS', tagName, } ); ... const content = pasteHandler ( { HTML: html, plainText, mode, tagName, canUserUseUnfilteredHTML, } ); ... } 的调用的结果,也定义在const rawTransforms = getRawTransformations(); const phrasingContentSchema = getPhrasingContentSchema( 'paste' ); const blockContentSchema = getBlockContentSchema( rawTransforms, phrasingContentSchema, true ); const blocks = compact( flatMap( pieces, ( piece ) => { ... if ( ! canUserUseUnfilteredHTML ) { // Should run before `figureContentReducer`. filters.unshift( iframeRemover ); } const schema = { ...blockContentSchema, // Keep top-level phrasing content, normalised by `normaliseBlocks`. ...phrasingContentSchema, }; piece = deepFilterHTML( piece, filters, blockContentSchema ); piece = removeInvalidHTML( piece, schema ); piece = normaliseBlocks( piece ); piece = deepFilterHTML( piece, [ htmlFormattingRemover, brRemover, emptyParagraphRemover, ], blockContentSchema ); ... return htmlToBlocks( { html: piece, rawTransforms } ); } ) ); 中。 :)



rawTransforms-包含在getRawTransformations中定义的调用paste-handler.js的结果。这似乎删除了一些不可见的属性(u,abbr,data等)可能是此问题的一部分,但人们会遇到的更多问题是CSS样式,而不是这些属性。



phrasingContentSchema-包含对getPhrasingContentSchema的调用的结果,该调用在phrasing-content.js中定义。 。



blockContentSchema-在getBlockContentSchema中定义的过滤器之一。

我不确定,但我怀疑可能涉及到此代码段:



 utils.js 




phrasingContentReducer-在phrasing-content-reducer.js中定义,本质上是if ( node.nodeName === 'SPAN' && node.style ) { const { fontWeight, fontStyle, textDecorationLine, textDecoration, verticalAlign, } = node.style; 的包装,也在deepFilterHTML中找到。同样,不确定我是否可以理解这部分代码。



utils.js-在deepFilterNodeList中定义,本质上是utils.js的包装,也可以在removeInvalidHTML中找到。


请相信,utils.js JSDoc指出:“给出一个模式,解开或删除节点上的节点,属性和类”。



您会注意到一些未列入清单的功能-在查看它们的代码后,我认为它们不参与当前的问题(例如cleanNodeListutils.jscleanNodeList等)。

结论

我只是重写了大部分问题,稍后我将尝试进行细化并分享更多有关特定sni当我有机会看的时候,我不理解的代码片段就会出现。希望这可能对其他人有帮助/某人也许可以向我解释我所缺少的东西...或者我可以不停地走开。 :)

[1]从技术上讲,这并不总是正确的。某些块可能接受粘贴到其中的大多数/所有内容-例如HTML块。但是保留粘贴内容是一个例外,而不是规则。

[2]您可以在normaliseBlocks函数的brRemover中找到引用。

评论

数据可能不在剪贴板中吗?如果您知道一种使数据保持适当机制的方法,那么我认为GB团队会很乐意做出贡献,以便所有用户都能从中受益,我很好奇自己

@TomJNowell-我使用了一个名为ClipView的小应用程序来查看剪贴板的原始内容,并显示了CSS。另外,根据有关Github问题的一些对话,似乎决定剥离CSS并仅保留语义(HTML)内容。

您是否已经看过文档的这一部分?

嗨,Cas,我做到了。这些文档非常稀疏。

#1 楼

我在Gutenberg玩的还不是很多,但是将来我很可能需要解决类似的问题,

我要做的就是直接编辑函数,以便快速调试。

const rawTransforms = getRawTransformations();
const phrasingContentSchema = getPhrasingContentSchema( 'paste' );
const blockContentSchema = getBlockContentSchema( rawTransforms, phrasingContentSchema, true );

const blocks = compact( flatMap( pieces, ( piece ) => {
    ...
    // console.log( "Piece - deepFilterHTML" )
    // console.log( piece );

    piece = deepFilterHTML( piece, filters, blockContentSchema );

    // console.log( "Piece - removeInvalidHTML" )
    // console.log( piece );

    piece = removeInvalidHTML( piece, schema );

    // console.log( "Piece - normaliseBlocks" )
    // console.log( piece );

    piece = normaliseBlocks( piece );

    // console.log( "Piece - deepFilterHTML" )
    // console.log( piece );

    piece = deepFilterHTML( piece, [
        htmlFormattingRemover,
        brRemover,
        emptyParagraphRemover,
    ], blockContentSchema );

    ...

    return htmlToBlocks( { html: piece, rawTransforms } );
} ) );


我很确定对文档粘贴和HTML起作用的地方是“ cleanNodeList”函数,该函数具有4个参数:nodeList,doc, schema,内联

schema参数是“可以与提供的节点发生变异的函数数组。”

我想出了在您的情况下这将输出什么html / doc已过滤而不是未过滤

然后我想出了如何更改该参数的方法,因为我认为当它被“过滤”时,它将采用默认值。

这是在默认值上运行的代码多么苗条:

  cleanNodeList(node.childNodes, doc, schema, inline); // For inline mode, insert a line break when unwrapping nodes that
  // are not phrasing content.

  if (inline && !isPhrasingContent(node) && node.nextElementSibling) {
    Object(external_this_wp_dom_["insertAfter"])(doc.createElement('br'), node);
  }

  Object(external_this_wp_dom_["unwrap"])(node);


external_this_wp_dom _ [“ unwrap”]最有可能在运行默认过滤时依赖phrasing_content_phrasingContentSchema,并且从<span>标签的外观未定义都全部。

var phrasing_content_phrasingContentSchema = {
  strong: {},
  em: {},
  s: {},
  del: {},
  ins: {},
  a: {
    attributes: ['href', 'target', 'rel']
  },
  code: {},
  abbr: {
    attributes: ['title']
  },
  sub: {},
  sup: {},
  br: {},
  '#text': {}
}


希望能有所帮助。

#2 楼

在wp-includes / js / dist /中的我的blocks.js中,我找到RemoveInvalidHTML函数,该函数似乎负责从粘贴的HTML中删除样式。

 /**
 * Given a schema, unwraps or removes nodes, attributes and classes on HTML.
 *
 * @param {string} HTML   The HTML to clean up.
 * @param {Object} schema Schema for the HTML.
 * @param {Object} inline Whether to clean for inline mode.
 *
 * @return {string} The cleaned up HTML.
 */


function removeInvalidHTML(HTML, schema, inline) {
  var doc = document.implementation.createHTMLDocument('');
  doc.body.innerHTML = HTML;
  cleanNodeList(doc.body.childNodes, doc, schema, inline);
  return doc.body.innerHTML;
}
 


如您所见,这仅返回innerHTML。修改(创建此版本的自定义版本)此功能可能会解决您的问题。