Merge pull request #388 from ArthurHoaro/pluginadmin
Fixes #378 - Plugin administration UI.
This commit is contained in:
commit
53603f5823
20 changed files with 636 additions and 7 deletions
|
@ -73,6 +73,106 @@ function writeConfig($config, $isLoggedIn)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process plugin administration form data and save it in an array.
|
||||
*
|
||||
* @param array $formData Data sent by the plugin admin form.
|
||||
*
|
||||
* @return array New list of enabled plugin, ordered.
|
||||
*
|
||||
* @throws PluginConfigOrderException Plugins can't be sorted because their order is invalid.
|
||||
*/
|
||||
function save_plugin_config($formData)
|
||||
{
|
||||
// Make sure there are no duplicates in orders.
|
||||
if (!validate_plugin_order($formData)) {
|
||||
throw new PluginConfigOrderException();
|
||||
}
|
||||
|
||||
$plugins = array();
|
||||
$newEnabledPlugins = array();
|
||||
foreach ($formData as $key => $data) {
|
||||
if (startsWith($key, 'order')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is no order, it means a disabled plugin has been enabled.
|
||||
if (isset($formData['order_' . $key])) {
|
||||
$plugins[(int) $formData['order_' . $key]] = $key;
|
||||
}
|
||||
else {
|
||||
$newEnabledPlugins[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
// New enabled plugins will be added at the end of order.
|
||||
$plugins = array_merge($plugins, $newEnabledPlugins);
|
||||
|
||||
// Sort plugins by order.
|
||||
if (!ksort($plugins)) {
|
||||
throw new PluginConfigOrderException();
|
||||
}
|
||||
|
||||
$finalPlugins = array();
|
||||
// Make plugins order continuous.
|
||||
foreach ($plugins as $plugin) {
|
||||
$finalPlugins[] = $plugin;
|
||||
}
|
||||
|
||||
return $finalPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate plugin array submitted.
|
||||
* Will fail if there is duplicate orders value.
|
||||
*
|
||||
* @param array $formData Data from submitted form.
|
||||
*
|
||||
* @return bool true if ok, false otherwise.
|
||||
*/
|
||||
function validate_plugin_order($formData)
|
||||
{
|
||||
$orders = array();
|
||||
foreach ($formData as $key => $value) {
|
||||
// No duplicate order allowed.
|
||||
if (in_array($value, $orders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (startsWith($key, 'order')) {
|
||||
$orders[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affect plugin parameters values into plugins array.
|
||||
*
|
||||
* @param mixed $plugins Plugins array ($plugins[<plugin_name>]['parameters']['param_name'] = <value>.
|
||||
* @param mixed $config Plugins configuration.
|
||||
*
|
||||
* @return mixed Updated $plugins array.
|
||||
*/
|
||||
function load_plugin_parameter_values($plugins, $config)
|
||||
{
|
||||
$out = $plugins;
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
if (empty($plugin['parameters'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($plugin['parameters'] as $key => $param) {
|
||||
if (!empty($config[$key])) {
|
||||
$out[$name]['parameters'][$key] = $config[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Milestone 0.9 - shaarli/Shaarli#41: options.php is not supported anymore.
|
||||
* ==> if user is loggedIn, merge its content with config.php, then delete options.php.
|
||||
|
@ -132,3 +232,17 @@ public function __construct()
|
|||
$this->message = 'You are not authorized to alter config.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception used if an error occur while saving plugin configuration.
|
||||
*/
|
||||
class PluginConfigOrderException extends Exception
|
||||
{
|
||||
/**
|
||||
* Construct exception.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->message = 'An error occurred while trying to save plugins loading order.';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,12 @@ class PluginManager
|
|||
*/
|
||||
public static $PLUGINS_PATH = 'plugins';
|
||||
|
||||
/**
|
||||
* Plugins meta files extension.
|
||||
* @var string $META_EXT
|
||||
*/
|
||||
public static $META_EXT = 'meta';
|
||||
|
||||
/**
|
||||
* Private constructor: new instances not allowed.
|
||||
*/
|
||||
|
@ -162,6 +168,51 @@ public function buildHookName($hook, $pluginName)
|
|||
{
|
||||
return 'hook_' . $pluginName . '_' . $hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve plugins metadata from *.meta (INI) files into an array.
|
||||
* Metadata contains:
|
||||
* - plugin description [description]
|
||||
* - parameters split with ';' [parameters]
|
||||
*
|
||||
* Respects plugins order from settings.
|
||||
*
|
||||
* @return array plugins metadata.
|
||||
*/
|
||||
public function getPluginsMeta()
|
||||
{
|
||||
$metaData = array();
|
||||
$dirs = glob(self::$PLUGINS_PATH . '/*', GLOB_ONLYDIR | GLOB_MARK);
|
||||
|
||||
// Browse all plugin directories.
|
||||
foreach ($dirs as $pluginDir) {
|
||||
$plugin = basename($pluginDir);
|
||||
$metaFile = $pluginDir . $plugin . '.' . self::$META_EXT;
|
||||
if (!is_file($metaFile) || !is_readable($metaFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$metaData[$plugin] = parse_ini_file($metaFile);
|
||||
$metaData[$plugin]['order'] = array_search($plugin, $this->authorizedPlugins);
|
||||
|
||||
// Read parameters and format them into an array.
|
||||
if (isset($metaData[$plugin]['parameters'])) {
|
||||
$params = explode(';', $metaData[$plugin]['parameters']);
|
||||
} else {
|
||||
$params = array();
|
||||
}
|
||||
$metaData[$plugin]['parameters'] = array();
|
||||
foreach ($params as $param) {
|
||||
if (empty($param)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$metaData[$plugin]['parameters'][$param] = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $metaData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,6 +35,10 @@ class Router
|
|||
|
||||
public static $PAGE_LINKLIST = 'linklist';
|
||||
|
||||
public static $PAGE_PLUGINSADMIN = 'pluginadmin';
|
||||
|
||||
public static $PAGE_SAVE_PLUGINSADMIN = 'save_pluginadmin';
|
||||
|
||||
/**
|
||||
* Reproducing renderPage() if hell, to avoid regression.
|
||||
*
|
||||
|
@ -112,6 +116,14 @@ public static function findPage($query, $get, $loggedIn)
|
|||
return self::$PAGE_IMPORT;
|
||||
}
|
||||
|
||||
if (startswith($query, 'do='. self::$PAGE_PLUGINSADMIN)) {
|
||||
return self::$PAGE_PLUGINSADMIN;
|
||||
}
|
||||
|
||||
if (startswith($query, 'do='. self::$PAGE_SAVE_PLUGINSADMIN)) {
|
||||
return self::$PAGE_SAVE_PLUGINSADMIN;
|
||||
}
|
||||
|
||||
return self::$PAGE_LINKLIST;
|
||||
}
|
||||
}
|
67
inc/plugin_admin.js
Normal file
67
inc/plugin_admin.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Change the position counter of a row.
|
||||
*
|
||||
* @param elem Element Node to change.
|
||||
* @param toPos int New position.
|
||||
*/
|
||||
function changePos(elem, toPos)
|
||||
{
|
||||
var elemName = elem.getAttribute('data-line')
|
||||
|
||||
elem.setAttribute('data-order', toPos);
|
||||
var hiddenInput = document.querySelector('[name="order_'+ elemName +'"]');
|
||||
hiddenInput.setAttribute('value', toPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a row up or down.
|
||||
*
|
||||
* @param pos Element Node to move.
|
||||
* @param move int Move: +1 (down) or -1 (up)
|
||||
*/
|
||||
function changeOrder(pos, move)
|
||||
{
|
||||
var newpos = parseInt(pos) + move;
|
||||
var line = document.querySelector('[data-order="'+ pos +'"]');
|
||||
var changeline = document.querySelector('[data-order="'+ newpos +'"]');
|
||||
var parent = changeline.parentNode;
|
||||
|
||||
changePos(line, newpos);
|
||||
changePos(changeline, parseInt(pos));
|
||||
var changeItem = move < 0 ? changeline : changeline.nextSibling;
|
||||
parent.insertBefore(line, changeItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a row up in the table.
|
||||
*
|
||||
* @param pos int row counter.
|
||||
*
|
||||
* @returns false
|
||||
*/
|
||||
function orderUp(pos)
|
||||
{
|
||||
if (pos == 0) {
|
||||
return false;
|
||||
}
|
||||
changeOrder(pos, -1);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a row down in the table.
|
||||
*
|
||||
* @param pos int row counter.
|
||||
*
|
||||
* @returns false
|
||||
*/
|
||||
function orderDown(pos)
|
||||
{
|
||||
var lastpos = document.querySelector('[data-order]:last-child').getAttribute('data-order');
|
||||
if (pos == lastpos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
changeOrder(pos, +1);
|
||||
return false;
|
||||
}
|
|
@ -1102,6 +1102,66 @@ ul.errors {
|
|||
float: left;
|
||||
}
|
||||
|
||||
#pluginsadmin {
|
||||
width: 80%;
|
||||
padding: 20px 0 0 20px;
|
||||
}
|
||||
|
||||
#pluginsadmin section {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
#pluginsadmin .plugin_parameters {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
#pluginsadmin h1 {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#pluginsadmin h2 {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#pluginsadmin table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#pluginsadmin table, #pluginsadmin th, #pluginsadmin td {
|
||||
border-width: 1px 0;
|
||||
border-style: solid;
|
||||
border-color: #c0c0c0;
|
||||
}
|
||||
|
||||
#pluginsadmin table th {
|
||||
font-weight: bold;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
#pluginsadmin table td {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
#pluginsadmin input[type=submit] {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
#pluginsadmin .plugin_parameter {
|
||||
padding: 5px 0;
|
||||
border-width: 1px 0;
|
||||
border-style: solid;
|
||||
border-color: #c0c0c0;
|
||||
}
|
||||
|
||||
#pluginsadmin .float_label {
|
||||
float: left;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#pluginsadmin a {
|
||||
color: black;
|
||||
}
|
||||
/* 404 page */
|
||||
.error-container {
|
||||
|
||||
|
|
48
index.php
48
index.php
|
@ -1770,6 +1770,54 @@ function renderPage()
|
|||
exit;
|
||||
}
|
||||
|
||||
// Plugin administration page
|
||||
if ($targetPage == Router::$PAGE_PLUGINSADMIN) {
|
||||
$pluginMeta = $pluginManager->getPluginsMeta();
|
||||
|
||||
// Split plugins into 2 arrays: ordered enabled plugins and disabled.
|
||||
$enabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] !== false; });
|
||||
// Load parameters.
|
||||
$enabledPlugins = load_plugin_parameter_values($enabledPlugins, $GLOBALS['plugins']);
|
||||
uasort(
|
||||
$enabledPlugins,
|
||||
function($a, $b) { return $a['order'] - $b['order']; }
|
||||
);
|
||||
$disabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] === false; });
|
||||
|
||||
$PAGE->assign('enabledPlugins', $enabledPlugins);
|
||||
$PAGE->assign('disabledPlugins', $disabledPlugins);
|
||||
$PAGE->renderPage('pluginsadmin');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Plugin administration form action
|
||||
if ($targetPage == Router::$PAGE_SAVE_PLUGINSADMIN) {
|
||||
try {
|
||||
if (isset($_POST['parameters_form'])) {
|
||||
unset($_POST['parameters_form']);
|
||||
foreach ($_POST as $param => $value) {
|
||||
$GLOBALS['plugins'][$param] = escape($value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$GLOBALS['config']['ENABLED_PLUGINS'] = save_plugin_config($_POST);
|
||||
}
|
||||
writeConfig($GLOBALS, isLoggedIn());
|
||||
}
|
||||
catch (Exception $e) {
|
||||
error_log(
|
||||
'ERROR while saving plugin configuration:.' . PHP_EOL .
|
||||
$e->getMessage()
|
||||
);
|
||||
|
||||
// TODO: do not handle exceptions/errors in JS.
|
||||
echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=pluginsadmin\';</script>';
|
||||
exit;
|
||||
}
|
||||
header('Location: ?do='. Router::$PAGE_PLUGINSADMIN);
|
||||
exit;
|
||||
}
|
||||
|
||||
// -------- Otherwise, simply display search form and links:
|
||||
showLinkList($PAGE, $LINKSDB);
|
||||
exit;
|
||||
|
|
1
plugins/addlink_toolbar/addlink_toolbar.meta
Normal file
1
plugins/addlink_toolbar/addlink_toolbar.meta
Normal file
|
@ -0,0 +1 @@
|
|||
description="Adds the addlink input on the linklist page."
|
1
plugins/archiveorg/archiveorg.meta
Normal file
1
plugins/archiveorg/archiveorg.meta
Normal file
|
@ -0,0 +1 @@
|
|||
description="For each link, add an Archive.org icon."
|
1
plugins/demo_plugin/demo_plugin.meta
Normal file
1
plugins/demo_plugin/demo_plugin.meta
Normal file
|
@ -0,0 +1 @@
|
|||
description="A demo plugin covering all use cases for template designers and plugin developers."
|
1
plugins/playvideos/playvideos.meta
Normal file
1
plugins/playvideos/playvideos.meta
Normal file
|
@ -0,0 +1 @@
|
|||
description="Add a button in the toolbar allowing to watch all videos."
|
1
plugins/qrcode/qrcode.meta
Normal file
1
plugins/qrcode/qrcode.meta
Normal file
|
@ -0,0 +1 @@
|
|||
description="For each link, add a QRCode icon ."
|
2
plugins/readityourself/readityourself.meta
Normal file
2
plugins/readityourself/readityourself.meta
Normal file
|
@ -0,0 +1,2 @@
|
|||
description="For each link, add a ReadItYourself icon to save the shaared URL."
|
||||
parameters=READITYOUSELF_URL;
|
|
@ -13,7 +13,7 @@
|
|||
include PluginManager::$PLUGINS_PATH . '/readityourself/config.php';
|
||||
}
|
||||
|
||||
if (!isset($GLOBALS['plugins']['READITYOUSELF_URL'])) {
|
||||
if (empty($GLOBALS['plugins']['READITYOUSELF_URL'])) {
|
||||
$GLOBALS['plugin_errors'][] = 'Readityourself plugin error: '.
|
||||
'Please define "$GLOBALS[\'plugins\'][\'READITYOUSELF_URL\']" '.
|
||||
'in "plugins/readityourself/config.php" or in your Shaarli config.php file.';
|
||||
|
|
2
plugins/wallabag/wallabag.meta
Normal file
2
plugins/wallabag/wallabag.meta
Normal file
|
@ -0,0 +1,2 @@
|
|||
description="For each link, add a Wallabag icon to save it in your instance."
|
||||
parameters="WALLABAG_URL"
|
|
@ -11,7 +11,7 @@
|
|||
include PluginManager::$PLUGINS_PATH . '/wallabag/config.php';
|
||||
}
|
||||
|
||||
if (!isset($GLOBALS['plugins']['WALLABAG_URL'])) {
|
||||
if (empty($GLOBALS['plugins']['WALLABAG_URL'])) {
|
||||
$GLOBALS['plugin_errors'][] = 'Wallabag plugin error: '.
|
||||
'Please define "$GLOBALS[\'plugins\'][\'WALLABAG_URL\']" '.
|
||||
'in "plugins/wallabag/config.php" or in your Shaarli config.php file.';
|
||||
|
|
|
@ -174,4 +174,113 @@ public function testMergeDeprecatedConfigNoFile()
|
|||
include self::$configFields['config']['CONFIG_FILE'];
|
||||
$this->assertEquals(self::$configFields['login'], $GLOBALS['login']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config with valid data.
|
||||
*
|
||||
* @throws PluginConfigOrderException
|
||||
*/
|
||||
public function testSavePluginConfigValid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2, // no plugin related
|
||||
'plugin2' => 0, // new - at the end
|
||||
'plugin3' => 0, // 2nd
|
||||
'order_plugin3' => 8,
|
||||
'plugin4' => 0, // 1st
|
||||
'order_plugin4' => 5,
|
||||
);
|
||||
|
||||
$expected = array(
|
||||
'plugin3',
|
||||
'plugin4',
|
||||
'plugin2',
|
||||
);
|
||||
|
||||
$out = save_plugin_config($data);
|
||||
$this->assertEquals($expected, $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config with invalid data.
|
||||
*
|
||||
* @expectedException PluginConfigOrderException
|
||||
*/
|
||||
public function testSavePluginConfigInvalid()
|
||||
{
|
||||
$data = array(
|
||||
'plugin2' => 0,
|
||||
'plugin3' => 0,
|
||||
'order_plugin3' => 0,
|
||||
'plugin4' => 0,
|
||||
'order_plugin4' => 0,
|
||||
);
|
||||
|
||||
save_plugin_config($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save_plugin_config without data.
|
||||
*/
|
||||
public function testSavePluginConfigEmpty()
|
||||
{
|
||||
$this->assertEquals(array(), save_plugin_config(array()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validate_plugin_order with valid data.
|
||||
*/
|
||||
public function testValidatePluginOrderValid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2,
|
||||
'plugin2' => 0,
|
||||
'plugin3' => 0,
|
||||
'order_plugin3' => 1,
|
||||
'plugin4' => 0,
|
||||
'order_plugin4' => 5,
|
||||
);
|
||||
|
||||
$this->assertTrue(validate_plugin_order($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validate_plugin_order with invalid data.
|
||||
*/
|
||||
public function testValidatePluginOrderInvalid()
|
||||
{
|
||||
$data = array(
|
||||
'order_plugin1' => 2,
|
||||
'order_plugin3' => 1,
|
||||
'order_plugin4' => 1,
|
||||
);
|
||||
|
||||
$this->assertFalse(validate_plugin_order($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test load_plugin_parameter_values.
|
||||
*/
|
||||
public function testLoadPluginParameterValues()
|
||||
{
|
||||
$plugins = array(
|
||||
'plugin_name' => array(
|
||||
'parameters' => array(
|
||||
'param1' => true,
|
||||
'param2' => false,
|
||||
'param3' => '',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$parameters = array(
|
||||
'param1' => 'value1',
|
||||
'param2' => 'value2',
|
||||
);
|
||||
|
||||
$result = load_plugin_parameter_values($plugins, $parameters);
|
||||
$this->assertEquals('value1', $result['plugin_name']['parameters']['param1']);
|
||||
$this->assertEquals('value2', $result['plugin_name']['parameters']['param2']);
|
||||
$this->assertEquals('', $result['plugin_name']['parameters']['param3']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,4 +63,23 @@ public function testPluginNotFound()
|
|||
|
||||
$pluginManager->load(array('nope', 'renope'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test plugin metadata loading.
|
||||
*/
|
||||
public function testGetPluginsMeta()
|
||||
{
|
||||
$pluginManager = PluginManager::getInstance();
|
||||
|
||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
||||
$pluginManager->load(array(self::$pluginName));
|
||||
|
||||
$expectedParameters = array(
|
||||
'pop' => '',
|
||||
'hip' => '',
|
||||
);
|
||||
$meta = $pluginManager->getPluginsMeta();
|
||||
$this->assertEquals('test plugin', $meta[self::$pluginName]['description']);
|
||||
$this->assertEquals($expectedParameters, $meta[self::$pluginName]['parameters']);
|
||||
}
|
||||
}
|
2
tests/plugins/test/test.meta
Normal file
2
tests/plugins/test/test.meta
Normal file
|
@ -0,0 +1,2 @@
|
|||
description="test plugin"
|
||||
parameters="pop;hip"
|
131
tpl/pluginsadmin.html
Normal file
131
tpl/pluginsadmin.html
Normal file
|
@ -0,0 +1,131 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>{include="includes"}</head>
|
||||
<body>
|
||||
<div id="pageheader">
|
||||
{include="page.header"}
|
||||
</div>
|
||||
|
||||
<noscript>
|
||||
<div>
|
||||
<ul class="errors">
|
||||
<li>You need to enable Javascript to change plugin loading order.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</noscript>
|
||||
|
||||
<div id="pluginsadmin">
|
||||
<form action="?do=save_pluginadmin" method="POST">
|
||||
<section id="enabled_plugins">
|
||||
<h1>Enabled Plugins</h1>
|
||||
|
||||
<div>
|
||||
{if="count($enabledPlugins)==0"}
|
||||
<p>No plugin enabled.</p>
|
||||
{else}
|
||||
<table id="plugin_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="center">Disable</th>
|
||||
<th class="center">Order</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{loop="$enabledPlugins"}
|
||||
<tr data-line="{$key}" data-order="{$counter}">
|
||||
<td class="center"><input type="checkbox" name="{$key}" checked="checked"></td>
|
||||
<td class="center">
|
||||
<a href="#"
|
||||
onclick="return orderUp(this.parentNode.parentNode.getAttribute('data-order'));">
|
||||
▲
|
||||
</a>
|
||||
<a href="#"
|
||||
onclick="return orderDown(this.parentNode.parentNode.getAttribute('data-order'));">
|
||||
▼
|
||||
</a>
|
||||
<input type="hidden" name="order_{$key}" value="{$counter}">
|
||||
</td>
|
||||
<td>{$key}</td>
|
||||
<td>{$value.description}</td>
|
||||
</tr>
|
||||
{/loop}
|
||||
</tbody>
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="disabled_plugins">
|
||||
<h1>Disabled Plugins</h1>
|
||||
|
||||
<div>
|
||||
{if="count($disabledPlugins)==0"}
|
||||
<p>No plugin disabled.</p>
|
||||
{else}
|
||||
<table>
|
||||
<tr>
|
||||
<th class="center">Enable</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
{loop="$disabledPlugins"}
|
||||
<tr>
|
||||
<td class="center"><input type="checkbox" name="{$key}"></td>
|
||||
<td>{$key}</td>
|
||||
<td>{$value.description}</td>
|
||||
</tr>
|
||||
{/loop}
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<input type="submit" value="Save"/>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
||||
<form action="?do=save_pluginadmin" method="POST">
|
||||
<section id="plugin_parameters">
|
||||
<h1>Enabled Plugin Parameters</h1>
|
||||
|
||||
<div>
|
||||
{if="count($enabledPlugins)==0"}
|
||||
<p>No plugin enabled.</p>
|
||||
{else}
|
||||
{loop="$enabledPlugins"}
|
||||
{if="count($value.parameters) > 0"}
|
||||
<div class="plugin_parameters">
|
||||
<h2>{$key}</h2>
|
||||
{loop="$value.parameters"}
|
||||
<div class="plugin_parameter">
|
||||
<div class="float_label">
|
||||
<label for="{$key}">
|
||||
<code>{$key}</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="float_input">
|
||||
<input name="{$key}" value="{$value}" id="{$key}"/>
|
||||
</div>
|
||||
</div>
|
||||
{/loop}
|
||||
</div>
|
||||
{/if}
|
||||
{/loop}
|
||||
{/if}
|
||||
<div class="center">
|
||||
<input type="submit" name="parameters_form" value="Save"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
{include="page.footer"}
|
||||
|
||||
<script src="inc/plugin_admin.js#"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -5,11 +5,18 @@
|
|||
<div id="pageheader">
|
||||
{include="page.header"}
|
||||
<div id="toolsdiv">
|
||||
{if="!$GLOBALS['config']['OPEN_SHAARLI']"}<a href="?do=changepasswd"><b>Change password</b> <span>: Change your password.</span></a><br><br>{/if}
|
||||
<a href="?do=configure"><b>Configure your Shaarli</b> <span>: Change Title, timezone...</span></a><br><br>
|
||||
<a href="?do=changetag"><b>Rename/delete tags</b> <span>: Rename or delete a tag in all links</span></a><br><br>
|
||||
<a href="?do=import"><b>Import</b> <span>: Import Netscape html bookmarks (as exported from Firefox, Chrome, Opera, delicious...)</span></a> <br><br>
|
||||
<a href="?do=export"><b>Export</b> <span>: Export Netscape html bookmarks (which can be imported in Firefox, Chrome, Opera, delicious...)</span></a><br><br>
|
||||
<a href="?do=configure"><b>Configure your Shaarli</b><span>: Change Title, timezone...</span></a>
|
||||
<br><br>
|
||||
<a href="?do=pluginadmin"><b>Plugin administration</b><span>: Enable, disable and configure plugins.</span></a>
|
||||
<br><br>
|
||||
{if="!$GLOBALS['config']['OPEN_SHAARLI']"}<a href="?do=changepasswd"><b>Change password</b><span>: Change your password.</span></a>
|
||||
<br><br>{/if}
|
||||
<a href="?do=changetag"><b>Rename/delete tags</b><span>: Rename or delete a tag in all links</span></a>
|
||||
<br><br>
|
||||
<a href="?do=import"><b>Import</b><span>: Import Netscape html bookmarks (as exported from Firefox, Chrome, Opera, delicious...)</span></a>
|
||||
<br><br>
|
||||
<a href="?do=export"><b>Export</b><span>: Export Netscape html bookmarks (which can be imported in Firefox, Chrome, Opera, delicious...)</span></a>
|
||||
<br><br>
|
||||
<a class="smallbutton"
|
||||
onclick="return alertBookmarklet();"
|
||||
href="javascript:(
|
||||
|
|
Loading…
Reference in a new issue