From 579201fe7c2aa618ee824ee41844a1f68877fa73 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Tue, 30 Apr 2024 01:42:37 +0900 Subject: [PATCH] Separate editor and uploader related PHP and JS code into their own native files --- .../editor/skins/ckeditor/config.blade.php | 83 ++++++ modules/editor/skins/ckeditor/editor.html | 242 ++---------------- .../editor/skins/ckeditor/file_upload.html | 37 +-- modules/editor/skins/ckeditor/js/editor.js | 162 ++++++++++++ .../editor/skins/ckeditor/js/file_upload.js | 29 +++ 5 files changed, 308 insertions(+), 245 deletions(-) create mode 100644 modules/editor/skins/ckeditor/config.blade.php create mode 100644 modules/editor/skins/ckeditor/js/editor.js create mode 100644 modules/editor/skins/ckeditor/js/file_upload.js diff --git a/modules/editor/skins/ckeditor/config.blade.php b/modules/editor/skins/ckeditor/config.blade.php new file mode 100644 index 000000000..4db6ff2c8 --- /dev/null +++ b/modules/editor/skins/ckeditor/config.blade.php @@ -0,0 +1,83 @@ +@php + +// Basic configuration +$ckconfig = new \stdClass; +$ckconfig->skin = $colorset; +$ckconfig->auto_dark_mode = $editor_auto_dark_mode ?? false; +$ckconfig->legacy_html_mode = $html_mode ?? false; +$ckconfig->language = str_replace('jp', 'ja', Context::getLangType()); +$ckconfig->height = $editor_height ?? 100; +$ckconfig->toolbar = $editor_toolbar ?? 'default'; +$ckconfig->hide_toolbar = $editor_toolbar_hide ?? false; +$ckconfig->focus = $editor_focus ?? false; +$ckconfig->ios_patch = (bool)preg_match('/i(Phone|Pad|Pod)/', $_SERVER['HTTP_USER_AGENT'] ?? ''); + +// Plugin configuration +$ckconfig->add_plugins = $editor_additional_plugins ?? []; +$ckconfig->remove_plugins = $editor_remove_plugins ?? []; +$ckconfig->add_plugins[] = 'rx_upload'; +if ($ckconfig->ios_patch) { + $ckconfig->add_plugins[] = 'divarea'; + $ckconfig->add_plugins[] = 'ios_enterkey'; + $ckconfig->remove_plugins[] = 'enterkey'; +} + +// Font configuration +$ckconfig->default_font = $content_font ?: 'none'; +$ckconfig->default_font_size = intval(preg_replace('/\D/', '', $content_font_size ?? '13'), 10); +$ckconfig->fonts = array_values(array_map('strval', $lang->edit->fontlist ?: [])); +$ckconfig->font_sizes = [8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 24, 28, 32, 36, 40, 48]; +if (!in_array($ckconfig->default_font, $ckconfig->fonts) && $ckconfig->default_font !== 'none') { + array_unshift($ckconfig->fonts, $ckconfig->default_font); +} +if (!in_array($ckconfig->default_font_size, $ckconfig->font_sizes)) { + $ckconfig->font_sizes[] = $ckconfig->default_font_size; + sort($ckconfig->font_sizes); +} +foreach ($ckconfig->fonts as &$_font_name) { + $_font_name = trim(array_first(explode(',', $_font_name, 2))) . '/' . $_font_name; +} +foreach ($ckconfig->font_sizes as &$_font_size) { + $_font_size = $_font_size . '/' . $_font_size . 'px'; +} + +// CSS configuration +$ckconfig->css_files = array_values($editor_additional_css ?: []); +$ckconfig->css_content = ''; +$ckconfig->css_vars = (object)[ + 'colorset' => $colorset, + 'content_font' => $content_font ?: 'none', + 'content_font_size' => $content_font_size ?: '13', + 'content_line_height' => $content_line_height ?: 'none', + 'content_word_break' => $content_word_break ?: 'none', + 'content_paragraph_spacing' => $content_paragraph_spacing ?: 'none', +]; + +// Legacy editor component configuration +$ckconfig->enable_component = $enable_component ?? false; +$ckconfig->enable_default_component = $enable_default_component ?? false; +$ckconfig->components = []; +foreach ($component_list ?? [] as $component_name => $component) { + $ckconfig->components[$component_name] = escape($component->title, false); +} + +// Cache-busting timestamp +$ckconfig->custom_config_exists = file_exists(RX_BASEDIR . 'common/js/plugins/ckeditor/ckeditor/config.js'); +$_filemtime1 = filemtime(RX_BASEDIR . 'common/js/plugins/ckeditor/ckeditor/ckeditor.js'); +$_filemtime2 = $ckconfig->custom_config_exists ? filemtime(RX_BASEDIR . 'common/js/plugins/ckeditor/ckeditor/config.js') : 0; +$ckconfig->timestamp = max($_filemtime1, $_filemtime2, $ckconfig_timestamp ?? 0); + +// Set initial min-height to prevent layout shift when editor is loaded. +if ($editor_toolbar_hide) { + $ckconfig->initial_height = $editor_height + 55; +} elseif ($editor_toolbar === 'simple') { + $ckconfig->initial_height = $editor_height + 71; +} else { + $ckconfig->initial_height = $editor_height + 137; +} + +if (str_contains($_SERVER['HTTP_USER_AGENT'] ?? '', 'Firefox/')) { + $ckconfig->initial_height += 2; +} + +@endphp diff --git a/modules/editor/skins/ckeditor/editor.html b/modules/editor/skins/ckeditor/editor.html index 09a9d95d2..173c3f01a 100644 --- a/modules/editor/skins/ckeditor/editor.html +++ b/modules/editor/skins/ckeditor/editor.html @@ -1,42 +1,17 @@ + + -{@ - $css_var = new stdClass; - $css_var->colorset = $colorset; - $css_var->content_font = $content_font ?: 'none'; - $css_var->content_font_size = $content_font_size ?: 'none'; - $css_var->content_line_height = $content_line_height ?: 'none'; - $css_var->content_word_break = $content_word_break ?: 'none'; - $css_var->content_paragraph_spacing = $content_paragraph_spacing ?: 'none'; + - $css_file_list = array_values($editor_additional_css ?: []); - $css_content = ''; + + + - $filemtime1 = filemtime(RX_BASEDIR . 'common/js/plugins/ckeditor/ckeditor/ckeditor.js'); - $filemtime2 = file_exists(RX_BASEDIR . 'common/js/plugins/ckeditor/ckeditor/config.js') ? filemtime(RX_BASEDIR . 'common/js/plugins/ckeditor/ckeditor/config.js') : 0; - $filemtimestamp = max($filemtime1, $filemtime2, $editor_config_timestamp ?? 0); - - // Start with fixed min-height to prevent layout shift when editor is loaded. - if ($editor_toolbar_hide): - $editor_height_fixed = $editor_height + 55; - elseif ($editor_toolbar === 'simple'): - $editor_height_fixed = $editor_height + 71; - else: - $editor_height_fixed = $editor_height + 137; - endif; - - if (str_contains($_SERVER['HTTP_USER_AGENT'], 'Firefox/')): - $editor_height_fixed += 2; - endif; -} - - - - - - + + - - - + + + -
+ +
+
-

 

