diff --git a/.travis.yml b/.travis.yml index 386df2727..951bd0c8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,6 @@ jobs: services: - mysql before_script: - - npm install grunt grunt-cli grunt-contrib-jshint grunt-contrib-csslint grunt-phplint --save-dev - mysql -u root -e "CREATE DATABASE rhymix CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci" - mysql -u root -e "GRANT ALL PRIVILEGES ON rhymix.* TO travis@localhost" - mysql -u root -e "SET PASSWORD FOR travis@localhost = PASSWORD('travis'); FLUSH PRIVILEGES" @@ -21,7 +20,7 @@ before_script: - wget https://codeception.com/releases/2.3.9/codecept.phar - php -S localhost:8000 & script: - - grunt lint + - if find . -name "*.php" ! -path "./vendor/*" -print0 | xargs -0 -n 1 -P 8 php -l | grep -v "No syntax errors detected"; then exit 1; fi - php codecept.phar build - php codecept.phar run --debug --fail-fast --env travis notifications: diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 8144ce46e..000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,87 +0,0 @@ -module.exports = function(grunt) { - "use strict"; - - grunt.file.defaultEncoding = 'utf8'; - - grunt.initConfig({ - jshint: { - files: [ - 'Gruntfile.js', - 'common/js/*.js', - 'modules/admin/tpl/js/*.js', - 'modules/board/tpl/js/*.js', - 'modules/board/skins/*/*.js', - 'modules/editor/tpl/js/*.js', - 'modules/menu/tpl/js/*.js', - 'modules/widget/tpl/js/*.js', - ], - options : { - ignores : [ - '**/jquery*.js', - '**/swfupload.js', - '**/**.min.js', - '**/*-packed.js', - '**/*.compressed.js', - '**/jquery-*.js', - '**/jquery.*.js', - 'common/js/html5.js', - 'common/js/x.js', - 'common/js/xe.js', - 'common/js/xml2json.js', - 'common/js/modernizr.js', - 'vendor/**', - 'tests/**', - ] - } - }, - csslint: { - 'common-css': { - options: { - import : 2, - 'adjoining-classes' : false, - 'box-model' : false, - 'box-sizing' : false, - 'font-sizes' : false, - 'duplicate-background-images' : false, - 'order-alphabetical' : false, - 'ids' : false, - 'important' : false, - 'overqualified-elements' : false, - 'qualified-headings' : false, - 'star-property-hack' : false, - 'underscore-property-hack' : false, - }, - src: [ - 'common/css/*.css', - '!common/css/bootstrap.css', - '!common/css/bootstrap-responsive.css', - '!**/*.min.css', - '!vendor/**', - '!tests/**', - ] - } - }, - phplint: { - default : { - options: { - phpCmd: "php", - }, - src: [ - "**/*.php", - "!files/**", - "!tests/**", - "!tools/**", - "!common/libraries/**", - "!vendor/**", - "!tests/_output/**" - ], - }, - } - }); - - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-csslint'); - grunt.loadNpmTasks('grunt-phplint'); - - grunt.registerTask('lint', ['jshint', 'csslint', 'phplint']); -}; diff --git a/common/js/plugins/ckeditor/ckeditor/plugins/ios_enterkey/plugin.js b/common/js/plugins/ckeditor/ckeditor/plugins/ios_enterkey/plugin.js index cb2921cf8..8eaf74580 100644 --- a/common/js/plugins/ckeditor/ckeditor/plugins/ios_enterkey/plugin.js +++ b/common/js/plugins/ckeditor/ckeditor/plugins/ios_enterkey/plugin.js @@ -3,22 +3,124 @@ * * https://github.com/rhymix/rhymix/issues/932 */ -CKEDITOR.plugins.add( 'ios_enterkey', -{ - icons: 'ios_enterkey', - init: function(editor) - { - editor.on('contentDom', function() - { - var editable = editor.editable(); - editable.attachListener(editable, 'keyup', function(e) - { - if(e.data.getKey() === 13) - { - $(editor.document.$).find('.cke_wysiwyg_div').blur(); - $(editor.document.$).find('.cke_wysiwyg_div').focus(); - } - }); - }); - } +CKEDITOR.plugins.add( 'ios_enterkey', { + icons: 'ios_enterkey', + init: function(editor) { + editor.setKeystroke( [ + [ 13, '' ], + [ CKEDITOR.SHIFT + 13, '' ] + ] ); + + editor.on('contentDom', function() { + var selection; + var bookmarks; + var range; + var data; + var shift = false; + + var editable = editor.editable(); + editable.attachListener(editable, 'keyup', function(e) { + + if(e.data.getKey() === 13) { + var eventData = { + dataValue: data + }; + editor.fire( 'afterSetData', eventData ); + + range.moveToBookmark(bookmarks[0]); + range.collapse( true ); + range.select(); + + if(shift) { + shiftEnter(editor); + } else { + enter(editor); + } + + shift = false; + } + }); + + editable.attachListener(editable, 'keydown', function(e) { + if(e.data.getKey() === 13) { + selection = editor.getSelection(); + bookmarks = selection.createBookmarks(true); + data = editor.getData(); + range = selection.getRanges()[0]; + + if(e.data.$.shiftKey) shift = true; + } + }); + }); + + plugin = CKEDITOR.plugins.enterkey; + enterBr = plugin.enterBr; + enterBlock = plugin.enterBlock; + headerTagRegex = /^h[1-6]$/; + + function shiftEnter( editor ) { + // On SHIFT+ENTER: + // 1. We want to enforce the mode to be respected, instead + // of cloning the current block. (https://dev.ckeditor.com/ticket/77) + return enter( editor, editor.activeShiftEnterMode, 1 ); + } + + function enter( editor, mode, forceMode ) { + forceMode = editor.config.forceEnterMode || forceMode; + + // Only effective within document. + if ( editor.mode != 'wysiwyg' ) + return; + + if ( !mode ) + mode = editor.activeEnterMode; + + // TODO this should be handled by setting editor.activeEnterMode on selection change. + // Check path block specialities: + // 1. Cannot be a un-splittable element, e.g. table caption; + var path = editor.elementPath(); + + if ( path && !path.isContextFor( 'p' ) ) { + mode = CKEDITOR.ENTER_BR; + forceMode = 1; + } + + editor.fire( 'saveSnapshot' ); // Save undo step. + + if ( mode == CKEDITOR.ENTER_BR ) + enterBr( editor, mode, null, forceMode ); + else + enterBlock( editor, mode, null, forceMode ); + + editor.fire( 'saveSnapshot' ); + } + + function getRange( editor ) { + // Get the selection ranges. + var ranges = editor.getSelection().getRanges( true ); + + // Delete the contents of all ranges except the first one. + for ( var i = ranges.length - 1; i > 0; i-- ) { + ranges[ i ].deleteContents(); + } + + // Return the first range. + return ranges[ 0 ]; + } + + function replaceRangeWithClosestEditableRoot( range ) { + var closestEditable = range.startContainer.getAscendant( function( node ) { + return node.type == CKEDITOR.NODE_ELEMENT && node.getAttribute( 'contenteditable' ) == 'true'; + }, true ); + + if ( range.root.equals( closestEditable ) ) { + return range; + } else { + var newRange = new CKEDITOR.dom.range( closestEditable ); + + newRange.moveToRange( range ); + return newRange; + } + } + } }); diff --git a/modules/editor/editor.admin.controller.php b/modules/editor/editor.admin.controller.php index 93ed9a511..d7a589956 100644 --- a/modules/editor/editor.admin.controller.php +++ b/modules/editor/editor.admin.controller.php @@ -147,21 +147,25 @@ class editorAdminController extends editor $config = new stdClass; $config->editor_skin = $configVars->editor_skin; + $config->editor_colorset = $configVars->editor_colorset; $config->editor_height = $configVars->editor_height; - $config->mobile_editor_height = $configVars->mobile_editor_height; $config->editor_toolbar = $configVars->editor_toolbar; $config->editor_toolbar_hide = $configVars->editor_toolbar_hide === 'Y' ? 'Y' : 'N'; + $config->mobile_editor_skin = $configVars->mobile_editor_skin; + $config->mobile_editor_colorset = $configVars->mobile_editor_colorset; + $config->mobile_editor_height = $configVars->mobile_editor_height; $config->mobile_editor_toolbar = $configVars->mobile_editor_toolbar; $config->mobile_editor_toolbar_hide = $configVars->mobile_editor_toolbar_hide === 'Y' ? 'Y' : 'N'; $config->comment_editor_skin = $configVars->comment_editor_skin; + $config->comment_editor_colorset = $configVars->comment_editor_colorset; $config->comment_editor_height = $configVars->comment_editor_height; - $config->mobile_comment_editor_height = $configVars->mobile_comment_editor_height; $config->comment_editor_toolbar = $configVars->comment_editor_toolbar; $config->comment_editor_toolbar_hide = $configVars->comment_editor_toolbar_hide === 'Y' ? 'Y' : 'N'; + $config->mobile_comment_editor_skin = $configVars->mobile_comment_editor_skin; + $config->mobile_comment_editor_colorset = $configVars->mobile_comment_editor_colorset; + $config->mobile_comment_editor_height = $configVars->mobile_comment_editor_height; $config->mobile_comment_editor_toolbar = $configVars->mobile_comment_editor_toolbar; $config->mobile_comment_editor_toolbar_hide = $configVars->mobile_comment_editor_toolbar_hide === 'Y' ? 'Y' : 'N'; - $config->sel_editor_colorset = $configVars->sel_editor_colorset; - $config->sel_comment_editor_colorset = $configVars->sel_comment_editor_colorset; if ($configVars->font_defined === 'Y') { diff --git a/modules/editor/editor.admin.view.php b/modules/editor/editor.admin.view.php index 6f800ae24..8edcdde89 100644 --- a/modules/editor/editor.admin.view.php +++ b/modules/editor/editor.admin.view.php @@ -20,16 +20,11 @@ class editorAdminView extends editor */ function dispEditorAdminIndex() { - $component_count = 0; - $site_module_info = Context::get('site_module_info'); - $site_srl = (int)$site_module_info->site_srl; - - // Get a type of component + // Get module config $oEditorModel = getModel('editor'); $oModuleModel = getModel('module'); $editor_config = $oModuleModel->getModuleConfig('editor'); - - if(!$editor_config) + if (!is_object($editor_config)) { $editor_config = new stdClass(); } @@ -42,36 +37,54 @@ class editorAdminView extends editor $editor_config->$key = $val; } } - - $component_list = $oEditorModel->getComponentList(false, $site_srl, true); - $editor_skin_list = FileHandler::readDir(_XE_PATH_.'modules/editor/skins'); - $editor_skin_list = array_filter($editor_skin_list, function($name) { return !starts_with('xpresseditor', $name) && !starts_with('dreditor', $name); }); - - $skin_info = $oModuleModel->loadSkinInfo($this->module_path,$editor_config->editor_skin); - $comment_skin_info = $oModuleModel->loadSkinInfo($this->module_path,$editor_config->comment_editor_skin); - - // Get install info, update info, count - $oAutoinstallModel = getModel('autoinstall'); - foreach($component_list as $component_name => $xml_info) + + // Get skin info + $editor_skin_list = array(); + $skin_dir_list = FileHandler::readDir($this->module_path . 'skins'); + foreach ($skin_dir_list as $skin) + { + if (starts_with('xpresseditor', $skin) || starts_with('dreditor', $skin)) + { + continue; + } + + $skin_info = $oModuleModel->loadSkinInfo($this->module_path, $skin); + foreach ($skin_info->colorset ?: [] as $colorset) + { + unset($colorset->screenshot); + } + $editor_skin_list[$skin] = $skin_info; + } + + // Get editor component info + $oAutoinstallModel = getModel('autoinstall'); + $component_list = $oEditorModel->getComponentList(false, 0, true); + $component_count = count($component_list); + $targetpackages = array(); + foreach ($component_list as $xml_info) { - $component_count++; $xml_info->path = './modules/editor/components/'.$xml_info->component_name; $xml_info->delete_url = $oAutoinstallModel->getRemoveUrlByPath($xml_info->path); $xml_info->package_srl = $oAutoinstallModel->getPackageSrlByPath($xml_info->path); - if($xml_info->package_srl) $targetpackages[$xml_info->package_srl] = 0; + if ($xml_info->package_srl) + { + $targetpackages[$xml_info->package_srl] = 0; + } } - - if(is_array($targetpackages)) $packages = $oAutoinstallModel->getInstalledPackages(array_keys($targetpackages)); - - foreach($component_list as $component_name => $xml_info) + if (count($targetpackages)) { - if($packages[$xml_info->package_srl]) $xml_info->need_update = $packages[$xml_info->package_srl]->need_update; + $packages = $oAutoinstallModel->getInstalledPackages(array_keys($targetpackages)); + } + foreach ($component_list as $xml_info) + { + if ($packages[$xml_info->package_srl]) + { + $xml_info->need_update = $packages[$xml_info->package_srl]->need_update; + } } Context::set('editor_config', $editor_config); Context::set('editor_skin_list', $editor_skin_list); - Context::set('editor_colorset_list', $skin_info->colorset); - Context::set('comment_editor_colorset_list', $comment_skin_info->colorset); Context::set('component_list', $component_list); Context::set('component_count', $component_count); diff --git a/modules/editor/editor.class.php b/modules/editor/editor.class.php index 320ff997d..687db71eb 100644 --- a/modules/editor/editor.class.php +++ b/modules/editor/editor.class.php @@ -23,21 +23,25 @@ class editor extends ModuleObject */ public $default_editor_config = array( 'editor_skin' => 'ckeditor', + 'editor_colorset' => 'moono-lisa', 'editor_height' => 300, 'editor_toolbar' => 'default', 'editor_toolbar_hide' => 'N', + 'mobile_editor_skin' => 'simpleeditor', + 'mobile_editor_colorset' => 'light', 'mobile_editor_height' => 200, 'mobile_editor_toolbar' => 'simple', 'mobile_editor_toolbar_hide' => 'Y', - 'sel_editor_colorset' => 'moono-lisa', 'comment_editor_skin' => 'ckeditor', + 'comment_editor_colorset' => 'moono-lisa', 'comment_editor_height' => 100, 'comment_editor_toolbar' => 'simple', 'comment_editor_toolbar_hide' => 'N', + 'mobile_comment_editor_skin' => 'simpleeditor', + 'mobile_comment_editor_colorset' => 'light', 'mobile_comment_editor_height' => 100, 'mobile_comment_editor_toolbar' => 'simple', 'mobile_comment_editor_toolbar_hide' => 'Y', - 'sel_comment_editor_colorset' => 'moono-lisa', 'content_font' => '', 'content_font_size' => '13px', 'content_line_height' => '160%', diff --git a/modules/editor/editor.controller.php b/modules/editor/editor.controller.php index 45c65f21a..057f623ed 100644 --- a/modules/editor/editor.controller.php +++ b/modules/editor/editor.controller.php @@ -85,8 +85,11 @@ class editorController extends editor */ function procEditorInsertModuleConfig() { + // Get request vars + $vars = Context::getRequestVars(); + // To configure many of modules at once - $target_module_srl = Context::get('target_module_srl'); + $target_module_srl = $vars->target_module_srl; $target_module_srl = array_map('trim', explode(',', $target_module_srl)); $logged_info = Context::get('logged_info'); $module_srl = array(); @@ -110,56 +113,85 @@ class editorController extends editor $module_srl[] = $srl; } - $editor_config = new stdClass; - $editor_config->default_editor_settings = Context::get('default_editor_settings'); - if($editor_config->default_editor_settings !== 'Y') $editor_config->default_editor_settings = 'N'; - $editor_config->editor_skin = Context::get('editor_skin'); - $editor_config->comment_editor_skin = Context::get('comment_editor_skin'); - $editor_config->content_font = Context::get('content_font'); - if($editor_config->content_font) + // Apply default settings? + $config = new stdClass; + $config->default_editor_settings = $vars->default_editor_settings; + if ($config->default_editor_settings !== 'Y') { - $font_list = array(); - $fonts = explode(',',$editor_config->content_font); - for($i=0,$c=count($fonts);$i<$c;$i++) - { - $font = trim(str_replace(array('"','\''),'',$fonts[$i])); - if(!$font) continue; - $font_list[] = $font; - } - if(count($font_list)) $editor_config->content_font = '"'.implode('","',$font_list).'"'; + $config->default_editor_settings = 'N'; } - $editor_config->content_font_size = Context::get('content_font_size'); - $editor_config->sel_editor_colorset = Context::get('sel_editor_colorset'); - $editor_config->sel_comment_editor_colorset = Context::get('sel_comment_editor_colorset'); + + // Apply module-specific editor settings. + $config->editor_skin = $vars->editor_skin; + $config->editor_colorset = $vars->editor_colorset; + $config->editor_height = $vars->editor_height; + $config->editor_toolbar = $vars->editor_toolbar; + $config->editor_toolbar_hide = $vars->editor_toolbar_hide === 'Y' ? 'Y' : 'N'; + $config->mobile_editor_skin = $vars->mobile_editor_skin; + $config->mobile_editor_colorset = $vars->mobile_editor_colorset; + $config->mobile_editor_height = $vars->mobile_editor_height; + $config->mobile_editor_toolbar = $vars->mobile_editor_toolbar; + $config->mobile_editor_toolbar_hide = $vars->mobile_editor_toolbar_hide === 'Y' ? 'Y' : 'N'; + $config->comment_editor_skin = $vars->comment_editor_skin; + $config->comment_editor_colorset = $vars->comment_editor_colorset; + $config->comment_editor_height = $vars->comment_editor_height; + $config->comment_editor_toolbar = $vars->comment_editor_toolbar; + $config->comment_editor_toolbar_hide = $vars->comment_editor_toolbar_hide === 'Y' ? 'Y' : 'N'; + $config->mobile_comment_editor_skin = $vars->mobile_comment_editor_skin; + $config->mobile_comment_editor_colorset = $vars->mobile_comment_editor_colorset; + $config->mobile_comment_editor_height = $vars->mobile_comment_editor_height; + $config->mobile_comment_editor_toolbar = $vars->mobile_comment_editor_toolbar; + $config->mobile_comment_editor_toolbar_hide = $vars->mobile_comment_editor_toolbar_hide === 'Y' ? 'Y' : 'N'; - $grants = array('enable_html_grant','enable_comment_html_grant','upload_file_grant','comment_upload_file_grant','enable_default_component_grant','enable_comment_default_component_grant','enable_component_grant','enable_comment_component_grant'); + if ($vars->font_defined === 'Y') + { + $config->font_defined = 'Y'; + $config->content_font = $vars->content_font_defined; + } + else + { + $config->font_defined = $vars->font_defined = 'N'; + $config->content_font = $vars->content_font; + } + + $config->content_font_size = trim($vars->content_font_size); + $config->enable_autosave = $vars->enable_autosave ?: 'Y'; + $config->allow_html = $vars->allow_html ?: 'Y'; + + // Apply module-specific permissions. + $grants = array( + 'enable_html_grant', + 'enable_comment_html_grant', + 'upload_file_grant', + 'comment_upload_file_grant', + 'enable_default_component_grant', + 'enable_comment_default_component_grant', + 'enable_component_grant', + 'enable_comment_component_grant', + ); foreach($grants as $key) { $grant = Context::get($key); if(!$grant) { - $editor_config->{$key} = array(); + $config->{$key} = array(); } else if(is_array($grant)) { - $editor_config->{$key} = $grant; + $config->{$key} = $grant; } else { - $editor_config->{$key} = explode('|@|', $grant); + $config->{$key} = explode('|@|', $grant); } } - $editor_config->editor_height = (int)Context::get('editor_height'); - $editor_config->comment_editor_height = (int)Context::get('comment_editor_height'); - $editor_config->enable_autosave = Context::get('enable_autosave') ?: 'Y'; - $editor_config->allow_html = Context::get('allow_html') ?: 'Y'; - + // Save settings. $oModuleController = getController('module'); foreach ($module_srl as $srl) { - $oModuleController->insertModulePartConfig('editor', $srl, $editor_config); + $oModuleController->insertModulePartConfig('editor', $srl, $config); } $this->setError(-1); diff --git a/modules/editor/editor.model.php b/modules/editor/editor.model.php index 936434ec5..36e8a8982 100644 --- a/modules/editor/editor.model.php +++ b/modules/editor/editor.model.php @@ -53,7 +53,7 @@ class editorModel extends editor if(!is_array($editor_config->enable_comment_component_grant)) $editor_config->enable_comment_component_grant= array(); // Load the default config for editor module. - $editor_default_config = $oModuleModel->getModuleConfig('editor'); + $editor_default_config = $oModuleModel->getModuleConfig('editor') ?: new stdClass; // Check whether we should use the default config. if($editor_config->default_editor_settings !== 'Y' && $editor_default_config->editor_skin && $editor_config->editor_skin && $editor_default_config->editor_skin !== $editor_config->editor_skin) @@ -122,21 +122,25 @@ class editorModel extends editor { $option->editor_skin = $this->default_editor_config['editor_skin']; } - if (!$option->sel_editor_colorset) + if (!$option->editor_colorset) { - $option->sel_editor_colorset = $option->colorset ?: $this->default_editor_config['sel_editor_colorset']; + $option->editor_colorset = $option->colorset ?: ($option->sel_editor_colorset ?: $this->default_editor_config['editor_colorset']); } if (!$option->editor_height) { $option->editor_height = $option->height ?: $this->default_editor_config['editor_height']; } - if ($option->editor_skin === 'ckeditor' && preg_match('/^(?:white|black)(_text_(?:use|no)html)?$/', $option->sel_editor_colorset)) + if ($option->editor_skin === 'ckeditor' && !in_array($option->editor_colorset, array('moono', 'moono-dark', 'moono-lisa'))) { - $option->sel_editor_colorset = 'moono-lisa'; + $option->editor_colorset = 'moono-lisa'; + } + if ($option->editor_skin === 'simpleeditor' && !in_array($option->editor_colorset, array('light', 'dark'))) + { + $option->editor_colorset = 'light'; } Context::set('skin', $option->editor_skin); Context::set('editor_path', $this->module_path . 'skins/' . $option->editor_skin . '/'); - Context::set('colorset', $option->sel_editor_colorset); + Context::set('colorset', $option->editor_colorset); Context::set('editor_height', $option->editor_height); Context::set('editor_toolbar', $option->editor_toolbar); Context::set('editor_toolbar_hide', toBool($option->editor_toolbar_hide)); @@ -269,6 +273,8 @@ class editorModel extends editor } if ($is_mobile) { + $option->editor_skin = $option->mobile_editor_skin ?: $option->editor_skin; + $option->editor_colorset = $option->mobile_editor_colorset ?: ($option->editor_colorset ?: $option->sel_editor_colorset); $option->editor_height = $option->mobile_editor_height; $option->editor_toolbar = $option->mobile_editor_toolbar; $option->editor_toolbar_hide = $option->mobile_editor_toolbar_hide; @@ -281,18 +287,20 @@ class editorModel extends editor { $option->$key = $val; } - $option->editor_skin = $option->comment_editor_skin; - $option->sel_editor_colorset = $option->sel_comment_editor_colorset; - $option->upload_file_grant = $option->comment_upload_file_grant; - $option->enable_default_component_grant = $option->enable_comment_default_component_grant; - $option->enable_component_grant = $option->enable_comment_component_grant; - $option->enable_html_grant = $option->enable_comment_html_grant; + $option->editor_skin = $option->comment_editor_skin ?: $option->editor_skin; + $option->editor_colorset = $option->comment_editor_colorset ?: ($option->editor_colorset ?: $option->sel_editor_colorset); $option->editor_height = $option->comment_editor_height; $option->editor_toolbar = $option->comment_editor_toolbar; $option->editor_toolbar_hide = $option->comment_editor_toolbar_hide; $option->enable_autosave = 'N'; + $option->upload_file_grant = $option->comment_upload_file_grant; + $option->enable_default_component_grant = $option->enable_comment_default_component_grant; + $option->enable_component_grant = $option->enable_comment_component_grant; + $option->enable_html_grant = $option->enable_comment_html_grant; if ($is_mobile) { + $option->editor_skin = $option->mobile_comment_editor_skin ?: ($option->comment_editor_skin ?: $option->editor_skin); + $option->editor_colorset = $option->mobile_comment_editor_colorset ?: ($option->comment_editor_colorset ?: ($option->editor_colorset ?: $option->sel_editor_colorset)); $option->editor_height = $option->mobile_comment_editor_height; $option->editor_toolbar = $option->mobile_comment_editor_toolbar; $option->editor_toolbar_hide = $option->mobile_comment_editor_toolbar_hide; diff --git a/modules/editor/editor.view.php b/modules/editor/editor.view.php index 648bdd786..dbfc5df7f 100644 --- a/modules/editor/editor.view.php +++ b/modules/editor/editor.view.php @@ -123,23 +123,46 @@ class editorView extends editor $current_module_srl = $current_module_info->module_srl; if(!$current_module_srl) return new BaseObject(); } + // Get editors settings + $oModuleModel = getModel('module'); $oEditorModel = getModel('editor'); $editor_config = $oEditorModel->getEditorConfig($current_module_srl); + if (!is_object($editor_config)) + { + $editor_config = new stdClass(); + } + + // Use default config for missing values. + foreach ($this->default_editor_config as $key => $val) + { + if (!isset($editor_config->$key)) + { + $editor_config->$key = $val; + } + } + + // Get skin info + $editor_skin_list = array(); + $skin_dir_list = FileHandler::readDir($this->module_path . 'skins'); + foreach ($skin_dir_list as $skin) + { + if (starts_with('xpresseditor', $skin) || starts_with('dreditor', $skin)) + { + continue; + } + + $skin_info = $oModuleModel->loadSkinInfo($this->module_path, $skin); + foreach ($skin_info->colorset ?: [] as $colorset) + { + unset($colorset->screenshot); + } + $editor_skin_list[$skin] = $skin_info; + } Context::set('editor_config', $editor_config); - - $oModuleModel = getModel('module'); - // Get a list of editor skin - $editor_skin_list = FileHandler::readDir(_XE_PATH_.'modules/editor/skins'); - $editor_skin_list = array_filter($editor_skin_list, function($name) { return !starts_with('xpresseditor', $name) && !starts_with('dreditor', $name); }); Context::set('editor_skin_list', $editor_skin_list); - - $skin_info = $oModuleModel->loadSkinInfo($this->module_path,$editor_config->editor_skin); - Context::set('editor_colorset_list', $skin_info->colorset); - $skin_info = $oModuleModel->loadSkinInfo($this->module_path,$editor_config->comment_editor_skin); - Context::set('editor_comment_colorset_list', $skin_info->colorset); - + // Get a group list $oMemberModel = getModel('member'); $site_module_info = Context::get('site_module_info'); diff --git a/modules/editor/lang/en.php b/modules/editor/lang/en.php index c13cca566..4c0646238 100644 --- a/modules/editor/lang/en.php +++ b/modules/editor/lang/en.php @@ -2,13 +2,13 @@ $lang->editor_component = 'Editor Component'; $lang->main_editor = 'Main Editor'; $lang->comment_editor = 'Comment Editor'; +$lang->guide_editor_skin = 'Editor Skin'; +$lang->guide_editor_height = 'Height'; +$lang->guide_editor_toolbar = 'Toolbar'; +$lang->editor_toolbar_default = 'Default'; +$lang->editor_toolbar_simple = 'Simple'; +$lang->editor_toolbar_hide = 'Hidden'; $lang->editor_common_settings = 'Common Settings'; -$lang->guide_choose_main_editor = 'Main editor'; -$lang->guide_set_height_main_editor = 'Main editor height'; -$lang->guide_set_main_editor_toolbar = 'Main editor toolbar'; -$lang->guide_choose_comment_editor = 'Comment editor'; -$lang->guide_set_height_comment_editor = 'Comment editor height'; -$lang->guide_set_comment_editor_toolbar = 'Comment editor toolbar'; $lang->guide_additional_css = 'Additional CSS Files'; $lang->about_additional_css = 'To load additional CSS files inside the editor, such as web fonts, please enter one URL per line.'; $lang->guide_additional_mobile_css = 'Additional CSS Files for Mobile'; diff --git a/modules/editor/lang/ko.php b/modules/editor/lang/ko.php index ce81203d4..f74b6731c 100644 --- a/modules/editor/lang/ko.php +++ b/modules/editor/lang/ko.php @@ -3,12 +3,9 @@ $lang->editor_now = '현재 설정 상태'; $lang->editor_component = '에디터 컴포넌트'; $lang->main_editor = '본문 에디터'; $lang->comment_editor = '댓글 에디터'; -$lang->guide_choose_main_editor = '본문 에디터'; -$lang->guide_set_height_main_editor = '본문 에디터 높이'; -$lang->guide_set_main_editor_toolbar = '본문 에디터 도구상자'; -$lang->guide_choose_comment_editor = '댓글 에디터'; -$lang->guide_set_height_comment_editor = '댓글 에디터 높이'; -$lang->guide_set_comment_editor_toolbar = '댓글 에디터 도구상자'; +$lang->guide_editor_skin = '에디터 스킨'; +$lang->guide_editor_height = '높이'; +$lang->guide_editor_toolbar = '도구상자'; $lang->editor_toolbar_default = '기본'; $lang->editor_toolbar_simple = '간단'; $lang->editor_toolbar_hide = '숨김'; diff --git a/modules/editor/skins/ckeditor/editor.html b/modules/editor/skins/ckeditor/editor.html index 7c2a7d319..6f3998975 100644 --- a/modules/editor/skins/ckeditor/editor.html +++ b/modules/editor/skins/ckeditor/editor.html @@ -155,6 +155,7 @@ var auto_saved_msg = "{$lang->msg_auto_saved}"; // https://github.com/rhymix/rhymix/issues/932 if (CKEDITOR.env.iOS) { settings.ckeconfig.extraPlugins = (settings.ckeconfig.extraPlugins ? (settings.ckeconfig.extraPlugins + ',') : '') + 'divarea,ios_enterkey'; + settings.ckeconfig.removePlugins = (settings.ckeconfig.removePlugins ? (settings.ckeconfig.removePlugins + ',') : '') + 'enterkey'; settings.loadXeComponent = false; var additional_styles = '.cke_wysiwyg_div { padding: 8px !important; }'; $('head').append('' + additional_styles + css_content.replace(/\.xe_content\.editable/g, '.cke_wysiwyg_div') + ''); diff --git a/modules/editor/skins/ckeditor/skin.xml b/modules/editor/skins/ckeditor/skin.xml index 210944e74..d928338ed 100644 --- a/modules/editor/skins/ckeditor/skin.xml +++ b/modules/editor/skins/ckeditor/skin.xml @@ -1,6 +1,6 @@ - CKEditor 스킨 + CKEditor CKEditor 1.0.0 2015-02-24 diff --git a/modules/editor/skins/simpleeditor/css/simpleeditor.less b/modules/editor/skins/simpleeditor/css/simpleeditor.less new file mode 100644 index 000000000..cc0e2dd92 --- /dev/null +++ b/modules/editor/skins/simpleeditor/css/simpleeditor.less @@ -0,0 +1,29 @@ +.rx_simpleeditor { + width: 100%; + min-height: 60px; + box-sizing: border-box; + outline: 0 solid transparent; + resize: vertical; + overflow-y: auto; + &.light { + border: 1px solid #c4c4c4; + background: #fff; + padding: 10px; + } + &.dark { + border-color: #111; + background: #333; + color: #fff; + } + iframe { + max-width: 100%; + padding: 5px 0; + } + img { + max-width: 50%; + padding: 5px 0; + } + img.thumbnail { + max-width: 160px; + } +} diff --git a/modules/editor/skins/simpleeditor/editor.html b/modules/editor/skins/simpleeditor/editor.html new file mode 100644 index 000000000..93bf30514 --- /dev/null +++ b/modules/editor/skins/simpleeditor/editor.html @@ -0,0 +1,16 @@ + + + + + +
+
+
+ + + +
diff --git a/modules/editor/skins/simpleeditor/js/interface.js b/modules/editor/skins/simpleeditor/js/interface.js new file mode 100644 index 000000000..754eb5934 --- /dev/null +++ b/modules/editor/skins/simpleeditor/js/interface.js @@ -0,0 +1,16 @@ +function _getSimpleEditorInstance(editor_sequence) { + return jQuery('#simpleeditor_instance_' + editor_sequence); +} + +function editorGetContent(editor_sequence) { + return _getSimpleEditorInstance(editor_sequence).html().escape(); +} + +function editorReplaceHTML(iframe_obj, content) { + var editor_sequence = parseInt(iframe_obj.id.replace(/^.*_/, ''), 10); + _getSimpleEditorInstance(editor_sequence).html(content); +} + +function editorGetIFrame(editor_sequence) { + return _getSimpleEditorInstance(editor_sequence).get(0); +} diff --git a/modules/editor/skins/simpleeditor/js/simpleeditor.js b/modules/editor/skins/simpleeditor/js/simpleeditor.js new file mode 100644 index 000000000..2cfda25b5 --- /dev/null +++ b/modules/editor/skins/simpleeditor/js/simpleeditor.js @@ -0,0 +1,155 @@ +"use strict"; + +(function($) { + + // Save the cursor position. + var ranges = []; + var saveSelection = function() { + var sel = window.getSelection(); + ranges = []; + if (sel.getRangeAt && sel.rangeCount) { + for (let i = 0; i < sel.rangeCount; i++) { + ranges.push(sel.getRangeAt(i)); + } + } + }; + + // Insert content at cursor position. + var insertContent = function(instance, content) { + if (content.match(/<(audio|video)\b[^>]+>(<\/p>)?/)) { + content = content + '


'; + } + if (ranges.length) { + var range = ranges[0]; + range.collapse(false); + ranges = []; + } else { + var range = document.createRange(); + range.selectNodeContents(instance.get(0)); + range.collapse(false); + } + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + if (String(navigator.userAgent).match(/Trident\/7/)) { + range.insertNode(range.createContextualFragment(content)); + range.collapse(false); + } else { + document.execCommand('insertHTML', false, content); + } + }; + + // Simplify HTML content by removing unnecessary tags. + var simplifyContent = function(str) { + str = String(str); + str = str.replace(//gs, ''); + str = str.replace(/<\/?(\?xml|meta|link|font|span|style|script|noscript|frame|noframes|(?:st1|o):[a-z0-9]+)\b[^>]*?>/ig, ''); + str = str.replace(/(id|class|style|on(?:[a-z0-9]+)|Mso(?:[a-z0-9]+))="[^"]*"/ig, ''); + str = str.replace(/(<\/?)div(\W)/g, '$1p$2'); + return str; + }; + + // Convert YouTube links. + var convertYouTube = function(str) { + var regexp = /https?:\/\/(www\.youtube(?:-nocookie)?\.com\/(?:watch\?v=|v\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]+)\S*/g; + var embed = '

'; + return String(str).replace(regexp, embed); + }; + + // Page load event handler. + $(function() { + $('.rx_simpleeditor').each(function() { + + // Load editor info. + var editor = $(this); + var editor_sequence = editor.data('editor-sequence'); + var content_key = editor.data('editor-content-key-name'); + var primary_key = editor.data('editor-primary-key-name'); + var insert_form = editor.closest('form'); + var content_input = insert_form.find('input,textarea').filter('[name=' + content_key + ']'); + var editor_height = editor.data('editor-height'); + if (editor_height) { + editor.css('height', editor_height + 'px'); + } + + // Set editor sequence and other info to the form. + insert_form[0].setAttribute('editor_sequence', editor_sequence); + editorRelKeys[editor_sequence] = {}; + editorRelKeys[editor_sequence].primary = insert_form.find("input[name='" + primary_key + "']"); + editorRelKeys[editor_sequence].content = content_input; + editorRelKeys[editor_sequence].func = editorGetContent; + + // Force

as paragraph separator. + document.execCommand('defaultParagraphSeparator', false, 'p'); + + // Capture some simple keyboard shortcuts. + editor.on('keydown', function(event) { + if (!event.ctrlKey) { + return; + } + var char = String.fromCharCode(event.which).toLowerCase(); + if (char === 'b') { + document.execCommand('bold'); + event.preventDefault(); + } + if (char === 'i') { + document.execCommand('italic'); + event.preventDefault(); + } + if (char === 'u') { + document.execCommand('underline'); + event.preventDefault(); + } + }); + + // Save cursor position on moseup & keyup. + editor.on('mouseup keyup', function() { + saveSelection(); + }); + + // Clean up pasted content. + editor.on('paste', function(event) { + var clipboard_data = (event.clipboardData || window.clipboardData || event.originalEvent.clipboardData); + if (typeof clipboard_data !== 'undefined') { + var content = clipboard_data.getData('text/html'); + if (content === '') { + content = clipboard_data.getData('text'); + } + } else { + return; + } + content = convertYouTube(simplifyContent(content)); + insertContent(editor, content); + event.preventDefault(); + }); + + // Load existing content. + if (content_input.size()) { + editor.html(content_input.val()); + } + + // Copy edited content to the actual input element. + editor.on('input blur mouseup keyup', function() { + var content = simplifyContent(editor.html()); + content_input.val(content); + }); + }); + }); + + // Simulate CKEditor for file upload integration. + window._getCkeInstance = function(editor_sequence) { + var instance = $('#simpleeditor_instance_' + editor_sequence); + return { + getData: function() { + return String(instance.html()); + }, + setData: function(content) { + instance.html(content); + }, + insertHtml: function(content) { + insertContent(instance, content); + } + }; + }; + +})(jQuery); diff --git a/modules/editor/skins/simpleeditor/skin.xml b/modules/editor/skins/simpleeditor/skin.xml new file mode 100644 index 000000000..eca9dd0ad --- /dev/null +++ b/modules/editor/skins/simpleeditor/skin.xml @@ -0,0 +1,15 @@ + + + SimpleEditor + SimpleEditor + 1.0.0 + 2020-07-07 + + + Light + + + Dark + + + diff --git a/modules/editor/tpl/admin_index.html b/modules/editor/tpl/admin_index.html index 75aa7e161..acc5bb6dd 100644 --- a/modules/editor/tpl/admin_index.html +++ b/modules/editor/tpl/admin_index.html @@ -33,41 +33,61 @@

{$lang->main_editor}

- +
- +
- - - -
- -
-
-
- -
-

{$lang->pc} px

-

{$lang->mobile} px

-
-
-
- -
-

{$lang->pc} - - + +

+

+ {$lang->guide_editor_height} + px +

+

+ {$lang->guide_editor_toolbar} +  

-

{$lang->mobile} - - +

+
+
+ +
+

+ + +

+

+ {$lang->guide_editor_height} + px

+

+

+ {$lang->guide_editor_toolbar} +  

@@ -76,40 +96,59 @@

{$lang->comment_editor}

- +
- - - -
- -
-
- -
- -
-

{$lang->pc} px

-

{$lang->mobile} px  

-
-
-
- -
-

{$lang->pc} - - + +

+

+ {$lang->guide_editor_height} + px +

+

+ {$lang->guide_editor_toolbar} +  

-

{$lang->mobile} - - +

+
+
+ +
+

+ + +

+

+ {$lang->guide_editor_height} + px

+

+

+ {$lang->guide_editor_toolbar} +  

@@ -120,10 +159,10 @@
-