|
1 | 1 | <?php
|
| 2 | + |
2 | 3 | /**
|
3 |
| - * @copyright Copyright 2003-2023 Zen Cart Development Team |
| 4 | + * CKEditor 5 |
| 5 | + * |
| 6 | + * Custom config can be set up in /editors/ckeditor5/config.js |
| 7 | + * |
| 8 | + * @copyright Copyright 2003-2024 Zen Cart Development Team |
4 | 9 | * @copyright Portions Copyright 2010 Kuroi Web Design
|
5 | 10 | * @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
|
6 |
| - * @version $Id: Scott C Wilson 2022 Oct 16 Modified in v1.5.8a $ |
| 11 | + * @version $Id: Modified 2024-07-01 $ |
| 12 | + * |
| 13 | + * @var language $lng |
| 14 | + * |
| 15 | + * Ref: https://ckeditor.com/docs/ckeditor5/latest/getting-started/installation/quick-start.html#installing-ckeditor-5-from-cdn |
| 16 | + * Ref: https://github.com/ckeditor/ckeditor5/releases |
7 | 17 | */
|
8 | 18 | if (!defined('IS_ADMIN_FLAG')) {
|
9 |
| - die('Illegal Access'); |
| 19 | + die('Illegal Access'); |
| 20 | +} |
| 21 | + |
| 22 | +// To "upgrade" to a newer version, set the number here. See https://github.com/ckeditor/ckeditor5/releases for latest. |
| 23 | +const CKEDITOR_VERSION = '42.0.0'; |
| 24 | + |
| 25 | + |
| 26 | +// for compatibility with pre-ZC-v2.0.0 where class is PSR-autoloaded |
| 27 | +if (!isset($lng)) { |
| 28 | + if (!class_exists('language')) { |
| 29 | + include(DIR_FS_CATALOG . DIR_WS_CLASSES . 'language.php'); |
| 30 | + } |
| 31 | + $lng = new language; |
10 | 32 | }
|
11 |
| -// prepare list of languages supported by this website, so we can tell CKEditor |
12 |
| -$var = zen_get_languages(); |
13 |
| -$jsLanguageLookupArray = "var lang = new Array;\n"; |
14 |
| -foreach ($var as $key) |
15 |
| -{ |
16 |
| - $jsLanguageLookupArray .= " lang[" . $key['id'] . "] = '" . $key['code'] . "';\n"; |
| 33 | +// Get an array of languages: [1=>'en', 2=>'fr', etc] to match up textarea ID suffix to know which language the editor should use for that field. |
| 34 | +if (method_exists($lng, 'get_language_list')) { |
| 35 | + $langArray = $lng->get_language_list(); |
| 36 | +} else { |
| 37 | + // fallback for compatibility with pre-ZC-v2.0.0 |
| 38 | + $langArray = []; |
| 39 | + foreach ($lng->catalog_languages as $lang) { |
| 40 | + $langArray[$lang['id']] = $lang['code']; |
| 41 | + } |
17 | 42 | }
|
18 | 43 | ?>
|
19 |
| -<script>window.jQuery || document.write('<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"><\/script>');</script> |
20 |
| -<script>window.jQuery || document.write('<script src="includes/javascript/jquery.min.js"><\/script>');</script> |
21 |
| -<script src="https://cdn.ckeditor.com/4.22.1/standard-all/ckeditor.js" title="CKEditorCDN"></script> |
22 |
| - |
23 |
| -<script title="ckEditor-Initialize"> |
24 |
| - jQuery(document).ready(function() { |
25 |
| - <?php echo $jsLanguageLookupArray; ?> |
26 |
| - // Activate on every textarea field that has the editorHook class and does not have the noEditor class |
27 |
| - jQuery('textarea.editorHook').each(function() { |
28 |
| - if (!jQuery(this).hasClass('noEditor')) |
29 |
| - { |
30 |
| - // handle multi-language variants of fields |
31 |
| - index = jQuery(this).attr('name').match(/\d+/); |
32 |
| - if (index == null) index = <?php echo $_SESSION['languages_id'] ?>; |
33 |
| - |
34 |
| - CKEDITOR.replace(jQuery(this).attr('name'), |
35 |
| - { |
36 |
| - customConfig: '<?php echo (function_exists('zen_catalog_base_link') ? zen_catalog_base_link() : '/') . DIR_WS_EDITORS . 'ckeditor/config.js'; ?>', |
37 |
| - language: lang[index] |
38 |
| - }); |
| 44 | + |
| 45 | +<link title="CKEditorCSS" rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/<?= CKEDITOR_VERSION ?>/ckeditor5.css"> |
| 46 | +<style> |
| 47 | + /* for Bootstrap compatibility to prevent interfering with tables */ |
| 48 | + .ck-content .table { |
| 49 | + width: auto; |
| 50 | + } |
| 51 | +</style> |
| 52 | +<script title="CKEditor5CDN" type="importmap"> |
| 53 | + { |
| 54 | + "imports": { |
| 55 | + "ckeditor5": "https://cdn.ckeditor.com/ckeditor5/<?= CKEDITOR_VERSION ?>/ckeditor5.js", |
| 56 | + "ckeditor5/": "https://cdn.ckeditor.com/ckeditor5/<?= CKEDITOR_VERSION ?>/" |
| 57 | + } |
| 58 | + } |
| 59 | +</script> |
| 60 | +<script title="CKEditor-custom-config" src="<?= (function_exists('zen_catalog_base_link') ? zen_catalog_base_link() : '/') . DIR_WS_EDITORS . 'ckeditor5/config.js' ?>"></script> |
| 61 | +<script title="CKEditor-initialize" type="module"> |
| 62 | + const langArray = <?= json_encode($langArray) ?>; |
| 63 | + const defaultLang = '<?= DEFAULT_LANGUAGE ?>'; |
| 64 | + const sessionLangId = '<?= $_SESSION['languages_id'] ?>'; |
| 65 | + const sessionLangCode = '<?= $_SESSION['languages_code'] ?>'; |
| 66 | + |
| 67 | + // Get list of textarea fields that have the editorHook class and do not have the noEditor class |
| 68 | + const editorElements = document.querySelectorAll('.editorHook:not(.noEditor)'); |
| 69 | + |
| 70 | + import { |
| 71 | + Alignment, |
| 72 | + Autoformat, |
| 73 | + AutoImage, |
| 74 | + AutoLink, |
| 75 | + BlockQuote, |
| 76 | + Bold, |
| 77 | + ClassicEditor, |
| 78 | + Clipboard, |
| 79 | + Code, |
| 80 | + CodeBlock, |
| 81 | + Essentials, |
| 82 | + FindAndReplace, |
| 83 | + Font, |
| 84 | + GeneralHtmlSupport, |
| 85 | + Heading, |
| 86 | + HtmlEmbed, |
| 87 | + Image, |
| 88 | + ImageCaption, |
| 89 | + ImageInsert, |
| 90 | + ImageResize, |
| 91 | + ImageStyle, |
| 92 | + ImageToolbar, |
| 93 | + Indent, |
| 94 | + IndentBlock, |
| 95 | + Italic, |
| 96 | + LinkImage, |
| 97 | + List, |
| 98 | + MediaEmbed, |
| 99 | + Paragraph, |
| 100 | + PasteFromMarkdownExperimental, |
| 101 | + PasteFromOffice, |
| 102 | + RemoveFormat, |
| 103 | + SelectAll, |
| 104 | + ShowBlocks, |
| 105 | + SourceEditing, |
| 106 | + SpecialCharacters, |
| 107 | + SpecialCharactersEssentials, |
| 108 | + Strikethrough, |
| 109 | + Style, |
| 110 | + Subscript, |
| 111 | + Superscript, |
| 112 | + Table, |
| 113 | + TableCellProperties, |
| 114 | + TableColumnResize, |
| 115 | + TableProperties, |
| 116 | + TableToolbar, |
| 117 | + TextPartLanguage, |
| 118 | + Underline, |
| 119 | + Undo |
| 120 | + } from 'ckeditor5'; |
| 121 | + |
| 122 | + <?php |
| 123 | + // import translations needed |
| 124 | + foreach ($langArray as $langCode) { |
| 125 | + echo "import " . $langCode . "Translation from 'ckeditor5/translations/" . $langCode . ".js';\n"; |
| 126 | + } |
| 127 | + ?> |
| 128 | + const uiLanguages = { |
| 129 | + <?php |
| 130 | + foreach ($langArray as $langCode) { |
| 131 | + echo '"' . $langCode . '": ' . $langCode . 'Translation,'; |
| 132 | + } |
| 133 | + ?> |
| 134 | + }; |
| 135 | + |
| 136 | + |
| 137 | + const editorConfig = { |
| 138 | + plugins: [ |
| 139 | + Essentials, Font, Bold, Italic, Underline, Strikethrough, Subscript, Superscript, Code, |
| 140 | + Clipboard, PasteFromOffice, Autoformat, PasteFromMarkdownExperimental, FindAndReplace, |
| 141 | + CodeBlock, Heading, Paragraph, Undo, BlockQuote, Indent, IndentBlock, List, SelectAll, |
| 142 | + Alignment, GeneralHtmlSupport, HtmlEmbed, Style, SourceEditing, MediaEmbed, TextPartLanguage, ShowBlocks, |
| 143 | + SpecialCharacters, SpecialCharactersEssentials, RemoveFormat, |
| 144 | + Table, TableToolbar, TableProperties, TableCellProperties, TableColumnResize, |
| 145 | + Image, AutoImage, ImageInsert, ImageToolbar, ImageCaption, ImageStyle, ImageResize, LinkImage |
| 146 | + ], |
| 147 | + toolbar: { |
| 148 | + items: [ |
| 149 | + 'undo', 'redo', 'findAndReplace', |
| 150 | + '|', 'link', 'insertImage', 'mediaEmbed', 'insertTable', |
| 151 | + '|', 'heading', 'fontsize', /* 'fontfamily', */ 'specialCharacters', |
| 152 | + '|', 'showBlocks', |
| 153 | + // 'sourceEditing' may or may not be desired. Do not use if admins might paste content from untrusted sources |
| 154 | + 'sourceEditing', |
| 155 | + // using htmlEmbed poses a security risk: do not use if Admins might paste content from untrusted sources; A sanitizer should be configured if htmlEmbed is enabled. |
| 156 | + // 'htmlEmbed', |
| 157 | + '-', 'bold', 'italic', 'underline', 'strikethrough', |
| 158 | + // 'superscript', 'subscript', |
| 159 | + 'code', |
| 160 | + '|', 'removeFormat', |
| 161 | + '|', 'numberedList', 'bulletedList', 'indent', 'outdent', 'blockQuote', 'alignment', |
| 162 | + '|', 'fontColor', 'fontBackgroundColor', |
| 163 | + ], |
| 164 | + shouldNotGroupWhenFull: true |
| 165 | + }, |
| 166 | + |
| 167 | + image: { |
| 168 | + insert: { |
| 169 | + integrations: ['url'/*, 'upload', 'assetManager'*/], |
| 170 | + |
| 171 | + // If "type" setting is omitted, the editor defaults to 'block'. |
| 172 | + type: 'auto' |
| 173 | + }, |
| 174 | + // image toolbar layout: |
| 175 | + toolbar: [ |
| 176 | + 'imageStyle:block', |
| 177 | + 'imageStyle:side', |
| 178 | + '|', |
| 179 | + 'toggleImageCaption', |
| 180 | + 'imageTextAlternative', |
| 181 | + '|', |
| 182 | + 'linkImage', |
| 183 | + '|', |
| 184 | + 'imageStyle:inline', |
| 185 | + 'imageStyle:block', |
| 186 | + 'imageStyle:wrapText', |
| 187 | + ], |
| 188 | + }, |
| 189 | + |
| 190 | + link: { |
| 191 | + defaultProtocol: 'https://', |
| 192 | + allowedProtocols: [ 'https?', 'tel', 'sms', 'mailto'], |
| 193 | + decorators: { |
| 194 | + openInNewTab: { |
| 195 | + mode: 'manual', |
| 196 | + label: 'Open in a new tab', |
| 197 | + attributes: { |
| 198 | + target: '_blank', |
| 199 | + rel: 'noopener noreferrer' |
| 200 | + } |
| 201 | + } |
| 202 | + } |
| 203 | + }, |
| 204 | + |
| 205 | + table: { |
| 206 | + contentToolbar: [ |
| 207 | + 'tableColumn', 'tableRow', 'mergeTableCells', |
| 208 | + 'tableProperties', 'tableCellProperties', |
| 209 | + ], |
| 210 | + }, |
| 211 | + }; |
| 212 | + |
| 213 | + |
| 214 | +// console.log(editorElements); |
| 215 | + // Loop through the target elements and activate the Editor on each. |
| 216 | + for (const editorElement of editorElements) { |
| 217 | + |
| 218 | + // Determine language to use for this element's content and the UI |
| 219 | + const contentLangCode = langArray[editorElement.name.match(/\d+/) ?? sessionLangId]; |
| 220 | + const langConfig = { |
| 221 | + language: { |
| 222 | + // ui: sessionLangCode, |
| 223 | + content: contentLangCode, |
39 | 224 | }
|
40 |
| - }); |
41 |
| - }); |
| 225 | + }; |
| 226 | + |
| 227 | + const translationsConfig = { |
| 228 | + translations: [ |
| 229 | + uiLanguages[contentLangCode], |
| 230 | + // uiLanguages[sessionLangCode], |
| 231 | + ] |
| 232 | + }; |
| 233 | + |
| 234 | + // In case the override/custom config.js doesn't load or is not present, fallback to empty object. |
| 235 | + let customConfig = {}; |
| 236 | + if (typeof myCKEditorConfig !== 'undefined') { |
| 237 | + customConfig = myCKEditorConfig; |
| 238 | + } |
| 239 | + |
| 240 | + // Combine configs: First use the master config above, then any custom overrides from /editors/ckeditor5/config.js, and then override language for specific fields |
| 241 | + const currentEditorConfig = {...editorConfig, ...translationsConfig, ...customConfig, ...langConfig}; |
| 242 | +//console.log(currentEditorConfig); |
| 243 | + |
| 244 | + // Instantiate this editor instance, before looping to the next one on the page. |
| 245 | + ClassicEditor |
| 246 | + .create(editorElement, currentEditorConfig) |
| 247 | + .then(editor => { |
| 248 | + window.editor = editor; |
| 249 | + }) |
| 250 | + .catch(error => { |
| 251 | + // console.error(error.stack); |
| 252 | + console.error(error); |
| 253 | + }); |
| 254 | + } |
42 | 255 | </script>
|
43 | 256 |
|
44 | 257 | <?php
|
45 |
| -// Other options: |
46 |
| -// - Edit your /editors/ckeditor/config.js file to control the toolbar buttons, add additional plugins, control the UI color, etc |
47 |
| -// |
48 |
| -// Advanced: |
49 |
| -// https://ckeditor.com/docs/ckeditor4/latest/features/styles.html#the-stylesheet-parser-plugin |
50 |
| -// - set custom styles in the /editors/ckeditor/styles.js file |
51 |
| -// - import a template-specific stylesheet from catalog-side, using config.contentsCss setting, so dialogs "look like catalog-side" in admin editor |
| 258 | +// - Edit your /editors/ckeditor5/config.js file to control the toolbar buttons, add additional plugins, etc |
0 commit comments