use namespace
This commit is contained in:
parent
f1d7cb368e
commit
dae470074c
10 changed files with 622 additions and 646 deletions
18
_admin.php
18
_admin.php
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
$admin = implode('\\', ['Dotclear', 'Plugin', basename(__DIR__), 'Admin']);
|
||||
if ($admin::init()) {
|
||||
$admin::process();
|
||||
}
|
19
_config.php
19
_config.php
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
$config = implode('\\', ['Dotclear', 'Plugin', basename(__DIR__), 'Config']);
|
||||
if ($config::init()) {
|
||||
$config::process();
|
||||
$config::render();
|
||||
}
|
22
_prepend.php
22
_prepend.php
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
$prepend = implode('\\', ['Dotclear', 'Plugin', basename(__DIR__), 'Prepend']);
|
||||
if (!class_exists($prepend)) {
|
||||
require implode(DIRECTORY_SEPARATOR, [__DIR__, 'inc', 'Prepend.php']);
|
||||
|
||||
if ($prepend::init()) {
|
||||
$prepend::process();
|
||||
}
|
||||
}
|
239
inc/Core.php
239
inc/Core.php
|
@ -1,239 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\tweakStores;
|
||||
|
||||
/* clearbricks ns */
|
||||
use files;
|
||||
use text;
|
||||
use xmlTag;
|
||||
|
||||
/* php ns */
|
||||
use DOMDocument;
|
||||
use Exception;
|
||||
|
||||
class Core
|
||||
{
|
||||
/** @var array List of notice messages */
|
||||
public static $notice = [];
|
||||
|
||||
/** @var array List of failed messages */
|
||||
public static $failed = [];
|
||||
|
||||
# taken from lib.moduleslist.php
|
||||
public static function sanitizeModule(string $id, array $module): array
|
||||
{
|
||||
$label = empty($module['label']) ? $id : $module['label'];
|
||||
$name = __(empty($module['name']) ? $label : $module['name']);
|
||||
$oname = empty($module['name']) ? $label : $module['name'];
|
||||
|
||||
return array_merge(
|
||||
# Default values
|
||||
[
|
||||
'desc' => '',
|
||||
'author' => '',
|
||||
'version' => 0,
|
||||
'current_version' => 0,
|
||||
'root' => '',
|
||||
'root_writable' => false,
|
||||
'permissions' => null,
|
||||
'parent' => null,
|
||||
'priority' => 1000,
|
||||
'standalone_config' => false,
|
||||
'support' => '',
|
||||
'section' => '',
|
||||
'tags' => '',
|
||||
'details' => '',
|
||||
'sshot' => '',
|
||||
'score' => 0,
|
||||
'type' => null,
|
||||
'requires' => [],
|
||||
'settings' => [],
|
||||
'repository' => '',
|
||||
'dc_min' => 0,
|
||||
],
|
||||
# Module's values
|
||||
$module,
|
||||
# Clean up values
|
||||
[
|
||||
'id' => $id,
|
||||
'sid' => self::sanitizeString($id),
|
||||
'label' => $label,
|
||||
'name' => $name,
|
||||
'oname' => $oname,
|
||||
'sname' => self::sanitizeString($name),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
# taken from lib.moduleslist.php
|
||||
public static function sanitizeString(string $str): string
|
||||
{
|
||||
return (string) preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str));
|
||||
}
|
||||
|
||||
public static function parseFilePattern(string $id, array $module, string $file_pattern): string
|
||||
{
|
||||
$module = self::sanitizeModule($id, $module);
|
||||
|
||||
return text::tidyURL(str_replace(
|
||||
[
|
||||
'%type%',
|
||||
'%id%',
|
||||
'%version%',
|
||||
'%author%',
|
||||
],
|
||||
[
|
||||
$module['type'],
|
||||
$module['id'],
|
||||
$module['version'],
|
||||
$module['author'],
|
||||
],
|
||||
$file_pattern
|
||||
));
|
||||
}
|
||||
|
||||
public static function generateXML(string $id, array $module, string $file_pattern): string
|
||||
{
|
||||
if (!is_array($module) || empty($module)) {
|
||||
return '';
|
||||
}
|
||||
$module = self::sanitizeModule($id, $module);
|
||||
$rsp = new xmlTag('module');
|
||||
|
||||
self::$notice = [];
|
||||
self::$failed = [];
|
||||
|
||||
# id
|
||||
if (empty($module['id'])) {
|
||||
self::$failed[] = 'unknow module';
|
||||
}
|
||||
$rsp->id = $module['id'];
|
||||
|
||||
# name
|
||||
if (empty($module['name'])) {
|
||||
self::$failed[] = 'no module name set in _define.php';
|
||||
}
|
||||
$rsp->name($module['oname']);
|
||||
|
||||
# version
|
||||
if (empty($module['version'])) {
|
||||
self::$failed[] = 'no module version set in _define.php';
|
||||
}
|
||||
$rsp->version($module['version']);
|
||||
|
||||
# author
|
||||
if (empty($module['author'])) {
|
||||
self::$failed[] = 'no module author set in _define.php';
|
||||
}
|
||||
$rsp->author($module['author']);
|
||||
|
||||
# desc
|
||||
if (empty($module['desc'])) {
|
||||
self::$failed[] = 'no module description set in _define.php';
|
||||
}
|
||||
$rsp->desc($module['desc']);
|
||||
|
||||
# repository
|
||||
if (empty($module['repository'])) {
|
||||
self::$failed[] = 'no repository set in _define.php';
|
||||
}
|
||||
|
||||
# file
|
||||
$file_pattern = self::parseFilePattern($id, $module, $file_pattern);
|
||||
if (empty($file_pattern)) {
|
||||
self::$failed[] = 'no zip file pattern set in Tweak Store configuration';
|
||||
}
|
||||
$rsp->file($file_pattern);
|
||||
|
||||
# da dc_min or requires core
|
||||
if (!empty($module['requires']) && is_array($module['requires'])) {
|
||||
foreach ($module['requires'] as $req) {
|
||||
if (!is_array($req)) {
|
||||
$req = [$req];
|
||||
}
|
||||
if ($req[0] == 'core') {
|
||||
$module['dc_min'] = $req[1];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($module['dc_min'])) {
|
||||
self::$notice[] = 'no minimum dotclear version';
|
||||
} else {
|
||||
$rsp->insertNode(new xmlTag('da:dcmin', $module['dc_min']));
|
||||
}
|
||||
|
||||
# details
|
||||
if (empty($module['details'])) {
|
||||
self::$notice[] = 'no details URL';
|
||||
} else {
|
||||
$rsp->insertNode(new xmlTag('da:details', $module['details']));
|
||||
}
|
||||
|
||||
# section
|
||||
if (!empty($module['section'])) {
|
||||
$rsp->insertNode(new xmlTag('da:section', $module['section']));
|
||||
}
|
||||
|
||||
# support
|
||||
if (empty($module['support'])) {
|
||||
self::$notice[] = 'no support URL';
|
||||
} else {
|
||||
$rsp->insertNode(new xmlTag('da:support', $module['support']));
|
||||
}
|
||||
|
||||
$res = new xmlTag('modules', $rsp);
|
||||
$res->insertAttr('xmlns:da', 'http://dotaddict.org/da/');
|
||||
|
||||
return self::prettyXML($res->toXML());
|
||||
}
|
||||
|
||||
public static function writeXML(string $id, array $module, string $file_pattern): bool
|
||||
{
|
||||
self::$failed = [];
|
||||
if (!$module['root_writable']) {
|
||||
return false;
|
||||
}
|
||||
$content = self::generateXML($id, $module, $file_pattern);
|
||||
if (!empty(self::$failed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
files::putContent($module['root'] . '/dcstore.xml', $content);
|
||||
} catch (Exception $e) {
|
||||
self::$failed[] = $e->getMessage();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function prettyXML(string $str): string
|
||||
{
|
||||
if (class_exists('DOMDocument')) {
|
||||
$dom = new DOMDocument('1.0');
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
$dom->loadXML($str);
|
||||
|
||||
return (string) $dom->saveXML();
|
||||
}
|
||||
|
||||
return (string) str_replace('><', ">\n<", $str);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\tweakStores;
|
||||
|
||||
/* clearbricks ns */
|
||||
use Clearbricks;
|
||||
|
||||
class Prepend
|
||||
{
|
||||
private const LIBS = [
|
||||
'Admin',
|
||||
'Config',
|
||||
'Core',
|
||||
];
|
||||
protected static $init = false;
|
||||
|
||||
public static function init(): bool
|
||||
{
|
||||
self::$init = defined('DC_RC_PATH');
|
||||
|
||||
return self::$init;
|
||||
}
|
||||
|
||||
public static function process(): ?bool
|
||||
{
|
||||
if (!self::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (self::LIBS as $lib) {
|
||||
Clearbricks::lib()->autoload([
|
||||
__NAMESPACE__ . '\\' . $lib => __DIR__ . DIRECTORY_SEPARATOR . $lib . '.php',
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
264
src/Backend.php
264
src/Backend.php
|
@ -14,270 +14,38 @@ declare(strict_types=1);
|
|||
|
||||
namespace Dotclear\Plugin\tweakStores;
|
||||
|
||||
/* dotclear ns */
|
||||
use dcCore;
|
||||
use dcPage;
|
||||
use dcNsProcess;
|
||||
|
||||
/* clearbricks ns */
|
||||
use form;
|
||||
use html;
|
||||
|
||||
/* php ns */
|
||||
use Exception;
|
||||
|
||||
class Admin
|
||||
class Backend extends dcNsProcess
|
||||
{
|
||||
private static $pid = '';
|
||||
protected static $init = false;
|
||||
|
||||
public static function init(): bool
|
||||
{
|
||||
if (defined('DC_CONTEXT_ADMIN')
|
||||
&& dcCore::app()->auth->isSuperAdmin()
|
||||
&& dcCore::app()->blog->settings->get(basename(__NAMESPACE__))->get('active')
|
||||
) {
|
||||
dcCore::app()->auth->user_prefs->addWorkspace('interface');
|
||||
self::$pid = basename(dirname(__DIR__));
|
||||
self::$init = true;
|
||||
}
|
||||
static::$init = My::phpCompliant()
|
||||
&& defined('DC_CONTEXT_ADMIN')
|
||||
&& dcCore::app()->auth->isSuperAdmin()
|
||||
&& dcCore::app()->blog->settings->get(My::id())->get('active');
|
||||
|
||||
return self::$init;
|
||||
return static::$init;
|
||||
}
|
||||
|
||||
public static function process(): ?bool
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!self::$init) {
|
||||
if (!static::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dcCore::app()->blog->settings->get(self::$pid)->get('packman')) {
|
||||
// create dcstore.xml file on the fly when plugin packman pack a module
|
||||
dcCore::app()->addBehavior('packmanBeforeCreatePackage', function (array $module): void {
|
||||
Core::writeXML($module['id'], $module, dcCore::app()->blog->settings->get(self::$pid)->get('file_pattern'));
|
||||
});
|
||||
}
|
||||
|
||||
dcCore::app()->addBehaviors([
|
||||
// addd some js
|
||||
'pluginsToolsHeadersV2' => [self::class, 'modulesToolsHeaders'],
|
||||
'themesToolsHeadersV2' => [self::class, 'modulesToolsHeaders'],
|
||||
// admin plugins page tab
|
||||
'pluginsToolsTabsV2' => function (): void {
|
||||
self::modulesToolsTabs(dcCore::app()->plugins->getModules(), explode(',', DC_DISTRIB_PLUGINS), dcCore::app()->adminurl->get('admin.plugins'));
|
||||
},
|
||||
// admin themes page tab
|
||||
'themesToolsTabsV2' => function (): void {
|
||||
self::modulesToolsTabs(dcCore::app()->themes->getModules(), explode(',', DC_DISTRIB_THEMES), dcCore::app()->adminurl->get('admin.blog.theme'));
|
||||
},
|
||||
'pluginsToolsHeadersV2' => [BackendBehaviors::class, 'modulesToolsHeaders'],
|
||||
'themesToolsHeadersV2' => [BackendBehaviors::class, 'modulesToolsHeaders'],
|
||||
// admin modules page tab
|
||||
'pluginsToolsTabsV2' => [BackendBehaviors::class, 'pluginsToolsTabsV2'],
|
||||
'themesToolsTabsV2' => [BackendBehaviors::class, 'themesToolsTabsV2'],
|
||||
// add to plugin pacKman
|
||||
'packmanBeforeCreatePackage' => [BackendBehaviors::class, 'packmanBeforeCreatePackage'],
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function modulesToolsHeaders(bool $is_plugin): string
|
||||
{
|
||||
return
|
||||
dcPage::jsJson('ts_copied', ['alert' => __('Copied to clipboard')]) .
|
||||
dcPage::jsModuleLoad(self::$pid . '/js/admin.js') .
|
||||
(
|
||||
!dcCore::app()->auth->user_prefs->interface->colorsyntax ? '' :
|
||||
dcPage::jsLoadCodeMirror(dcCore::app()->auth->user_prefs->interface->colorsyntax_theme) .
|
||||
dcPage::jsModuleLoad(self::$pid . '/js/cms.js')
|
||||
);
|
||||
}
|
||||
|
||||
protected static function modulesToolsTabs(array $modules, array $excludes, string $page_url): void
|
||||
{
|
||||
$page_url .= '#' . self::$pid;
|
||||
$user_ui_colorsyntax = dcCore::app()->auth->user_prefs->interface->colorsyntax;
|
||||
$user_ui_colorsyntax_theme = dcCore::app()->auth->user_prefs->interface->colorsyntax_theme;
|
||||
$combo = self::comboModules($modules, $excludes);
|
||||
$file_pattern = dcCore::app()->blog->settings->get(self::$pid)->get('file_pattern');
|
||||
|
||||
# check dcstore repo
|
||||
$url = '';
|
||||
if (!empty($_POST['checkxml_id']) && in_array($_POST['checkxml_id'], $combo)) {
|
||||
if (empty($modules[$_POST['checkxml_id']]['repository'])) {
|
||||
$url = __('This module has no repository set in its _define.php file.');
|
||||
} else {
|
||||
try {
|
||||
$url = $modules[$_POST['checkxml_id']]['repository'];
|
||||
if (false === strpos($url, 'dcstore.xml')) {
|
||||
$url .= '/dcstore.xml';
|
||||
}
|
||||
if (function_exists('curl_init')) {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_REFERER, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$file_content = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
} else {
|
||||
$file_content = file_get_contents($url);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$file_content = __('Failed to read third party repository');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# generate xml code
|
||||
if (!empty($_POST['buildxml_id']) && in_array($_POST['buildxml_id'], $combo)) {
|
||||
$xml_content = Core::generateXML($_POST['buildxml_id'], $modules[$_POST['buildxml_id']], $file_pattern);
|
||||
}
|
||||
|
||||
# write dcstore.xml file
|
||||
if (!empty($_POST['write_xml'])) {
|
||||
if (empty($_POST['your_pwd']) || !dcCore::app()->auth->checkPassword($_POST['your_pwd'])) {
|
||||
dcCore::app()->error->add(__('Password verification failed'));
|
||||
} else {
|
||||
$ret = Core::writeXML($_POST['buildxml_id'], $modules[$_POST['buildxml_id']], $file_pattern);
|
||||
if (!empty(Core::$failed)) {
|
||||
dcCore::app()->error->add(implode(' ', Core::$failed));
|
||||
}
|
||||
}
|
||||
}
|
||||
echo
|
||||
'<div class="multi-part" id="' . self::$pid . '" title="' . dcCore::app()->plugins->moduleInfo(self::$pid, 'name') . '">' .
|
||||
'<h3>' . __('Tweak third-party repositories') . '</h3>';
|
||||
|
||||
if (!empty($_POST['write_xml'])) {
|
||||
if (dcCore::app()->error->flag()) {
|
||||
echo dcCore::app()->error->toHTML();
|
||||
} else {
|
||||
echo '<p class="success">' . __('File successfully written') . '</p>';
|
||||
}
|
||||
}
|
||||
if (count($combo) < 2) {
|
||||
echo
|
||||
'<div class="info">' . __('There is no module to tweak') . '</div>' .
|
||||
'</div>';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
echo
|
||||
'<form method="post" action="' . $page_url . '" id="checkxml" class="fieldset">' .
|
||||
'<h4>' . __('Check repository') . '</h4>' .
|
||||
'<p>' . __('This checks if dcstore.xml file is present on third party repository.') . '</p>' .
|
||||
'<p class="field"><label for="buildxml_id" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Module to parse:') . '</label> ' .
|
||||
form::combo('checkxml_id', $combo, empty($_POST['checkxml_id']) ? '-' : html::escapeHTML($_POST['checkxml_id'])) .
|
||||
'</p>' .
|
||||
'<p><input type="submit" name="check_xml" value="' . __('Check') . '" />' .
|
||||
dcCore::app()->formNonce() . '</p>' .
|
||||
'</form>';
|
||||
|
||||
if (!empty($url)) {
|
||||
echo
|
||||
'<div class="fieldset">' .
|
||||
'<h4>' . __('Repositiory contents') . '</h4>' .
|
||||
'<p>' . $url . '</p>' .
|
||||
(
|
||||
empty($file_content) ? '' :
|
||||
'<pre>' . form::textArea('file_xml', 165, 14, [
|
||||
'default' => html::escapeHTML(Core::prettyXML($file_content)),
|
||||
'class' => 'maximal',
|
||||
'extra_html' => 'readonly="true"',
|
||||
]) . '</pre>' .
|
||||
(
|
||||
!$user_ui_colorsyntax ? '' :
|
||||
dcPage::jsRunCodeMirror('editor', 'file_xml', 'dotclear', $user_ui_colorsyntax_theme)
|
||||
)
|
||||
) .
|
||||
'</div>';
|
||||
}
|
||||
|
||||
if (empty($file_pattern)) {
|
||||
echo sprintf(
|
||||
'<div class="fieldset"><h4>' . __('Generate xml code') . '</h4><p class="info"><a href="%s">%s</a></p></div>',
|
||||
dcCore::app()->adminurl->get('admin.plugins', ['module' => self::$pid, 'conf' => 1, 'redir' => $page_url]),
|
||||
__('You must configure zip file pattern to complete xml code automatically.')
|
||||
);
|
||||
} else {
|
||||
echo
|
||||
'<form method="post" action="' . $page_url . '" id="buildxml" class="fieldset">' .
|
||||
'<h4>' . __('Generate xml code') . '</h4>' .
|
||||
'<p>' . __('This helps to generate content of dcstore.xml for seleted module.') . '</p>' .
|
||||
'<p class="field"><label for="buildxml_id" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Module to parse:') . '</label> ' .
|
||||
form::combo('buildxml_id', $combo, empty($_POST['buildxml_id']) ? '-' : html::escapeHTML($_POST['buildxml_id'])) .
|
||||
'</p>' .
|
||||
'<p><input type="submit" name="build_xml" value="' . __('Generate') . '" />' .
|
||||
dcCore::app()->formNonce() . '</p>' .
|
||||
'</form>';
|
||||
}
|
||||
if (!empty($_POST['buildxml_id'])) {
|
||||
echo
|
||||
'<form method="post" action="' . $page_url . '" id="writexml" class="fieldset">' .
|
||||
'<h4>' . sprintf(__('Generated code for module: %s'), html::escapeHTML($_POST['buildxml_id'])) . '</h4>';
|
||||
|
||||
if (!empty(Core::$failed)) {
|
||||
echo '<p class="info">' . sprintf(__('Failed to parse XML code: %s'), implode(', ', Core::$failed)) . '</p> ';
|
||||
}
|
||||
if (!empty(Core::$notice)) {
|
||||
echo '<p class="info">' . sprintf(__('Code is not fully filled: %s'), implode(', ', Core::$notice)) . '</p> ';
|
||||
}
|
||||
if (!empty($xml_content)) {
|
||||
if (empty(Core::$failed) && empty(Core::$notice)) {
|
||||
echo '<p class="info">' . __('Code is complete') . '</p>';
|
||||
}
|
||||
echo
|
||||
'<pre>' . form::textArea('gen_xml', 165, 14, [
|
||||
'default' => html::escapeHTML(Core::prettyXML($xml_content)),
|
||||
'class' => 'maximal',
|
||||
'extra_html' => 'readonly="true"',
|
||||
]) . '</pre>' .
|
||||
(
|
||||
!$user_ui_colorsyntax ? '' :
|
||||
dcPage::jsRunCodeMirror('editor', 'gen_xml', 'dotclear', $user_ui_colorsyntax_theme)
|
||||
);
|
||||
|
||||
if (empty(Core::$failed)
|
||||
&& $modules[$_POST['buildxml_id']]['root_writable']
|
||||
&& dcCore::app()->auth->isSuperAdmin()
|
||||
) {
|
||||
echo
|
||||
'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Your password:') . '</label> ' .
|
||||
form::password(
|
||||
['your_pwd', 'your_pwd2'],
|
||||
20,
|
||||
255,
|
||||
[
|
||||
'extra_html' => 'required placeholder="' . __('Password') . '"',
|
||||
'autocomplete' => 'current-password',
|
||||
]
|
||||
) . '</p>' .
|
||||
'<p><input type="submit" name="write_xml" value="' . __('Save to module directory') . '" /> ' .
|
||||
'<a class="hidden-if-no-js button" href="#' . self::$pid . '" id="ts_copy_button">' . __('Copy to clipboard') . '</a>' .
|
||||
form::hidden('buildxml_id', $_POST['buildxml_id']) .
|
||||
dcCore::app()->formNonce() . '</p>';
|
||||
}
|
||||
echo sprintf(
|
||||
'<p class="info"><a href="%s">%s</a></p>',
|
||||
dcCore::app()->adminurl->get('admin.plugins', ['module' => self::$pid, 'conf' => 1, 'redir' => $page_url]),
|
||||
__('You can edit zip file pattern from configuration page.')
|
||||
);
|
||||
}
|
||||
echo
|
||||
'</form>';
|
||||
}
|
||||
echo
|
||||
'</div>';
|
||||
}
|
||||
|
||||
# create list of module for combo and remove official modules
|
||||
protected static function comboModules(array $modules, array $excludes): array
|
||||
{
|
||||
$combo = [__('Select a module') => '0'];
|
||||
foreach ($modules as $id => $module) {
|
||||
if (in_array($id, $excludes)) {
|
||||
continue;
|
||||
}
|
||||
$combo[$module['name'] . ' ' . $module['version']] = $id;
|
||||
}
|
||||
|
||||
return $combo;
|
||||
}
|
||||
}
|
||||
|
|
421
src/BackendBehaviors.php
Normal file
421
src/BackendBehaviors.php
Normal file
|
@ -0,0 +1,421 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\tweakStores;
|
||||
|
||||
/* dotclear ns */
|
||||
use dcCore;
|
||||
use dcModuleDefine;
|
||||
use dcModules;
|
||||
use dcPage;
|
||||
|
||||
/* clearbricks ns */
|
||||
use files;
|
||||
use form;
|
||||
use html;
|
||||
use text;
|
||||
use xmlTag;
|
||||
|
||||
/* php ns */
|
||||
use DOMDocument;
|
||||
use Exception;
|
||||
|
||||
class BackendBehaviors
|
||||
{
|
||||
/** @var array List of notice messages */
|
||||
private static $notice = [];
|
||||
|
||||
/** @var array List of failed messages */
|
||||
private static $failed = [];
|
||||
|
||||
public static function packmanBeforeCreatePackage(array $module): void
|
||||
{
|
||||
if (!dcCore::app()->blog->settings->get(My::id())->get('packman')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// move from array to dcModuleDefine object
|
||||
$modules = $module['type'] == 'theme' ? dcCore::app()->themes : dcCore::app()->plugins;
|
||||
$define = $modules->getDefine($module['id']);
|
||||
|
||||
self::writeXML($define, dcCore::app()->blog->settings->get(My::id())->get('file_pattern'));
|
||||
}
|
||||
|
||||
public static function modulesToolsHeaders(bool $is_plugin): string
|
||||
{
|
||||
return
|
||||
dcPage::jsJson('ts_copied', ['alert' => __('Copied to clipboard')]) .
|
||||
dcPage::jsModuleLoad(My::id() . '/js/backend.js') .
|
||||
(
|
||||
!dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax') ? '' :
|
||||
dcPage::jsLoadCodeMirror(dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax_theme')) .
|
||||
dcPage::jsModuleLoad(My::id() . '/js/cms.js')
|
||||
);
|
||||
}
|
||||
|
||||
public static function pluginsToolsTabsV2(): void
|
||||
{
|
||||
self::modulesToolsTabs(dcCore::app()->plugins, explode(',', DC_DISTRIB_PLUGINS), dcCore::app()->adminurl->get('admin.plugins'));
|
||||
}
|
||||
|
||||
public static function themesToolsTabsV2(): void
|
||||
{
|
||||
self::modulesToolsTabs(dcCore::app()->themes, explode(',', DC_DISTRIB_THEMES), dcCore::app()->adminurl->get('admin.blog.theme'));
|
||||
}
|
||||
|
||||
private static function modulesToolsTabs(dcModules $modules, array $excludes, string $page_url): void
|
||||
{
|
||||
$page_url .= '#' . My::id();
|
||||
$user_ui_colorsyntax = dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax');
|
||||
$user_ui_colorsyntax_theme = dcCore::app()->auth->user_prefs->get('interface')->get('colorsyntax_theme');
|
||||
$file_pattern = (new Settings())->file_pattern;
|
||||
|
||||
$module = $modules->getDefine($_POST['ts_id'] ?? '-');
|
||||
$combo = self::comboModules($modules, $excludes);
|
||||
$form = '<p class="field"><label for="buildxml_id" class="classic required">' .
|
||||
'<abbr title="' . __('Required field') . '">*</abbr> ' . __('Module to parse:') . '</label> ' .
|
||||
form::combo('ts_id', $combo, $module->isDefined() ? html::escapeHTML($module->get('id')) : '-') .
|
||||
'</p>';
|
||||
|
||||
# check dcstore repo
|
||||
$url = '';
|
||||
if (!empty($_POST['check_xml']) && $module->isDefined()) {
|
||||
if (empty($module->get('repository'))) {
|
||||
$url = __('This module has no repository set in its _define.php file.');
|
||||
} else {
|
||||
try {
|
||||
$url = $module->get('repository');
|
||||
if (false === strpos($url, 'dcstore.xml')) {
|
||||
$url .= '/dcstore.xml';
|
||||
}
|
||||
if (function_exists('curl_init')) {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_REFERER, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$file_content = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
} else {
|
||||
$file_content = file_get_contents($url);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$file_content = __('Failed to read third party repository');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# generate xml code
|
||||
if (!empty($_POST['build_xml']) && $module->isDefined()) {
|
||||
$xml_content = self::generateXML($module, $file_pattern);
|
||||
}
|
||||
|
||||
# write dcstore.xml file
|
||||
if (!empty($_POST['write_xml'])) {
|
||||
if (empty($_POST['your_pwd']) || !dcCore::app()->auth->checkPassword($_POST['your_pwd'])) {
|
||||
dcCore::app()->error->add(__('Password verification failed'));
|
||||
} else {
|
||||
$ret = self::writeXML($module, $file_pattern);
|
||||
if (!empty(self::$failed)) {
|
||||
dcCore::app()->error->add(implode(' ', self::$failed));
|
||||
}
|
||||
}
|
||||
}
|
||||
echo
|
||||
'<div class="multi-part" id="' . My::id() . '" title="' . My::name() . '">' .
|
||||
'<h3>' . __('Tweak third-party repositories') . '</h3>';
|
||||
|
||||
if (!empty($_POST['write_xml'])) {
|
||||
if (dcCore::app()->error->flag()) {
|
||||
echo dcCore::app()->error->toHTML();
|
||||
} else {
|
||||
echo '<p class="success">' . __('File successfully written') . '</p>';
|
||||
}
|
||||
}
|
||||
if (count($combo) < 2) {
|
||||
echo
|
||||
'<div class="info">' . __('There is no module to tweak') . '</div>' .
|
||||
'</div>';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
echo
|
||||
'<form method="post" action="' . $page_url . '" id="checkxml" class="fieldset">' .
|
||||
'<h4>' . __('Check repository') . '</h4>' .
|
||||
'<p>' . __('This checks if dcstore.xml file is present on third party repository.') . '</p>' .
|
||||
$form .
|
||||
'<p><input type="submit" name="check_xml" value="' . __('Check') . '" />' .
|
||||
dcCore::app()->formNonce() . '</p>' .
|
||||
'</form>';
|
||||
|
||||
if (!empty($url)) {
|
||||
echo
|
||||
'<div class="fieldset">' .
|
||||
'<h4>' . __('Repositiory contents') . '</h4>' .
|
||||
'<p>' . $url . '</p>' .
|
||||
(
|
||||
empty($file_content) ? '' :
|
||||
'<pre>' . form::textArea('file_xml', 165, 14, [
|
||||
'default' => html::escapeHTML(self::prettyXML($file_content)),
|
||||
'class' => 'maximal',
|
||||
'extra_html' => 'readonly="true"',
|
||||
]) . '</pre>' .
|
||||
(
|
||||
!$user_ui_colorsyntax ? '' :
|
||||
dcPage::jsRunCodeMirror('editor', 'file_xml', 'dotclear', $user_ui_colorsyntax_theme)
|
||||
)
|
||||
) .
|
||||
'</div>';
|
||||
}
|
||||
|
||||
if (empty($file_pattern)) {
|
||||
echo sprintf(
|
||||
'<div class="fieldset"><h4>' . __('Generate xml code') . '</h4><p class="info"><a href="%s">%s</a></p></div>',
|
||||
dcCore::app()->adminurl->get('admin.plugins', ['module' => My::id(), 'conf' => 1, 'redir' => $page_url]),
|
||||
__('You must configure zip file pattern to complete xml code automatically.')
|
||||
);
|
||||
} else {
|
||||
echo
|
||||
'<form method="post" action="' . $page_url . '" id="buildxml" class="fieldset">' .
|
||||
'<h4>' . __('Generate xml code') . '</h4>' .
|
||||
'<p>' . __('This helps to generate content of dcstore.xml for seleted module.') . '</p>' .
|
||||
$form .
|
||||
'<p><input type="submit" name="build_xml" value="' . __('Generate') . '" />' .
|
||||
dcCore::app()->formNonce() . '</p>' .
|
||||
'</form>';
|
||||
}
|
||||
if (!empty($_POST['build_xml'])) {
|
||||
echo
|
||||
'<form method="post" action="' . $page_url . '" id="writexml" class="fieldset">' .
|
||||
'<h4>' . sprintf(__('Generated code for module: %s'), html::escapeHTML($module->get('id'))) . '</h4>';
|
||||
|
||||
if (!empty(self::$failed)) {
|
||||
echo '<p class="info">' . sprintf(__('Failed to parse XML code: %s'), implode(', ', self::$failed)) . '</p> ';
|
||||
}
|
||||
if (!empty(self::$notice)) {
|
||||
echo '<p class="info">' . sprintf(__('Code is not fully filled: %s'), implode(', ', self::$notice)) . '</p> ';
|
||||
}
|
||||
if (!empty($xml_content)) {
|
||||
if (empty(self::$failed) && empty(self::$notice)) {
|
||||
echo '<p class="info">' . __('Code is complete') . '</p>';
|
||||
}
|
||||
echo
|
||||
'<pre>' . form::textArea('gen_xml', 165, 14, [
|
||||
'default' => html::escapeHTML(self::prettyXML($xml_content)),
|
||||
'class' => 'maximal',
|
||||
'extra_html' => 'readonly="true"',
|
||||
]) . '</pre>' .
|
||||
(
|
||||
!$user_ui_colorsyntax ? '' :
|
||||
dcPage::jsRunCodeMirror('editor', 'gen_xml', 'dotclear', $user_ui_colorsyntax_theme)
|
||||
);
|
||||
|
||||
if (empty(self::$failed)
|
||||
&& $module->get('root_writable')
|
||||
&& dcCore::app()->auth->isSuperAdmin()
|
||||
) {
|
||||
echo
|
||||
'<p class="field"><label for="your_pwd2" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Your password:') . '</label> ' .
|
||||
form::password(
|
||||
['your_pwd', 'your_pwd2'],
|
||||
20,
|
||||
255,
|
||||
[
|
||||
'extra_html' => 'required placeholder="' . __('Password') . '"',
|
||||
'autocomplete' => 'current-password',
|
||||
]
|
||||
) . '</p>' .
|
||||
'<p><input type="submit" name="write_xml" value="' . __('Save to module directory') . '" /> ' .
|
||||
'<a class="hidden-if-no-js button" href="#' . My::id() . '" id="ts_copy_button">' . __('Copy to clipboard') . '</a>' .
|
||||
form::hidden('ts_id', $_POST['ts_id']) .
|
||||
dcCore::app()->formNonce() . '</p>';
|
||||
}
|
||||
echo sprintf(
|
||||
'<p class="info"><a href="%s">%s</a></p>',
|
||||
dcCore::app()->adminurl->get('admin.plugins', ['module' => My::id(), 'conf' => 1, 'redir' => $page_url]),
|
||||
__('You can edit zip file pattern from configuration page.')
|
||||
);
|
||||
}
|
||||
echo
|
||||
'</form>';
|
||||
}
|
||||
echo
|
||||
'</div>';
|
||||
}
|
||||
|
||||
# create list of module for combo and remove official modules
|
||||
private static function comboModules(dcModules $modules, array $excludes): array
|
||||
{
|
||||
$combo = [__('Select a module') => '0'];
|
||||
foreach ($modules->getDefines() as $module) {
|
||||
if (in_array($module->get('id'), $excludes)) {
|
||||
continue;
|
||||
}
|
||||
$combo[$module->get('name') . ' ' . $module->get('version')] = $module->get('id');
|
||||
}
|
||||
|
||||
return $combo;
|
||||
}
|
||||
|
||||
private static function parseFilePattern(dcModuleDefine $module, string $file_pattern): string
|
||||
{
|
||||
return text::tidyURL(str_replace(
|
||||
[
|
||||
'%type%',
|
||||
'%id%',
|
||||
'%version%',
|
||||
'%author%',
|
||||
],
|
||||
[
|
||||
$module->get('type'),
|
||||
$module->get('id'),
|
||||
$module->get('version'),
|
||||
$module->get('author'),
|
||||
],
|
||||
$file_pattern
|
||||
));
|
||||
}
|
||||
|
||||
private static function generateXML(dcModuleDefine $module, string $file_pattern): string
|
||||
{
|
||||
$rsp = new xmlTag('module');
|
||||
|
||||
self::$notice = [];
|
||||
self::$failed = [];
|
||||
|
||||
# id
|
||||
if (!$module->isDefined()) {
|
||||
self::$failed[] = 'unknow module';
|
||||
}
|
||||
$rsp->id = $module->get('id');
|
||||
|
||||
# name
|
||||
if (empty($module->get('name'))) {
|
||||
self::$failed[] = 'no module name set in _define.php';
|
||||
}
|
||||
$rsp->name($module->get('name'));
|
||||
|
||||
# version
|
||||
if (empty($module->get('version'))) {
|
||||
self::$failed[] = 'no module version set in _define.php';
|
||||
}
|
||||
$rsp->version($module->get('version'));
|
||||
|
||||
# author
|
||||
if (empty($module->get('author'))) {
|
||||
self::$failed[] = 'no module author set in _define.php';
|
||||
}
|
||||
$rsp->author($module->get('author'));
|
||||
|
||||
# desc
|
||||
if (empty($module->get('desc'))) {
|
||||
self::$failed[] = 'no module description set in _define.php';
|
||||
}
|
||||
$rsp->desc($module->get('desc'));
|
||||
|
||||
# repository
|
||||
if (empty($module->get('repository'))) {
|
||||
self::$failed[] = 'no repository set in _define.php';
|
||||
}
|
||||
|
||||
# file
|
||||
$file_pattern = self::parseFilePattern($module, $file_pattern);
|
||||
if (empty($file_pattern)) {
|
||||
self::$failed[] = 'no zip file pattern set in Tweak Store configuration';
|
||||
}
|
||||
$rsp->file($file_pattern);
|
||||
|
||||
# da dc_min or requires core
|
||||
if (!empty($module->get('requires')) && is_array($module->get('requires'))) {
|
||||
foreach ($module->get('requires') as $req) {
|
||||
if (!is_array($req)) {
|
||||
$req = [$req];
|
||||
}
|
||||
if ($req[0] == 'core') {
|
||||
$module->set('dc_min', $req[1]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($module->get('dc_min'))) {
|
||||
self::$notice[] = 'no minimum dotclear version';
|
||||
} else {
|
||||
$rsp->insertNode(new xmlTag('da:dcmin', $module->get('dc_min')));
|
||||
}
|
||||
|
||||
# details
|
||||
if (empty($module->get('details'))) {
|
||||
self::$notice[] = 'no details URL';
|
||||
} else {
|
||||
$rsp->insertNode(new xmlTag('da:details', $module->get('details')));
|
||||
}
|
||||
|
||||
# section
|
||||
if (!empty($module->get('section'))) {
|
||||
$rsp->insertNode(new xmlTag('da:section', $module->get('section')));
|
||||
}
|
||||
|
||||
# support
|
||||
if (empty($module->get('support'))) {
|
||||
self::$notice[] = 'no support URL';
|
||||
} else {
|
||||
$rsp->insertNode(new xmlTag('da:support', $module->get('support')));
|
||||
}
|
||||
|
||||
$res = new xmlTag('modules', $rsp);
|
||||
$res->insertAttr('xmlns:da', 'http://dotaddict.org/da/');
|
||||
|
||||
return self::prettyXML($res->toXML());
|
||||
}
|
||||
|
||||
private static function writeXML(dcModuleDefine $module, string $file_pattern): bool
|
||||
{
|
||||
self::$failed = [];
|
||||
if (!$module->get('root_writable')) {
|
||||
return false;
|
||||
}
|
||||
$content = self::generateXML($module, $file_pattern);
|
||||
if (!empty(self::$failed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
files::putContent($module->get('root') . DIRECTORY_SEPARATOR . 'dcstore.xml', $content);
|
||||
} catch (Exception $e) {
|
||||
self::$failed[] = $e->getMessage();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function prettyXML(string $str): string
|
||||
{
|
||||
if (class_exists('DOMDocument')) {
|
||||
$dom = new DOMDocument('1.0');
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
$dom->loadXML($str);
|
||||
|
||||
return (string) $dom->saveXML();
|
||||
}
|
||||
|
||||
return (string) str_replace('><', ">\n<", $str);
|
||||
}
|
||||
}
|
109
src/Config.php
109
src/Config.php
|
@ -16,89 +16,98 @@ namespace Dotclear\Plugin\tweakStores;
|
|||
|
||||
/* dotclear ns */
|
||||
use dcCore;
|
||||
use dcNsProcess;
|
||||
use dcPage;
|
||||
|
||||
/* clearbricks ns */
|
||||
use form;
|
||||
use http;
|
||||
use Dotclear\Helper\Html\Form\{
|
||||
Checkbox,
|
||||
Div,
|
||||
Fieldset,
|
||||
Input,
|
||||
Label,
|
||||
Legend,
|
||||
Note,
|
||||
Para
|
||||
};
|
||||
|
||||
/* php ns */
|
||||
use Exception;
|
||||
|
||||
class Config
|
||||
class Config extends dcNsProcess
|
||||
{
|
||||
private static $pid = '';
|
||||
protected static $init = false;
|
||||
|
||||
public static function init(): bool
|
||||
{
|
||||
if (defined('DC_CONTEXT_ADMIN') && defined('DC_CONTEXT_MODULE')) {
|
||||
dcPage::checkSuper();
|
||||
self::$pid = basename(dirname(__DIR__));
|
||||
self::$init = true;
|
||||
}
|
||||
static::$init = My::phpCompliant()
|
||||
&& defined('DC_CONTEXT_ADMIN')
|
||||
&& defined('DC_CONTEXT_MODULE')
|
||||
&& dcCore::app()->auth->isSuperAdmin();
|
||||
|
||||
return self::$init;
|
||||
return static::$init;
|
||||
}
|
||||
|
||||
public static function process(): ?bool
|
||||
public static function process(): bool
|
||||
{
|
||||
if (!self::$init) {
|
||||
if (!static::$init) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($_POST['save'])) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
|
||||
$s = new Settings();
|
||||
|
||||
try {
|
||||
$s = dcCore::app()->blog->settings->get(self::$pid);
|
||||
$s->put('active', !empty($_POST['s_active']));
|
||||
$s->put('packman', !empty($_POST['s_packman']));
|
||||
$s->put('file_pattern', $_POST['s_file_pattern']);
|
||||
foreach ($s->listSettings() as $key) {
|
||||
$s->writeSetting($key, $_POST['ts_' . $key] ?? '');
|
||||
}
|
||||
|
||||
dcPage::addSuccessNotice(
|
||||
__('Configuration successfully updated')
|
||||
);
|
||||
http::redirect(
|
||||
dcCore::app()->admin->__get('list')->getURL('module=' . self::$pid . '&conf=1&redir=' . dcCore::app()->admin->__get('list')->getRedir())
|
||||
dcCore::app()->adminurl->redirect(
|
||||
'admin.plugins',
|
||||
['module' => My::id(), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()]
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
dcCore::app()->error->add($e->getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function render(): void
|
||||
{
|
||||
$s = dcCore::app()->blog->settings->get(self::$pid);
|
||||
if (!static::$init) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '
|
||||
<div class="fieldset">
|
||||
<h4>' . dcCore::app()->plugins->moduleInfo(self::$pid, 'name') . '</h4>
|
||||
$s = new Settings();
|
||||
|
||||
<p><label class="classic" for="s_active">' .
|
||||
form::checkbox('s_active', 1, (bool) $s->get('active')) . ' ' .
|
||||
__('Enable plugin') . '</label></p>
|
||||
<p class="form-note">' . __('If enabled, new tab "Tweak stores" allows your to perfom actions relative to third-party repositories.') . '</p>
|
||||
|
||||
<p><label class="classic" for="s_packman">' .
|
||||
form::checkbox('s_packman', 1, (bool) $s->get('packman')) . ' ' .
|
||||
__('Enable packman behaviors') . '</label></p>
|
||||
<p class="form-note">' . __('If enabled, plugin pacKman will (re)generate on the fly dcstore.xml file at root directory of the module.') . '</p>
|
||||
|
||||
<p><label class="classic" for="s_file_pattern">' . __('Predictable URL to zip file on the external repository') .
|
||||
form::field('s_file_pattern', 65, 255, (string) $s->get('file_pattern'), 'maximal') . '
|
||||
</label></p>
|
||||
<p class="form-note">' .
|
||||
__('You can use widcard like %author%, %type%, %id%, %version%.') . '<br /> ' .
|
||||
__('For example on github https://github.com/MyGitName/%id%/releases/download/v%version%/%type%-%id%.zip') . '<br />' .
|
||||
__('Note: on github, you must create a release and join to it the module zip file.') . '
|
||||
</p>
|
||||
|
||||
</div>';
|
||||
echo (new Div())->items([
|
||||
(new Fieldset())->class('fieldset')->legend(new Legend(__('Interface')))->fields([
|
||||
// s_active
|
||||
(new Para())->items([
|
||||
(new Checkbox('ts_active', $s->active))->value(1),
|
||||
(new Label(__('Enable plugin'), Label::OUTSIDE_LABEL_AFTER))->for('ts_active')->class('classic'),
|
||||
]),
|
||||
(new Note())->text(__('If enabled, new tab "Tweak stores" allows your to perfom actions relative to third-party repositories.'))->class('form-note'),
|
||||
// s_file_pattern
|
||||
(new Para())->items([
|
||||
(new Label(__('Predictable URL to zip file on the external repository')))->for('ts_file_pattern'),
|
||||
(new Input('ts_file_pattern'))->size(65)->maxlenght(255)->value($s->file_pattern),
|
||||
]),
|
||||
(new Note())->text(__('You can use widcard like %author%, %type%, %id%, %version%.'))->class('form-note'),
|
||||
(new Note())->text(__('For example on github https://github.com/MyGitName/%id%/releases/download/v%version%/%type%-%id%.zip'))->class('form-note'),
|
||||
(new Note())->text(__('Note: on github, you must create a release and join to it the module zip file.'))->class('form-note'),
|
||||
]),
|
||||
(new Fieldset())->class('fieldset')->legend(new Legend(__('Behaviors')))->fields([
|
||||
// s_packman
|
||||
(new Para())->items([
|
||||
(new Checkbox('ts_packman', $s->packman))->value(1),
|
||||
(new Label(__('Enable packman behaviors'), Label::OUTSIDE_LABEL_AFTER))->for('ts_packman')->class('classic'),
|
||||
]),
|
||||
(new Note())->text(__('If enabled, plugin pacKman will (re)generate on the fly dcstore.xml file at root directory of the module.'))->class('form-note'),
|
||||
]),
|
||||
])->render();
|
||||
}
|
||||
}
|
||||
|
|
50
src/My.php
Normal file
50
src/My.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\tweakStores;
|
||||
|
||||
use dcCore;
|
||||
|
||||
/**
|
||||
* Plugin definitions
|
||||
*/
|
||||
class My
|
||||
{
|
||||
/** @var string Required php version */
|
||||
public const PHP_MIN = '8.1';
|
||||
|
||||
/**
|
||||
* This module id
|
||||
*/
|
||||
public static function id(): string
|
||||
{
|
||||
return basename(dirname(__DIR__));
|
||||
}
|
||||
|
||||
/**
|
||||
* This module name
|
||||
*/
|
||||
public static function name(): string
|
||||
{
|
||||
return __((string) dcCore::app()->plugins->moduleInfo(self::id(), 'name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check php version
|
||||
*/
|
||||
public static function phpCompliant(): bool
|
||||
{
|
||||
return version_compare(phpversion(), self::PHP_MIN, '>=');
|
||||
}
|
||||
}
|
76
src/Settings.php
Normal file
76
src/Settings.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* @brief tweakStores, a plugin for Dotclear 2
|
||||
*
|
||||
* @package Dotclear
|
||||
* @subpackage Plugin
|
||||
*
|
||||
* @author Jean-Christian Denis and Contributors
|
||||
*
|
||||
* @copyright Jean-Christian Denis
|
||||
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Dotclear\Plugin\tweakStores;
|
||||
|
||||
use dcCore;
|
||||
|
||||
class Settings
|
||||
{
|
||||
// Enable this plugin
|
||||
public readonly bool $active;
|
||||
|
||||
// Enable plugin pacKman behavior
|
||||
public readonly bool $packman;
|
||||
|
||||
// Predictable dcstore url
|
||||
public readonly string $file_pattern;
|
||||
|
||||
/**
|
||||
* Constructor set up plugin settings
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$s = dcCore::app()->blog->settings->get(My::id());
|
||||
|
||||
$this->active = (bool) ($s->get('active') ?? false);
|
||||
$this->packman = (bool) ($s->get('packman') ?? false);
|
||||
$this->file_pattern = (string) ($s->get('file_pattern') ?? '');
|
||||
}
|
||||
|
||||
public function getSetting(string $key): mixed
|
||||
{
|
||||
return $this->{$key} ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite a plugin settings (in db)
|
||||
*
|
||||
* @param string $key The setting ID
|
||||
* @param mixed $value The setting value
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function writeSetting(string $key, mixed $value): bool
|
||||
{
|
||||
if (property_exists($this, $key) && settype($value, gettype($this->{$key})) === true) {
|
||||
dcCore::app()->blog->settings->get(My::id())->drop($key);
|
||||
dcCore::app()->blog->settings->get(My::id())->put($key, $value, gettype($this->{$key}), '', true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* List defined settings keys
|
||||
*
|
||||
* @return array The settings keys
|
||||
*/
|
||||
public function listSettings(): array
|
||||
{
|
||||
return array_keys(get_class_vars(Settings::class));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue