簡體   English   中英

如何從CKEditor 5中的Insert事件中獲取文本?

[英]How to get the text from an Insert event in CKEditor 5?

我正在嘗試從CKEditor 5處理插入事件。

editor.document.on("change", (eventInfo, type, data) => {
  switch (type) {
    case "insert":
    console.log(type, data);
    break;
  }
});

在編輯器中鍵入時,將調用回調。 事件回調中的data參數看起來像這樣:

{
  range: {
    start: {
      root: { ... },
      path: [0, 14]
    },
    end: {
      root: { ... },
      path: [0, 15]
    }
  }
}

我沒有看到一種方便的方法來確定實際插入的文本。 我可以調用data.range.root.getNodeByPath(data.range.start.path); 這似乎讓我得到了插入文本的文本節點。那么我們應該查看文本節點的data字段嗎? 我們是否應該假設路徑中的最后一項始終是范圍的開始和結束的偏移量並使用它來進行子串? 我認為插入事件也會因為插入非文本類型的東西而被觸發(例如元素)。 我們怎么知道這確實是事件的文本類型?

有沒有我想念的東西,或者只有不同的方式一起完成這一切?

首先,讓我描述你目前是如何做到的(2018年1月)。 請記住,CKEditor 5現在正在進行大規模的重構,事情會發生變化。 最后,我將描述完成此重構后的樣子。 如果你不介意等待一段時間讓重構結束,你可以跳到后面的部分。

編輯: 1.0.0-beta.1於3月15日發布,因此您可以跳轉到“自2018年3月以來”部分。

直到2018年3月(最高1.0.0-alpha.2

(如果您需要了解有關某些類API或事件的更多信息, 請查看文檔 。)

您最好的選擇就是迭代插入的范圍。

let data = '';

for ( const child of data.range.getItems() ) {
    if ( child.is( 'textProxy' ) ) {
        data += child.data;
    }
}

請注意,迭代整個范圍時始終返回TextProxy實例,即使整個Text節點包含在范圍內也是如此。

(您可以閱讀有關在CKEditor5和Angular2中對字符串進行字符串化的更多信息- 在編輯器中單擊內部獲取插入符號的准確位置以獲取數據 。)

請記住, InsertOperation可能會插入多個不同類型的節點。 大多數情況下,這些只是單個字符或元素,但可以提供更多節點。 這就是為什么data沒有額外的data.item或類似屬性的原因。 可能有data.items但那些與Array.from( data.range.getItems() )

Document#change

您之后沒有提到要對此信息做什么。 獲取范圍的內容很簡單,但如果您想以某種方式對這些更改做出反應並更改模型,那么您需要小心。 觸發change事件時,可能已經有更多的更改入隊。 例如:

  • 協作服務可以立即實現更多變更,
  • 一個不同的特征可能已經對同一個變化做出了反應,並將其變化排列在可能使模型不同的變化中。

如果你確切知道你將使用哪些功能,你可能會堅持我的建議。 請記住,您對模型所做的任何更改都應在Document#enqueueChanges()塊中完成(否則,它將不會呈現)。

如果您希望此解決方案具有防彈性,您可能必須這樣做:

  1. 在迭代data.range子節點時,如果找到TextProxy ,則創建跨越該節點的LiveRange
  2. 然后,在enqueueChanges()塊中,迭代存儲的LiveRange並通過它們的子LiveRange
  3. 為每個找到的TextProxy實例執行邏輯。
  4. 記得事后destroy()所有的LiveRange

正如您所看到的,這似乎不必要地復雜化。 提供一個開放靈活的框架(如CKE5)存在一些缺點,並且考慮到所有邊緣情況都是其中之一。 但確實如此,它可能更簡單,這就是我們首先開始重構的原因。

自2018年3月起(從1.0.0-beta.1

1.0.0-beta.1中的重大變化將是模型的引入model.Differ類,改進的事件結構和模型的大部分新API。

首先, Document#event:change在所有enqueueChange塊完成后將觸發Document#event:change 這意味着您不必擔心其他更改是否會影響您在回調中所做出的更改。

此外,將添加engine.Document#registerPostFixer()方法,您將能夠使用它來注冊回調。 change事件仍然可用,但change事件和registerPostFixer之間會略有不同(我們將在指南和文檔中介紹它們)。

其次,您將可以訪問model.Differ實例,該實例將在第一次更改之前的模型狀態與您希望對更改作出反應的時刻的模型狀態之間存儲差異。 您將迭代所有差異項並檢查確切的位置和更改的位置。

除此之外,還將在重構中進行許多其他更改,下面的代碼片段也會反映出來。 所以,在新的世界里,它看起來像這樣:

editor.document.registerPostFixer( writer => {
    const changes = editor.document.differ.getChanges();

    for ( const entry of changes ) {
        if ( entry.type == 'insert' && entry.name == '$text' ) {
            // Use `writer` to do your logic here.
            // `entry` also contains `length` and `position` properties.
        }
    }
} );

在代碼方面,它可能比第一個代碼段更多,但是:

  1. 第一個片段不完整。
  2. 在新方法中要考慮的邊緣情況要少得多。
  3. 新方法更容易掌握 - 在完成所有更改后,您可以使用所有更改,而不是在其他更改排隊時對更改作出反應,並且可能會使模型陷入困境。

writer是一個對象,將用於對模型進行更改(而不是Document#batch API)。 它將包含insertText()insertElement()remove()等方法。

您可以檢查model.Differ API和測試,因為它們已在master分支上可用。 (內部代碼將更改,但API將保持不變。)

@Szymon Cofalik的答案走向了“如何根據變革聽眾應用一些變化”的方向。 這使得它比從Document#change事件中獲取文本所需要的要復雜得多,后者歸結為以下片段:

let data = '';

for ( const child of data.range.getChildren() ) {
    if ( child.is( 'textProxy' ) ) {
        data += child.data;
    }
}

但是,對變化做出反應是一項棘手的任務,因此,如果您打算這樣做,請務必閱讀Szymon的深刻見解。

暫無
暫無

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

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