ckeditor.off-canvas-css-reset.es6.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /**
  2. * @file
  3. * Provides styles for CKEditor inside off-canvas dialogs.
  4. */
  5. (($, CKEDITOR) => {
  6. /**
  7. * Takes a string of CKEditor CSS and modifies it for use in off-canvas.
  8. *
  9. * @param {string} originalCss
  10. * The CSS rules from CKEditor.
  11. * @return {string}
  12. * The rules from originalCss with extra specificity for off-canvas.
  13. */
  14. const convertToOffCanvasCss = originalCss => {
  15. const selectorPrefix = '#drupal-off-canvas ';
  16. const skinPath = `${CKEDITOR.basePath}${CKEDITOR.skinName}/`;
  17. const css = originalCss
  18. .substring(originalCss.indexOf('*/') + 2)
  19. .trim()
  20. .replace(/}/g, `}${selectorPrefix}`)
  21. .replace(/,/g, `,${selectorPrefix}`)
  22. .replace(/url\(/g, skinPath);
  23. return `${selectorPrefix}${css}`;
  24. };
  25. /**
  26. * Inserts CSS rules into DOM.
  27. *
  28. * @param {string} cssToInsert
  29. * CSS rules to be inserted
  30. */
  31. const insertCss = cssToInsert => {
  32. const offCanvasCss = document.createElement('style');
  33. offCanvasCss.innerHTML = cssToInsert;
  34. offCanvasCss.setAttribute('id', 'ckeditor-off-canvas-reset');
  35. document.body.appendChild(offCanvasCss);
  36. };
  37. /**
  38. * Adds CSS so CKEditor is styled properly in off-canvas.
  39. */
  40. const addCkeditorOffCanvasCss = () => {
  41. // If #ckeditor-off-canvas-reset exists, this has already run.
  42. if (document.getElementById('ckeditor-off-canvas-reset')) {
  43. return;
  44. }
  45. // CKEDITOR.skin.getPath() requires the CKEDITOR.skinName property.
  46. // @see https://stackoverflow.com/a/17336982
  47. CKEDITOR.skinName = CKEDITOR.skin.name;
  48. // Get the paths to the css CKEditor is using.
  49. const editorCssPath = CKEDITOR.skin.getPath('editor');
  50. const dialogCssPath = CKEDITOR.skin.getPath('dialog');
  51. // The key for cached CSS in localStorage is based on the CSS paths.
  52. const storedOffCanvasCss = window.localStorage.getItem(
  53. `Drupal.off-canvas.css.${editorCssPath}${dialogCssPath}`,
  54. );
  55. // See if CSS is cached in localStorage, and use that when available.
  56. if (storedOffCanvasCss) {
  57. insertCss(storedOffCanvasCss);
  58. return;
  59. }
  60. // If CSS unavailable in localStorage, get the files via AJAX and parse.
  61. $.when($.get(editorCssPath), $.get(dialogCssPath)).done(
  62. (editorCss, dialogCss) => {
  63. const offCanvasEditorCss = convertToOffCanvasCss(editorCss[0]);
  64. const offCanvasDialogCss = convertToOffCanvasCss(dialogCss[0]);
  65. const cssToInsert = `#drupal-off-canvas .cke_inner * {background: transparent;}
  66. ${offCanvasEditorCss}
  67. ${offCanvasDialogCss}`;
  68. insertCss(cssToInsert);
  69. // The localStorage key for accessing the cached CSS is based on the
  70. // paths of the CKEditor CSS files. This prevents localStorage from
  71. // providing outdated CSS. If new files are used due to using a new
  72. // skin, a new localStorage key is created.
  73. //
  74. // The CSS paths also include the cache-busting query string that is
  75. // stored in state and CKEDITOR.timestamp. This query string changes on
  76. // update and cache clear and prevents localStorage from providing
  77. // stale CKEditor CSS.
  78. //
  79. // Before adding the CSS rules to localStorage, there is a check that
  80. // confirms the cache-busting query (CKEDITOR.timestamp) is in the CSS
  81. // paths. This prevents localStorage from caching something unbustable.
  82. //
  83. // @see ckeditor_library_info_alter()
  84. if (
  85. CKEDITOR.timestamp &&
  86. editorCssPath.indexOf(CKEDITOR.timestamp) !== -1 &&
  87. dialogCssPath.indexOf(CKEDITOR.timestamp) !== -1
  88. ) {
  89. Object.keys(window.localStorage).forEach(key => {
  90. if (key.indexOf('Drupal.off-canvas.css.') === 0) {
  91. window.localStorage.removeItem(key);
  92. }
  93. });
  94. window.localStorage.setItem(
  95. `Drupal.off-canvas.css.${editorCssPath}${dialogCssPath}`,
  96. cssToInsert,
  97. );
  98. }
  99. },
  100. );
  101. };
  102. addCkeditorOffCanvasCss();
  103. })(jQuery, CKEDITOR);