From 7c2f728b9b812e8a104d5d4e1cc4f3d7d235d726 Mon Sep 17 00:00:00 2001 From: Florian Bogner <f.bogner@pcsg.de> Date: Mon, 8 May 2017 14:51:05 +0200 Subject: [PATCH] feat: Added dependency management --- ajax/getActivePlugins.php | 11 - ajax/getPluginData.php | 22 ++ bin/Editor.js | 65 +++-- bin/Settings.js | 2 + bin/classes/Settings.js | 12 +- plugins/dependencies.json | 89 ++++++ src/QUI/Ckeditor/Plugins/Manager.php | 390 +++++++++++++++++++-------- 7 files changed, 424 insertions(+), 167 deletions(-) delete mode 100644 ajax/getActivePlugins.php create mode 100644 ajax/getPluginData.php create mode 100644 plugins/dependencies.json diff --git a/ajax/getActivePlugins.php b/ajax/getActivePlugins.php deleted file mode 100644 index 2e261a7..0000000 --- a/ajax/getActivePlugins.php +++ /dev/null @@ -1,11 +0,0 @@ -<?php - -QUI::$Ajax->registerFunction( - 'package_quiqqer_ckeditor4_ajax_getActivePlugins', - function () { - $Manager = new \QUI\Ckeditor\Plugins\Manager(); - - return $Manager->getActivePlugins(); - }, - array() -); diff --git a/ajax/getPluginData.php b/ajax/getPluginData.php new file mode 100644 index 0000000..48c20d0 --- /dev/null +++ b/ajax/getPluginData.php @@ -0,0 +1,22 @@ +<?php + +QUI::$Ajax->registerFunction( + 'package_quiqqer_ckeditor4_ajax_getPluginData', + function () { + $Manager = new \QUI\Ckeditor\Plugins\Manager(); + + // Build the web reachable path for the plugin directory + $pluginPath = QUI::getPackage("quiqqer/ckeditor4")->getVarDir() . "plugins"; + $varParent = dirname(VAR_DIR); + $pluginPath = str_replace($varParent, "", $pluginPath); + + + $data = array( + 'plugins' => $Manager->getActivePlugins(), + 'pluginPath' => $pluginPath + ); + + return $data; + }, + array() +); diff --git a/bin/Editor.js b/bin/Editor.js index dc1db83..1c7786c 100644 --- a/bin/Editor.js +++ b/bin/Editor.js @@ -213,9 +213,21 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ ); - Settings.getPlugins().then(function (plugins) { + Settings.getPluginData().then(function (pluginData) { + var plugins = pluginData.plugins; + var pluginPath = pluginData.pluginPath; + var extraPlugins = plugins.join(","); + + for (var i = 0, len = plugins.length; i < len; i++) { + var pluginName = plugins[i]; + if (!window.CKEDITOR.plugins.get(pluginName)) { + window.CKEDITOR.plugins.addExternal(pluginName, pluginPath + "/bin/" + pluginName + "/", ""); + } + } + + window.CKEDITOR.replace(instance, { skinName : 'moono-lisa', customConfig : '', @@ -265,8 +277,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ this.$onInstanceReadyListener ); } - } - , + }, /** * event : instance ready @@ -290,8 +301,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ this.fireEvent('loaded', [this, instance.editor]); instance.editor.focus(); - } - , + }, /** * event : on resize @@ -302,8 +312,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ containerSize = Container.getSize(); Instance.resize(containerSize.x, containerSize.y); - } - , + }, /** * Editor onSetContent Event @@ -315,8 +324,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ if (Editor.getInstance()) { Editor.getInstance().setData(content); } - } - , + }, /** * Editor onGetContent Event @@ -327,8 +335,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ if (Editor.getInstance()) { Editor.setAttribute('content', Editor.getInstance().getData()); } - } - , + }, /** * Set the focus to the editor @@ -337,8 +344,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ if (this.getInstance()) { this.getInstance().focus(); } - } - , + }, /** * Switch to source mode @@ -347,8 +353,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ if (this.getInstance()) { this.getInstance().setMode('source'); } - } - , + }, /** * Switch to wysiwyg editor @@ -357,8 +362,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ if (this.getInstance()) { this.getInstance().setMode('wysiwyg'); } - } - , + }, /** * Hide the toolbar @@ -369,8 +373,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ if (Toolbar) { Toolbar.setStyle('display', 'none'); } - } - , + }, /** * show the toolbar @@ -381,8 +384,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ if (Toolbar) { Toolbar.setStyle('display', null); } - } - , + }, /** * Set the height of the instance @@ -395,8 +397,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ } this.setAttribute('height', height); - } - , + }, /** * Set the height of the instance @@ -409,8 +410,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ } this.setAttribute('width', width); - } - , + }, /** * event : on add css @@ -433,8 +433,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ Doc.head.appendChild(Link); } - } - , + }, /** * event : on Drop @@ -446,8 +445,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ for (var i = 0, len = params.length; i < len; i++) { Instance.insertHtml("<img src=" + params[i].url + " />"); } - } - , + }, // /** // * Generate the extra plugins option in dependence of the toolbar @@ -683,8 +681,7 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ }; return ev; - } - , + }, /** * edit the link dialog @@ -793,7 +790,5 @@ define('package/quiqqer/ckeditor4/bin/Editor', [ return ev; } - }) - ; -}) -; + }); +}); diff --git a/bin/Settings.js b/bin/Settings.js index 9297e93..9658910 100644 --- a/bin/Settings.js +++ b/bin/Settings.js @@ -1,5 +1,7 @@ define('package/quiqqer/ckeditor4/bin/Settings', [ 'package/quiqqer/ckeditor4/bin/classes/Settings' ], function(Settings) { + "use strict"; + return new Settings(); }); \ No newline at end of file diff --git a/bin/classes/Settings.js b/bin/classes/Settings.js index 2d7d98f..113cbe6 100644 --- a/bin/classes/Settings.js +++ b/bin/classes/Settings.js @@ -12,21 +12,21 @@ define('package/quiqqer/ckeditor4/bin/classes/Settings', [ Extends: QUIDOM, initialize: function () { - this.plugins = null; + this.pluginData = null; }, - getPlugins: function () { + getPluginData: function () { var self = this; - if (this.plugins !== null) { - return Promise.resolve(this.plugins); + if (this.pluginData !== null) { + return Promise.resolve(this.pluginData); } return new Promise(function (resolve, reject) { - QUIAjax.get("package_quiqqer_ckeditor4_ajax_getActivePlugins", function (result) { + QUIAjax.get("package_quiqqer_ckeditor4_ajax_getPluginData", function (result) { - self.plugins = result; + self.pluginData = result; resolve(result); }, { 'package': 'quiqqer/ckeditor4', diff --git a/plugins/dependencies.json b/plugins/dependencies.json new file mode 100644 index 0000000..a322df5 --- /dev/null +++ b/plugins/dependencies.json @@ -0,0 +1,89 @@ +{ + "codesnippetgeshi": [ + "ajax", + "codesnippet" + ], + "autolink": [ + "ajax", + "clipboard" + ], + "widget": [ + "clipboard", + "lineutils", + "widgetselection" + ], + "pastetext": [ + "clipboard" + ], + "notification": [ + "toolbar" + ], + "bbcode": [ + "entities" + ], + "indentlist": [ + "indent" + ], + "list": [ + "indentlist" + ], + "autoembed": [ + "undo", + "autolink" + ], + "dialogui": [ + "dialog" + ], + "link": [ + "fakeobjects", + "dialog" + ], + "colorbutton": [ + "floatpanel", + "panelbutton" + ], + "notificationaggregator": [ + "notification" + ], + "embedbase": [ + "notificationaggregator", + "widget" + ], + "floatpanel": [ + "panel" + ], + "panelbutton": [ + "button" + ], + "codesnippet": [ + "widget", + "embedbase" + ], + "ajax": [ + "xml" + ], + "embed": [ + "embedbase" + ], + "embedsemantic": [ + "embedbase" + ], + "toolbar": [ + "button" + ], + "a11yhelp": [ + "dialog" + ], + "about": [ + "dialog" + ], + "clipboard": [ + "dialog" + ], + "dialogadvtab": [ + "dialog" + ], + "colordialog": [ + "dialog" + ] +} \ No newline at end of file diff --git a/src/QUI/Ckeditor/Plugins/Manager.php b/src/QUI/Ckeditor/Plugins/Manager.php index e6fda09..d9ece8b 100644 --- a/src/QUI/Ckeditor/Plugins/Manager.php +++ b/src/QUI/Ckeditor/Plugins/Manager.php @@ -4,15 +4,32 @@ namespace QUI\Ckeditor\Plugins; use QUI\Exception; +use QUI\System\Log; use QUI\Utils\Security\Orthos; use QUI\Utils\System\File; +/** + * Class Manager + * + * @package QUI\Ckeditor\Plugins + */ class Manager { protected $activePluginDir; protected $installedPluginDir; + protected $dependencies; + + /** + * List of plugins which should be installed + * @var array + */ + protected $blacklist = array( + "divarea", + "copyformatting" + ); + /** * Manager constructor. @@ -32,85 +49,110 @@ class Manager } } + ######################################### + # Installation # + ######################################### + /** - * Activates the given plugin name - * - * @param $pluginName - * - * @throws Exception + * Updates the plugins */ - public function activate($pluginName) + public function updatePlugins() { - $pluginName = Orthos::clearPath($pluginName); - $pluginName = str_replace("/", "", $pluginName); + $srcDirs = array( + OPT_DIR . "ckeditor/ckeditor/plugins", + OPT_DIR . "quiqqer/ckeditor4/plugins/quiqqer", + OPT_DIR . "quiqqer/ckeditor4/plugins/ckeditor4", - if (!is_dir($this->installedPluginDir . "/" . $pluginName)) { - throw new Exception(array("quiqqer/ckeditor4", "exception.plugin.activate.plugin.not.found")); - } + ); - if (is_dir($this->activePluginDir . "/" . $pluginName)) { - throw new Exception(array("quiqqer/ckeditor4", "exception.plugin.already.active")); - } + foreach ($srcDirs as $srcDir) { + if (!is_dir($srcDir)) { + return; + } - rename($this->installedPluginDir . "/" . $pluginName, $this->activePluginDir . "/" . $pluginName); - } - /** - * Deactivates the given plugin name - * - * @param $pluginName - * - * @throws Exception - */ - public function deactivate($pluginName) - { - $pluginName = Orthos::clearPath($pluginName); - $pluginName = str_replace("/", "", $pluginName); + foreach (scandir($srcDir) as $entry) { + if ($entry == "." || $entry == "..") { + continue; + } - if (!is_dir($this->activePluginDir . "/" . $pluginName)) { - throw new Exception(array("quiqqer/ckeditor4", "exception.plugin.activate.plugin.not.active")); - } + if (!is_dir($srcDir . "/" . $entry)) { + continue; + } - if (is_dir($this->installedPluginDir . "/" . $pluginName)) { - File::deleteDir($this->activePluginDir . "/" . $pluginName); + # Check if/where the plugin is installed + $targetDir = $this->installedPluginDir . "/" . $entry; + if (is_dir($this->activePluginDir . "/" . $entry)) { + $targetDir = $this->activePluginDir . "/" . $entry; + } - return; - } + if (is_dir($targetDir)) { + File::deleteDir($targetDir); + } - rename($this->activePluginDir . "/" . $pluginName, $this->installedPluginDir . "/" . $pluginName); + + File::dircopy( + $srcDir . "/" . $entry, + $targetDir + ); + } + } } /** - * Returns a list of all plugins and their details - * Format: - * array( - * [0] => array( - * ["name"] => "pluginname", - * ["state"] => 0|1 (1 for active; 0 for inactive) - * ) - * ) + * Installs the plugins from the source packages quiqqer/ckeditor4 and ckeditor4/ckeditor4 * - * @return array */ - public function getAllPlugins() + public function installPluginsFromSource() { - $result = array(); + $srcDirs = array( + OPT_DIR . "ckeditor/ckeditor/plugins", + OPT_DIR . "quiqqer/ckeditor4/plugins/quiqqer", + OPT_DIR . "quiqqer/ckeditor4/plugins/ckeditor4" - foreach ($this->getActivePlugins() as $plugin) { - $result[] = array( - 'name' => $plugin, - 'state' => 1 - ); + ); + + foreach ($srcDirs as $srcDir) { + $targetDir = $this->installedPluginDir; + + if (!is_dir($srcDir)) { + return; + } + + foreach (scandir($srcDir) as $entry) { + if ($entry == "." || $entry == "..") { + continue; + } + + if (!is_dir($srcDir . "/" . $entry)) { + continue; + } + + if (is_dir($targetDir . "/" . $entry)) { + continue; + } + + if (is_dir($this->activePluginDir . "/" . $entry)) { + continue; + } + + if (in_array($entry, $this->blacklist)) { + continue; + } + + $this->copyDir( + $srcDir . "/" . $entry, + $targetDir . "/" . $entry + ); + } } - foreach ($this->getInstalledPlugins() as $plugin) { - $result[] = array( - 'name' => $plugin, - 'state' => 0 + if (file_exists(OPT_DIR . "quiqqer/ckeditor4/plugins/dependencies.json")) { + copy( + OPT_DIR . "quiqqer/ckeditor4/plugins/dependencies.json", + $this->getPluginDir() . "/dependencies.json" ); } - - return $result; } /** @@ -145,6 +187,76 @@ class Manager return $result; } + ######################################### + # Enable/Disable # + ######################################### + + /** + * Activates the given plugin name + * + * @param $pluginName + * + * @throws Exception + */ + public function activate($pluginName) + { + $pluginName = Orthos::clearPath($pluginName); + $pluginName = str_replace("/", "", $pluginName); + + if (!is_dir($this->installedPluginDir . "/" . $pluginName)) { + throw new Exception(array("quiqqer/ckeditor4", "exception.plugin.activate.plugin.not.found")); + } + + if (is_dir($this->activePluginDir . "/" . $pluginName)) { + throw new Exception(array("quiqqer/ckeditor4", "exception.plugin.already.active")); + } + + $deps = $this->getDependencies($pluginName); + foreach ($deps as $dep) { + try { + $this->activate($dep); + } catch (\Exception $Exception) { + + } + + } + + rename($this->installedPluginDir . "/" . $pluginName, $this->activePluginDir . "/" . $pluginName); + } + + /** + * Deactivates the given plugin name + * + * @param $pluginName + * + * @throws Exception + */ + public function deactivate($pluginName) + { + $pluginName = Orthos::clearPath($pluginName); + $pluginName = str_replace("/", "", $pluginName); + + if (!is_dir($this->activePluginDir . "/" . $pluginName)) { + throw new Exception(array("quiqqer/ckeditor4", "exception.plugin.activate.plugin.not.active")); + } + + if (is_dir($this->installedPluginDir . "/" . $pluginName)) { + File::deleteDir($this->activePluginDir . "/" . $pluginName); + + return; + } + + foreach ($this->getDependentPlugins($pluginName) as $depName) { + try { + $this->deactivate($depName); + } catch (\Exception $Exception) { + } + + } + + rename($this->activePluginDir . "/" . $pluginName, $this->installedPluginDir . "/" . $pluginName); + } + /** * Returns all active plugins * @@ -175,94 +287,142 @@ class Manager return $result; } + ######################################### + # Dependencies # + ######################################### + /** - * Installs the plugins from the source packages quiqqer/ckeditor4 and ckeditor4/ckeditor4 + * Gets all dependencies for the given plugin. + * Including dependencies fo dependencies + * Returns false on error * + * @param $pluginName + * + * @return array|false */ - public function installPluginsFromSource() + public function getDependencies($pluginName) { - $srcDirs = array( - OPT_DIR . "ckeditor/ckeditor/plugins", - OPT_DIR . "quiqqer/ckeditor4/plugins" + try { + $this->loadDependencies(); + } catch (\Exception $Exception) { + return false; + } - ); + $result = array(); - foreach ($srcDirs as $srcDir) { - $targetDir = $this->installedPluginDir; + if (!isset($this->dependencies[$pluginName])) { + return array(); + } - if (!is_dir($srcDir)) { - return; - } + $deps = $this->dependencies[$pluginName]; + foreach ($deps as $dep) { - foreach (scandir($srcDir) as $entry) { - if ($entry == "." || $entry == "..") { - continue; - } + $result[] = $dep; - if (!is_dir($srcDir . "/" . $entry)) { - continue; - } + $subDeps = $this->getDependencies($dep); - if (is_dir($targetDir . "/" . $entry)) { - continue; - } + $result = array_merge($result, $subDeps); + } - if (is_dir($this->activePluginDir . "/" . $entry)) { - continue; - } + $result = array_unique($result); + return $result; + } - $this->copyDir( - $srcDir . "/" . $entry, - $targetDir . "/" . $entry - ); + /** + * Returns an array of packages that depend on the given plugin + * Returns false on error + * + * @param $pluginName + * + * @return array|bool + */ + public function getDependentPlugins($pluginName) + { + $result = array(); + + try { + $this->loadDependencies(); + } catch (\Exception $Exception) { + return false; + } + + + foreach ($this->dependencies as $pkg => $deps) { + + if (in_array($pluginName, $deps)) { + $result[] = $pkg; } } + + $result = array_unique($result); + + return $result; } /** - * Updates the plugins + * Loads the dependencies for the installed modules + * + * @throws Exception */ - public function updatePlugins() + protected function loadDependencies() { - $srcDirs = array( - OPT_DIR . "ckeditor/ckeditor/plugins", - OPT_DIR . "quiqqer/ckeditor4/plugins" + if (isset($this->dependencies) && !empty($this->dependencies)) { + return; + } - ); + if (!file_exists($this->getPluginDir() . "/dependencies.json")) { + Log::addWarning("Missing dependency file: " . $this->getPluginDir() . "/dependencies.json"); - foreach ($srcDirs as $srcDir) { - if (!is_dir($srcDir)) { - return; - } + throw new Exception("missing.dependency.file"); + } + $json = file_get_contents($this->getPluginDir() . "/dependencies.json"); + $deps = json_decode($json, true); - foreach (scandir($srcDir) as $entry) { - if ($entry == "." || $entry == "..") { - continue; - } + if (json_last_error() !== JSON_ERROR_NONE) { + throw new Exception(json_last_error_msg()); + } - if (!is_dir($srcDir . "/" . $entry)) { - continue; - } + $this->dependencies = $deps; - # Check if/where the plugin is installed - $targetDir = $this->installedPluginDir . "/" . $entry; - if (is_dir($this->activePluginDir . "/" . $entry)) { - $targetDir = $this->activePluginDir . "/" . $entry; - } + } - if (is_dir($targetDir)) { - File::deleteDir($targetDir); - } + ######################################### + # Helper # + ######################################### + + /** + * Returns a list of all plugins and their details + * Format: + * array( + * [0] => array( + * ["name"] => "pluginname", + * ["state"] => 0|1 (1 for active; 0 for inactive) + * ) + * ) + * + * @return array + */ + public function getAllPlugins() + { + $result = array(); + foreach ($this->getActivePlugins() as $plugin) { + $result[] = array( + 'name' => $plugin, + 'state' => 1 + ); + } - File::dircopy( - $srcDir . "/" . $entry, - $targetDir - ); - } + foreach ($this->getInstalledPlugins() as $plugin) { + $result[] = array( + 'name' => $plugin, + 'state' => 0 + ); } + + return $result; } /** -- GitLab