+ +

 

+ - - - - - + + + diff --git a/modules/editor/skins/ckeditor/file_upload.html b/modules/editor/skins/ckeditor/file_upload.html index 51f51ec70..4bfd9ac34 100644 --- a/modules/editor/skins/ckeditor/file_upload.html +++ b/modules/editor/skins/ckeditor/file_upload.html @@ -1,10 +1,12 @@ - + + +
diff --git a/modules/editor/skins/ckeditor/js/editor.js b/modules/editor/skins/ckeditor/js/editor.js new file mode 100644 index 000000000..4ecfe4b1f --- /dev/null +++ b/modules/editor/skins/ckeditor/js/editor.js @@ -0,0 +1,162 @@ +'use strict'; + +/** + * Initialize each instance of CKEditor on the page. + */ +$(function() { + $('.rx_ckeditor').each(function() { + + // Load editor configuration. + const container = $(this); + const form = container.closest('form'); + const editor_sequence = parseInt(container.data('editorSequence'), 10); + const config = container.data('editorConfig'); + + // Apply auto dark mode. + if (config.auto_dark_mode) { + $('body').addClass('cke_auto_dark_mode'); + if (getColorScheme() === 'dark') { + if (config.skin !== 'moono-lisa') { + config.skin = 'moono-dark'; + } + } + } + + // If the default font is not set, use the browser default font. + if (config.default_font === 'none' && window.getComputedStyle) { + let test_content = $('
').hide().appendTo($(document.body)); + let test_styles = window.getComputedStyle(test_content[0], null); + if (test_styles && test_styles.getPropertyValue) { + default_font = test_styles.getPropertyValue('font-family'); + if (default_font) { + config.default_font = $.trim(default_font.split(',')[0].replace(/['"]/g, '')); + config.css_content = '.rhymix_content.editable { font-family:' + default_font + '; } ' + config.css_content; + } + } + } + + // Define the initial structure for CKEditor settings. + const settings = { + ckeconfig: { + height: config.height, + skin: config.skin, + contentsCss: config.css_files, + font_defaultLabel: config.default_font, + font_names: config.fonts.join(';'), + fontSize_defaultLabel: config.default_font_size, + fontSize_sizes: config.font_sizes.join(';'), + toolbarStartupExpanded: !config.hide_toolbar, + toolbarCanCollapse: true, + allowedContent: true, + startupFocus: config.focus, + language: config.language, + iframe_attributes: {}, + versionCheck: false, + xe_editor_sequence: editor_sequence + }, + loadXeComponent: true, + enableToolbar: true + }; + + // Add stylesheets from the current document. + $('link[rel=stylesheet]').each(function() { + settings.ckeconfig.contentsCss.push($(this).attr('href')); + }); + + // Add and remove plugins. + if (config.add_plugins) { + settings.ckeconfig.extraPlugins = config.add_plugins.join(','); + } + if (config.remove_plugins) { + settings.ckeconfig.removePlugins = config.remove_plugins.join(','); + } + + // Add editor components. + if (config.enable_component) { + settings.ckeconfig.xe_component_arrays = config.components; + } else { + settings.ckeconfig.xe_component_arrays = {}; + settings.loadXeComponent = false; + } + + if (!config.enable_default_component) { + settings.enableToolbar = false; + settings.ckeconfig.toolbarCanCollapse = false; + } + + // Patch for iOS: https://github.com/rhymix/rhymix/issues/932 + if (config.ios_patch) { + settings.loadXeComponent = false; + $('head').append('' + ); + } + + // Define the simple toolbar. + if (config.toolbar === 'simple') { + settings.ckeconfig.toolbar = [ + { name: 'styles', items: [ 'Font', 'FontSize', '-', 'Bold', 'Italic', 'Underline', 'Strike', 'TextColor', 'BGColor' ] }, + { name: 'paragraph', items: [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight' ] }, + { name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste' ] }, + { name: 'insert', items: [ 'Link', 'Image', 'Table' ] }, + { name: 'tools', items: [ 'Maximize', '-', 'Source' ] } + ]; + } + + // Support legacy HTML (full editing) mode. + if (!config.legacy_html_mode) { + settings.ckeconfig.removeButtons = 'Save,Preview,Print,Cut,Copy,Paste,Source'; + } + + // Disable loading of custom configuration if config.js does not exist. + if (!config.custom_config_exists) { + CKEDITOR.config.customConfig = ''; + } + + // Prevent removal of icon fonts and Google code. + CKEDITOR.dtd.$removeEmpty.i = 0; + CKEDITOR.dtd.$removeEmpty.ins = 0; + + // Set the cache-busting timestamp for plugins. + CKEDITOR.timestamp = config.timestamp; + + // Set the custom CSS content. + CKEDITOR.addCss(config.css_content); + + // Initialize the CKEditor XE app. + const ckeApp = container.XeCkEditor(settings); + + // Add use_editor and use_html fields to the parent form. + const use_editor = form.find('input[name=use_editor]'); + const use_html = form.find('input[name=use_html]'); + if (use_editor.length) { + use_editor.val('Y'); + } else { + form.append(''); + } + if (use_html.length) { + use_html.val('Y'); + } else { + form.append(''); + } + + }); +}); + +/** + * This function is only retained for backward compatibility. + * Do not depend on it for any reason. + */ +function ckInsertUploadedFile() { + if (typeof console == "object" && typeof console.warn == "function") { + const msg = "DEPRECATED : ckInsertUploadedFile() is obsolete in Rhymix."; + if (navigator.userAgent.match(/Firefox/)) { + console.error(msg); + } else { + console.warn(msg); + } + } +} diff --git a/modules/editor/skins/ckeditor/js/file_upload.js b/modules/editor/skins/ckeditor/js/file_upload.js new file mode 100644 index 000000000..f21023af9 --- /dev/null +++ b/modules/editor/skins/ckeditor/js/file_upload.js @@ -0,0 +1,29 @@ +'use strict'; + +/** + * Initialize each instance of file uploader on the page. + */ +$(function() { + $('.xefu-container').each(function() { + const container = $(this); + const data = container.data(); + container.data('instance', container.xeUploader({ + maxFileSize: parseInt(data.maxFileSize, 10), + maxChunkSize: parseInt(data.maxChunkSize, 10), + autoinsertTypes: data.autoinsertTypes, + autoinsertPosition: data.autoinsertPosition, + singleFileUploads: true + })); + }); +}); + +/** + * This function is only retained for backward compatibility. + * Do not depend on it for any reason. + */ +function reloadUploader(editor_sequence) { + var container = $('#xefu-container-' + editor_sequence); + if (container.length) { + container.data('instance').loadFilelist(container); + } +}