resources added f1
This commit is contained in:
56
Asset/js/relocate.js
Normal file
56
Asset/js/relocate.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* OrganonTweaks -- place the "Remove this Column" entry inside the native column menu.
|
||||||
|
*
|
||||||
|
* Kanboard only exposes the template:board:column:dropdown hook AFTER the column menu
|
||||||
|
* <ul>, and its dropdown JS clones just that <ul> when the menu opens. So the hook item
|
||||||
|
* cannot reach the menu on its own. column_dropdown.php renders the item hidden next to
|
||||||
|
* the menu; this script moves each such item into that column's real <ul> so it appears
|
||||||
|
* alongside the native entries. It re-runs when the board is redrawn (AJAX polling /
|
||||||
|
* drag-and-drop refresh).
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function relocate() {
|
||||||
|
var items = document.querySelectorAll(".organontweaks-remove-column-item");
|
||||||
|
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
var li = items[i];
|
||||||
|
|
||||||
|
// Already moved into a menu list: just make sure it is visible.
|
||||||
|
if (li.closest("ul")) {
|
||||||
|
li.style.display = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The hook renders the item as a child of the column's dropdown wrapper;
|
||||||
|
// its first <ul> is the native menu.
|
||||||
|
var menu = li.parentNode ? li.parentNode.querySelector("ul") : null;
|
||||||
|
|
||||||
|
if (menu) {
|
||||||
|
menu.appendChild(li);
|
||||||
|
li.style.display = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
if (!document.getElementById("board")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relocate();
|
||||||
|
|
||||||
|
var container = document.getElementById("board-container");
|
||||||
|
|
||||||
|
if (container && window.MutationObserver) {
|
||||||
|
new MutationObserver(relocate).observe(container, { childList: true, subtree: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === "loading") {
|
||||||
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
})();
|
||||||
71
Controller/ColumnController.php
Normal file
71
Controller/ColumnController.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Plugin\OrganonTweaks\Controller;
|
||||||
|
|
||||||
|
use Kanboard\Controller\BaseController;
|
||||||
|
use Kanboard\Core\Controller\AccessForbiddenException;
|
||||||
|
use Kanboard\Model\TaskModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an empty board column straight from its header menu.
|
||||||
|
*/
|
||||||
|
class ColumnController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Confirmation dialog.
|
||||||
|
*/
|
||||||
|
public function confirm()
|
||||||
|
{
|
||||||
|
$project = $this->getProject();
|
||||||
|
$column_id = $this->request->getIntegerParam('column_id');
|
||||||
|
$this->checkAccess($project['id'], $column_id);
|
||||||
|
|
||||||
|
$this->response->html($this->template->render('organonTweaks:board/remove_column', array(
|
||||||
|
'project' => $project,
|
||||||
|
'column' => $this->columnModel->getColumnTitleById($column_id),
|
||||||
|
'column_id' => $column_id,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the column and return to the board.
|
||||||
|
*/
|
||||||
|
public function remove()
|
||||||
|
{
|
||||||
|
$project = $this->getProject();
|
||||||
|
$values = $this->request->getValues();
|
||||||
|
$column_id = isset($values['column_id']) ? (int) $values['column_id'] : 0;
|
||||||
|
|
||||||
|
$this->checkAccess($project['id'], $column_id);
|
||||||
|
|
||||||
|
if ($this->columnModel->remove($column_id)) {
|
||||||
|
$this->flash->success(t('Column removed successfully.'));
|
||||||
|
} else {
|
||||||
|
$this->flash->failure(t('Unable to remove this column.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect($this->helper->url->to('BoardViewController', 'show', array('project_id' => $project['id'])));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow only users who can manage columns, and only for a column with no tasks at all
|
||||||
|
* (open or closed) -- ColumnModel::remove() is a bare delete, so a non-empty column
|
||||||
|
* would orphan its tasks.
|
||||||
|
*/
|
||||||
|
private function checkAccess($project_id, $column_id)
|
||||||
|
{
|
||||||
|
if (! $this->helper->user->hasProjectAccess('ColumnController', 'remove', $project_id)) {
|
||||||
|
throw new AccessForbiddenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = $this->taskFinderModel->countByColumnId(
|
||||||
|
$project_id,
|
||||||
|
$column_id,
|
||||||
|
array(TaskModel::STATUS_OPEN, TaskModel::STATUS_CLOSED)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($count > 0) {
|
||||||
|
throw new AccessForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Helper/OrganonColumnHelper.php
Normal file
31
Helper/OrganonColumnHelper.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Plugin\OrganonTweaks\Helper;
|
||||||
|
|
||||||
|
use Kanboard\Core\Base;
|
||||||
|
use Kanboard\Model\TaskModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template helper for column tweaks. Exposes an emptiness check that counts BOTH open and
|
||||||
|
* closed tasks (the board's own $column['nb_tasks'] is open-only), so a column that only
|
||||||
|
* holds closed tasks is still treated as non-empty.
|
||||||
|
*/
|
||||||
|
class OrganonColumnHelper extends Base
|
||||||
|
{
|
||||||
|
private static $emptyCache = array();
|
||||||
|
|
||||||
|
public function hasNoTasks($project_id, $column_id)
|
||||||
|
{
|
||||||
|
if (! isset(self::$emptyCache[$column_id])) {
|
||||||
|
$count = $this->taskFinderModel->countByColumnId(
|
||||||
|
$project_id,
|
||||||
|
$column_id,
|
||||||
|
array(TaskModel::STATUS_OPEN, TaskModel::STATUS_CLOSED)
|
||||||
|
);
|
||||||
|
|
||||||
|
self::$emptyCache[$column_id] = ($count === 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$emptyCache[$column_id];
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Template/board/column_dropdown.php
Normal file
12
Template/board/column_dropdown.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php if ($this->user->hasProjectAccess('ColumnController', 'remove', $column['project_id']) && $this->OrganonColumnHelper->hasNoTasks($column['project_id'], $column['id'])): ?>
|
||||||
|
<?php /* Rendered outside the menu <ul> by the only column hook, then moved into it by
|
||||||
|
Asset/js/relocate.js. Hidden until relocated so it never flashes in the header.
|
||||||
|
Shown only for empty columns (no open or closed tasks). */ ?>
|
||||||
|
<li class="organontweaks-remove-column-item" style="display: none;">
|
||||||
|
<?= $this->modal->confirm('trash-o', t('Remove this Column'), 'ColumnController', 'confirm', array(
|
||||||
|
'plugin' => 'OrganonTweaks',
|
||||||
|
'project_id' => $column['project_id'],
|
||||||
|
'column_id' => $column['id'],
|
||||||
|
)) ?>
|
||||||
|
</li>
|
||||||
|
<?php endif ?>
|
||||||
17
Template/board/remove_column.php
Normal file
17
Template/board/remove_column.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('Remove this column') ?></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" action="<?= $this->url->href('ColumnController', 'remove', array('plugin' => 'OrganonTweaks', 'project_id' => $project['id'])) ?>">
|
||||||
|
<?= $this->form->csrf() ?>
|
||||||
|
<?= $this->form->hidden('column_id', array('column_id' => $column_id)) ?>
|
||||||
|
|
||||||
|
<p class="alert alert-info">
|
||||||
|
<?= t('Do you really want to remove this column: "%s"?', $column) ?>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<?= $this->modal->submitButtons(array(
|
||||||
|
'submitLabel' => t('Remove'),
|
||||||
|
'color' => 'red',
|
||||||
|
)) ?>
|
||||||
|
</form>
|
||||||
Reference in New Issue
Block a user