a13f7ca6a6
Generic: Repo Health / Site Health (push) Has been cancelled
Generic: Repo Health / Access control (push) Has been cancelled
Universal: Auto Version Bump / Version Bump (push) Has been cancelled
Generic: Repo Health / Release configuration (push) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Update all references in Makefile, manifest.xml, .gitignore, and CI workflows (ci-joomla, pr-check, repo-health) to use source/ as the primary directory with src/ as a fallback for compatibility. Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
121 lines
3.7 KiB
PHP
121 lines
3.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @package MokoJoomBackup
|
|
* @subpackage com_mokobackup
|
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
* @license GNU General Public License version 3 or later; see LICENSE
|
|
*/
|
|
|
|
namespace Joomla\Component\MokoBackup\Administrator\Field;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\Form\FormField;
|
|
use Joomla\CMS\Language\Text;
|
|
|
|
class ExcludeListField extends FormField
|
|
{
|
|
protected $type = 'ExcludeList';
|
|
|
|
protected function getInput(): string
|
|
{
|
|
$id = htmlspecialchars($this->id, ENT_QUOTES, 'UTF-8');
|
|
$name = htmlspecialchars($this->name, ENT_QUOTES, 'UTF-8');
|
|
$placeholder = htmlspecialchars((string) ($this->element['hint'] ?? ''), ENT_QUOTES, 'UTF-8');
|
|
|
|
// Parse current values (newline-separated)
|
|
$items = [];
|
|
|
|
if (!empty($this->value)) {
|
|
$items = array_values(array_filter(array_map('trim', explode("\n", str_replace("\r", '', $this->value)))));
|
|
}
|
|
|
|
$html = '<div id="' . $id . '_wrapper">';
|
|
$html .= '<input type="hidden" name="' . $name . '" id="' . $id . '" value="" />';
|
|
$html .= '<table class="table table-sm mb-1" id="' . $id . '_table">';
|
|
$html .= '<tbody>';
|
|
|
|
foreach ($items as $item) {
|
|
$safeItem = htmlspecialchars($item, ENT_QUOTES, 'UTF-8');
|
|
$html .= '<tr>';
|
|
$html .= '<td><input type="text" class="form-control form-control-sm ' . $id . '_input" value="' . $safeItem . '" placeholder="' . $placeholder . '" /></td>';
|
|
$html .= '<td class="w-1"><button type="button" class="btn btn-sm btn-outline-danger ' . $id . '_remove"><span class="icon-delete" aria-hidden="true"></span></button></td>';
|
|
$html .= '</tr>';
|
|
}
|
|
|
|
$html .= '</tbody></table>';
|
|
$html .= '<button type="button" class="btn btn-sm btn-outline-success" id="' . $id . '_add">';
|
|
$html .= '<span class="icon-plus" aria-hidden="true"></span> ' . Text::_('JGLOBAL_FIELD_ADD') . '</button>';
|
|
$html .= '</div>';
|
|
|
|
$html .= <<<SCRIPT
|
|
<script>
|
|
(function() {
|
|
var wrapper = document.getElementById('{$id}_wrapper');
|
|
var hidden = document.getElementById('{$id}');
|
|
var tbody = document.querySelector('#{$id}_table tbody');
|
|
var addBtn = document.getElementById('{$id}_add');
|
|
var placeholder = '{$placeholder}';
|
|
|
|
function sync() {
|
|
var vals = [];
|
|
wrapper.querySelectorAll('.{$id}_input').forEach(function(inp) {
|
|
var v = inp.value.trim();
|
|
if (v) vals.push(v);
|
|
});
|
|
hidden.value = vals.join('\\n');
|
|
}
|
|
|
|
function addRow(value) {
|
|
var tr = document.createElement('tr');
|
|
var td1 = document.createElement('td');
|
|
var inp = document.createElement('input');
|
|
inp.type = 'text';
|
|
inp.className = 'form-control form-control-sm {$id}_input';
|
|
inp.value = value || '';
|
|
inp.placeholder = placeholder;
|
|
inp.addEventListener('input', sync);
|
|
td1.appendChild(inp);
|
|
|
|
var td2 = document.createElement('td');
|
|
td2.className = 'w-1';
|
|
var btn = document.createElement('button');
|
|
btn.type = 'button';
|
|
btn.className = 'btn btn-sm btn-outline-danger {$id}_remove';
|
|
var icon = document.createElement('span');
|
|
icon.className = 'icon-delete';
|
|
icon.setAttribute('aria-hidden', 'true');
|
|
btn.appendChild(icon);
|
|
btn.addEventListener('click', function() { tr.remove(); sync(); });
|
|
td2.appendChild(btn);
|
|
|
|
tr.appendChild(td1);
|
|
tr.appendChild(td2);
|
|
tbody.appendChild(tr);
|
|
inp.focus();
|
|
}
|
|
|
|
addBtn.addEventListener('click', function() { addRow(''); });
|
|
|
|
wrapper.querySelectorAll('.{$id}_input').forEach(function(inp) {
|
|
inp.addEventListener('input', sync);
|
|
});
|
|
|
|
wrapper.querySelectorAll('.{$id}_remove').forEach(function(btn) {
|
|
btn.addEventListener('click', function() {
|
|
btn.closest('tr').remove();
|
|
sync();
|
|
});
|
|
});
|
|
|
|
sync();
|
|
})();
|
|
</script>
|
|
SCRIPT;
|
|
|
|
return $html;
|
|
}
|
|
}
|