如何将 "target" 属性添加到 ckeditor5 中的 `a` 标签?
How to add "target" attribute to `a` tag in ckeditor5?
我已经为 link 创建了自己的插件。现在我想向插件生成的 a
标签添加一些其他属性,例如 target
、rel
.
但是我无法完成它。这是转换器的我的插件代码。
我应该添加什么转换器以便 a
标签可以支持其他属性?
/**
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/
/**
* @module link/linkediting
*/
import LinkEditing from '@ckeditor/ckeditor5-link/src/linkediting';
import {
downcastAttributeToElement
} from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
import { upcastElementToAttribute } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
import LinkCommand from './uclinkcommand';
import UnlinkCommand from './ucunlinkcommand';
import { createLinkElement } from '@ckeditor/ckeditor5-link/src/utils';
import { ensureSafeUrl } from './utils';
import bindTwoStepCaretToAttribute from '@ckeditor/ckeditor5-engine/src/utils/bindtwostepcarettoattribute';
/**
* The link engine feature.
*
* It introduces the `linkHref="url"` attribute in the model which renders to the view as a `<a href="url">` element.
*
* @extends module:core/plugin~Plugin
*/
export default class UcLinkEditing extends LinkEditing {
/**
* @inheritDoc
*/
init() {
const editor = this.editor;
// Allow link attribute on all inline nodes.
editor.model.schema.extend( '$text', { allowAttributes: 'linkHref' } );
editor.conversion.for( 'dataDowncast' )
.add( downcastAttributeToElement( { model: 'linkHref', view: createLinkElement } ) );
editor.conversion.for( 'editingDowncast' )
.add( downcastAttributeToElement( { model: 'linkHref', view: ( href, writer ) => {
return createLinkElement( ensureSafeUrl( href ), writer );
} } ) );
editor.conversion.for( 'upcast' )
.add( upcastElementToAttribute( {
view: {
name: 'a',
attribute: {
href: true
}
},
model: {
key: 'linkHref',
value: viewElement => viewElement.getAttribute( 'href' )
}
} ) );
// Create linking commands.
editor.commands.add( 'ucLink', new LinkCommand( editor ) );
editor.commands.add( 'ucUnlink', new UnlinkCommand( editor ) );
// Enable two-step caret movement for `linkHref` attribute.
bindTwoStepCaretToAttribute( editor.editing.view, editor.model, this, 'linkHref' );
// Setup highlight over selected link.
this._setupLinkHighlight();
}
}
简介
在开始编写代码之前,我想借此机会解释一下 CKEditor 5 内联元素(如 <a>
)的方法,以便解决方案更容易理解。有了这些知识,以后类似的问题就不会麻烦了。以下是一个全面的教程,因此请阅读很长时间。
即使您可能了解理论部分的大部分内容,我还是建议您阅读它以全面了解 CKEditor 5 中的工作原理。
另外,请注意,我将为原始 CKEditor 5 插件提供一个解决方案,因为它对寻求有关此问题的教程的其他社区成员更有价值。不过,我希望通过本教程的洞察力,您将能够根据您的自定义插件调整代码示例。
此外,请记住,本教程不讨论此插件的 UI 部分,仅讨论应如何配置以进行转换。添加和删除属性是 UI 或代码其他部分的工作。这里我只讨论引擎的东西。
CKEditor 5 中的内联元素
首先,让我们确定哪些元素是内联的。通过内联元素,我理解 <strong>
、<a>
或 <span>
等元素。与 <p>
、<blockquote>
或 <div>
不同,内联元素不会构造数据。相反,它们以特定的(视觉和语义)方式标记一些文本。因此,在某种程度上,这些元素是文本给定部分的特征。因此,我们说文本的给定部分是粗体,或者文本的给定部分 is/has a link.
同样,在模型中,我们不直接将 <a>
或 <strong>
表示为元素。相反,我们允许将属性添加到文本的一部分。这就是文本特征(如粗体、斜体或 link)的表示方式。
例如,在模型中,我们可能有一个带有 Foo bar
文本的 <paragraph>
元素,其中 bar
的 bold
属性设置为 true
.我们会这样记下来:<paragraph>Foo <$text bold="true">bar</$text></paragraph>
。看,那里没有 <strong>
或任何其他附加元素。它只是一些带有属性的文本。稍后,bold
属性被转换为 <strong>
元素。
顺便说一下:来自模型属性的视图元素有它们自己的 class: view.AttributeElement
而不是内联元素也可以称为属性元素。可悲的是,名称与 "attribute" 作为视图元素的属性冲突(更糟糕的是,属性元素允许具有属性)。
当然,文本可能有多个属性,它们都被转换为各自的视图内联元素。请记住,在模型中,属性没有任何固定顺序。这与视图或 HTML 相反,其中内联元素一个接一个地嵌套。嵌套发生在从模型到视图的转换过程中。这使得模型中的工作更简单,因为特征不需要处理模型中的元素的破坏或重新排列。
考虑这个模型字符串:
<paragraph>
<$text bold="true">Foo </$text>
<$text bold="true" linkHref="bar.html">bar</$text>
<$text bold="true"> baz</$text>
</paragraph>
它是粗体 Foo bar baz
文本,在 bar
上带有 link。转换时会转换为:
<p>
<strong>Foo </strong><a href="bar.html"><strong>bar</strong></a><strong> baz</strong>
</p>
请注意,<a>
元素的转换方式始终是最顶层元素。这是故意的,这样 none 元素将永远破坏 <a>
元素。看到这个,不正确的 view/HTML 字符串:
<p>
<a href="bar.html">Foo </a><strong><a href="bar.html">bar</a></strong>
</p>
生成的view/HTML有两个link元素相邻,这是错误的。
我们使用 priority
属性 of view.AttributeElement
来定义哪个元素应该在其他元素之上。大多数元素,如 <strong>
不关心它并保持默认优先级。但是,<a>
元素已更改优先级以保证 view/HTML.
中的正确顺序
复杂的内联元素和合并
到目前为止,我们主要讨论了更简单的内联元素,即没有属性的元素。例如 <strong>
、<em>
。相反,<a>
有额外的属性。
很容易想出需要 mark/style 文本的一部分但足够自定义的功能,因此仅使用标签是不够的。一个例子是字体系列功能。使用时,它会将 fontFamily
属性添加到文本,稍后将其转换为具有适当 style
属性的 <span>
元素。
此时,你要问如果在一个文本的同一部分设置多个这样的属性会怎样?以此模型为例:
<paragraph>
<$text fontFamily="Tahoma" fontSize="big">Foo</$text>
</paragraph>
以上属性转换如下:
fontFamily="value"
转换为 <span style="font-family: value;">
,
fontSize="value"
转换为 <span class="text-value">
.
那么,我们可以期待什么样的view/HTML?
<p>
<span style="font-family: Tahoma;">
<span class="text-big">Foo</span>
</span>
</p>
然而,这似乎是错误的。为什么不只有一个 <span>
元素?这样不是更好吗?
<p>
<span style="font-family: Tahoma;" class="text-big">Foo</span>
</p>
为了解决这些情况,在CKEditor 5的转换机制中,我们实际上引入了合并机制。
在上面的场景中,我们有两个转换为 <span>
的属性。当第一个属性(比如 fontFamily
被转换时,视图中还没有 <span>
。因此 <span>
添加了 style
属性。但是,当 fontSize
被转换,视图中已经有<span>
。view.Writer
识别这个并检查这些元素是否可以合并。规则是三个:
- 元素必须具有相同的
view.Element#name
,
- 元素必须具有相同的
view.AttributeElement#priority
,
- 两个元素都不能设置
view.AttributeElement#id
。
我们还没有讨论 id
属性 但是,为了简单起见,我现在不会讨论它。足以说明一些属性元素防止合并很重要
正在向 link
添加另一个属性
至此,应该很清楚如何向 <a>
元素添加另一个属性了。
所有需要做的就是定义一个新的模型属性(linkTarget
或 linkRel
)并使其转换为具有所需(target="..."
)的 <a>
元素或 rel="..."
) 属性。然后,它将与原始 <a href="...">
元素合并。
请记住,来自原始 CKEditor 5 link 插件的 <a>
元素已指定自定义 priority
。这意味着新插件生成的元素需要指定相同的优先级才能正确合并。
向上转换合并的属性元素
目前,我们只讨论了向下转型(即从模型转换为视图)。现在让我们谈谈向上转换(即从视图转换为模型)。幸运的是,它比上一部分更容易。
有两个 "things" 可以向上转换 - 元素和属性。这里没有魔法——元素就是元素(<p>
、<a>
、<strong>
等),属性就是属性(class=""
、href=""
等)。
元素可以向上转换为元素 (<p>
-> <paragraph>
) 或属性 (<strong>
-> bold
, <a>
-> linkHref
).属性可以向上转换为属性。
我们的示例显然需要从元素向上转型到属性。实际上,<a>
元素被转换为 linkHref
属性,并且 linkHref
属性值取自 <a>
元素的 href=""
属性。
自然地,人们会为他们的新 linkTarget
或 linkRel
属性定义相同的转换。然而,这里有一个陷阱。视图的每个部分只能转换("consumed")一次(向下转换时模型也是如此)。
这是什么意思?简单地说,如果给定 元素名称 或给定元素属性已经转换了一个特征,那么这两个特征都不能转换它。这样功能就可以正确地相互覆盖。这也意味着可以引入通用转换器(例如,如果没有其他功能将 <div>
识别为可以由该功能转换的内容,则 <div>
可以转换为 <paragraph>
)。这也有助于发现冲突的转换器。
回到我们的例子。我们不能定义两个转换相同元素 (<a>
) 的元素到属性转换器并期望它们同时一起工作。一个会覆盖另一个。
由于我们不想更改原始的 link 插件,因此我们需要保持该转换器不变。但是,新插件的向上转换转换器将是一个属性到属性转换器。由于该转换器不会转换元素(或者更确切地说,元素名称),它将与原始转换器一起工作。
代码示例
这里是 link 目标插件的代码示例。下面我会解释其中的一部分。
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { downcastAttributeToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
import { upcastAttributeToAttribute } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
class LinkTarget extends Plugin {
init() {
const editor = this.editor;
editor.model.schema.extend( '$text', { allowAttributes: 'linkTarget' } );
editor.conversion.for( 'downcast' ).add( downcastAttributeToElement( {
model: 'linkTarget',
view: ( attributeValue, writer ) => {
return writer.createAttributeElement( 'a', { target: attributeValue }, { priority: 5 } );
},
converterPriority: 'low'
} ) );
editor.conversion.for( 'upcast' ).add( upcastAttributeToAttribute( {
view: {
name: 'a',
key: 'target'
},
model: 'linkTarget',
converterPriority: 'low'
} ) );
}
}
对于这么长的教程来说,它肯定是一个小片段。希望其中大部分是不言自明的。
首先,我们通过定义文本允许的新属性 linkTarget
来扩展 Schema
。
然后,我们定义向下转换。 downcastAttributeToElement
用于创建将与原始 <a>
元素合并的 <a target="...">
元素。请记住,此处创建的 <a>
元素的优先级定义为 5
,就像在原始 link 插件中一样。
最后一步是向上转换。 upcastAttributeToAttribute
helper 被使用,如前所述。在view
配置中,指定只转换<a>
元素的target
属性(name: 'a'
)。这并不意味着 <a>
元素将被转换!这只是转换器的过滤配置,因此它不会转换其他元素的 target
属性。
最后,两个转换器都以低于原始转换器的优先级添加,以防止任何假设性问题。
以上示例适用于 ckeditor5-engine
和 ckeditor5-link
的当前母版。
当我在 2022 年遇到同样的问题时,我发现这个答案非常有帮助,我想添加 id
属性但没有创建自己的插件,我只是编辑了 Link
ckeditor5-build-classic
包中的插件然后我 re-builded 它。
1- 在 @module link/linkediting
中:
- 允许所有内联节点上的 link 属性。
editor.model.schema.extend( '$text', { allowAttributes: ['linkHref', 'linkId'] } );
- 为
upcast
添加转换以保留现有 id
属性或创建新属性:
editor.conversion.for( 'upcast' ).attributeToAttribute( {
view: {
name: 'a'
},
model: {
key: 'linkId',
value: viewElement => {
let id = viewElement.getAttribute( 'id' );
if (id)
return id;
return 'id_'+Math.floor(Math.random() * 10000)
}
},
converterPriority: 'low'
} ) ;
- 为
editingDowncast
添加转换,以将模型转换为视图:
editor.conversion.for( 'editingDowncast' ).attributeToElement( {
model: 'linkId',
view: ( attributeValue, conversionApi ) => {
return conversionApi.writer.createAttributeElement( 'a', { id: attributeValue }, { priority: 5 } );
},
converterPriority: 'low'
} ) ;
- 为
dataDowncast
添加转换,以在调用 getDate()
时获取属性:
editor.conversion.for( 'dataDowncast' )
.attributeToElement( {
model: 'linkId',
view: ( attributeValue, conversionApi ) => {
return conversionApi.writer.createAttributeElement( 'a', { id: attributeValue }, { priority: 5 } );
}
} ) ;
2- in @module link/linkcommand
:为了创建 id
,我只想要一个随机字符串,所以我没有在表单中创建任何新字段,只是在该行之后添加了这一行负责linkHref
属性
writer.setAttribute( 'linkId', 'id_'+Math.floor(Math.random() * 10000), range );
我已经为 link 创建了自己的插件。现在我想向插件生成的 a
标签添加一些其他属性,例如 target
、rel
.
但是我无法完成它。这是转换器的我的插件代码。
我应该添加什么转换器以便 a
标签可以支持其他属性?
/**
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/
/**
* @module link/linkediting
*/
import LinkEditing from '@ckeditor/ckeditor5-link/src/linkediting';
import {
downcastAttributeToElement
} from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
import { upcastElementToAttribute } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
import LinkCommand from './uclinkcommand';
import UnlinkCommand from './ucunlinkcommand';
import { createLinkElement } from '@ckeditor/ckeditor5-link/src/utils';
import { ensureSafeUrl } from './utils';
import bindTwoStepCaretToAttribute from '@ckeditor/ckeditor5-engine/src/utils/bindtwostepcarettoattribute';
/**
* The link engine feature.
*
* It introduces the `linkHref="url"` attribute in the model which renders to the view as a `<a href="url">` element.
*
* @extends module:core/plugin~Plugin
*/
export default class UcLinkEditing extends LinkEditing {
/**
* @inheritDoc
*/
init() {
const editor = this.editor;
// Allow link attribute on all inline nodes.
editor.model.schema.extend( '$text', { allowAttributes: 'linkHref' } );
editor.conversion.for( 'dataDowncast' )
.add( downcastAttributeToElement( { model: 'linkHref', view: createLinkElement } ) );
editor.conversion.for( 'editingDowncast' )
.add( downcastAttributeToElement( { model: 'linkHref', view: ( href, writer ) => {
return createLinkElement( ensureSafeUrl( href ), writer );
} } ) );
editor.conversion.for( 'upcast' )
.add( upcastElementToAttribute( {
view: {
name: 'a',
attribute: {
href: true
}
},
model: {
key: 'linkHref',
value: viewElement => viewElement.getAttribute( 'href' )
}
} ) );
// Create linking commands.
editor.commands.add( 'ucLink', new LinkCommand( editor ) );
editor.commands.add( 'ucUnlink', new UnlinkCommand( editor ) );
// Enable two-step caret movement for `linkHref` attribute.
bindTwoStepCaretToAttribute( editor.editing.view, editor.model, this, 'linkHref' );
// Setup highlight over selected link.
this._setupLinkHighlight();
}
}
简介
在开始编写代码之前,我想借此机会解释一下 CKEditor 5 内联元素(如 <a>
)的方法,以便解决方案更容易理解。有了这些知识,以后类似的问题就不会麻烦了。以下是一个全面的教程,因此请阅读很长时间。
即使您可能了解理论部分的大部分内容,我还是建议您阅读它以全面了解 CKEditor 5 中的工作原理。
另外,请注意,我将为原始 CKEditor 5 插件提供一个解决方案,因为它对寻求有关此问题的教程的其他社区成员更有价值。不过,我希望通过本教程的洞察力,您将能够根据您的自定义插件调整代码示例。
此外,请记住,本教程不讨论此插件的 UI 部分,仅讨论应如何配置以进行转换。添加和删除属性是 UI 或代码其他部分的工作。这里我只讨论引擎的东西。
CKEditor 5 中的内联元素
首先,让我们确定哪些元素是内联的。通过内联元素,我理解 <strong>
、<a>
或 <span>
等元素。与 <p>
、<blockquote>
或 <div>
不同,内联元素不会构造数据。相反,它们以特定的(视觉和语义)方式标记一些文本。因此,在某种程度上,这些元素是文本给定部分的特征。因此,我们说文本的给定部分是粗体,或者文本的给定部分 is/has a link.
同样,在模型中,我们不直接将 <a>
或 <strong>
表示为元素。相反,我们允许将属性添加到文本的一部分。这就是文本特征(如粗体、斜体或 link)的表示方式。
例如,在模型中,我们可能有一个带有 Foo bar
文本的 <paragraph>
元素,其中 bar
的 bold
属性设置为 true
.我们会这样记下来:<paragraph>Foo <$text bold="true">bar</$text></paragraph>
。看,那里没有 <strong>
或任何其他附加元素。它只是一些带有属性的文本。稍后,bold
属性被转换为 <strong>
元素。
顺便说一下:来自模型属性的视图元素有它们自己的 class: view.AttributeElement
而不是内联元素也可以称为属性元素。可悲的是,名称与 "attribute" 作为视图元素的属性冲突(更糟糕的是,属性元素允许具有属性)。
当然,文本可能有多个属性,它们都被转换为各自的视图内联元素。请记住,在模型中,属性没有任何固定顺序。这与视图或 HTML 相反,其中内联元素一个接一个地嵌套。嵌套发生在从模型到视图的转换过程中。这使得模型中的工作更简单,因为特征不需要处理模型中的元素的破坏或重新排列。
考虑这个模型字符串:
<paragraph>
<$text bold="true">Foo </$text>
<$text bold="true" linkHref="bar.html">bar</$text>
<$text bold="true"> baz</$text>
</paragraph>
它是粗体 Foo bar baz
文本,在 bar
上带有 link。转换时会转换为:
<p>
<strong>Foo </strong><a href="bar.html"><strong>bar</strong></a><strong> baz</strong>
</p>
请注意,<a>
元素的转换方式始终是最顶层元素。这是故意的,这样 none 元素将永远破坏 <a>
元素。看到这个,不正确的 view/HTML 字符串:
<p>
<a href="bar.html">Foo </a><strong><a href="bar.html">bar</a></strong>
</p>
生成的view/HTML有两个link元素相邻,这是错误的。
我们使用 priority
属性 of view.AttributeElement
来定义哪个元素应该在其他元素之上。大多数元素,如 <strong>
不关心它并保持默认优先级。但是,<a>
元素已更改优先级以保证 view/HTML.
复杂的内联元素和合并
到目前为止,我们主要讨论了更简单的内联元素,即没有属性的元素。例如 <strong>
、<em>
。相反,<a>
有额外的属性。
很容易想出需要 mark/style 文本的一部分但足够自定义的功能,因此仅使用标签是不够的。一个例子是字体系列功能。使用时,它会将 fontFamily
属性添加到文本,稍后将其转换为具有适当 style
属性的 <span>
元素。
此时,你要问如果在一个文本的同一部分设置多个这样的属性会怎样?以此模型为例:
<paragraph>
<$text fontFamily="Tahoma" fontSize="big">Foo</$text>
</paragraph>
以上属性转换如下:
fontFamily="value"
转换为<span style="font-family: value;">
,fontSize="value"
转换为<span class="text-value">
.
那么,我们可以期待什么样的view/HTML?
<p>
<span style="font-family: Tahoma;">
<span class="text-big">Foo</span>
</span>
</p>
然而,这似乎是错误的。为什么不只有一个 <span>
元素?这样不是更好吗?
<p>
<span style="font-family: Tahoma;" class="text-big">Foo</span>
</p>
为了解决这些情况,在CKEditor 5的转换机制中,我们实际上引入了合并机制。
在上面的场景中,我们有两个转换为 <span>
的属性。当第一个属性(比如 fontFamily
被转换时,视图中还没有 <span>
。因此 <span>
添加了 style
属性。但是,当 fontSize
被转换,视图中已经有<span>
。view.Writer
识别这个并检查这些元素是否可以合并。规则是三个:
- 元素必须具有相同的
view.Element#name
, - 元素必须具有相同的
view.AttributeElement#priority
, - 两个元素都不能设置
view.AttributeElement#id
。
我们还没有讨论 id
属性 但是,为了简单起见,我现在不会讨论它。足以说明一些属性元素防止合并很重要
正在向 link
添加另一个属性至此,应该很清楚如何向 <a>
元素添加另一个属性了。
所有需要做的就是定义一个新的模型属性(linkTarget
或 linkRel
)并使其转换为具有所需(target="..."
)的 <a>
元素或 rel="..."
) 属性。然后,它将与原始 <a href="...">
元素合并。
请记住,来自原始 CKEditor 5 link 插件的 <a>
元素已指定自定义 priority
。这意味着新插件生成的元素需要指定相同的优先级才能正确合并。
向上转换合并的属性元素
目前,我们只讨论了向下转型(即从模型转换为视图)。现在让我们谈谈向上转换(即从视图转换为模型)。幸运的是,它比上一部分更容易。
有两个 "things" 可以向上转换 - 元素和属性。这里没有魔法——元素就是元素(<p>
、<a>
、<strong>
等),属性就是属性(class=""
、href=""
等)。
元素可以向上转换为元素 (<p>
-> <paragraph>
) 或属性 (<strong>
-> bold
, <a>
-> linkHref
).属性可以向上转换为属性。
我们的示例显然需要从元素向上转型到属性。实际上,<a>
元素被转换为 linkHref
属性,并且 linkHref
属性值取自 <a>
元素的 href=""
属性。
自然地,人们会为他们的新 linkTarget
或 linkRel
属性定义相同的转换。然而,这里有一个陷阱。视图的每个部分只能转换("consumed")一次(向下转换时模型也是如此)。
这是什么意思?简单地说,如果给定 元素名称 或给定元素属性已经转换了一个特征,那么这两个特征都不能转换它。这样功能就可以正确地相互覆盖。这也意味着可以引入通用转换器(例如,如果没有其他功能将 <div>
识别为可以由该功能转换的内容,则 <div>
可以转换为 <paragraph>
)。这也有助于发现冲突的转换器。
回到我们的例子。我们不能定义两个转换相同元素 (<a>
) 的元素到属性转换器并期望它们同时一起工作。一个会覆盖另一个。
由于我们不想更改原始的 link 插件,因此我们需要保持该转换器不变。但是,新插件的向上转换转换器将是一个属性到属性转换器。由于该转换器不会转换元素(或者更确切地说,元素名称),它将与原始转换器一起工作。
代码示例
这里是 link 目标插件的代码示例。下面我会解释其中的一部分。
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { downcastAttributeToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
import { upcastAttributeToAttribute } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
class LinkTarget extends Plugin {
init() {
const editor = this.editor;
editor.model.schema.extend( '$text', { allowAttributes: 'linkTarget' } );
editor.conversion.for( 'downcast' ).add( downcastAttributeToElement( {
model: 'linkTarget',
view: ( attributeValue, writer ) => {
return writer.createAttributeElement( 'a', { target: attributeValue }, { priority: 5 } );
},
converterPriority: 'low'
} ) );
editor.conversion.for( 'upcast' ).add( upcastAttributeToAttribute( {
view: {
name: 'a',
key: 'target'
},
model: 'linkTarget',
converterPriority: 'low'
} ) );
}
}
对于这么长的教程来说,它肯定是一个小片段。希望其中大部分是不言自明的。
首先,我们通过定义文本允许的新属性 linkTarget
来扩展 Schema
。
然后,我们定义向下转换。 downcastAttributeToElement
用于创建将与原始 <a>
元素合并的 <a target="...">
元素。请记住,此处创建的 <a>
元素的优先级定义为 5
,就像在原始 link 插件中一样。
最后一步是向上转换。 upcastAttributeToAttribute
helper 被使用,如前所述。在view
配置中,指定只转换<a>
元素的target
属性(name: 'a'
)。这并不意味着 <a>
元素将被转换!这只是转换器的过滤配置,因此它不会转换其他元素的 target
属性。
最后,两个转换器都以低于原始转换器的优先级添加,以防止任何假设性问题。
以上示例适用于 ckeditor5-engine
和 ckeditor5-link
的当前母版。
当我在 2022 年遇到同样的问题时,我发现这个答案非常有帮助,我想添加 id
属性但没有创建自己的插件,我只是编辑了 Link
ckeditor5-build-classic
包中的插件然后我 re-builded 它。
1- 在 @module link/linkediting
中:
- 允许所有内联节点上的 link 属性。
editor.model.schema.extend( '$text', { allowAttributes: ['linkHref', 'linkId'] } );
- 为
upcast
添加转换以保留现有id
属性或创建新属性:
editor.conversion.for( 'upcast' ).attributeToAttribute( {
view: {
name: 'a'
},
model: {
key: 'linkId',
value: viewElement => {
let id = viewElement.getAttribute( 'id' );
if (id)
return id;
return 'id_'+Math.floor(Math.random() * 10000)
}
},
converterPriority: 'low'
} ) ;
- 为
editingDowncast
添加转换,以将模型转换为视图:
editor.conversion.for( 'editingDowncast' ).attributeToElement( {
model: 'linkId',
view: ( attributeValue, conversionApi ) => {
return conversionApi.writer.createAttributeElement( 'a', { id: attributeValue }, { priority: 5 } );
},
converterPriority: 'low'
} ) ;
- 为
dataDowncast
添加转换,以在调用getDate()
时获取属性:
editor.conversion.for( 'dataDowncast' )
.attributeToElement( {
model: 'linkId',
view: ( attributeValue, conversionApi ) => {
return conversionApi.writer.createAttributeElement( 'a', { id: attributeValue }, { priority: 5 } );
}
} ) ;
2- in @module link/linkcommand
:为了创建 id
,我只想要一个随机字符串,所以我没有在表单中创建任何新字段,只是在该行之后添加了这一行负责linkHref
属性
writer.setAttribute( 'linkId', 'id_'+Math.floor(Math.random() * 10000), range );