6 Commits
v1.9 ... master

7 changed files with 61 additions and 15 deletions

View File

@@ -75,7 +75,42 @@
trigger.options[i].disabled = isTarget; trigger.options[i].disabled = isTarget;
} }
if (trigger.value === target.value) { trigger.value = "any"; } if (trigger.value === target.value) { trigger.value = "any"; }
if (invert) { invert.disabled = (trigger.value === "any"); }
if (invert) {
var invertDisabled = (trigger.value === "any");
invert.disabled = invertDisabled;
var invertLabel = invert.closest("label");
if (invertLabel) { invertLabel.style.opacity = invertDisabled ? "0.5" : ""; }
}
}
// Move-mode makes copies moot, so grey out "Link copies to the template" while it is checked
// (disabled -> it won't post, so the saved value is 0).
function applyMove() {
var move = document.querySelector('input[name="recoreco_move"]');
var link = document.querySelector('input[name="recoreco_link_copies"]');
if (!move || !link) { return; }
link.disabled = move.checked;
var label = link.closest("label");
if (label) { label.style.opacity = move.checked ? "0.5" : ""; }
}
// Italicize the card's current column in the target/trigger dropdowns, so you can see where it
// sits right now. (<option> styling is honored by Chrome/Firefox; Safari may ignore it.)
function applyCurrentItalic() {
var form = document.querySelector('form[data-recoreco-current]');
if (!form) { return; }
var current = form.getAttribute("data-recoreco-current");
var selects = form.querySelectorAll('select[name="recoreco_target_column"], select[name="recoreco_trigger_column"]');
for (var s = 0; s < selects.length; s++) {
for (var i = 0; i < selects[s].options.length; i++) {
if (selects[s].options[i].value === current) {
selects[s].options[i].style.fontStyle = "italic";
}
}
}
} }
document.addEventListener("change", function (e) { document.addEventListener("change", function (e) {
@@ -88,6 +123,9 @@
if (e.target && (e.target.name === "recoreco_target_column" || e.target.name === "recoreco_trigger_column")) { if (e.target && (e.target.name === "recoreco_target_column" || e.target.name === "recoreco_trigger_column")) {
applyTrigger(); applyTrigger();
} }
if (e.target && e.target.name === "recoreco_move") {
applyMove();
}
}); });
if (window.MutationObserver) { if (window.MutationObserver) {
@@ -97,6 +135,8 @@
select.setAttribute("data-recoreco-init", "1"); select.setAttribute("data-recoreco-init", "1");
apply(select); apply(select);
applyTrigger(); applyTrigger();
applyMove();
applyCurrentItalic();
} }
}).observe(document.body, { childList: true, subtree: true }); }).observe(document.body, { childList: true, subtree: true });
} }

View File

@@ -120,13 +120,13 @@ class RecurrenceController extends BaseController
return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'])), true); return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'])), true);
} }
// Columns the copy can land in: every column except the template's own (the copy must move). // Target columns: ALL of the project's columns. This used to exclude the card's own column (a
// duplicate copy "must move"), but move-mode legitimately rests the card IN the target, so the
// target must be any column -- otherwise a moved card's own target vanishes from the dropdown and
// a re-save would silently reset it. `target != trigger` is enforced in the modal instead.
private function targetColumns(array $task) private function targetColumns(array $task)
{ {
$columns = $this->columnModel->getList($task['project_id']); return $this->columnModel->getList($task['project_id']);
unset($columns[$task['column_id']]);
return $columns;
} }
// A stored/posted target, if still a valid non-current column; otherwise the first one (or 0). // A stored/posted target, if still a valid non-current column; otherwise the first one (or 0).

View File

@@ -62,7 +62,7 @@ class Plugin extends Base
public function getPluginVersion() public function getPluginVersion()
{ {
return '1.9.0'; return '1.9.4';
} }
public function getPluginHomepage() public function getPluginHomepage()

View File

