簡體   English   中英

無法輸入到CKEditor5的EditableElement

[英]Can not input to EditableElement of CKEditor5

在CKEditor5中,我嘗試實現自定義元素以將模型轉換為視圖以進行編輯。 然后,容器元素(@ ckeditor / ckeditor5-engine / src / view / containerelement)中的可編輯元素(@ ckeditor / ckeditor5-engine / src / view / editableelement)集中在父容器元素上,無法進行編輯。

例如,如果實現如下:

buildModelConverter().for(editing.modelToView)
            .fromElement('myElement')
            .toElement(new ContainerElement('div', {}, [new EditableElement('h4')]));

插入“ myElement”和按下“ abc”后實際編輯dom的結果。 (我希望將“ abc”的文本輸入到h4標簽中,但是...)

<div>​​​​​​​
  abc
  <h4>
    <br data-cke-filler="true">
  </h4>
</div>

我也嘗試使用小部件來應用contenteditable屬性。 但是,無法在h4中輸入文本。

<div class="ck-widget" contenteditable="false">​​​​​​​
  <h4 class="ck-editable" contenteditable="true">
    <br data-cke-filler="true">
  </h4>
</div>

是此錯誤,還是我對容器元素的理解有誤?

[額外細節]

我假設要制作一個用於排名列表的小部件插件。

首先,由於具有多個項目,因此排名列表由<ol><li>標記構成。 我通過定義兩個模式(例如“ rankingList”和“ rankingListItem”)解決了這一問題,因此我使用嵌套的模型元素實現了動態元素。

const item1 = new ModelElement('rankingListItem');
const item2 = new ModelElement('rankingListItem');
const model = new ModelElement('rankingList', {}, [item1, item2]);
// and insert

接下來,排名列表的項目具有鏈接,圖像,標題和注釋。 因此,排名列表項具有以下DOM結構:

<ol><!-- apply toWidget -->
  <li>
    <a href="link[editable]">
      <img src="image[editable]">
      <h3>title[editable]</h3>
      <p>notes[editable]</p>
    </a>
  </li>
  ...
</ol>

我希望view元素如下:

const {ref, src, title, notes} = data; // how to get data?
const view = new ContainerElement('a', {ref}, [
    new EmptyElement('img', {src}),
    new EditableElement('h3', {}, new Text(title)),
    new EditableElement('p', {}, new Text(title)),
  ]);
// maybe incorrect ...

總之,我想使用可編輯視圖不破壞定義的DOM樹。 我怎么知道呢?

感謝您描述您的情況。 目前,對於我們而言,了解開發人員如何使用該編輯器以及您的期望是非常重要的。

不幸的是,這看起來像一個非常復雜的功能。 看起來還需要自定義UI(以編輯鏈接url和image src-除非添加到編輯器后它們沒有更改)。 您似乎遇到了兩個問題:

  • 模型和視圖之間的位置映射,
  • 嵌套的可編輯內容。

首先,回答有關EditableElement的問題-將它們用於h3p元素似乎是正確的。

但是,這種復雜功能需要自定義轉換器。 轉換器構建器(您使用過的)專用於簡單情況下,例如元素到元素的轉換或屬性到屬性的轉換。

在漂亮的API后面,構建轉換器是一個函數工廠,它創建一個或多個函數。 那些然后加入作為回調來ModelConversionDispatcher (其editor.editing.modelToView是一個實例)。 ModelConversionDispatcher在轉換期間觸發一系列事件,這是將模型中的更改轉換為視圖的過程。

如前所述,您將必須自己編寫這些轉換函數。

由於沒有太多主題可以提供詳細且詳盡的答案,所以我僅向您簡要介紹您應該感興趣的內容。遺憾的是,目前還沒有有關從頭開始創建自定義轉換器的指南。 這是一個非常廣泛的主題。

首先,讓我從大多數問題的根源向您解釋。 如您所知,編輯器具有三層:模型(數據),視圖(類似於DOM的結構)和DOM。 將模型轉換為視圖,然后將視圖呈現為DOM。 同樣,另一種方式是,當您加載數據時,DOM被轉換為視圖,而視圖被轉換為模型。 這就是為什么您需要為功能提供模型到視圖轉換器和視圖到模型轉換器的原因。

這個難題的重要部分是engine.conversion.Mapper 它的作用是從模型到視圖映射元素和位置。 您可能已經看到,模型可能與視圖完全不同。 這些之間正確的位置映射是關鍵。 當您在插入符號位置(在DOM中)鍵入字母時,該位置將映射到模型,並且該字母會插入模型中,然后才轉換回視圖和DOM。 如果視圖到模型的位置轉換錯誤,則您將無法在該位置鍵入或做任何事情。

Mapper本身非常簡單。 它所需要的只是指定哪些視圖元素綁定到哪些模型元素。 例如,在模型中,您可能具有:

