Commit 28875c2c authored by Tino Goratsch's avatar Tino Goratsch

rework how the CKEditor gets initialized

parent 6de2e735
<?php
/**
* Copyright (c) by the ACP3 Developers.
* See the LICENSE file at the top-level module directory for licensing details.
*/
namespace ACP3\Core\Assets;
use ACP3\Core;
class IncludeJs
{
/**
* @var \ACP3\Core\Assets
*/
private $assets;
/**
* @var \ACP3\Core\Assets\FileResolver
*/
private $fileResolver;
/**
* @var \ACP3\Core\Environment\ApplicationPath
*/
private $appPath;
/**
* @var array
*/
private $alreadyIncluded = [];
/**
* @param \ACP3\Core\Assets $assets
* @param \ACP3\Core\Assets\FileResolver $fileResolver
* @param \ACP3\Core\Environment\ApplicationPath $appPath
*/
public function __construct(
Core\Assets $assets,
Core\Assets\FileResolver $fileResolver,
Core\Environment\ApplicationPath $appPath
) {
$this->assets = $assets;
$this->fileResolver = $fileResolver;
$this->appPath = $appPath;
}
/**
* @param string $module
* @param string $filePath
* @param string[] $dependencies
*
* @return string
*/
public function add(string $module, string $filePath, array $dependencies = []): string
{
if (!empty($dependencies)) {
$this->assets->enableLibraries($dependencies);
}
if ($this->hasValidParams($module, $filePath)) {
$key = $module . '/' . $filePath;
// Do not include the same file multiple times
if (isset($this->alreadyIncluded[$key]) === false) {
$this->alreadyIncluded[$key] = true;
return \sprintf(
'<script defer src="%s"></script>',
$this->resolvePath($module, $filePath) . '?v=' . Core\Application\BootstrapInterface::VERSION
);
}
return '';
}
if (empty($dependencies)) {
throw new \InvalidArgumentException(
'Not all necessary arguments for the function ' . __FUNCTION__ . ' were passed!'
);
}
return '';
}
/**
* @param string $module
* @param string $filePath
*
* @return bool
*/
private function hasValidParams(string $module, string $filePath): bool
{
return isset($module, $filePath) === true
&& (bool) \preg_match('=/=', $module) === false
&& (bool) \preg_match('=\./=', $filePath) === false;
}
/**
* @param string $module
* @param string $filePath
*
* @return string
*/
protected function resolvePath(string $module, string $filePath): string
{
$module = \ucfirst($module);
$path = $this->fileResolver->getStaticAssetPath(
$module . '/Resources/',
$module . '/',
'Assets/js',
$filePath . '.js'
);
if (\strpos($path, '/ACP3/Modules/') !== false) {
$path = $this->appPath->getWebRoot() . \substr($path, \strpos($path, '/ACP3/Modules/') + 1);
} else {
$path = $this->appPath->getWebRoot() . \substr($path, \strlen(ACP3_ROOT_DIR));
}
return $path;
}
}
......@@ -12,104 +12,31 @@ use ACP3\Core;
class IncludeJs extends AbstractFunction
{
/**
* @var \ACP3\Core\Assets
* @var \ACP3\Core\Assets\IncludeJs
*/
protected $assets;
/**
* @var \ACP3\Core\Assets\FileResolver
*/
protected $fileResolver;
/**
* @var \ACP3\Core\Environment\ApplicationPath
*/
protected $appPath;
/**
* @var array
*/
protected $alreadyIncluded = [];
/**
* @param \ACP3\Core\Assets $assets
* @param \ACP3\Core\Assets\FileResolver $fileResolver
* @param \ACP3\Core\Environment\ApplicationPath $appPath
*/
public function __construct(
Core\Assets $assets,
Core\Assets\FileResolver $fileResolver,
Core\Environment\ApplicationPath $appPath
) {
$this->assets = $assets;
$this->fileResolver = $fileResolver;
$this->appPath = $appPath;
}
/**
* {@inheritdoc}
*/
public function __invoke(array $params, \Smarty_Internal_Template $smarty)
{
if (!empty($params['depends'])) {
$this->assets->enableLibraries(\explode(',', $params['depends']));
}
if ($this->hasValidParams($params)) {
$key = $params['module'] . '/' . $params['file'];
// Do not include the same file multiple times
if (isset($this->alreadyIncluded[$key]) === false) {
$this->alreadyIncluded[$key] = true;
return \sprintf(
'<script defer src="%s"></script>',
$this->resolvePath($params) . '?v=' . Core\Application\BootstrapInterface::VERSION
);
}
return '';
}
if (empty($params['depends'])) {
throw new \Exception('Not all necessary arguments for the function ' . __FUNCTION__ . ' were passed!');
}
return '';
}
private $includeJs;
/**
* @param array $params
*
* @return bool
* @param \ACP3\Core\Assets\IncludeJs $includeJs
*/
private function hasValidParams(array $params)
public function __construct(Core\Assets\IncludeJs $includeJs)
{
return isset($params['module'], $params['file']) === true &&
(bool) \preg_match('=/=', $params['module']) === false &&
(bool) \preg_match('=\./=', $params['file']) === false;
$this->includeJs = $includeJs;
}
/**
* @param array $params
* {@inheritdoc}
*
* @return string
* @throws \InvalidArgumentException
*/
protected function resolvePath(array $params)
public function __invoke(array $params, \Smarty_Internal_Template $smarty)
{
$module = \ucfirst($params['module']);
$file = $params['file'];
$path = $this->fileResolver->getStaticAssetPath(
$module . '/Resources/',
$module . '/',
'Assets/js',
$file . '.js'
);
$dependencies = $params['depends'] ?? [];
if (\strpos($path, '/ACP3/Modules/') !== false) {
$path = $this->appPath->getWebRoot() . \substr($path, \strpos($path, '/ACP3/Modules/') + 1);
} else {
$path = $this->appPath->getWebRoot() . \substr($path, \strlen(ACP3_ROOT_DIR));
if (\is_string($dependencies)) {
$dependencies = \explode(',', $dependencies);
}
return $path;
return $this->includeJs->add($params['module'], $params['file'], $dependencies);
}
}
......@@ -52,7 +52,8 @@ services:
smarty.plugin.include_js:
class: ACP3\Core\View\Renderer\Smarty\Functions\IncludeJs
arguments: ['@core.assets', '@core.assets.file_resolver', '@core.environment.application_path']
arguments:
- '@core.assets.include_js'
tags:
- { name: smarty.plugin.function, pluginName: include_js }
......
......@@ -44,6 +44,13 @@ services:
- '@core.environment.theme'
- '@core.modules'
core.assets.include_js:
class: ACP3\Core\Assets\IncludeJs
arguments:
- '@core.assets'
- '@core.assets.file_resolver'
- '@core.environment.application_path'
core.assets.libraries:
class: ACP3\Core\Assets\Libraries
arguments:
......
......@@ -193,12 +193,14 @@
this.replaceContent(hash, responseData);
this.rebindHandlers(hash);
$(document).trigger('acp3.ajaxFrom.complete');
if (typeof hash !== 'undefined') {
window.location.hash = hash;
}
}
} catch (err) {
console.error(err.message);
} catch (e) {
console.error(e);
}
}).fail((jqXHR) => {
if (jqXHR.status === 400) {
......
{event name="core.wysiwyg.`$wysiwyg.friendly_name|lower`.before" id=$wysiwyg.id}
<textarea name="{$wysiwyg.name}" id="{$wysiwyg.id}" cols="60" rows="6" class="form-control">{$wysiwyg.value|escape:'html'}</textarea>
<textarea name="{$wysiwyg.name}"
id="{$wysiwyg.id}"
cols="60"
rows="6"
{if !empty($wysiwyg.data_config)}data-wysiwyg-config='{$wysiwyg.data_config}'{/if}
class="wysiwyg-{$wysiwyg.friendly_name|lower} form-control">{$wysiwyg.value|escape:'html'}</textarea>
{javascripts}
{include file="asset:System/Partials/wysiwyg_config.tpl" js=$wysiwyg.js}
{/javascripts}
......
/*
* Copyright (c) by the ACP3 Developers.
* See the LICENSE file at the top-level module directory for licensing details.
*/
/* global CKEDITOR */
const initializeCKEditorInstances = () => {
jQuery('.wysiwyg-ckeditor').each((index, element) => {
const config = jQuery(element).data('wysiwygConfig');
if (typeof CKEDITOR.instances[element.id] !== 'undefined') {
CKEDITOR.instances[element.id].destroy(true);
}
if (config) {
CKEDITOR.replace(element.id, config);
} else {
CKEDITOR.replace(element.id);
}
});
};
jQuery(document).ready(($) => {
$(document).on('acp3.ajaxFrom.submit.before', () => {
if (typeof CKEDITOR === 'undefined') {
return;
}
for (const instance in CKEDITOR.instances) {
if (!CKEDITOR.instances.hasOwnProperty(instance)) {
return;
}
CKEDITOR.instances[instance].updateElement();
}
});
$(document).on('acp3.ajaxFrom.complete', () => {
initializeCKEditorInstances();
});
initializeCKEditorInstances();
});
"use strict";/*
* Copyright (c) by the ACP3 Developers.
* See the LICENSE file at the top-level module directory for licensing details.
*/ /* global CKEDITOR */var initializeCKEditorInstances=function(){jQuery(".wysiwyg-ckeditor").each(function(a,b){var c=jQuery(b).data("wysiwygConfig");"undefined"!=typeof CKEDITOR.instances[b.id]&&CKEDITOR.instances[b.id].destroy(!0),c?CKEDITOR.replace(b.id,c):CKEDITOR.replace(b.id)})};jQuery(document).ready(function(a){a(document).on("acp3.ajaxFrom.submit.before",function(){if("undefined"!=typeof CKEDITOR)for(var a in CKEDITOR.instances){if(!CKEDITOR.instances.hasOwnProperty(a))return;CKEDITOR.instances[a].updateElement()}}),a(document).on("acp3.ajaxFrom.complete",function(){initializeCKEditorInstances()}),initializeCKEditorInstances()});
\ No newline at end of file
<script defer>
jQuery(document).ready(function ($) {
$(document).on('acp3.ajaxFrom.submit.before', function () {
if (typeof CKEDITOR !== "undefined") {
for (var instance in CKEDITOR.instances) {
CKEDITOR.instances[instance].updateElement();
}
}
});
});
</script>
{include_js module="Wysiwygckeditor" file="partials/ckeditor"}
......@@ -3,6 +3,7 @@ services:
class: ACP3\Modules\ACP3\Wysiwygckeditor\WYSIWYG\Editor\CKEditor
arguments:
- '@core.acl'
- '@core.assets.include_js'
- '@core.modules'
- '@core.i18n.translator'
- '@core.environment.application_path'
......
......@@ -41,24 +41,19 @@ class CKEditor extends Textarea
* @var \ACP3\Core\ACL
*/
private $acl;
/**
* @var \ACP3\Core\Assets\IncludeJs
*/
private $includeJs;
/**
* @var bool
*/
private $isInitialized = false;
/**
* CKEditor constructor.
*
* @param \ACP3\Core\ACL $acl
* @param \ACP3\Core\Modules $modules
* @param \ACP3\Core\I18n\Translator $translator
* @param \ACP3\Core\Environment\ApplicationPath $appPath
* @param \ACP3\Modules\ACP3\Emoticons\Model\Repository\EmoticonRepository|null $emoticonRepository
* @param \ACP3\Modules\ACP3\Filemanager\Helpers|null $filemanagerHelpers
*/
public function __construct(
Core\ACL $acl,
Core\Assets\IncludeJs $includeJs,
Core\Modules $modules,
Core\I18n\Translator $translator,
Core\Environment\ApplicationPath $appPath,
......@@ -71,6 +66,7 @@ class CKEditor extends Textarea
$this->emoticonRepository = $emoticonRepository;
$this->filemanagerHelpers = $filemanagerHelpers;
$this->acl = $acl;
$this->includeJs = $includeJs;
}
/**
......@@ -89,7 +85,7 @@ class CKEditor extends Textarea
parent::setParameters($params);
$this->config['toolbar'] = (isset($params['toolbar']) && $params['toolbar'] === 'simple') ? 'Basic' : 'Full';
$this->config['height'] = (($params['height'] ?? 250)) . 'px';
$this->config['height'] = ($params['height'] ?? 250) . 'px';
}
/**
......@@ -102,8 +98,9 @@ class CKEditor extends Textarea
'id' => $this->id,
'name' => $this->name,
'value' => $this->value,
'js' => $this->editor(),
'js' => $this->init(),
'advanced' => $this->advanced,
'data_config' => $this->configure(),
];
if ($wysiwyg['advanced'] === true) {
......@@ -118,7 +115,7 @@ class CKEditor extends Textarea
*
* @return string
*/
private function configure()
private function configure(): string
{
$this->config['entities'] = false;
$this->config['extraPlugins'] = 'divarea,embed,codemirror';
......@@ -145,7 +142,7 @@ class CKEditor extends Textarea
];
// Full toolbar
if ((!isset($this->config['toolbar']) || $this->config['toolbar'] !== 'Basic')) {
if (!isset($this->config['toolbar']) || $this->config['toolbar'] !== 'Basic') {
$this->configureFullToolbar();
} else { // basic toolbar
$this->configureBasicToolbar();
......@@ -154,37 +151,6 @@ class CKEditor extends Textarea
return \json_encode($this->config);
}
/**
* @return array
*/
private function editor()
{
$out = $this->init();
// Add custom plugins
$ckeditorPluginsDir = $this->appPath->getWebRoot() . 'ACP3/Modules/ACP3/Wysiwygckeditor/Resources/Assets/js/ckeditor/plugins/';
$js = "CKEDITOR.plugins.addExternal('codemirror', '" . $ckeditorPluginsDir . "codemirror/');\n";
$js .= "CKEDITOR.plugins.addExternal('divarea', '" . $ckeditorPluginsDir . "divarea/');\n";
$js .= "CKEDITOR.plugins.addExternal('embedbase', '" . $ckeditorPluginsDir . "embedbase/');\n";
$js .= "CKEDITOR.plugins.addExternal('embed', '" . $ckeditorPluginsDir . "embed/');\n";
$js .= 'CKEDITOR.dtd.$removeEmpty[\'i\'] = false;' . "\n";
$config = $this->configure();
if (!empty($config)) {
$js .= "CKEDITOR.replace('" . $this->id . "', " . $config . ');';
} else {
$js .= "CKEDITOR.replace('" . $this->id . "');";
}
$out .= $this->script($js);
return [
'template' => 'Wysiwygckeditor/ckeditor.tpl',
'config' => $out,
];
}
/**
* Prints javascript code.
*
......@@ -192,7 +158,7 @@ class CKEditor extends Textarea
*
* @return string
*/
private function script($js)
private function script(string $js): string
{
$out = '<script type="text/javascript">';
$out .= $js;
......@@ -204,7 +170,7 @@ class CKEditor extends Textarea
/**
* @return string
*/
private function init()
private function init(): string
{
if ($this->isInitialized === true) {
return '';
......@@ -221,18 +187,29 @@ class CKEditor extends Textarea
$out .= '<script type="text/javascript" src="' . $basePath . "ckeditor.js\"></script>\n";
// Add custom plugins
$ckeditorPluginsDir = $this->appPath->getWebRoot() . 'ACP3/Modules/ACP3/Wysiwygckeditor/Resources/Assets/js/ckeditor/plugins/';
$js = "CKEDITOR.plugins.addExternal('codemirror', '" . $ckeditorPluginsDir . "codemirror/');\n";
$js .= "CKEDITOR.plugins.addExternal('divarea', '" . $ckeditorPluginsDir . "divarea/');\n";
$js .= "CKEDITOR.plugins.addExternal('embedbase', '" . $ckeditorPluginsDir . "embedbase/');\n";
$js .= "CKEDITOR.plugins.addExternal('embed', '" . $ckeditorPluginsDir . "embed/');\n";
$js .= 'CKEDITOR.dtd.$removeEmpty[\'i\'] = false;' . "\n";
$out .= $this->script($js);
$out .= $this->includeJs->add('Wysiwygckeditor', 'partials/ckeditor');
return $out;
}
private function applyEmoticons()
private function applyEmoticons(): void
{
$this->config['smiley_path'] = $this->appPath->getWebRoot() . 'uploads/emoticons/';
$this->config['smiley_images'] = $this->config['smiley_descriptions'] = '';
$emoticons = $this->emoticonRepository->getAll();
$cEmoticons = \count($emoticons);
$images = $descriptions = [];
for ($i = 0; $i < $cEmoticons; ++$i) {
foreach ($emoticons as $i => $emoticon) {
$images[] = $emoticons[$i]['img'];
$descriptions[] = $emoticons[$i]['description'];
}
......@@ -241,7 +218,7 @@ class CKEditor extends Textarea
$this->config['smiley_descriptions'] = $descriptions;
}
private function addFileManager()
private function addFileManager(): void
{
if ($this->filemanagerHelpers === null) {
return;
......@@ -253,7 +230,7 @@ class CKEditor extends Textarea
$this->config['filebrowserBrowseUrl'] = $this->filemanagerHelpers->getFilemanagerPath();
}
private function configureFullToolbar()
private function configureFullToolbar(): void
{
$this->config['extraPlugins'] = 'codemirror,divarea,embedbase,embed';
......@@ -284,7 +261,7 @@ class CKEditor extends Textarea
}
}
private function configureBasicToolbar()
private function configureBasicToolbar(): void
{
$this->config['extraPlugins'] = 'divarea,codemirror';
$this->config['toolbar'] = [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment