Verified Commit a9ee5c10 authored by Dave Long's avatar Dave Long
Browse files

Issue #3342874 by star-szr, Wim Leers, DamienMcKenna: Allow inline HTML comments in CKEditor 5

(cherry picked from commit 66716dc9)
parent e54a7cec
Loading
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -83,6 +83,17 @@ ckeditor5_style:
    elements:
      - <$any-html5-element class>

ckeditor5_htmlComments:
  ckeditor5:
    plugins:
      - htmlSupport.HtmlComment
  drupal:
    label: HTML Comment support
    elements: false
    library: core/ckeditor5.htmlSupport
    # @see \Drupal\ckeditor5\Plugin\CKEditor5PluginManagerInterface::getEnabledDefinitions()
    conditions: []

ckeditor5_arbitraryHtmlSupport:
  ckeditor5:
    plugins: [htmlSupport.GeneralHtmlSupport]
+1 −1
Original line number Diff line number Diff line
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.drupalHtmlEngine=t())}(globalThis,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,r)=>{e.exports=r("dll-reference CKEditor5.dll")("./src/core.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function r(n){var p=t[n];if(void 0!==p)return p.exports;var s=t[n]={exports:{}};return e[n](s,s.exports,r),s.exports}r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";r.d(n,{default:()=>o});var e=r("ckeditor5/src/core.js");class t{constructor(){this.chunks=[],this.selfClosingTags=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]}build(){return this.chunks.join("")}appendNode(e){e.nodeType===Node.TEXT_NODE?this._appendText(e):e.nodeType===Node.ELEMENT_NODE?this._appendElement(e):e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&this._appendChildren(e)}_appendElement(e){const t=e.nodeName.toLowerCase();this._append("<"),this._append(t),this._appendAttributes(e),this._append(">"),this.selfClosingTags.includes(t)||(this._appendChildren(e),this._append("</"),this._append(t),this._append(">"))}_appendChildren(e){Object.keys(e.childNodes).forEach((t=>{this.appendNode(e.childNodes[t])}))}_appendAttributes(e){Object.keys(e.attributes).forEach((t=>{this._append(" "),this._append(e.attributes[t].name),this._append('="'),this._append(this.constructor._escapeAttribute(e.attributes[t].value)),this._append('"')}))}_appendText(e){const t=document.implementation.createHTMLDocument("").createElement("p");t.textContent=e.textContent,this._append(t.innerHTML)}_append(e){this.chunks.push(e)}static _escapeAttribute(e){return e.replace(/&/g,"&amp;").replace(/'/g,"&apos;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r\n/g,"&#13;").replace(/[\r\n]/g,"&#13;")}}class p{getHtml(e){const r=new t;return r.appendNode(e),r.build()}}class s extends e.Plugin{init(){this.editor.data.processor.htmlWriter=new p}static get pluginName(){return"DrupalHtmlEngine"}}const o={DrupalHtmlEngine:s}})(),n=n.default})()));
 No newline at end of file
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.drupalHtmlEngine=t())}(globalThis,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,n)=>{e.exports=n("dll-reference CKEditor5.dll")("./src/core.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function n(p){var r=t[p];if(void 0!==r)return r.exports;var s=t[p]={exports:{}};return e[p](s,s.exports,n),s.exports}n.d=(e,t)=>{for(var p in t)n.o(t,p)&&!n.o(e,p)&&Object.defineProperty(e,p,{enumerable:!0,get:t[p]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var p={};return(()=>{"use strict";n.d(p,{default:()=>o});var e=n("ckeditor5/src/core.js");class t{constructor(){this.chunks=[],this.selfClosingTags=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]}build(){return this.chunks.join("")}appendNode(e){e.nodeType===Node.TEXT_NODE?this._appendText(e):e.nodeType===Node.ELEMENT_NODE?this._appendElement(e):e.nodeType===Node.DOCUMENT_FRAGMENT_NODE?this._appendChildren(e):e.nodeType===Node.COMMENT_NODE&&this._appendComment(e)}_appendElement(e){const t=e.nodeName.toLowerCase();this._append("<"),this._append(t),this._appendAttributes(e),this._append(">"),this.selfClosingTags.includes(t)||(this._appendChildren(e),this._append("</"),this._append(t),this._append(">"))}_appendChildren(e){Object.keys(e.childNodes).forEach((t=>{this.appendNode(e.childNodes[t])}))}_appendAttributes(e){Object.keys(e.attributes).forEach((t=>{this._append(" "),this._append(e.attributes[t].name),this._append('="'),this._append(this.constructor._escapeAttribute(e.attributes[t].value)),this._append('"')}))}_appendText(e){const t=document.implementation.createHTMLDocument("").createElement("p");t.textContent=e.textContent,this._append(t.innerHTML)}_appendComment(e){this._append("\x3c!--"),this._append(e.textContent),this._append("--\x3e")}_append(e){this.chunks.push(e)}static _escapeAttribute(e){return e.replace(/&/g,"&amp;").replace(/'/g,"&apos;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r\n/g,"&#13;").replace(/[\r\n]/g,"&#13;")}}class r{getHtml(e){const n=new t;return n.appendNode(e),n.build()}}class s extends e.Plugin{init(){this.editor.data.processor.htmlWriter=new r}static get pluginName(){return"DrupalHtmlEngine"}}const o={DrupalHtmlEngine:s}})(),p=p.default})()));
 No newline at end of file