<listItem type="bulleted" indent="0">Foo</listItem>
<listItem type="bulleted" indent="1">Bar</listItem>

在視圖中時,您有:

<ul>
  <li>
    Foo
    <ul>
      <li>Bar</li>
    </ul>
  </li>
</ul>

如果映射器知道第一個listItem與第一個<li>綁定,第二個listItem與第二個<li>綁定,則它能夠正確轉換位置。

回到你的情況。 每個轉換器必須為Mapper提供數據。 由於您使用的是轉換器構建器,因此由它生成的轉換器已經做到了。 但是它們很簡單,因此當您提供以下信息時:

buildModelConverter().for(editing.modelToView)
        .fromElement('myElement')
        .toElement(new ContainerElement('div', {}, [new EditableElement('h4')]));

假定myElement<div>綁定。 因此,在<div>寫入的所有內容將直接進入myElement ,然后在myElement的開頭myElement

<div>
  <h4></h4>
</div>

假設您只是在<h4>處寫了x ,該位置將被映射到模型中的myElement偏移量0 ,然后在<div>的開頭呈現給視圖。

模型:

<myElement>x</myElement>

視圖:

<div>x<h4></h4></div>

如您所見,您的情況是<h4>應該與myElement綁定。

目前,我們處於重構階段。 目標之一是為轉換器制造商提供更多實用程序功能。 這些實用程序之一是具有包裝器元素的元素的轉換器,例如上述“ div + h4”情況。 這也是圖像特征的情況。 該圖像在模型中由<image>表示,但在視圖中為<figure><img /></figure> 您可以查看ckeditor5-image來查看這些轉換器的外觀。 我們要簡化它們。

不幸的是,您的實際情況更加復雜,因為內部有多個元素。 CKE5體系結構應該能夠處理您的情況,但是您必須了解,如果沒有適當的指導,這幾乎是不可能寫的。

如果您想ckeditor5-image ,則應該研究 ckeditor5-image庫。 這並不容易,但這是最好的方法。 Image插件以及ImageCaption與您的情況非常相似。

模型:

<image alt="x" src="y">
  <caption>Foo</caption>
</image>

視圖:

<figure class="image">
  <img alt="x" src="y" />
  <figcaption>Foo</caption>
</figure>

在您的情況下,我會在兩行之間看到模型:

<rankItem imageSrc="x" linkUrl="y">
  <rankTitle>Foo</rankTitle>
  <rankNotes>Bar</rankNotes>
</rankItem>

而且我會讓視圖更重一點,但是編寫轉換器會更容易:

<li contenteditable="false">
  <a href="y">
    <img src="x" />
    <span class="data">
      <span class="title" contenteditable="true">Foo</span>
      <span class="notes" contenteditable="true">Bar</span>
    </span>
  </a>
</li>

對於rankTitlerankNotes基於caption元素( ckeditor5-image/src/imagecaption/imagecaptionengine.js )。

對於rankItem基於image元素( ckeditor5-image/src/image/ )。

再次提醒您-我們正在簡化所有步驟。 我們希望人們編寫自己的功能,甚至像您這樣的復雜功能。 但是,我們知道它現在有多么復雜。 因此,目前沒有文檔-我們正在尋求更改和簡化操作。

最后,您可以使用Link插件和使用Converter Builder構建的元素來更簡單地創建該排名列表:

  • rankList > <ol class="rank">
  • rankItem > <li>
  • rankImage > <img />
  • rankNotes > <span class="notes">
  • rankTitle > <span class="title">

但是,由於整個結構都是可編輯的,因此有可能將其弄亂。

模型:

<rankList>
  <rankItem>
    <rankImage linkHref="" />
    <rankTitle>Foo</rankTitle>
    <rankNotes>Bar</rankNotes>
  </rankItem>
  ...
</rankList>

其中“ Foo”和“ Bar”也設置了linkHref屬性。

視圖:

<ol class="rank">
  <li>
    <a href=""><img src="" /></a>
    <span class="title"><a href="">Title</a></span>
    <span class="notes"><a href="">Foo</a></span>
  </li>
  ...
</ol>

這樣的事情雖然遠非完美,但只要我們在重構之前和編寫指南之前就應該容易編寫得多。

當然,您還必須提供視圖模型轉換器。 您可能想要自己編寫它們(請查看ckeditor5-list/src/converters.js viewModelConverter() -盡管您會更輕松,因為它是平坦的,而不是嵌套列表)。 或者,您可以通過轉換器生成器生成它們。

也許可以使用上面的方法(更簡單),但是使用contentEditable屬性來控制結構。 rankList必須使用contentEditable="false"轉換為<ol> 例如,也許您可​​以以某種方式使用toWidget進行更好的選擇處理。 rankNotesrankTitle必須轉換為具有contentEditable="true"元素(可能使用toWidgetEditable() )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM