summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Controller/Board.php24
-rw-r--r--app/Helper/Board.php24
-rw-r--r--app/Model/UserSession.php24
-rw-r--r--app/Template/board/task_private.php88
-rw-r--r--app/Template/layout.php2
-rw-r--r--app/Template/project/filters.php13
-rw-r--r--assets/js/app.js15
-rw-r--r--assets/js/src/board.js73
8 files changed, 133 insertions, 130 deletions
diff --git a/app/Controller/Board.php b/app/Controller/Board.php
index caaa38ef..ac80a192 100644
--- a/app/Controller/Board.php
+++ b/app/Controller/Board.php
@@ -310,4 +310,28 @@ class Board extends Base
'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList(),
)));
}
+
+ /**
+ * Enable collapsed mode
+ *
+ * @access public
+ */
+ public function collapse()
+ {
+ $project_id = $this->request->getIntegerParam('project_id');
+ $this->userSession->setBoardDisplayMode($project_id, true);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project_id)));
+ }
+
+ /**
+ * Enable expanded mode
+ *
+ * @access public
+ */
+ public function expand()
+ {
+ $project_id = $this->request->getIntegerParam('project_id');
+ $this->userSession->setBoardDisplayMode($project_id, false);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project_id)));
+ }
}
diff --git a/app/Helper/Board.php b/app/Helper/Board.php
new file mode 100644
index 00000000..452a3b70
--- /dev/null
+++ b/app/Helper/Board.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Helper;
+
+/**
+ * Board Helper
+ *
+ * @package helper
+ * @author Frederic Guillot
+ */
+class Board extends \Core\Base
+{
+ /**
+ * Return true if tasks are collapsed
+ *
+ * @access public
+ * @param integer $project_id
+ * @return boolean
+ */
+ public function isCollapsed($project_id)
+ {
+ return $this->userSession->isBoardCollapsed($project_id);
+ }
+}
diff --git a/app/Model/UserSession.php b/app/Model/UserSession.php
index 6de4a182..44a9c2a2 100644
--- a/app/Model/UserSession.php
+++ b/app/Model/UserSession.php
@@ -118,4 +118,28 @@ class UserSession extends Base
{
$_SESSION['filters'][$project_id] = $filters;
}
+
+ /**
+ * Is board collapsed or expanded
+ *
+ * @access public
+ * @param integer $project_id
+ * @return boolean
+ */
+ public function isBoardCollapsed($project_id)
+ {
+ return ! empty($_SESSION['board_collapsed'][$project_id]) ? $_SESSION['board_collapsed'][$project_id] : false;
+ }
+
+ /**
+ * Set board display mode
+ *
+ * @access public
+ * @param integer $project_id
+ * @param boolean $collapsed
+ */
+ public function setBoardDisplayMode($project_id, $collapsed)
+ {
+ $_SESSION['board_collapsed'][$project_id] = $collapsed;
+ }
}
diff --git a/app/Template/board/task_private.php b/app/Template/board/task_private.php
index 3f4010ea..7eaff580 100644
--- a/app/Template/board/task_private.php
+++ b/app/Template/board/task_private.php
@@ -10,53 +10,55 @@
<?= $this->render('board/task_menu', array('task' => $task)) ?>
- <div class="task-board-collapsed" style="display: none">
- <?php if (! empty($task['assignee_username'])): ?>
- <span title="<?= $this->e($task['assignee_name'] ?: $task['assignee_username']) ?>">
- <?= $this->e($this->user->getInitials($task['assignee_name'] ?: $task['assignee_username'])) ?>
- </span> -
- <?php endif ?>
- <span class="tooltip" title="<?= $this->e($task['title']) ?>"
- <?= $this->url->link($this->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-collapsed-title') ?>
- </span>
- </div>
+ <?php if ($this->board->isCollapsed($project['id'])): ?>
+ <div class="task-board-collapsed">
+ <?php if (! empty($task['assignee_username'])): ?>
+ <span title="<?= $this->e($task['assignee_name'] ?: $task['assignee_username']) ?>">
+ <?= $this->e($this->user->getInitials($task['assignee_name'] ?: $task['assignee_username'])) ?>
+ </span> -
+ <?php endif ?>
+ <span class="tooltip" title="<?= $this->e($task['title']) ?>"
+ <?= $this->url->link($this->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-collapsed-title') ?>
+ </span>
+ </div>
+ <?php else: ?>
+ <div class="task-board-expanded">
- <div class="task-board-expanded">
+ <?php if ($task['reference']): ?>
+ <span class="task-board-reference" title="<?= t('Reference') ?>">
+ (<?= $task['reference'] ?>)
+ </span>
+ <?php endif ?>
- <?php if ($task['reference']): ?>
- <span class="task-board-reference" title="<?= t('Reference') ?>">
- (<?= $task['reference'] ?>)
- </span>
- <?php endif ?>
+ <span class="task-board-user <?= $this->user->isCurrentUser($task['owner_id']) ? 'task-board-current-user' : '' ?>">
+ <?= $this->url->link(
+ (! empty($task['owner_id']) ? ($task['assignee_name'] ?: $task['assignee_username']) : t('Nobody assigned')),
+ 'board',
+ 'changeAssignee',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id']),
+ false,
+ 'task-board-popover',
+ t('Change assignee')
+ ) ?>
+ </span>
- <span class="task-board-user <?= $this->user->isCurrentUser($task['owner_id']) ? 'task-board-current-user' : '' ?>">
- <?= $this->url->link(
- (! empty($task['owner_id']) ? ($task['assignee_name'] ?: $task['assignee_username']) : t('Nobody assigned')),
- 'board',
- 'changeAssignee',
- array('task_id' => $task['id'], 'project_id' => $task['project_id']),
- false,
- 'task-board-popover',
- t('Change assignee')
- ) ?>
- </span>
+ <?php if ($task['is_active'] == 1): ?>
+ <div class="task-board-days">
+ <span title="<?= t('Task age in days')?>" class="task-days-age"><?= $this->dt->age($task['date_creation']) ?></span>
+ <span title="<?= t('Days in this column')?>" class="task-days-incolumn"><?= $this->dt->age($task['date_moved']) ?></span>
+ </div>
+ <?php else: ?>
+ <div class="task-board-closed"><i class="fa fa-ban fa-fw"></i><?= t('Closed') ?></div>
+ <?php endif ?>
- <?php if ($task['is_active'] == 1): ?>
- <div class="task-board-days">
- <span title="<?= t('Task age in days')?>" class="task-days-age"><?= $this->dt->age($task['date_creation']) ?></span>
- <span title="<?= t('Days in this column')?>" class="task-days-incolumn"><?= $this->dt->age($task['date_moved']) ?></span>
- </div>
- <?php else: ?>
- <div class="task-board-closed"><i class="fa fa-ban fa-fw"></i><?= t('Closed') ?></div>
- <?php endif ?>
+ <div class="task-board-title">
+ <?= $this->url->link($this->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ </div>
- <div class="task-board-title">
- <?= $this->url->link($this->e($task['title']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
+ <?= $this->render('board/task_footer', array(
+ 'task' => $task,
+ 'not_editable' => $not_editable,
+ )) ?>
</div>
-
- <?= $this->render('board/task_footer', array(
- 'task' => $task,
- 'not_editable' => $not_editable,
- )) ?>
- </div>
+ <?php endif ?>
</div>
diff --git a/app/Template/layout.php b/app/Template/layout.php
index d804d3d5..a9f1cbc3 100644
--- a/app/Template/layout.php
+++ b/app/Template/layout.php
@@ -48,7 +48,7 @@
<ul>
<?php if (isset($board_selector) && ! empty($board_selector)): ?>
<li>
- <select id="board-selector" tabindex=="-1" data-notfound="<?= t('No results match:') ?>" data-placeholder="<?= t('Display another project') ?>" data-board-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
+ <select id="board-selector" tabindex="-1" data-notfound="<?= t('No results match:') ?>" data-placeholder="<?= t('Display another project') ?>" data-board-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
<option value=""></option>
<?php foreach($board_selector as $board_id => $board_name): ?>
<option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option>
diff --git a/app/Template/project/filters.php b/app/Template/project/filters.php
index 396baadf..3beb2f44 100644
--- a/app/Template/project/filters.php
+++ b/app/Template/project/filters.php
@@ -5,12 +5,13 @@
<ul>
<?php if (isset($is_board)): ?>
<li>
- <span class="filter-collapse">
- <i class="fa fa-compress fa-fw"></i> <a href="#" class="filter-collapse-link" title="<?= t('Keyboard shortcut: "%s"', 's') ?>"><?= t('Collapse tasks') ?></a>
- </span>
- <span class="filter-expand" style="display: none">
- <i class="fa fa-expand fa-fw"></i> <a href="#" class="filter-expand-link" title="<?= t('Keyboard shortcut: "%s"', 's') ?>"><?= t('Expand tasks') ?></a>
- </span>
+ <?php if ($this->board->isCollapsed($project['id'])): ?>
+ <i class="fa fa-expand fa-fw"></i>
+ <?= $this->url->link(t('Expand tasks'), 'board', 'expand', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
+ <?php else: ?>
+ <i class="fa fa-compress fa-fw"></i>
+ <?= $this->url->link(t('Collapse tasks'), 'board', 'collapse', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
+ <?php endif ?>
</li>
<li>
<span class="filter-compact">
diff --git a/assets/js/app.js b/assets/js/app.js
index d31c1737..33160e68 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -150,14 +150,13 @@ Mousetrap.bind("b",function(b){b.preventDefault();$("#board-selector").trigger("
".popover",Kanboard.Popover);$("[autofocus]").each(function(b,a){$(this).focus()});$(".form-date").datepicker({showOtherMonths:!0,selectOtherMonths:!0,dateFormat:"yy-mm-dd",constrainInput:!1});$(".form-datetime").datetimepicker({controlType:"select",oneLine:!0,dateFormat:"yy-mm-dd",constrainInput:!1});$("#markdown-preview").click(Kanboard.MarkdownPreview);$("#markdown-write").click(Kanboard.MarkdownWriter);$(".auto-select").focus(function(){$(this).select()});$(".dropit-submenu").hide();$(".dropdown").not(".dropit").dropit({triggerParentEl:"span"});
$(".task-autocomplete").length&&(""==$(".opposite_task_id").val()&&$(".task-autocomplete").parent().find("input[type=submit]").attr("disabled","disabled"),$(".task-autocomplete").autocomplete({source:$(".task-autocomplete").data("search-url"),minLength:1,select:function(b,a){var c=$(".task-autocomplete").data("dst-field");$("input[name="+c+"]").val(a.item.id);$(".task-autocomplete").parent().find("input[type=submit]").removeAttr("disabled")}}));$(".tooltip").tooltip({content:function(){return'<div class="markdown">'+
$(this).attr("title")+"</div>"},position:{my:"left-20 top",at:"center bottom+9",using:function(b,a){$(this).css(b);var c=a.target.left+a.target.width/2-a.element.left-20;$("<div>").addClass("tooltip-arrow").addClass(a.vertical).addClass(1>c?"align-left":"align-right").appendTo(this)}}});Kanboard.Exists("screenshot-zone")&&Kanboard.Screenshot.Init()}}}();
-(function(){function b(a){a.preventDefault();a.stopPropagation();Kanboard.Popover(a,Kanboard.InitAfterAjax)}function a(){Mousetrap.bind("n",function(){Kanboard.OpenPopover($("#board").data("task-creation-url"),Kanboard.InitAfterAjax)});Mousetrap.bind("s",function(){"expanded"===(Kanboard.GetStorageItem(e())||"expanded")?(d(),Kanboard.SetStorageItem(e(),"collapsed")):(f(),Kanboard.SetStorageItem(e(),"expanded"))});Mousetrap.bind("c",function(){n()})}function c(){$(".filter-expand-link").click(function(a){a.preventDefault();
-f();Kanboard.SetStorageItem(e(),"expanded")});$(".filter-collapse-link").click(function(a){a.preventDefault();d();Kanboard.SetStorageItem(e(),"collapsed")});h()}function e(){return"board_stacking_"+$("#board").data("project-id")}function d(){$(".filter-collapse").hide();$(".task-board-collapsed").show();$(".filter-expand").show();$(".task-board-expanded").hide()}function f(){$(".filter-collapse").show();$(".task-board-collapsed").hide();$(".filter-expand").hide();$(".task-board-expanded").show()}
-function h(){"expanded"===(Kanboard.GetStorageItem(e())||"expanded")?f():d()}function g(){$(".column").sortable({delay:300,distance:5,connectWith:".column",placeholder:"draggable-placeholder",items:".draggable-item",stop:function(a,c){k(c.item.attr("data-task-id"),c.item.parent().attr("data-column-id"),c.item.index()+1,c.item.parent().attr("data-swimlane-id"))}});$("#board").on("click",".task-board-popover",b);$("#board").on("click",".task-board",function(){window.location=$(this).data("task-url")});
-$(".task-board-tooltip").tooltip({track:!1,position:{my:"left-20 top",at:"center bottom+9",using:function(a,c){$(this).css(a);var b=c.target.left+c.target.width/2-c.element.left-20;$("<div>").addClass("tooltip-arrow").addClass(c.vertical).addClass(1>b?"align-left":"align-right").appendTo(this)}},content:function(a){if(a=$(this).attr("data-href")){var c=this;$.get(a,function p(a){$(".ui-tooltip-content:visible").html(a);a=$(".ui-tooltip:visible");a.css({top:"",left:""});a.children(".tooltip-arrow").remove();
-var b=$(c).tooltip("option","position");b.of=$(c);a.position(b);$("#tooltip-subtasks a").not(".popover").click(function(a){a.preventDefault();a.stopPropagation();$(this).hasClass("popover-subtask-restriction")?(Kanboard.OpenPopover($(this).attr("href")),$(c).tooltip("close")):$.get($(this).attr("href"),p)})});return'<i class="fa fa-refresh fa-spin fa-2x"></i>'}}}).on("mouseenter",function(){var a=this;$(this).tooltip("open");$(".ui-tooltip").on("mouseleave",function(){$(a).tooltip("close")})}).on("mouseleave focusout",
-function(a){a.stopImmediatePropagation();var c=this;setTimeout(function(){$(".ui-tooltip:hover").length||$(c).tooltip("close")},100)});var a=parseInt($("#board").attr("data-check-interval"));0<a&&(m=window.setInterval(q,1E3*a))}function k(a,c,b,d){clearInterval(m);$.ajax({cache:!1,url:$("#board").attr("data-save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:a,column_id:c,swimlane_id:d,position:b}),success:function(a){$("#board-container").remove();$("#main").append(a);
-Kanboard.InitAfterAjax();g();h();l()}})}function q(){Kanboard.IsVisible()&&$.ajax({cache:!1,url:$("#board").attr("data-check-url"),statusCode:{200:function(a){$("#board-container").remove();$("#main").append(a);Kanboard.InitAfterAjax();clearInterval(m);g();h();l()}}})}function r(){jQuery(document).on("click",".filter-toggle-scrolling",function(a){a.preventDefault();n()});l()}function n(){var a=Kanboard.GetStorageItem("horizontal_scroll")||1;Kanboard.SetStorageItem("horizontal_scroll",0==a?1:0);l()}
-function l(){0==Kanboard.GetStorageItem("horizontal_scroll")?($(".filter-wide").show(),$(".filter-compact").hide(),$("#board-container").addClass("board-container-compact"),$("#board th").addClass("board-column-compact")):($(".filter-wide").hide(),$(".filter-compact").show(),$("#board-container").removeClass("board-container-compact"),$("#board th").removeClass("board-column-compact"))}var m=null;jQuery(document).ready(function(){Kanboard.Exists("board")&&(g(),c(),r(),a())})})();
+(function(){function b(a){a.preventDefault();a.stopPropagation();Kanboard.Popover(a,Kanboard.InitAfterAjax)}function a(){Mousetrap.bind("n",function(){Kanboard.OpenPopover($("#board").data("task-creation-url"),Kanboard.InitAfterAjax)});Mousetrap.bind("s",function(){window.location=$(".board-display-mode").attr("href")});Mousetrap.bind("c",function(){h()})}function c(){$(".column").sortable({delay:300,distance:5,connectWith:".column",placeholder:"draggable-placeholder",items:".draggable-item",stop:function(a,
+c){e(c.item.attr("data-task-id"),c.item.parent().attr("data-column-id"),c.item.index()+1,c.item.parent().attr("data-swimlane-id"))}});$("#board").on("click",".task-board-popover",b);$("#board").on("click",".task-board",function(){window.location=$(this).data("task-url")});$(".task-board-tooltip").tooltip({track:!1,position:{my:"left-20 top",at:"center bottom+9",using:function(a,c){$(this).css(a);var b=c.target.left+c.target.width/2-c.element.left-20;$("<div>").addClass("tooltip-arrow").addClass(c.vertical).addClass(1>
+b?"align-left":"align-right").appendTo(this)}},content:function(a){if(a=$(this).attr("data-href")){var c=this;$.get(a,function l(a){$(".ui-tooltip-content:visible").html(a);a=$(".ui-tooltip:visible");a.css({top:"",left:""});a.children(".tooltip-arrow").remove();var b=$(c).tooltip("option","position");b.of=$(c);a.position(b);$("#tooltip-subtasks a").not(".popover").click(function(a){a.preventDefault();a.stopPropagation();$(this).hasClass("popover-subtask-restriction")?(Kanboard.OpenPopover($(this).attr("href")),
+$(c).tooltip("close")):$.get($(this).attr("href"),l)})});return'<i class="fa fa-refresh fa-spin fa-2x"></i>'}}}).on("mouseenter",function(){var a=this;$(this).tooltip("open");$(".ui-tooltip").on("mouseleave",function(){$(a).tooltip("close")})}).on("mouseleave focusout",function(a){a.stopImmediatePropagation();var c=this;setTimeout(function(){$(".ui-tooltip:hover").length||$(c).tooltip("close")},100)});var a=parseInt($("#board").attr("data-check-interval"));0<a&&(k=window.setInterval(d,1E3*a))}function e(a,
+b,d,e){clearInterval(k);$.ajax({cache:!1,url:$("#board").attr("data-save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:a,column_id:b,swimlane_id:e,position:d}),success:function(a){$("#board-container").remove();$("#main").append(a);Kanboard.InitAfterAjax();c();g()}})}function d(){Kanboard.IsVisible()&&$.ajax({cache:!1,url:$("#board").attr("data-check-url"),statusCode:{200:function(a){$("#board-container").remove();$("#main").append(a);Kanboard.InitAfterAjax();
+clearInterval(k);c();g()}}})}function f(){jQuery(document).on("click",".filter-toggle-scrolling",function(a){a.preventDefault();h()});g()}function h(){var a=Kanboard.GetStorageItem("horizontal_scroll")||1;Kanboard.SetStorageItem("horizontal_scroll",0==a?1:0);g()}function g(){0==Kanboard.GetStorageItem("horizontal_scroll")?($(".filter-wide").show(),$(".filter-compact").hide(),$("#board-container").addClass("board-container-compact"),$("#board th").addClass("board-column-compact")):($(".filter-wide").hide(),
+$(".filter-compact").show(),$("#board-container").removeClass("board-container-compact"),$("#board th").removeClass("board-column-compact"))}var k=null;jQuery(document).ready(function(){Kanboard.Exists("board")&&(c(),f(),a())})})();
(function(){jQuery(document).ready(function(){if(Kanboard.Exists("calendar")){var b=$("#calendar");b.fullCalendar({lang:$("body").data("js-lang"),editable:!0,eventLimit:!0,defaultView:"month",header:{left:"prev,next today",center:"title",right:"month,agendaWeek,agendaDay"},eventDrop:function(a){$.ajax({cache:!1,url:b.data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:a.id,date_due:a.start.format()})})},viewRender:function(){var a=b.data("check-url"),
c={start:b.fullCalendar("getView").start.format(),end:b.fullCalendar("getView").end.format()},e;for(e in c)a+="&"+e+"="+c[e];$.getJSON(a,function(a){b.fullCalendar("removeEvents");b.fullCalendar("addEventSource",a);b.fullCalendar("rerenderEvents")})}})}})})();
(function(){function b(a){return 86400<=a?Math.round(a/86400)+"d":3600<=a?Math.round(a/3600)+"h":60<=a?Math.round(a/60)+"m":a+"s"}jQuery(document).ready(function(){if(Kanboard.Exists("analytic-task-repartition")){for(var a=$("#chart").data("metrics"),c=[],e=0;e<a.length;e++)c.push([a[e].column_title,a[e].nb_tasks]);c3.generate({data:{columns:c,type:"donut"}})}else if(Kanboard.Exists("analytic-user-repartition")){a=$("#chart").data("metrics");c=[];for(e=0;e<a.length;e++)c.push([a[e].user,a[e].nb_tasks]);
diff --git a/assets/js/src/board.js b/assets/js/src/board.js
index 01a16d59..d86610ef 100644
--- a/assets/js/src/board.js
+++ b/assets/js/src/board.js
@@ -20,7 +20,7 @@
});
Mousetrap.bind("s", function() {
- stack_toggle();
+ window.location = $(".board-display-mode").attr("href");
});
Mousetrap.bind("c", function() {
@@ -28,74 +28,6 @@
});
}
- // Collapse/Expand tasks
- function stack_load_events()
- {
- $(".filter-expand-link").click(function(e) {
- e.preventDefault();
- stack_expand();
- Kanboard.SetStorageItem(stack_key(), "expanded");
- });
-
- $(".filter-collapse-link").click(function(e) {
- e.preventDefault();
- stack_collapse();
- Kanboard.SetStorageItem(stack_key(), "collapsed");
- });
-
- stack_show();
- }
-
- function stack_key()
- {
- var projectId = $('#board').data('project-id');
- return "board_stacking_" + projectId;
- }
-
- function stack_collapse()
- {
- $(".filter-collapse").hide();
- $(".task-board-collapsed").show();
-
- $(".filter-expand").show();
- $(".task-board-expanded").hide();
- }
-
- function stack_expand()
- {
- $(".filter-collapse").show();
- $(".task-board-collapsed").hide();
-
- $(".filter-expand").hide();
- $(".task-board-expanded").show();
- }
-
- function stack_toggle()
- {
- var state = Kanboard.GetStorageItem(stack_key()) || "expanded";
-
- if (state === "expanded") {
- stack_collapse();
- Kanboard.SetStorageItem(stack_key(), "collapsed");
- }
- else {
- stack_expand();
- Kanboard.SetStorageItem(stack_key(), "expanded");
- }
- }
-
- function stack_show()
- {
- var state = Kanboard.GetStorageItem(stack_key()) || "expanded";
-
- if (state === "expanded") {
- stack_expand();
- }
- else {
- stack_collapse();
- }
- }
-
// Setup the board
function board_load_events()
{
@@ -243,7 +175,6 @@
$("#main").append(data);
Kanboard.InitAfterAjax();
board_load_events();
- stack_show();
compactview_reload();
}
});
@@ -263,7 +194,6 @@
Kanboard.InitAfterAjax();
board_unload_events();
board_load_events();
- stack_show();
compactview_reload();
}
}
@@ -312,7 +242,6 @@
if (Kanboard.Exists("board")) {
board_load_events();
- stack_load_events();
compactview_load_events();
keyboard_shortcuts();
}