+16 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ export default class DrupalHtmlBuilder {
      this._appendElement(node);
    } else if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
      this._appendChildren(node);
    } else if (node.nodeType === Node.COMMENT_NODE) {
      this._appendComment(node);
    }
  }

@@ -142,6 +144,20 @@ export default class DrupalHtmlBuilder {
    this._append(container.innerHTML);
  }

  /**
   * Appends a comment to the value.
   *
   * @param {DocumentFragment} node
   *  A document fragment to be appended to the value.
   *
   * @private
   */
  _appendComment(node) {
    this._append('<!--');
    this._append(node.textContent);
    this._append('-->');
  }

  /**
   * Appends a string to the value.
   *
+43 −0
Original line number Diff line number Diff line
@@ -745,4 +745,47 @@ public function testFilterHtmlAllowedGlobalAttributes(): void {
    $assert_session->responseContains('<p dir="ltr" lang="en">Hello World</p><p dir="rtl" lang="ar">مرحبا بالعالم</p>');
  }

  /**
   * Ensures that HTML comments are preserved in CKEditor 5.
   */
  public function testComments(): void {
    $page = $this->getSession()->getPage();
    $assert_session = $this->assertSession();

    // Add a node with text rendered via the Plain Text format.
    $this->drupalGet('node/add');
    $page->fillField('title[0][value]', 'My test content');
    $page->fillField('body[0][value]', '<!-- Hamsters, alpacas, llamas, and kittens are cute! --><p>This is a <em>test!</em></p>');
    $page->pressButton('Save');

    FilterFormat::create([
      'format' => 'ckeditor5',
      'name' => 'CKEditor 5 HTML comments test',
      'roles' => [RoleInterface::AUTHENTICATED_ID],
    ])->save();
    Editor::create([
      'format' => 'ckeditor5',
      'editor' => 'ckeditor5',
    ])->save();
    $this->assertSame([], array_map(
      function (ConstraintViolation $v) {
        return (string) $v->getMessage();
      },
      iterator_to_array(CKEditor5::validatePair(
        Editor::load('ckeditor5'),
        FilterFormat::load('ckeditor5')
      ))
    ));

    $this->drupalGet('node/1/edit');
    $page->selectFieldOption('body[0][format]', 'ckeditor5');
    $this->assertNotEmpty($assert_session->waitForText('Change text format?'));
    $page->pressButton('Continue');

    $this->assertNotEmpty($assert_session->waitForElement('css', '.ck-editor'));
    $page->pressButton('Save');

    $assert_session->responseContains('<!-- Hamsters, alpacas, llamas, and kittens are cute! --><p>This is a <em>test!</em></p>');
  }

}
+2 −0
Original line number Diff line number Diff line
@@ -1092,6 +1092,7 @@ public function testEnabledPlugins() {
      'ckeditor5_globalAttributeDir',
      'ckeditor5_globalAttributeLang',
      'ckeditor5_heading',
      'ckeditor5_htmlComments',
      'ckeditor5_paragraph',
      'ckeditor5_pasteFromOffice',
    ];
@@ -1214,6 +1215,7 @@ public function testEnabledPlugins() {
      'ckeditor5_emphasis',
      'ckeditor5_essentials',
      'ckeditor5_heading',
      'ckeditor5_htmlComments',
      'ckeditor5_paragraph',
      'ckeditor5_pasteFromOffice',
    ];
Loading