@@ -110,14 +110,16 @@ no database migration. Then add the cron entry above.
AGPL-3.0. See LICENSE. AGPL-3.0. See LICENSE.
## More Kanboard plugins by Ruben (drbeco) ## More Kanboard plugins by Dr. Beco
All free and AGPL-3.0, at [code.beco.cc](https://code.beco.cc/beco): All free and AGPL-3.0, at [code.beco.cc](https://code.beco.cc/beco):
- **[FinanceBuddy](https://code.beco.cc/beco/FinanceBuddy)** -- attach a money value (debit/credit - **[FinanceBuddy](https://code.beco.cc/beco/FinanceBuddy)** -- attach a money value (debit/credit
and installments) to cards, shown on the card and totalled per column. Pairs directly with and installments) to cards, shown on the card and totalled per column.
RecoReco: recurring bills spawn on schedule and their installments count down until the plan is - **[QualKard](https://code.beco.cc/beco/QualKard)** -- flashcard spaced repetition: grade a card by
paid off. dragging it to a column, and it comes back when due (needs RecoReco).
- **[WorkspaceOrg](https://code.beco.cc/beco/WorkspaceOrg)** -- group your projects into personal
per-user workspaces, shown on a "My workspaces" dashboard page with a badge on each project.
- **[OrganonTweaks](https://code.beco.cc/beco/OrganonTweaks)** -- an umbrella of small - **[OrganonTweaks](https://code.beco.cc/beco/OrganonTweaks)** -- an umbrella of small
quality-of-life board tweaks: remove an empty column, always show the comment icon, emphasize due quality-of-life board tweaks: remove an empty column, always show the comment icon, emphasize due
dates, extra search keywords and shared board filters, and more. dates, extra search keywords and shared board filters, and more.

View File

@@ -1,10 +1,14 @@
<?php $type = $this->RecoRecoHelper->iconType($task) ?> <?php $type = $this->RecoRecoHelper->iconType($task) ?>
<?php /* Calendar glyph (RecoReco is calendar recurrence), coloured by role so the template and its
copies are distinct at a glance, and distinct from Kanboard's native refresh recurrence icon:
dark blue = the recurring template (original), orange/dark-yellow = a generated copy.
Inline colour is CSP-safe (style-src allows 'unsafe-inline'); no stylesheet needed. */ ?>
<?php if ($type === 'template'): ?> <?php if ($type === 'template'): ?>
<span title="<?= t('RecoReco: recurring template') ?>"> <span title="<?= t('RecoReco: recurring template') ?>">
<i class="fa fa-refresh fa-rotate-90" role="img" aria-label="<?= t('RecoReco: recurring template') ?>"></i> <i class="fa fa-calendar" style="color: #1f4e99;" role="img" aria-label="<?= t('RecoReco: recurring template') ?>"></i>
</span> </span>
<?php elseif ($type === 'clone'): ?> <?php elseif ($type === 'clone'): ?>
<span title="<?= t('RecoReco: generated copy') ?>"> <span title="<?= t('RecoReco: generated copy') ?>">
<i class="fa fa-refresh fa-rotate-90 fa-inverse" role="img" aria-label="<?= t('RecoReco: generated copy') ?>"></i> <i class="fa fa-calendar" style="color: #e08e0b;" role="img" aria-label="<?= t('RecoReco: generated copy') ?>"></i>
</span> </span>
<?php endif ?> <?php endif ?>

View File

@@ -33,7 +33,7 @@
<p class="alert alert-info"><?= t('Add a target column first.') ?></p> <p class="alert alert-info"><?= t('Add a target column first.') ?></p>
<?php endif ?> <?php endif ?>
<form method="post" action="<?= $this->url->href('RecurrenceController', 'save', array('plugin' => 'RecoReco', 'task_id' => $task['id'])) ?>" autocomplete="off"> <form method="post" action="<?= $this->url->href('RecurrenceController', 'save', array('plugin' => 'RecoReco', 'task_id' => $task['id'])) ?>" autocomplete="off" data-recoreco-current="<?= (int) $task['column_id'] ?>">
<?= $this->form->csrf() ?> <?= $this->form->csrf() ?>
<?= $this->form->label(t('Make recurring'), 'recoreco_enabled') ?> <?= $this->form->label(t('Make recurring'), 'recoreco_enabled') ?>

View File

@@ -1 +1 @@
RecoReco v1.9 RecoReco v1.9.4