+ extension can have own settings page

This commit is contained in:
maxpozdeev 2022-09-08 11:55:05 +03:00
parent 85140018dd
commit 456d34d30d
6 changed files with 139 additions and 9 deletions

View file

@ -20,6 +20,7 @@ require_once(MTTINC. 'api/ListsController.php');
require_once(MTTINC. 'api/TasksController.php');
require_once(MTTINC. 'api/TagsController.php');
require_once(MTTINC. 'api/AuthController.php');
require_once(MTTINC. 'api/ExtSettingsController.php');
$endpoints = array(
'/lists' => [
@ -53,6 +54,10 @@ $endpoints = array(
'/(login|logout|session)' => [
'POST' => [ AuthController::class , 'postAction' ],
],
'/ext-settings/(.+)' => [
'GET' => [ ExtSettingsController::class , 'get' ],
'PUT' => [ ExtSettingsController::class , 'put' ],
]
);
$req = new ApiRequest();

View file

@ -598,6 +598,9 @@ var mytinytodo = window.mytinytodo = _mtt = {
else if (settingsPage == 'ext-activate' || settingsPage == 'ext-deactivate') {
activateExtension(settingsPage == 'ext-activate' ? true : false, this.dataset.ext);
}
else if (settingsPage == 'ext-index') {
showExtensionSettings(this.dataset.ext);
}
return false;
});
@ -606,6 +609,11 @@ var mytinytodo = window.mytinytodo = _mtt = {
return false;
});
$("#page_ajax").on('submit', '#ext_settings_form', function() {
saveExtensionSettings(this);
return false;
});
$(document).on('click', '.mtt-back-button', function() {
_mtt.pageBack(true);
this.blur();
@ -2518,16 +2526,10 @@ function flashInfo(str, details)
$("#msg").addClass('mtt-info').effect("highlight", {color:_mtt.theme.msgFlashColor}, 700);
}
function toggleMsgDetails()
{
var el = $("#msg>.msg-details");
if(!el) return;
if(el.css('display') == 'none') el.show();
else el.hide()
}
function hideAlert()
{
$("#msg>.msg-text").text('');
$("#msg>.msg-details").text('');
$("#msg").hide().removeClass('mtt-error mtt-info').find('.msg-details').hide();
}
@ -2654,6 +2656,40 @@ function activateExtension(activate, ext)
}, 'json');
}
function showExtensionSettings(ext, callback)
{
if (_mtt.pages.current && _mtt.pages.current.page == 'ajax' && _mtt.pages.current.pageClass == 'settings') {
$('#page_ajax').load(_mtt.apiUrl + 'ext-settings/' + ext, null, function() {
if (callback !== undefined) callback();
});
}
}
function saveExtensionSettings(frm)
{
if (!frm) return false;
var ext = frm.dataset.ext;
var params = {};
$(frm).find("input:hidden,input:text,input:password,input:checked,select").filter(":enabled").each(function() { params[this.name || '__'] = this.value; });
$.ajax({
url: _mtt.apiUrl + 'ext-settings/' + ext,
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify(params),
dataType: 'json',
success: function(json) {
if (json.saved) {
if (json.msg) showExtensionSettings(ext, function(){
flashInfo(json.msg);
});
else showExtensionSettings(ext);
}
}
});
}
/*
* Dialogs
*/

View file

@ -938,7 +938,9 @@ li.mtt-item-hidden { display:none; }
border-color: var(--color-border-focus);
box-shadow:0 0 0 2px var(--color-border-focus-shadow);
}
.mtt-settings-table a {
color: var(--color-text-default);
}
#modal {
position: absolute;

View file

@ -0,0 +1,78 @@
<?php declare(strict_types=1);
class ExtSettingsController extends ApiController {
/**
* Get extension settings page
* @return void
* @throws Exception
*/
function get($ext)
{
/** @var MTTExtension|MTTExtensionSettingsInterface $instance */
$instance = $this->extInstance($ext);
if (!$instance) {
return;
}
$data = $instance->settingsPage();
$title = htmlspecialchars($instance::title);
$escapedExt = htmlspecialchars($ext);
$e = function($s) { return __($s, true); };
$data =
<<<EOD
<h3 class="page-title"><a class="mtt-back-button"></a> $title </h3>
<div id="settings_msg" style="display:none"></div>
<form id="ext_settings_form" data-ext="$escapedExt">
<div class="mtt-settings-table">
$data
<div class="form-bottom-buttons">
<button type="submit">{$e('set_submit')}</button>
<button type="button" class="mtt-back-button">{$e('set_cancel')}</button>
</div>
</div>
</form>
EOD;
$this->response->htmlContent($data);
}
/**
* Save extension settings
* @return void
* @throws Exception
*/
function put($ext)
{
/** @var MTTExtension|MTTExtensionSettingsInterface $instance */
$instance = $this->extInstance($ext);
if (!$instance) {
return;
}
//$userError = '';
$saved = $instance->saveSettings($this->req->jsonBody ?? [], $userError);
$a = [ 'saved' => (int)$saved ];
if ($userError) {
$a['msg'] = $userError;
}
$this->response->data = $a;
}
private function extInstance($ext): ?MTTExtensionSettingsInterface
{
$instance = MTTExtensionLoader::extensionInstance($ext);
if (!$instance) {
$this->response->data = [ 'msg' => "Unknown extension" ];
$this->response->code = 404;
return null;
}
if (! ($instance instanceof MTTExtensionSettingsInterface) ) {
$this->response->data = [ 'msg' => "No settings page for extension" ];
$this->response->code = 500;
return null;
}
return $instance;
}
}

View file

@ -79,6 +79,11 @@ abstract class MTTExtension
}
interface MTTExtensionSettingsInterface
{
function settingsPage(): string;
function saveSettings(array $array, ?string &$userError): bool;
}
class MTTExtensionLoader

View file

@ -189,6 +189,10 @@ function listExtensions()
$out = "$ext ";
if (in_array($ext, $activatedExts)) {
$out .= "<a href='#' data-settings-link='ext-deactivate' data-ext='". htmlspecialchars($ext). "'>". __('set_deactivate', true). '</a>';
$instance = MTTExtensionLoader::extensionInstance($ext);
if ($instance instanceof MTTExtensionSettingsInterface) {
$out .= " <a href='#' data-settings-link='ext-index' data-ext='". htmlspecialchars($ext). "'>". __('a_settings', true). "</a>";
}
}
else {
$out .= "<a href='#' data-settings-link='ext-activate' data-ext='". htmlspecialchars($ext). "'>". __('set_activate', true). '</a>';