8
0

htmlembed.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /* globals window, document */
  6. import sanitizeHtml from 'sanitize-html';
  7. import { clone } from 'lodash-es';
  8. import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
  9. import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
  10. import Code from '@ckeditor/ckeditor5-basic-styles/src/code';
  11. import HtmlEmbed from '../../src/htmlembed';
  12. const previewsModeButton = document.getElementById( 'raw-html-previews-enabled' );
  13. const noPreviewsModeButton = document.getElementById( 'raw-html-previews-disabled' );
  14. previewsModeButton.addEventListener( 'change', handleModeChange );
  15. noPreviewsModeButton.addEventListener( 'change', handleModeChange );
  16. startMode( document.querySelector( 'input[name="mode"]:checked' ).value );
  17. async function handleModeChange( evt ) {
  18. await startMode( evt.target.value );
  19. }
  20. async function startMode( selectedMode ) {
  21. if ( selectedMode === 'enabled' ) {
  22. await startEnabledPreviewsMode();
  23. } else {
  24. await startDisabledPreviewsMode();
  25. }
  26. }
  27. async function startEnabledPreviewsMode() {
  28. await reloadEditor( {
  29. htmlEmbed: {
  30. showPreviews: true,
  31. sanitizeHtml( rawHtml ) {
  32. const config = getSanitizeHtmlConfig( sanitizeHtml.defaults );
  33. const cleanHtml = sanitizeHtml( rawHtml, config );
  34. return {
  35. html: cleanHtml,
  36. hasChanged: rawHtml !== cleanHtml
  37. };
  38. }
  39. }
  40. } );
  41. }
  42. async function startDisabledPreviewsMode() {
  43. await reloadEditor();
  44. }
  45. async function reloadEditor( config = {} ) {
  46. if ( window.editor ) {
  47. await window.editor.destroy();
  48. }
  49. config = Object.assign( config, {
  50. plugins: [ ArticlePluginSet, HtmlEmbed, Code ],
  51. toolbar: [
  52. 'heading', '|', 'bold', 'italic', 'link', '|',
  53. 'bulletedList', 'numberedList', 'blockQuote', 'insertTable', '|',
  54. 'undo', 'redo', '|', 'htmlEmbed'
  55. ],
  56. image: {
  57. toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]
  58. }
  59. } );
  60. window.editor = await ClassicEditor.create( document.querySelector( '#editor' ), config );
  61. }
  62. function getSanitizeHtmlConfig( defaultConfig ) {
  63. const config = clone( defaultConfig );
  64. config.allowedTags.push(
  65. // Allows embedding iframes.
  66. 'iframe',
  67. // Allows embedding media.
  68. 'audio',
  69. 'video',
  70. 'picture',
  71. 'source',
  72. 'img'
  73. );
  74. config.selfClosing.push( 'source' );
  75. // Remove duplicates.
  76. config.allowedTags = [ ...new Set( config.allowedTags ) ];
  77. config.allowedSchemesAppliedToAttributes.push(
  78. // Responsive images.
  79. 'srcset'
  80. );
  81. for ( const htmlTag of config.allowedTags ) {
  82. if ( !Array.isArray( config.allowedAttributes[ htmlTag ] ) ) {
  83. config.allowedAttributes[ htmlTag ] = [];
  84. }
  85. // Allow inlining styles for all elements.
  86. config.allowedAttributes[ htmlTag ].push( 'style' );
  87. }
  88. config.allowedAttributes.audio.push( 'controls' );
  89. config.allowedAttributes.video.push( 'width', 'height', 'controls' );
  90. config.allowedAttributes.iframe.push( 'src' );
  91. config.allowedAttributes.img.push( 'srcset', 'sizes', 'src' );
  92. config.allowedAttributes.source.push( 'src', 'srcset', 'media', 'sizes', 'type' );
  93. return config;
  94. }