diff --git a/_define.php b/_define.php index 7c551c1..5be80aa 100644 --- a/_define.php +++ b/_define.php @@ -10,7 +10,7 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { +if (!defined('DC_RC_PATH') || is_null(dcCore::app()->auth)) { return null; } @@ -22,7 +22,7 @@ $this->registerModule( [ 'requires' => [['core', '2.24']], 'permissions' => dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_CONTENT_ADMIN, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, initTemplator::PERMISSION_TEMPLATOR, ]), 'type' => 'plugin', diff --git a/src/Backend.php b/src/Backend.php index bba762a..8fc1661 100644 --- a/src/Backend.php +++ b/src/Backend.php @@ -10,161 +10,71 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -dcCore::app()->auth->setPermissionType(initTemplator::PERMISSION_TEMPLATOR, __('manage templates')); +namespace Dotclear\Plugin\templator; -dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( - __('Templates engine'), - dcCore::app()->adminurl->get('admin.plugin.templator'), - urldecode(dcPage::getPF('templator/icon.png')), - preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.templator')) . '(&.*)?$/', $_SERVER['REQUEST_URI']), - dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_CONTENT_ADMIN, - initTemplator::PERMISSION_TEMPLATOR, - ]), dcCore::app()->blog->id) -); +use dcAdmin; +use dcCore; +use dcMenu; +use dcNsProcess; +use dcPage; -if (dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_CONTENT_ADMIN, - initTemplator::PERMISSION_TEMPLATOR, -]), dcCore::app()->blog->id)) { - dcCore::app()->addBehavior('adminPostHeaders', ['templatorBehaviors','adminPostHeaders']); - dcCore::app()->addBehavior('adminPostFormItems', ['templatorBehaviors','adminPostFormItems']); - dcCore::app()->addBehavior('adminPageHeaders', ['templatorBehaviors','adminPostHeaders']); - dcCore::app()->addBehavior('adminPageFormItems', ['templatorBehaviors','adminPostFormItems']); - - dcCore::app()->addBehavior('adminAfterPostCreate', ['templatorBehaviors','adminBeforePostUpdate']); - dcCore::app()->addBehavior('adminBeforePostUpdate', ['templatorBehaviors','adminBeforePostUpdate']); - dcCore::app()->addBehavior('adminAfterPageCreate', ['templatorBehaviors','adminBeforePostUpdate']); - dcCore::app()->addBehavior('adminBeforePageUpdate', ['templatorBehaviors','adminBeforePostUpdate']); - - dcCore::app()->addBehavior('adminPostsActions', ['templatorBehaviors','adminPostsActions']); - dcCore::app()->addBehavior('adminPagesActions', ['templatorBehaviors','adminPostsActions']); - - dcCore::app()->addBehavior('adminFiltersListsV2', function (ArrayObject $sorts) { - $sorts['templator'] = [ - __('Templates engine'), - [ - __('Date') => 'post_upddt', - __('Title') => 'post_title', - __('Category') => 'cat_id', - ], - 'post_upddt', - 'desc', - [__('Entries per page'), 30], - ]; - }); -} - -class templatorBehaviors +class Backend extends dcNsProcess { - public static function adminPostHeaders() + public static function init(): bool { - return dcPage::jsLoad(dcPage::getPF('templator/js/admin.js')); + static::$init == defined('DC_CONTEXT_ADMIN') + && My::phpCompliant() + && !is_null(dcCore::app()->blog) && !is_null(dcCore::app()->auth) + && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + My::PERMISSION_TEMPLATOR, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog->id); + + return static::$init; } - public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, $post) + public static function process(): bool { - $selected = ''; - - if ($post) { - $post_meta = dcCore::app()->meta->getMetadata(['meta_type' => 'template', 'post_id' => $post->post_id]); - $selected = $post_meta->isEmpty() ? '' : $post_meta->meta_id; + if (!static::$init) { + return false; } - $sidebar_items['options-box']['items']['templator'] = '
' . - '
' . __('Template') . '
' . - '

' . - form::combo('post_tpl', self::getTemplateCombo(), $selected) . '

' . - '
'; - } - - public static function adminBeforePostUpdate($cur, $post_id) - { - $post_id = (int) $post_id; - - if (isset($_POST['post_tpl'])) { - dcCore::app()->meta->delPostMeta($post_id, 'template'); - if (!empty($_POST['post_tpl'])) { - dcCore::app()->meta->setPostMeta($post_id, 'template', $_POST['post_tpl']); - } - } - } - - public static function adminPostsActions(dcPostsActions $pa) - { - $pa->addAction( - [ - __('Appearance') => [ - __('Select the template') => 'tpl', - ], - ], - ['templatorBehaviors', 'adminPostsActionsCallback'] - ); - } - - public static function adminPostsActionsCallback(dcPostsActions $pa, ArrayObject $post) - { - # No entry - $posts_ids = $pa->getIDs(); - if (empty($posts_ids)) { - throw new Exception(__('No entry selected')); + // nullsafe + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) { + return false; } - if (isset($post['post_tpl'])) { - try { - foreach ($posts_ids as $post_id) { - dcCore::app()->meta->delPostMeta($post_id, 'template'); - if (!empty($post['post_tpl'])) { - dcCore::app()->meta->setPostMeta($post_id, 'template', $post['post_tpl']); - } - } - - dcAdminNotices::addSuccessNotice(__('Entries template updated.')); - $pa->redirect(true); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } + //backend sidebar menu icon + if ((dcCore::app()->menu[dcAdmin::MENU_PLUGINS] instanceof dcMenu)) { + dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( + My::name(), + dcCore::app()->adminurl->get('admin.plugin.' . My::id()), + urldecode(dcPage::getPF(My::id() . '/icon.png')), + preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . My::id())) . '(&.*)?$/', $_SERVER['REQUEST_URI']), + dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + My::PERMISSION_TEMPLATOR, + ]), dcCore::app()->blog->id) + ); } - $pa->beginPage( - dcPage::breadcrumb([ - html::escapeHTML(dcCore::app()->blog->name) => '', - $pa->getCallerTitle() => $pa->getRedirection(true), - __('Entry template') => '', - ]) - ); + dcCore::app()->addBehaviors([ + 'adminPostHeaders' => [BackendBehaviors::class,'adminPostHeaders'], + 'adminPostFormItems' => [BackendBehaviors::class,'adminPostFormItems'], + 'adminPageHeaders' => [BackendBehaviors::class,'adminPostHeaders'], + 'adminPageFormItems' => [BackendBehaviors::class,'adminPostFormItems'], + 'adminAfterPostCreate' => [BackendBehaviors::class,'adminBeforePostUpdate'], + 'adminBeforePostUpdate' => [BackendBehaviors::class,'adminBeforePostUpdate'], + 'adminAfterPageCreate' => [BackendBehaviors::class,'adminBeforePostUpdate'], + 'adminBeforePageUpdate' => [BackendBehaviors::class,'adminBeforePostUpdate'], + 'adminPostsActions' => [BackendBehaviors::class,'adminPostsActions'], + 'adminPagesActions' => [BackendBehaviors::class,'adminPostsActions'], + 'adminFiltersListsV2' => [BackendBehaviors::class, 'adminFiltersListsV2'], + 'initWidgets' => [Widgets::class, 'initWidgets'], + ]); - echo - '

' . __('Select template for the selection') . '

' . - '
' . - $pa->getCheckboxes() . - '

' . - form::combo('post_tpl', self::getTemplateCombo()) . '

' . - - '

' . - $pa->getHiddenFields() . - dcCore::app()->formNonce() . - form::hidden(['action'], 'tpl') . - '

' . - '
'; - - $pa->endPage(); - } - - private static function getTemplateCombo() - { - $tpl = [__('No specific template') => '']; - - foreach (dcCore::app()->templator->tpl as $k => $v) { - if (!preg_match('/^category-(.+)$/', $k) && !preg_match('/^list-(.+)$/', $k)) { - $tpl[$k] = $k; - } - } - - return $tpl; + return true; } } diff --git a/src/BackendBehaviors.php b/src/BackendBehaviors.php new file mode 100644 index 0000000..e647143 --- /dev/null +++ b/src/BackendBehaviors.php @@ -0,0 +1,157 @@ +meta->getMetadata(['meta_type' => 'template', 'post_id' => $post->f('post_id')]); + $selected = $post_meta->isEmpty() ? '' : $post_meta->f('meta_id'); + } + + $sidebar_items['options-box']['items']['templator'] = '
' . + '
' . __('Template') . '
' . + '

' . + form::combo('post_tpl', self::getTemplateCombo(), $selected) . '

' . + '
'; + } + + public static function adminBeforePostUpdate(Cursor $cur, string|int $post_id): void + { + $post_id = (int) $post_id; + + if (isset($_POST['post_tpl'])) { + dcCore::app()->meta->delPostMeta($post_id, 'template'); + if (!empty($_POST['post_tpl'])) { + dcCore::app()->meta->setPostMeta($post_id, 'template', $_POST['post_tpl']); + } + } + } + + public static function adminPostsActions(dcPostsActions $pa): void + { + $pa->addAction( + [ + __('Appearance') => [ + __('Select the template') => 'tpl', + ], + ], + ['templatorBehaviors', 'adminPostsActionsCallback'] + ); + } + + public static function adminPostsActionsCallback(dcPostsActions $pa, ArrayObject $post): void + { + # No entry + $posts_ids = $pa->getIDs(); + if (empty($posts_ids)) { + $pa->error(new Exception(__('No entry selected'))); + + return; + } + + if (isset($post['post_tpl']) && is_string($post['post_tpl'])) { + try { + foreach ($posts_ids as $post_id) { + dcCore::app()->meta->delPostMeta($post_id, 'template'); + if (!empty($post['post_tpl'])) { + dcCore::app()->meta->setPostMeta($post_id, 'template', $post['post_tpl']); + } + } + + dcPage::addSuccessNotice(__('Entries template updated.')); + $pa->redirect(true); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + } + + $pa->beginPage( + dcPage::breadcrumb([ + Html::escapeHTML((string) dcCore::app()->blog?->name) => '', + $pa->getCallerTitle() => $pa->getRedirection(true), + __('Entry template') => '', + ]) + ); + + echo + '

' . __('Select template for the selection') . '

' . + '
' . + $pa->getCheckboxes() . + '

' . + form::combo('post_tpl', self::getTemplateCombo()) . '

' . + + '

' . + $pa->getHiddenFields() . + dcCore::app()->formNonce() . + form::hidden(['action'], 'tpl') . + '

' . + '
'; + + $pa->endPage(); + } + + public static function adminFiltersListsV2(ArrayObject $sorts): void + { + $sorts['templator'] = [ + __('Templates engine'), + [ + __('Date') => 'post_upddt', + __('Title') => 'post_title', + __('Category') => 'cat_id', + ], + 'post_upddt', + 'desc', + [__('Entries per page'), 30], + ]; + } + + /** + * @return array + */ + private static function getTemplateCombo(): array + { + $tpl = [__('No specific template') => '']; + + $tpls = Templator::instance()->getTpl(); + foreach ($tpls as $k => $v) { + if (!preg_match('/^category-(.+)$/', $k) && !preg_match('/^list-(.+)$/', $k)) { + $tpl[$k] = $k; + } + } + + return $tpl; + } +} diff --git a/src/Frontend.php b/src/Frontend.php index 464cb32..525936e 100644 --- a/src/Frontend.php +++ b/src/Frontend.php @@ -10,33 +10,69 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return null; -} +declare(strict_types=1); -dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), dcCore::app()->templator->path); -dcCore::app()->addBehavior('urlHandlerBeforeGetData', ['publicTemplatorBehaviors','BeforeGetData']); +namespace Dotclear\Plugin\templator; -class publicTemplatorBehaviors +use dcCore; +use dcNsProcess; +use Dotclear\Database\MetaRecord; + +/** + * Frontend prepend. + */ +class Frontend extends dcNsProcess { - public static function BeforeGetData($_) + public static function init(): bool { - if (array_key_exists(dcCore::app()->url->type, dcCore::app()->getPostTypes()) || dcCore::app()->url->type == 'pages') { - $params = []; - $params['meta_type'] = 'template'; - $params['post_id'] = dcCore::app()->ctx->posts->post_id; - $post_meta = dcCore::app()->meta->getMetadata($params); + static::$init = My::phpCompliant(); - if (!$post_meta->isEmpty() && dcCore::app()->tpl->getFilePath($post_meta->meta_id)) { - dcCore::app()->ctx->current_tpl = $post_meta->meta_id; - } + return static::$init; + } + + public static function process(): bool + { + if (!static::$init) { + return false; } - if (dcCore::app()->ctx->current_tpl == 'category.html' && preg_match('/^[0-9]{1,}/', dcCore::app()->ctx->categories->cat_id, $cat_id)) { - $tpl = 'category-' . $cat_id[0] . '.html'; - if (dcCore::app()->tpl->getFilePath($tpl)) { - dcCore::app()->ctx->current_tpl = $tpl; - } - } + dcCore::app()->tpl->setPath( + dcCore::app()->tpl->getPath(), + Templator::instance()->getPath() + ); + + dcCore::app()->addBehaviors([ + 'urlHandlerBeforeGetData' => function ($_): void { + if (is_null(dcCore::app()->ctx)) { + return; + } + + if ((dcCore::app()->ctx->__get('posts') instanceof MetaRecord) + && (array_key_exists(dcCore::app()->url->type, dcCore::app()->getPostTypes()) || dcCore::app()->url->type == 'pages')) { + $params = []; + $params['meta_type'] = 'template'; + $params['post_id'] = dcCore::app()->ctx->__get('posts')->f('post_id'); + $post_meta = dcCore::app()->meta->getMetadata($params); + + if (!$post_meta->isEmpty() && is_string($post_meta->f('meta_id')) && dcCore::app()->tpl->getFilePath($post_meta->f('meta_id'))) { + dcCore::app()->ctx->__set('current_tpl', $post_meta->f('meta_id')); + } + } + + if (dcCore::app()->ctx->__get('current_tpl') == 'category.html' + && (dcCore::app()->ctx->__get('categories') instanceof MetaRecord) + && is_string(dcCore::app()->ctx->__get('categories')->f('cat_id')) + && preg_match('/^[0-9]{1,}/', dcCore::app()->ctx->__get('categories')->f('cat_id'), $cat_id) + ) { + $tpl = 'category-' . $cat_id[0] . '.html'; + if (dcCore::app()->tpl->getFilePath($tpl)) { + dcCore::app()->ctx->__set('current_tpl', $tpl); + } + } + }, + 'initWidgets' => [Widgets::class, 'initWidgets'], + ]); + + return true; } } diff --git a/src/Manage.php b/src/Manage.php index 31b7a25..0ffa8a8 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -10,621 +10,633 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -dcPage::check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_CONTENT_ADMIN, - initTemplator::PERMISSION_TEMPLATOR, -])); +namespace Dotclear\Plugin\templator; -$part = $_REQUEST['part'] ?? ''; +use adminGenericFilterV2; +use adminPostList; +use dcAdminFilters; +use dcCore; +use dcNsProcess; +use dcPage; +use dcPager; +use Dotclear\Helper\File\Files; +use Dotclear\Helper\Html\Html; +use Exception; -### grab info ### +use form; -if (in_array($part, ['files', 'delete'])) { - //Extend dcMedia to change settings to allow .html vs media_exclusion - $media = new templatorMedia(); - $media->chdir(dcCore::app()->templator->template_dir_name); - // For users with only templator permission, we use sudo. - dcCore::app()->auth->sudo([$media,'getDir']); - $dir = $media->dir; - $items = array_values($dir['files']); -} +class Manage extends dcNsProcess +{ + public static function init(): bool + { + static::$init == defined('DC_CONTEXT_ADMIN') + && My::phpCompliant() + && !is_null(dcCore::app()->auth) + && !is_null(dcCore::app()->blog) + && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + My::PERMISSION_TEMPLATOR, + ]), dcCore::app()->blog->id); -if (in_array($part, ['new', 'copycat'])) { - $has_categories = false; + return static::$init; + } - try { - $categories = dcCore::app()->blog->getCategories(['post_type' => 'post']); + public static function process(): bool + { + if (!static::$init) { + return false; + } - $categories_combo = []; - $l = $categories->level; - $full_name = [$categories->cat_title]; + // nullsafe + if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) { + return false; + } - while ($categories->fetch()) { - if ($categories->level < $l) { - $full_name = []; - } elseif ($categories->level == $l) { - array_pop($full_name); + // instances + $t = Templator::instance(); + $v = ManageVars::instance(); + + /* + * Duplicate dc template + */ + if ('new' == $v->part && !empty($_POST['filesource'])) { + try { + if ('category' == $_POST['filesource']) { + $name = 'category-' . $_POST['filecat'] . '.html'; + } elseif (!empty($_POST['filename'])) { + $name = Files::tidyFileName($_POST['filename']) . '.html'; + } else { + throw new Exception(__('Filename is empty.')); + } + $t->initializeTpl($name, $_POST['filesource']); + + if (!dcCore::app()->error->flag()) { + dcPage::addSuccessNotice(__('The new template has been successfully created.')); + dcCore::app()->adminurl->redirect('admin.plugin.templator'); + } + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); } - $full_name[] = html::escapeHTML($categories->cat_title); - - $categories_combo[implode(' › ', $full_name)] = $categories->cat_id; - - $l = $categories->level; - } - $has_categories = !$categories->isEmpty(); - } catch (Exception $e) { - } - - $combo_source = [ - __('Empty template') => 'empty', - 'post.html' => 'post', - ]; - - if (dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcPages::PERMISSION_PAGES]), dcCore::app()->blog->id) && dcCore::app()->plugins->moduleExists('pages')) { - $combo_source['page.html'] = 'page'; - } - - if ($has_categories) { - $combo_source['category.html'] = 'category'; - } -} - -### Action ### - -/* - * Duplicate dc template - */ -if ('new' == $part && !empty($_POST['filesource'])) { - try { - if ('category' == $_POST['filesource']) { - $name = 'category-' . $_POST['filecat'] . '.html'; - } elseif (!empty($_POST['filename'])) { - $name = files::tidyFileName($_POST['filename']) . '.html'; - } else { - throw new Exception(__('Filename is empty.')); - } - dcCore::app()->templator->initializeTpl($name, $_POST['filesource']); - - if (!dcCore::app()->error->flag()) { - dcAdminNotices::addSuccessNotice(__('The new template has been successfully created.')); - dcCore::app()->adminurl->redirect('admin.plugin.templator'); - } - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } -} - -/* - * Copy tempaltor template - */ -if ('copy' == $part && !empty($_POST['filename'])) { - try { - dcCore::app()->templator->copypasteTpl( - rawurldecode($_POST['filename']) . '.html', - rawurldecode($_POST['file']) - ); - - if (!dcCore::app()->error->flag()) { - dcAdminNotices::addSuccessNotice(__('The template has been successfully copied.')); - dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'files']); - } - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } -} - -/* - * Copy templator category template - */ -if ('copycat' == $part && !empty($_POST['filecat'])) { - try { - dcCore::app()->templator->copypasteTpl( - 'category-' . rawurldecode($_POST['filecat']) . '.html', - rawurldecode($_POST['file']) - ); - - if (!dcCore::app()->error->flag()) { - dcAdminNotices::addSuccessNotice(__('The template has been successfully copied.')); - dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'files']); - } - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } -} - -/* - * Delete tempaltor template - */ -if ('delete' == $part && !empty($_POST['file'])) { - try { - $file = rawurldecode($_POST['file']); - $media->removeItem($file); - dcCore::app()->meta->delMeta($file, 'template'); - - if (!dcCore::app()->error->flag()) { - dcAdminNotices::addSuccessNotice(__('The template has been successfully removed.')); - dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'files']); - } - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } -} - -### Display ### - -/* - * Check - */ - -if (!dcCore::app()->templator->canUseRessources(true)) { - dcCore::app()->error->add(__('The plugin is unusable with your configuration. You have to change file permissions.')); - echo - '' . __('Templator') . '' . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('New template') => '', - ]) . - dcPage::notices(); - - /* - * Duplicate dotclear template - */ -} elseif ('new' == $part) { - echo - '' . __('Templator') . '' . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('New template') => '', - ]) . - dcPage::notices() . - - '
' . - '

' . __('New template') . '

' . - '

' . - form::combo('filesource', $combo_source) . '

' . - '

' . - form::field('filename', 25, 255) . '

' . - '

' . __('Extension .html is automatically added to filename.') . '

'; - - if ($has_categories) { - echo - '

' . - form::combo('filecat', $categories_combo, '') . '

' . - '

' . __('Required only for category template.') . '

'; - } - - echo - '

' . - dcCore::app()->formNonce() . - '

' . - '
'; - - /* - * Copy templator template - */ -} elseif ('copy' == $part && !empty($_REQUEST['file'])) { - echo - '' . __('Templator') . '' . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('Copy available template') => '', - ]) . - dcPage::notices() . - - '
' . - '

' . __('Copy available template') . '

' . - '

' . - form::field('filename', 25, 255) . '' . html::escapeHTML('.html') . '

' . - '

' . sprintf( - __('To copy the template %s, you need to fill a new filename.'), - html::escapeHTML($_REQUEST['file']) - ) . '

' . - '

' . - ' ' . - '' . __('Cancel') . '' . - dcCore::app()->formNonce() . - form::hidden('file', html::escapeHTML($_REQUEST['file'])) . '

' . - '
'; - - /* - * Copy templator category template - */ -} elseif ('copycat' == $part && !empty($_REQUEST['file'])) { - $category_id = (int) str_replace(['category-','.html'], '', $_REQUEST['file']); - $cat_parents = dcCore::app()->blog->getCategoryParents($category_id); - $full_name = ''; - while ($cat_parents->fetch()) { - $full_name = $cat_parents->cat_title . ' › '; - }; - $name = $full_name . dcCore::app()->blog->getCategory($category_id)->cat_title; - - echo - '' . __('Templator') . '' . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('Copy available template') => '', - ]) . - dcPage::notices() . - - '
' . - '

' . __('Copy available template') . '

' . - '

' . - form::combo('filecat', $categories_combo, '') . '

' . - '

' . sprintf( - __('To copy the template %s (%s), you need to choose a category.'), - html::escapeHTML($_GET['file']), - $name - ) . '

' . - ' ' . - '' . __('Cancel') . '' . - dcCore::app()->formNonce() . - form::hidden('file', html::escapeHTML($_REQUEST['file'])) . '

' . - '
'; - - /* - * Delete templator template - */ -} elseif ('delete' == $part && !empty($_REQUEST['file'])) { - echo - '' . __('Templator') . '' . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('Delete available template') => '', - ]) . - dcPage::notices() . - - '
' . - '

' . __('Delete available template') . '

' . - '

' . sprintf( - __('Are you sure you want to remove the template "%s"?'), - html::escapeHTML($_GET['file']) - ) . '

' . - '

' . - '' . __('Cancel') . '' . - dcCore::app()->formNonce() . - form::hidden('file', html::escapeHTML($_GET['file'])) . '

' . - '
'; - - /* - * List templator templates - */ -} elseif ('files' == $part) { - echo - '' . __('Templator') . '' . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('Available templates') => '', - ]) . - dcPage::notices() . - '

' . __('Available templates') . '

'; - - if (count($items) == 0) { - echo '

' . __('No template.') . '

'; - } else { - // reuse "used templatro template" filter settings - $filter = new adminGenericFilterV2('templator'); - $filter->add(dcAdminFilters::getPageFilter()); - - $pager = new dcPager($filter->page, count($items), $filter->nb, 10); - - echo - '
' . - $pager->getLinks(); - - for ($i = $pager->index_start, $j = 0; $i <= $pager->index_end; $i++, $j++) { - echo templatorPager::templatorItemLine($items[$i], $j); } - echo - $pager->getLinks() . - '
'; - } + /* + * Copy tempaltor template + */ + if ('copy' == $v->part && !empty($_POST['filename'])) { + try { + $t->copypasteTpl( + rawurldecode($_POST['filename']) . '.html', + rawurldecode($_POST['file']) + ); - /* - * List Used templator template - */ -} elseif ('used' == $part) { - $tags = dcCore::app()->meta->getMetadata(['meta_type' => 'template']); - $tags = dcCore::app()->meta->computeMetaStats($tags); - $tags->sort('meta_id_lower', 'asc'); - - $last_letter = null; - $cols = ['','']; - $col = 0; - - while ($tags->fetch()) { - $letter = mb_strtoupper(mb_substr($tags->meta_id, 0, 1)); - - if ($last_letter != $letter) { - if ($tags->index() >= round($tags->count() / 2)) { - $col = 1; + if (!dcCore::app()->error->flag()) { + dcPage::addSuccessNotice(__('The template has been successfully copied.')); + dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'files']); + } + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); } - $cols[$col] .= '' . $letter . ''; } - $img = '%1$s'; - if (array_key_exists($tags->meta_id, dcCore::app()->templator->tpl)) { - $img_status = sprintf($img, __('available template'), 'check-on.png'); - } else { - $img_status = sprintf($img, __('missing template'), 'check-off.png'); - } + /* + * Copy templator category template + */ + if ('copycat' == $v->part && !empty($_POST['filecat'])) { + try { + $t->copypasteTpl( + 'category-' . rawurldecode($_POST['filecat']) . '.html', + rawurldecode($_POST['file']) + ); - $cols[$col] .= '' . - '' . $tags->meta_id . ' ' . $img_status . '' . - '' . $tags->count . ' ' . - (($tags->count == 1) ? __('entry') : __('entries')) . '' . - ''; - - $last_letter = $letter; - } - - $table = '
%s
'; - - echo - '' . __('Templator') . '' . - dcPage::cssLoad(dcPage::getPF('tags/style.css')) . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('Used templates') => '', - ]) . - dcPage::notices() . - '

' . __('Used templates') . '

'; - - if ($cols[0]) { - echo '
'; - printf($table, $cols[0]); - if ($cols[1]) { - printf($table, $cols[1]); - } - echo '
'; - } else { - echo '

' . __('No specific templates on this blog.') . '

'; - } - - /* - * Edit emplator template - */ -} elseif ('edit' == $part && !empty($_REQUEST['file'])) { - try { - try { - $name = rawurldecode($_REQUEST['file']); - $file = dcCore::app()->templator->getSourceContent($name); - $name = $file['f']; - - if (preg_match('/^category-(.+).html$/', $name, $cat_id)) { - $category = dcCore::app()->blog->getCategory((int) $cat_id[1]); - $full_name = ''; - $cat_parents = dcCore::app()->blog->getCategoryParents((int) $cat_id[1]); - while ($cat_parents->fetch()) { - $full_name = $cat_parents->cat_title . ' › '; - }; - $name .= ' (' . $full_name . $category->cat_title . ')'; + if (!dcCore::app()->error->flag()) { + dcPage::addSuccessNotice(__('The template has been successfully copied.')); + dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'files']); + } + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); } - } catch (Exception $e) { - $file = ''; - - throw $e; } - # Write file - if (!empty($_POST['write'])) { - $file['c'] = $_POST['file_content']; - dcCore::app()->templator->writeTpl($file['f'], $file['c']); + + /* + * Delete tempaltor template + */ + if ('delete' == $v->part && !empty($_POST['file'])) { + try { + $file = rawurldecode($_POST['file']); + $v->media->removeItem($file); + dcCore::app()->meta->delMeta($file, 'template'); + + if (!dcCore::app()->error->flag()) { + dcPage::addSuccessNotice(__('The template has been successfully removed.')); + dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'files']); + } + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } } - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); + + return true; } - dcCore::app()->auth->user_prefs->addWorkspace('interface'); + public static function render(): void + { + if (!static::$init) { + return; + } - echo - '' . __('Templator') . ''; + // nullsafe + if (is_null(dcCore::app()->auth) || is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl) || is_null(dcCore::app()->auth->user_prefs)) { + return; + } - if (dcCore::app()->auth->user_prefs->interface->colorsyntax) { - echo - dcPage::jsJson('dotclear_colorsyntax', ['colorsyntax' => dcCore::app()->auth->user_prefs->interface->colorsyntax]); - } - echo - dcPage::jsJson('theme_editor_msg', [ - 'saving_document' => __('Saving document...'), - 'document_saved' => __('Document saved'), - 'error_occurred' => __('An error occurred:'), - 'confirm_reset_file' => __('Are you sure you want to reset this file?'), - ]) . - dcPage::jsModuleLoad('themeEditor/js/script.js') . - dcPage::jsConfirmClose('file-form'); - if (dcCore::app()->auth->user_prefs->interface->colorsyntax) { - echo - dcPage::jsLoadCodeMirror(dcCore::app()->auth->user_prefs->interface->colorsyntax_theme); - } - echo - dcPage::cssModuleLoad('themeEditor/style.css') . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('Edit template') => '', - ]) . - dcPage::notices(); + // instances + $t = Templator::instance(); + $v = ManageVars::instance(); - if (($file['c'] !== null)) { - echo - '
' . - '

' . - '

' . form::textarea('file_content', 72, 25, [ - 'default' => html::escapeHTML($file['c']), - 'class' => 'maximal', - 'disabled' => !$file['w'], - ]) . '

'; + /* + * Check + */ - if ($file['w']) { + if (!$t->canUseRessources(true)) { + dcCore::app()->error->add(__('The plugin is unusable with your configuration. You have to change file permissions.')); echo - '

' . + '' . __('Templator') . '' . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('New template') => '', + ]) . + dcPage::notices(); + + /* + * Duplicate dotclear template + */ + } elseif ('new' == $v->part) { + echo + '' . __('Templator') . '' . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('New template') => '', + ]) . + dcPage::notices() . + + '' . + '

' . __('New template') . '

' . + '

' . + form::combo('filesource', $v->sources) . '

' . + '

' . + form::field('filename', 25, 255) . '

' . + '

' . __('Extension .html is automatically added to filename.') . '

'; + + if ($v->has_categories) { + echo + '

' . + form::combo('filecat', $v->categories, '') . '

' . + '

' . __('Required only for category template.') . '

'; + } + + echo + '

' . + dcCore::app()->formNonce() . + '

' . + ''; + + /* + * Copy templator template + */ + } elseif ('copy' == $v->part && !empty($_REQUEST['file'])) { + echo + '' . __('Templator') . '' . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('Copy available template') => '', + ]) . + dcPage::notices() . + + '
' . + '

' . __('Copy available template') . '

' . + '

' . + form::field('filename', 25, 255) . '' . Html::escapeHTML('.html') . '

' . + '

' . sprintf( + __('To copy the template %s, you need to fill a new filename.'), + Html::escapeHTML($_REQUEST['file']) + ) . '

' . + '

' . + ' ' . '' . __('Cancel') . '' . dcCore::app()->formNonce() . - form::hidden(['file_id'], html::escapeHTML($file['f'])) . - '

'; - } else { - echo '

' . __('This file is not writable. Please check your files permissions.') . '

'; - } + form::hidden('file', Html::escapeHTML($_REQUEST['file'])) . '

' . + '
'; + + /* + * Copy templator category template + */ + } elseif ('copycat' == $v->part && !empty($_REQUEST['file'])) { + $category_id = (int) str_replace(['category-','.html'], '', $_REQUEST['file']); + $cat_parents = dcCore::app()->blog->getCategoryParents($category_id); + $full_name = ''; + while ($cat_parents->fetch()) { + $full_name = $cat_parents->f('cat_title') . ' › '; + }; + $name = $full_name . dcCore::app()->blog->getCategory($category_id)->f('cat_title'); - echo - '
'; - if (dcCore::app()->auth->user_prefs->interface->colorsyntax) { echo - dcPage::jsJson('theme_editor_mode', ['mode' => 'html']) . - dcPage::jsModuleLoad('themeEditor/js/mode.js') . - dcPage::jsRunCodeMirror('editor', 'file_content', 'dotclear', dcCore::app()->auth->user_prefs->interface->colorsyntax_theme); - } - } + '' . __('Templator') . '' . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('Copy available template') => '', + ]) . + dcPage::notices() . - /* - * Edit posts options linked to a template - */ -} elseif ('posts' == $part && (!empty($_REQUEST['file']) || $_REQUEST['file'] == '0')) { - $file = $_REQUEST['file']; - $redir = $_REQUEST['redir'] ?? dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'used']); + '
' . + '

' . __('Copy available template') . '

' . + '

' . + form::combo('filecat', $v->categories, '') . '

' . + '

' . sprintf( + __('To copy the template %s (%s), you need to choose a category.'), + Html::escapeHTML($_GET['file']), + $name + ) . '

' . + ' ' . + '' . __('Cancel') . '' . + dcCore::app()->formNonce() . + form::hidden('file', Html::escapeHTML($_REQUEST['file'])) . '

' . + '
'; - # Unselect the template - if (!empty($_POST['action']) && 'unselecttpl' == $_POST['action'] && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ - dcAuth::PERMISSION_PUBLISH, - dcAuth::PERMISSION_CONTENT_ADMIN, - ]), dcCore::app()->blog->id)) { - try { - dcCore::app()->meta->delMeta($file, 'template'); - dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'posts', 'file' => $file]); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } - } + /* + * Delete templator template + */ + } elseif ('delete' == $v->part && !empty($_REQUEST['file'])) { + echo + '' . __('Templator') . '' . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('Delete available template') => '', + ]) . + dcPage::notices() . - $filter = new adminGenericFilterV2('templator'); - $filter->add(dcAdminFilters::getPageFilter()); - $filter->add('part', 'posts'); - $filter->add('file', $file); - $filter->add('post_type', ''); + '
' . + '

' . __('Delete available template') . '

' . + '

' . sprintf( + __('Are you sure you want to remove the template "%s"?'), + Html::escapeHTML($_GET['file']) + ) . '

' . + '

' . + '' . __('Cancel') . '' . + dcCore::app()->formNonce() . + form::hidden('file', Html::escapeHTML($_GET['file'])) . '

' . + '
'; - $params = $filter->params(); - $params['no_content'] = true; - $params['meta_id'] = $file; - $params['meta_type'] = 'template'; + /* + * List templator templates + */ + } elseif ('files' == $v->part) { + echo + '' . __('Templator') . '' . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('Available templates') => '', + ]) . + dcPage::notices() . + '

' . __('Available templates') . '

'; - # Get posts - try { - $posts = dcCore::app()->meta->getPostsByMeta($params); - $counter = dcCore::app()->meta->getPostsByMeta($params, true); - $post_list = new adminPostList($posts, $counter->f(0)); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - } + if (count($v->items) == 0) { + echo '

' . __('No template.') . '

'; + } else { + // reuse "used templatro template" filter settings + $filter = new adminGenericFilterV2('templator'); + $filter->add(dcAdminFilters::getPageFilter()); + $page = is_numeric($filter->value('page')) ? (int) $filter->value('page') : 1; + $nb = is_numeric($filter->value('nb')) ? (int) $filter->value('nb') : 1; - echo - '' . __('Templator') . '' . - dcPage::jsFilterControl($filter->show()) . - dcPage::jsLoad(dcPage::getPF('templator/js/posts.js')) . - $filter->js(dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'posts', 'file' => $file])) . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), - __('Unselect template') => '', - ]) . - dcPage::notices() . + $pager = new dcPager($page, count($v->items), $nb, 10); - '

' . sprintf(__('Unselect template "%s"'), '' . $file . '') . '

' . - '

' . __('Back') . '

'; + echo + '
' . + $pager->getLinks(); - if (!dcCore::app()->error->flag()) { - if ($posts->isEmpty() && !$filter->show()) { - echo '

' . __('There is no entries') . '

'; + for ($i = $pager->index_start, $j = 0; $i <= $pager->index_end; $i++, $j++) { + echo Pager::line($v->items[$i], $j); + } + + echo + $pager->getLinks() . + '
'; + } + + /* + * List Used templator template + */ + } elseif ('used' == $v->part) { + $tags = dcCore::app()->meta->getMetadata(['meta_type' => 'template']); + $tags = dcCore::app()->meta->computeMetaStats($tags); + $tags->sort('meta_id_lower', 'asc'); + + $last_letter = null; + $cols = ['','']; + $col = 0; + + while ($tags->fetch()) { + $meta_id = is_string($tags->f('meta_id')) ? $tags->f('meta_id') : ''; + $count = is_numeric($tags->f('count')) ? (int) $tags->f('count') : 1; + $letter = mb_strtoupper(mb_substr($meta_id, 0, 1)); + + if ($last_letter != $letter) { + if ($tags->index() >= round($tags->count() / 2)) { + $col = 1; + } + $cols[$col] .= '' . $letter . ''; + } + + $img = '%1$s'; + if (array_key_exists($meta_id, $t->getTpl())) { + $img_status = sprintf($img, __('available template'), 'check-on.png'); + } else { + $img_status = sprintf($img, __('missing template'), 'check-off.png'); + } + + $cols[$col] .= '' . + '' . $meta_id . ' ' . $img_status . '' . + '' . $count . ' ' . + (($count == 1) ? __('entry') : __('entries')) . '' . + ''; + + $last_letter = $letter; + } + + $table = '
%s
'; + + echo + '' . __('Templator') . '' . + dcPage::cssLoad(dcPage::getPF('tags/style.css')) . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('Used templates') => '', + ]) . + dcPage::notices() . + '

' . __('Used templates') . '

'; + + if ($cols[0]) { + echo '
'; + printf($table, $cols[0]); + if ($cols[1]) { + printf($table, $cols[1]); + } + echo '
'; + } else { + echo '

' . __('No specific templates on this blog.') . '

'; + } + + /* + * Edit emplator template + */ + } elseif ('edit' == $v->part && !empty($_REQUEST['file'])) { + $file = ['c' => '', 'w' => false, 'f' => '']; + $name = ''; + + try { + try { + $name = rawurldecode($_REQUEST['file']); + $file = $t->getSourceContent($name); + $name = $file['f']; + + if (preg_match('/^category-(.+).html$/', $name, $cat_id)) { + $category = dcCore::app()->blog->getCategory((int) $cat_id[1]); + $full_name = ''; + $cat_parents = dcCore::app()->blog->getCategoryParents((int) $cat_id[1]); + while ($cat_parents->fetch()) { + $full_name = $cat_parents->f('cat_title') . ' › '; + }; + $name .= '
(' . $full_name . $category->f('cat_title') . ')'; + } + } catch (Exception $e) { + $file['c'] = null; + + throw $e; + } + # Write file + if (!empty($_POST['write'])) { + $file['c'] = $_POST['file_content'] ?? null; + $t->writeTpl($file['f'], $file['c']); + } + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + + echo + '' . __('Templator') . ''; + + if (dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax')) { + echo + dcPage::jsJson('dotclear_colorsyntax', ['colorsyntax' => dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax')]); + } + echo + dcPage::jsJson('theme_editor_msg', [ + 'saving_document' => __('Saving document...'), + 'document_saved' => __('Document saved'), + 'error_occurred' => __('An error occurred:'), + 'confirm_reset_file' => __('Are you sure you want to reset this file?'), + ]) . + dcPage::jsModuleLoad('themeEditor/js/script.js') . + dcPage::jsConfirmClose('file-form'); + if (dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax')) { + $ict = dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax_theme'); + echo + dcPage::jsLoadCodeMirror(is_string($ict) ? $ict : ''); + } + echo + dcPage::cssModuleLoad('themeEditor/style.css') . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('Edit template') => '', + ]) . + dcPage::notices(); + + if (($file['c'] !== null)) { + echo + '
' . + '

' . + '

' . form::textarea('file_content', 72, 25, [ + 'default' => Html::escapeHTML($file['c']), + 'class' => 'maximal', + 'disabled' => !$file['w'], + ]) . '

'; + + if ($file['w']) { + echo + '

' . + '' . __('Cancel') . '' . + dcCore::app()->formNonce() . + form::hidden(['file_id'], Html::escapeHTML($file['f'])) . + '

'; + } else { + echo '

' . __('This file is not writable. Please check your files permissions.') . '

'; + } + + echo + '
'; + if (dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax')) { + $ict = dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax_theme'); + echo + dcPage::jsJson('theme_editor_mode', ['mode' => 'html']) . + dcPage::jsModuleLoad('themeEditor/js/mode.js') . + dcPage::jsRunCodeMirror('editor', 'file_content', 'dotclear', is_string($ict) ? $ict : ''); + } + } + + /* + * Edit posts options linked to a template + */ + } elseif ('posts' == $v->part && (!empty($_REQUEST['file']) || $_REQUEST['file'] == '0')) { + $file = $_REQUEST['file']; + $redir = $_REQUEST['redir'] ?? dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'used']); + + # Unselect the template + if (!empty($_POST['action']) && 'unselecttpl' == $_POST['action'] && dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + dcCore::app()->auth::PERMISSION_PUBLISH, + dcCore::app()->auth::PERMISSION_CONTENT_ADMIN, + ]), dcCore::app()->blog->id)) { + try { + dcCore::app()->meta->delMeta($file, 'template'); + dcCore::app()->adminurl->redirect('admin.plugin.templator', ['part' => 'posts', 'file' => $file]); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + } + + $filter = new adminGenericFilterV2('templator'); + $filter->add(dcAdminFilters::getPageFilter()); + $filter->add('part', 'posts'); + $filter->add('file', $file); + $filter->add('post_type', ''); + + $params = $filter->params(); + $params['no_content'] = true; + $params['meta_id'] = $file; + $params['meta_type'] = 'template'; + + # Get posts + try { + $posts = dcCore::app()->meta->getPostsByMeta($params); + if (is_null($posts)) { + throw new Exception(__('Failed to get posts meta')); + } + $counter = dcCore::app()->meta->getPostsByMeta($params, true)?->f(0); + $counter = is_numeric($counter) ? (int) $counter : 0; + $post_list = new adminPostList($posts, $counter); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + + echo + '' . __('Templator') . '' . + dcPage::jsFilterControl($filter->show()) . + dcPage::jsLoad(dcPage::getPF('templator/js/posts.js')) . + $filter->js(dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'posts', 'file' => $file])) . + '' . + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => dcCore::app()->adminurl->get('admin.plugin.templator'), + __('Unselect template') => '', + ]) . + dcPage::notices() . + + '

' . sprintf(__('Unselect template "%s"'), '' . $file . '') . '

' . + '

' . __('Back') . '

'; + + if (!dcCore::app()->error->flag() && isset($posts)) { + if ($posts->isEmpty() && !$filter->show()) { + echo '

' . __('There is no entries') . '

'; + } else { + $page = is_numeric($filter->value('page')) ? (int) $filter->value('page') : 1; + $nb = is_numeric($filter->value('nb')) ? (int) $filter->value('nb') : 0; + $filter->display( + 'admin.plugin.templator', + form::hidden('p', 'templator') . form::hidden('part', 'posts') . form::hidden('file', $file) + ); + # Show posts + $post_list->display( + $page, + $nb, + '
' . + + '%s' . + + '
' . + '

' . + + '

' . + '

' . + form::hidden('action', 'unselecttpl') . + dcCore::app()->adminurl->getHiddenFormFields('admin.plugin.templator', $filter->values()) . + form::hidden('redir', $redir) . + dcCore::app()->formNonce() . + '
' . + '
', + $filter->show() + ); + } + } + + /* + * Default page + */ } else { - $filter->display( - 'admin.plugin.templator', - form::hidden('p', 'templator') . form::hidden('part', 'posts') . form::hidden('file', $file) - ); - # Show posts - $post_list->display( - $filter->page, - $filter->nb, - '
' . + dcPage::openModule(My::name()); + echo + dcPage::breadcrumb([ + __('Plugins') => '', + __('Templates engine') => '', + ]) . + dcPage::notices(); - '%s' . - - '
' . - '

' . - - '

' . - '

' . - form::hidden('action', 'unselecttpl') . - dcCore::app()->adminurl->getHiddenFormFields('admin.plugin.templator', $filter->values()) . - form::hidden('redir', $redir) . - dcCore::app()->formNonce() . - '
' . - '
', - $filter->show(), - dcCore::app()->adminurl->get('admin.plugin.templator', $filter->values()) + $line = '
  • %s
  • '; + echo ' +

    ' . __('Manage additional templates') . '

    ' . + sprintf( + '

      %s

    ', + sprintf( + $line, + dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'files']), + __('Available templates') + ) . + sprintf( + $line, + dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'used']), + __('Used templates') + ) . + sprintf( + $line, + dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'new']), + __('New template') + ) ); } + + dcPage::helpBlock('templator'); + + dcPage::closeModule(); } - - /* - * Default page - */ -} else { - echo - '' . __('Templator') . '' . - '' . - dcPage::breadcrumb([ - __('Plugins') => '', - __('Templates engine') => '', - ]) . - dcPage::notices(); - - $line = '
  • %s
  • '; - echo ' -

    ' . __('Manage additional templates') . '

    ' . - sprintf( - '

      %s

    ', - sprintf( - $line, - dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'files']), - __('Available templates') - ) . - sprintf( - $line, - dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'used']), - __('Used templates') - ) . - sprintf( - $line, - dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'new']), - __('New template') - ) - ); } - -dcPage::helpBlock('templator'); - -echo ''; diff --git a/src/ManageVars.php b/src/ManageVars.php new file mode 100644 index 0000000..ea66467 --- /dev/null +++ b/src/ManageVars.php @@ -0,0 +1,147 @@ + $items The media items */ + public readonly array $items; + + /** @var array $categories The blog categories list */ + public readonly array $categories; + + /** @var bool $has_categories Blog has categories */ + public readonly bool $has_categories; + + /** @var array $sources The templates list */ + public readonly array $sources; + + /** + * Constructo sets properties. + */ + public function __construct() + { + // manage page + $name = $this->getPartName(($_REQUEST['part'] ?? '')); + $this->name = empty($name) ? __('Home') : $name; + $this->part = empty($name) ? '' : $_REQUEST['part']; + + // Extend dcMedia to change settings to allow .html vs media_exclusion + $this->media = new Media(); + $this->media->chdir(Templator::MY_TPL_DIR); + // For users with only templator permission, we use sudo. + dcCore::app()->auth?->sudo([$this->media,'getDir']); + $dir = $this->media->dir; + $this->items = array_values($dir['files']); + + // categories + $categories_combo = []; + $has_categories = false; + + try { + $categories = dcCore::app()->blog?->getCategories(['post_type' => 'post']); + if (!is_null($categories)) { + $l = is_numeric($categories->f('level')) ? (int) $categories->f('level') : 1; + $full_name = [is_string($categories->f('cat_title')) ? $categories->f('cat_title') : '']; + + while ($categories->fetch()) { + $id = is_numeric($categories->f('cat_id')) ? (int) $categories->f('cat_id') : 1; + $level = is_numeric($categories->f('level')) ? (int) $categories->f('level') : 1; + $title = is_string($categories->f('cat_title')) ? $categories->f('cat_title') : ''; + + if ($level < $l) { + $full_name = []; + } elseif ($level == $l) { + array_pop($full_name); + } + $full_name[] = Html::escapeHTML($title); + + $categories_combo[implode(' › ', $full_name)] = $id; + + $l = $level; + } + $has_categories = !$categories->isEmpty(); + } + } catch (Exception $e) { + } + $this->categories = $categories_combo; + $this->has_categories = $has_categories; + + // sources + $sources_combo = [ + __('Empty template') => 'empty', + 'post.html' => 'post', + ]; + + if (dcCore::app()->plugins->moduleExists('pages') + && dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([initPages::PERMISSION_PAGES]), dcCore::app()->blog?->id) + ) { + $sources_combo['page.html'] = 'page'; + } + + if ($has_categories) { + $sources_combo['category.html'] = 'category'; + } + $this->sources = $sources_combo; + } + + /** + * Get self instance. + * + * @return ManageVars Self instance + */ + public static function instance(): ManageVars + { + if (!(self::$container instanceof self)) { + self::$container = new self(); + } + + return self::$container; + } + + private function getPartName(string $part): string + { + $parts = [ + 'new' => __('New template'), + 'copy' => __('Copy available template'), + 'copycat' => __('Copy available category template'), + 'delete' => __('Delete available template'), + 'files' => __('Available templates'), + 'used' => __('Used templates'), + 'edit' => __('Edit template'), + 'posts' => __('Unselect template'), + ]; + + return array_key_exists($part, $parts) ? $parts[$part] : ''; + } +} diff --git a/src/Media.php b/src/Media.php index 551773f..49ec97f 100644 --- a/src/Media.php +++ b/src/Media.php @@ -10,7 +10,13 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -class templatorMedia extends dcMedia +declare(strict_types=1); + +namespace Dotclear\Plugin\templator; + +use dcMedia; + +class Media extends dcMedia { // limit to html files protected function isFileExclude(string $file): bool diff --git a/src/My.php b/src/My.php new file mode 100644 index 0000000..fb0b458 --- /dev/null +++ b/src/My.php @@ -0,0 +1,63 @@ +plugins->moduleInfo(self::id(), 'name'); + + return __(is_string($name) ? $name : self::id()); + } + + /** + * This module path. + */ + public static function path(): string + { + return dirname(__DIR__); + } + + /** + * Check this module PHP version compliant. + */ + public static function phpCompliant(): bool + { + return version_compare(phpversion(), self::PHP_MIN, '>='); + } +} diff --git a/src/Pager.php b/src/Pager.php index b9d0c3a..cc00e15 100644 --- a/src/Pager.php +++ b/src/Pager.php @@ -10,14 +10,24 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return; -} +declare(strict_types=1); -class templatorPager +namespace Dotclear\Plugin\templator; + +use dcCore; +use dcPage; +use Dotclear\Helper\File\File; +use Dotclear\Helper\File\Files; +use Exception; + +class Pager { - public static function templatorItemLine($f, $i) + public static function line(File $f, int $i): string { + if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->adminurl)) { + return ''; + } + $p_url = dcCore::app()->admin->getPageURL(); $fname = $f->basename; $count = ''; @@ -36,9 +46,9 @@ class templatorPager $full_name = ''; $cat_parents = dcCore::app()->blog->getCategoryParents($cat_id); while ($cat_parents->fetch()) { - $full_name = $cat_parents->cat_title . ' › '; + $full_name = $cat_parents->f('cat_title') . ' › '; }; - $fname = '' . __('Category') . ' : ' . $full_name . dcCore::app()->blog->getCategory($cat_id)->cat_title; + $fname = '' . __('Category') . ' : ' . $full_name . $category->f('cat_title'); $params['cat_id'] = $cat_id; $params['post_type'] = ''; $icon = dcPage::getPF('templator/img/template-alt.png'); @@ -66,18 +76,19 @@ class templatorPager $params['post_type'] = ''; try { - $counter = dcCore::app()->meta->getPostsByMeta($params, true); + $counter = dcCore::app()->meta->getPostsByMeta($params, true)?->f(0); + $counter = is_numeric($counter) ? (int) $counter : 0; $url = dcCore::app()->adminurl->get('admin.plugin.templator', [ 'part' => 'posts', 'file' => $fname, 'redir' => dcCore::app()->adminurl->get('admin.plugin.templator', ['part' => 'files']), ]); - if ($counter->f(0) == 0) { + if ($counter == 0) { $count = __('No entry'); - } elseif ($counter->f(0) == 1) { - $count = '' . $counter->f(0) . ' ' . __('entry') . ''; + } elseif ($counter == 1) { + $count = '' . $counter . ' ' . __('entry') . ''; } else { - $count = '' . $counter->f(0) . ' ' . __('entries') . ''; + $count = '' . $counter . ' ' . __('entries') . ''; } } catch (Exception $e) { dcCore::app()->error->add($e->getMessage()); @@ -100,7 +111,7 @@ class templatorPager $res .= '
  • ' . $count . '
  • ' . '
  • ' . $f->media_dtstr . ' - ' . - files::size($f->size) . + Files::size($f->size) . $details . '
  • '; } diff --git a/src/Prepend.php b/src/Prepend.php index 500167f..44924f1 100644 --- a/src/Prepend.php +++ b/src/Prepend.php @@ -10,40 +10,33 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return null; -} -Clearbricks::lib()->autoload([ - 'dcTemplator' => __DIR__ . '/inc/class.templator.php', - 'templatorMedia' => __DIR__ . '/inc/class.templator.media.php', - 'templatorPager' => __DIR__ . '/inc/class.templator.pager.php', -]); +declare(strict_types=1); -dcCore::app()->templator = new dcTemplator(); +namespace Dotclear\Plugin\templator; -dcCore::app()->addBehavior('initWidgets', ['templatorWidgets', 'initWidgets']); +use dcCore; +use dcNsProcess; -class templatorWidgets +class Prepend extends dcNsProcess { - public static function initWidgets($w) + public static function init(): bool { - $w->create('templatorWidget', __('Templator › Rendering'), ['widgetTemplator', 'getDataTpl']); - $tpl = ['      .html' => '']; - foreach (dcCore::app()->templator->tpl as $k => $v) { - if (preg_match('/^widget-(.+)$/', $k)) { - $tpl = array_merge($tpl, [$k => $k]); - } - } - $w->templatorWidget->setting('template', __('Template:'), '', 'combo', $tpl); - } -} - -class widgetTemplator -{ - public static function getDataTpl($w) - { - if (dcCore::app()->tpl->getFilePath($w->template)) { - echo dcCore::app()->tpl->getData($w->template); + static::$init = My::phpCompliant(); + + return static::$init; + } + + public static function process(): bool + { + if (!static::$init) { + return false; } + + dcCore::app()->auth?->setPermissionType( + My::PERMISSION_TEMPLATOR, + __('manage templates') + ); + + return true; } } diff --git a/src/Templator.php b/src/Templator.php index d381968..289c5a3 100644 --- a/src/Templator.php +++ b/src/Templator.php @@ -10,55 +10,116 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return null; -} +declare(strict_types=1); -class dcTemplator +namespace Dotclear\Plugin\templator; + +use dcCore; +use Dotclear\Helper\File\Files; +use Dotclear\Helper\File\Path; +use Dotclear\Helper\Html\Html; +use Exception; + +/** + * Templator main class. + */ +class Templator { - protected $tpls_default_name = 'dotty'; - protected $post_default_name = 'post.html'; - protected $page_default_name = 'page.html'; - protected $category_default_name = 'category.html'; + /** @var string This plugin folder for templates */ + public const MY_TPL_DIR = 'other-templates'; - public $template_dir_name = 'other-templates'; - public $path; + /** @var string The dotclear folder for templates */ + public const DC_TPL_DIR = 'default-templates'; - public $tpl = []; - public $theme_tpl = []; + /** @var string The themes folder for templates */ + public const THEME_TPL_DIR = 'tpl'; + + /** @var string The default tplset */ + public const DEFAULT_TPLSET = 'dotty'; + + /** @var string The default post template */ + public const DEFAULT_TPL_POST = 'post.html'; + + /** @var string The default page template */ + public const DEFAULT_TPL_PAGE = 'page.html'; + + /** @var string The default category tempalte */ + public const DEFAULT_TPL_CATEGORY = 'category.html'; + + /** @var Templator Self instance */ + private static $instance; + + /** @var string $path This plugin templates directory path */ + private string $path = ''; + + /** @var array The known templates files */ + private array $tpl = []; + + private string $file_tpl_post = ''; + private string $file_tpl_page = ''; + private string $file_tpl_category = ''; + + private string $user_path_theme = ''; + private string $user_tpl_post = ''; + private string $user_tpl_category = ''; + private string $user_tpl_page = ''; /** - * + * Constructor sets properties. */ public function __construct() { - $this->path = dcCore::app()->blog->public_path . '/' . $this->template_dir_name; - - // Initial templates - $this->post_tpl = DC_ROOT . '/inc/public/default-templates/' . $this->tpls_default_name . '/' . $this->post_default_name; - $this->category_tpl = DC_ROOT . '/inc/public/default-templates/' . $this->tpls_default_name . '/' . $this->category_default_name; - - if (dcCore::app()->plugins->moduleExists('pages')) { - $plugin_page = dcCore::app()->plugins->getModules('pages'); - $this->page_tpl = path::real($plugin_page['root'] . '/default-templates/' . $this->tpls_default_name . '/' . $this->page_default_name); + if (is_null(dcCore::app()->blog)) { + throw new Exception(__('Blog is not set')); } - $this->user_theme = dcCore::app()->blog->themes_path . '/' . dcCore::app()->blog->settings->system->theme; - $this->user_post_tpl = path::real($this->user_theme . '/tpl/' . $this->post_default_name); - $this->user_category_tpl = path::real($this->user_theme . '/tpl/' . $this->category_default_name); - $this->user_page_tpl = path::real($this->user_theme . '/tpl/' . $this->page_default_name); + $page_root = dcCore::app()->plugins->getDefine('pages')->get('root'); + + // Initial templates + $this->path = implode(DIRECTORY_SEPARATOR, [dcCore::app()->blog->public_path, self::MY_TPL_DIR]); + $this->file_tpl_post = implode(DIRECTORY_SEPARATOR, [DC_ROOT, 'inc', 'public', self::DC_TPL_DIR, self::DEFAULT_TPLSET, self::DEFAULT_TPL_POST]); + $this->file_tpl_category = implode(DIRECTORY_SEPARATOR, [DC_ROOT, 'inc', 'public', self::DC_TPL_DIR, self::DEFAULT_TPLSET, self::DEFAULT_TPL_CATEGORY]); + $this->file_tpl_page = Path::real(implode(DIRECTORY_SEPARATOR, [$page_root, self::DC_TPL_DIR, self::DEFAULT_TPLSET, self::DEFAULT_TPL_PAGE])) ?: ''; + + // user templates + $this->user_path_theme = dcCore::app()->blog->themes_path . DIRECTORY_SEPARATOR . dcCore::app()->blog->settings->get('system')->get('theme'); + $this->user_tpl_post = Path::real(implode(DIRECTORY_SEPARATOR, [$this->user_path_theme, self::THEME_TPL_DIR, self::DEFAULT_TPL_POST])) ?: ''; + $this->user_tpl_category = Path::real(implode(DIRECTORY_SEPARATOR, [$this->user_path_theme, self::THEME_TPL_DIR, self::DEFAULT_TPL_CATEGORY])) ?: ''; + $this->user_tpl_page = Path::real(implode(DIRECTORY_SEPARATOR, [$this->user_path_theme, self::THEME_TPL_DIR, self::DEFAULT_TPL_PAGE])) ?: ''; $this->findTemplates(); } + public static function instance(): Templator + { + if (!(self::$instance instanceof Templator)) { + self::$instance = new Templator(); + } + + return self::$instance; + } + + public function getPath(): string + { + return $this->path; + } + + /** + * @return array + */ + public function getTpl(): array + { + return $this->tpl; + } + /** * */ - public function canUseRessources($create = false) + public function canUseRessources(bool $create = false): bool { if (!is_dir($this->path)) { if ($create) { - files::makeDir($this->path); + Files::makeDir($this->path); } return true; @@ -80,9 +141,9 @@ class dcTemplator } /** - * + * @return array{c: string, w: bool, f: string} */ - public function getSourceContent($f) + public function getSourceContent(string $f): array { $source = $this->tpl; @@ -96,8 +157,8 @@ class dcTemplator } return [ - 'c' => file_get_contents($source[$f]), - 'w' => $this->getDestinationFile($f) !== false, + 'c' => (string) file_get_contents($source[$f]), + 'w' => !empty($this->getDestinationFile($f)), 'f' => $f, ]; } @@ -105,7 +166,7 @@ class dcTemplator /** * */ - public function filesList($item = '%1$s') + public function filesList(string $item = '%1$s'): string { $files = $this->tpl; @@ -117,7 +178,7 @@ class dcTemplator foreach ($files as $k => $v) { $li = sprintf('
  • %s
  • ', $item); - $list .= sprintf($li, $k, html::escapeHTML($k)); + $list .= sprintf($li, $k, Html::escapeHTML($k)); } return sprintf('
      %s
    ', $list); @@ -126,31 +187,31 @@ class dcTemplator /** * */ - public function initializeTpl($name, $type) + public function initializeTpl(string $name, string $type): void { if ($type == 'category') { - if ($this->user_category_tpl) { - $base = $this->user_category_tpl; + if ($this->user_tpl_category) { + $base = $this->user_tpl_category; } else { - $base = $this->category_tpl; + $base = $this->file_tpl_category; } } elseif ($type == 'page') { - if ($this->user_page_tpl) { - $base = $this->user_page_tpl; + if ($this->user_tpl_page) { + $base = $this->user_tpl_page; } else { - $base = $this->page_tpl; + $base = $this->file_tpl_page; } } else { - if ($this->user_post_tpl) { - $base = $this->user_post_tpl; + if ($this->user_tpl_post) { + $base = $this->user_tpl_post; } else { - $base = $this->post_tpl; + $base = $this->file_tpl_post; } } $source = [ - 'c' => file_get_contents($base), - 'w' => $this->getDestinationFile($name) !== false, + 'c' => (string) file_get_contents($base), + 'w' => !empty($this->getDestinationFile($name)), ]; if (!$source['w']) { @@ -171,7 +232,7 @@ class dcTemplator $content = $source['c']; if (!is_dir(dirname($dest))) { - files::makeDir(dirname($dest)); + Files::makeDir(dirname($dest)); } $fp = @fopen($dest, 'wb'); @@ -179,8 +240,8 @@ class dcTemplator throw new Exception('tocatch'); } - $content = preg_replace('/(\r?\n)/m', "\n", $content); - $content = preg_replace('/\r/m', "\n", $content); + $content = (string) preg_replace('/(\r?\n)/m', "\n", $content); + $content = (string) preg_replace('/\r/m', "\n", $content); fwrite($fp, $content); fclose($fp); @@ -192,7 +253,7 @@ class dcTemplator /** * */ - public function copypasteTpl($name, $source) + public function copypasteTpl(string $name, string $source): void { if ($name == $source) { throw new Exception(__('File already exists.')); @@ -202,7 +263,7 @@ class dcTemplator $data = [ 'c' => $file['c'], - 'w' => $this->getDestinationFile($name) !== false, + 'w' => !empty($this->getDestinationFile($name)), ]; if (!$data['w']) { @@ -219,7 +280,7 @@ class dcTemplator $content = $data['c']; if (!is_dir(dirname($dest))) { - files::makeDir(dirname($dest)); + Files::makeDir(dirname($dest)); } $fp = @fopen($dest, 'wb'); @@ -227,8 +288,8 @@ class dcTemplator throw new Exception('tocatch'); } - $content = preg_replace('/(\r?\n)/m', "\n", $content); - $content = preg_replace('/\r/m', "\n", $content); + $content = (string) preg_replace('/(\r?\n)/m', "\n", $content); + $content = (string) preg_replace('/\r/m', "\n", $content); fwrite($fp, $content); fclose($fp); @@ -240,7 +301,7 @@ class dcTemplator /** * */ - public function writeTpl($name, $content) + public function writeTpl(string $name, string $content): void { try { $dest = $this->getDestinationFile($name); @@ -250,16 +311,17 @@ class dcTemplator } if (!is_dir(dirname($dest))) { - files::makeDir(dirname($dest)); + Files::makeDir(dirname($dest)); } $fp = @fopen($dest, 'wb'); if (!$fp) { //throw new Exception('tocatch'); + return; } - $content = preg_replace('/(\r?\n)/m', "\n", $content); - $content = preg_replace('/\r/m', "\n", $content); + $content = (string) preg_replace('/(\r?\n)/m', "\n", $content); + $content = (string) preg_replace('/\r/m', "\n", $content); fwrite($fp, $content); fclose($fp); @@ -271,7 +333,7 @@ class dcTemplator /** * */ - public function copyTpl($name) + public function copyTpl(string $name): void { try { $file = $this->getSourceContent($name); @@ -282,7 +344,7 @@ class dcTemplator } if (!is_dir(dirname($dest))) { - files::makeDir(dirname($dest)); + Files::makeDir(dirname($dest)); } $fp = @fopen($dest, 'wb'); @@ -290,7 +352,7 @@ class dcTemplator throw new Exception('tocatch'); } - $content = preg_replace('/(\r?\n)/m', "\n", $file['c']); + $content = (string) preg_replace('/(\r?\n)/m', "\n", $file['c']); $content = preg_replace('/\r/m', "\n", $file['c']); fwrite($fp, $file['c']); @@ -300,11 +362,14 @@ class dcTemplator } } - protected function getDestinationFile($f, $totheme = false) + /** + * @return string The destination or empty string on error + */ + protected function getDestinationFile(string $f, bool $totheme = false): string { $dest = $this->path . '/' . $f; if ($totheme) { - $dest = $this->user_theme . '/tpl/' . $f; + $dest = implode(DIRECTORY_SEPARATOR, [$this->user_path_theme, self::THEME_TPL_DIR, $f]); } if (file_exists($dest) && is_writable($dest)) { @@ -315,27 +380,31 @@ class dcTemplator return $dest; } - return false; + return ''; } - protected function findTemplates() + protected function findTemplates(): void { $this->tpl = $this->getFilesInDir($this->path); - //$this->theme_tpl = $this->getFilesInDir(path::real($this->user_theme).'/tpl'); uksort($this->tpl, [$this,'sortFilesHelper']); - //uksort($this->theme_tpl,array($this,'sortFilesHelper')); } - protected function getFilesInDir($dir) + /** + * @return array + */ + protected function getFilesInDir(string $dir): array { - $dir = path::real($dir); + $res = []; + $dir = Path::real($dir); if (!$dir || !is_dir($dir) || !is_readable($dir)) { - return []; + return $res; } - $d = dir($dir); - $res = []; + $d = dir($dir); + if (!$d) { + return $res; + } while (($f = $d->read()) !== false) { if (is_file($dir . '/' . $f) && !preg_match('/^\./', $f)) { $res[$f] = $dir . '/' . $f; @@ -345,14 +414,14 @@ class dcTemplator return $res; } - protected function sortFilesHelper($a, $b) + protected function sortFilesHelper(string $a, string $b): int { if ($a == $b) { return 0; } - $ext_a = files::getExtension($a); - $ext_b = files::getExtension($b); + $ext_a = Files::getExtension($a); + $ext_b = Files::getExtension($b); return strcmp($ext_a . '.' . $a, $ext_b . '.' . $b); } diff --git a/src/Widgets.php b/src/Widgets.php new file mode 100644 index 0000000..4f079a0 --- /dev/null +++ b/src/Widgets.php @@ -0,0 +1,59 @@ + '']; + $tpls = Templator::instance()->getTpl(); + foreach ($tpls as $k => $v) { + if (preg_match('/^widget-(.+)$/', $k)) { + $tpl = array_merge($tpl, [$k => $k]); + } + } + + $w + ->create( + 'templatorWidget', + __('Templator › Rendering'), + [self::class, 'getDataTpl'] + ) + ->setting( + 'template', + __('Template:'), + '', + 'combo', + $tpl + ); + } + + public static function getDataTpl(WidgetsElement $w): string + { + return is_string($w->__get('template')) && dcCore::app()->tpl->getFilePath($w->__get('template')) ? + dcCore::app()->tpl->getData($w->__get('template')) : ''; + } +}