From 2650d9ae871d933e789010265e7fed00728394c7 Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Sun, 5 Mar 2023 23:01:56 +0100 Subject: [PATCH] add CSS header tool (experimental) --- src/module/cssheader.php | 274 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 src/module/cssheader.php diff --git a/src/module/cssheader.php b/src/module/cssheader.php new file mode 100644 index 0000000..c660168 --- /dev/null +++ b/src/module/cssheader.php @@ -0,0 +1,274 @@ + Allowed bloc replacement */ + private $bloc_wildcards = [ + '%year%', + '%module_id%', + '%module_name%', + '%module_author%', + '%module_type%', + '%user_cn%', + '%user_name%', + '%user_email%', + '%user_url%', + ]; + + /** @var array Allowed action for header */ + private $action_bloc = []; + + /** @var string Parsed bloc */ + private $bloc = ''; + + /** @var boolean Stop parsing files */ + private $stop_scan = false; + + /** @var string Settings bloc content */ + private $bloc_content = ''; + + protected function init(): bool + { + $this->setProperties([ + 'id' => 'cssheader', + 'name' => __('CSS header'), + 'description' => __('Add or remove phpdoc header bloc from css file'), + 'priority' => 340, + 'configurator' => true, + 'types' => ['plugin', 'theme'], + ]); + + $this->action_bloc = [ + __('Do nothing') => 0, + __('Add bloc if it does not exist') => 'create', + __('Add and overwrite bloc') => 'overwrite', + __('Overwrite bloc only if it exists') => 'replace', + __('Remove existing bloc header') => 'remove', + ]; + + $bloc_content = $this->getSetting('bloc_content'); + $this->bloc_content = is_string($bloc_content) ? $bloc_content : ''; + + return true; + } + + public function isConfigured(): bool + { + return !empty($this->getSetting('bloc_action')); + } + + public function configure($url): ?string + { + if (!empty($_POST['save'])) { + $this->setSettings([ + 'bloc_action' => !empty($_POST['bloc_action']) ? $_POST['bloc_action'] : '', + 'bloc_content' => !empty($_POST['bloc_content']) ? $_POST['bloc_content'] : '', + 'exclude_locales' => !empty($_POST['exclude_locales']), + 'exclude_templates' => !empty($_POST['exclude_templates']), + ]); + $this->redirect($url); + } + + return ' +

' . __('This feature is experimental and not tested yet.') . '

+ +

' . + form::combo('bloc_action', $this->action_bloc, $this->getSetting('bloc_action')) . ' +

+ +

+ +

+ +

' . __('Bloc content:') . '

+

' . + form::textarea('bloc_content', 50, 10, html::escapeHTML($this->bloc_content)) . ' +

' . + sprintf( + __('You can use wildcards %s'), + '%year%, %module_id%, %module_name%, %module_author%, %module_type%, %user_cn%, %user_name%, %user_email%, %user_url%' + ) . '
' . __('Do not put structural elements to the begining of lines.') . '

' . + '

' . __('Exemple') . '

' . self::$exemple . '
'; + } + + public function openModule(): ?bool + { + $bloc = trim($this->bloc_content); + + if (empty($bloc)) { + $this->setWarning(__('bloc is empty')); + + return null; + } + + $bloc = trim(str_replace("\r\n", "\n", $bloc)); + + try { + $this->bloc = (string) preg_replace_callback( + // use \u in bloc content for first_upper_case + '/(\\\u([a-z]{1}))/', + function ($str) { + return ucfirst($str[2]); + }, + str_replace( + $this->bloc_wildcards, + [ + date('Y'), + $this->module['id'], + $this->module['name'], + $this->module['author'], + $this->module['type'], + dcCore::app()->auth->getInfo('user_cn'), + dcCore::app()->auth->getinfo('user_name'), + dcCore::app()->auth->getInfo('user_email'), + dcCore::app()->auth->getInfo('user_url'), + ], + (string) $bloc + ) + ); + $this->setSuccess(__('Prepare header info')); + + return null; + } catch (Exception $e) { + $this->setError(__('Failed to parse bloc')); + + return null; + } + } + + public function openDirectory(): ?bool + { + $skipped = $this->stop_scan; + $this->stop_scan = false; + if (!empty($this->getSetting('exclude_locales')) && preg_match('/\/(locales|libs)(\/.*?|)$/', $this->path_full) + || !empty($this->getSetting('exclude_templates')) && preg_match('/\/(tpl|default-templates)(\/.*?|)$/', $this->path_full) + ) { + if (!$skipped) { + $this->setSuccess(__('Skip directory')); + } + $this->stop_scan = true; + } + + return null; + } + + public function readFile(&$content): ?bool + { + if ($this->stop_scan || $this->path_extension != 'css' || $this->hasError()) { + return null; + } + if (empty($this->getSetting('bloc_action'))) { + return null; + } + $clean = $this->deleteDocBloc($content); + if ($this->getSetting('bloc_action') == 'remove') { + $content = $clean; + + return null; + } + if ($content != $clean && $this->getSetting('bloc_action') == 'create') { + return null; + } + if ($content == $clean && $this->getSetting('bloc_action') == 'replace') { + return null; + } + + $content = $this->writeDocBloc($clean); + + return true; + } + + /** + * Write bloc content in file content + * + * @param string $content Old content + * @return string New content + */ + private function writeDocBloc(string $content): string + { + $res = preg_replace( + '/^(\/\*\*\n \*[\s|\n|\r\n]+)/', + "/**\n * " . str_replace("\n", "\n * ", trim($this->bloc)) . "\n */\n", + $content, + 1, + $count + ); + if ($count && $res) { + $res = str_replace("\n * \n", "\n *\n", $res); + $this->setSuccess(__('Write new doc bloc content')); + } + + return (string) $res; + } + + /** + * Delete bloc content in file content + * + * @param string $content Old content + * @return string New content + */ + private function deleteDocBloc(string $content): string + { + $res = preg_replace( + '/^(\*[\n|\r\n]{0,1}\s\*\/\*\*.*?\s\*\*\/\s\*[\n|\r\n]+)/msi', + '', + $content, + -1, + $count + ); + if ($count) { + $this->setSuccess(__('Delete old doc bloc content')); + } + + return (string) $res; + } +}