diff --git a/Asset/js/auto-adjust.js b/Asset/js/auto-adjust.js new file mode 100644 index 0000000..68cf64a --- /dev/null +++ b/Asset/js/auto-adjust.js @@ -0,0 +1,86 @@ +/* + * ShrinkVertically -- "Auto adjust" mode. Measure the collapsed board live and set the + * --sv-shrink-offset CSS variable so the columns exactly fill the remaining viewport and the + * native right-side vertical scrollbar is not needed. Loaded only when the setting is on + * (Settings -> Shrink Vertically); it overrides the static offset injected by layout/variable.php. + * + * The collapsed column height is calc(100vh - var(--sv-shrink-offset)). To fit the screen we need: + * offset = (task-list top, i.e. the chrome above) + (horizontal scrollbar below) + a small margin + * so column_bottom + scrollbar stays within the viewport. Both terms are measured from the DOM, so + * this adapts to any screen size, theme, or header height. + * + * Re-measures on resize, on collapse/expand (a class toggle), and after a board refresh + * (BoardDragAndDrop replaces #board-container -- so, like the other plugins, the observer is bound + * to the STABLE parent, not to the container that gets swapped out). + */ +(function () { + "use strict"; + + var BOTTOM_MARGIN = 16; // breathing room below the columns + var scheduled = false; + + function apply() { + scheduled = false; + + var list = document.querySelector("#board .board-task-list.board-task-list-compact"); + + if (! list) { + return; // board not collapsed -> nothing to auto-size + } + + var top = list.getBoundingClientRect().top; + var container = document.getElementById("board-container"); + var bar = container ? (container.offsetHeight - container.clientHeight) : 0; // horizontal scrollbar + + if (bar < 0) { + bar = 0; + } + + var offset = Math.ceil(top + bar + BOTTOM_MARGIN); + + if (offset < 0) { + offset = 0; + } + + var next = offset + "px"; + var root = document.documentElement; + + // Only write when it actually changes, so mid-drag class churn does not thrash layout. + if (root.style.getPropertyValue("--sv-shrink-offset") !== next) { + root.style.setProperty("--sv-shrink-offset", next); + } + } + + function schedule() { + if (! scheduled) { + scheduled = true; + window.requestAnimationFrame(apply); + } + } + + function init() { + var container = document.getElementById("board-container"); + + if (! container) { + return; // not a board page + } + + schedule(); + window.addEventListener("resize", schedule); + + if (window.MutationObserver && container.parentNode) { + new MutationObserver(schedule).observe(container.parentNode, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ["class"] + }); + } + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } +})(); diff --git a/Controller/ConfigController.php b/Controller/ConfigController.php index 6ce6618..4adf8f2 100644 --- a/Controller/ConfigController.php +++ b/Controller/ConfigController.php @@ -23,6 +23,7 @@ class ConfigController extends BaseController $offset = (int) $this->configModel->get('shrink_vertically_offset', self::DEFAULT_OFFSET); $barSize = (int) $this->configModel->get('shrink_vertically_bar_size', self::DEFAULT_BAR_SIZE); $topScrollbar = (int) $this->configModel->get('shrink_vertically_top_scrollbar', 1); + $auto = (int) $this->configModel->get('shrink_vertically_auto', 0); $this->response->html($this->helper->layout->config('shrinkVertically:config/show', array( 'title' => t('Settings').' > '.t('Shrink Vertically'), @@ -30,6 +31,7 @@ class ConfigController extends BaseController 'shrink_vertically_offset' => $offset, 'shrink_vertically_bar_size' => $barSize, 'shrink_vertically_top_scrollbar' => $topScrollbar, + 'shrink_vertically_auto' => $auto, ), 'errors' => array(), ))); @@ -39,18 +41,24 @@ class ConfigController extends BaseController { $values = $this->request->getValues(); - $offset = isset($values['shrink_vertically_offset']) ? (int) $values['shrink_vertically_offset'] : self::DEFAULT_OFFSET; + // In auto mode the offset input is disabled client-side, so the browser does not submit it. + // Fall back to the stored value (not the default) so enabling auto never wipes the manual offset. + $offset = isset($values['shrink_vertically_offset']) + ? (int) $values['shrink_vertically_offset'] + : (int) $this->configModel->get('shrink_vertically_offset', self::DEFAULT_OFFSET); $offset = max(self::MIN_OFFSET, min(self::MAX_OFFSET, $offset)); $barSize = isset($values['shrink_vertically_bar_size']) ? (int) $values['shrink_vertically_bar_size'] : self::DEFAULT_BAR_SIZE; $barSize = max(self::MIN_BAR_SIZE, min(self::MAX_BAR_SIZE, $barSize)); $topScrollbar = isset($values['shrink_vertically_top_scrollbar']) ? 1 : 0; + $auto = isset($values['shrink_vertically_auto']) ? 1 : 0; if ($this->configModel->save(array( 'shrink_vertically_offset' => $offset, 'shrink_vertically_bar_size' => $barSize, 'shrink_vertically_top_scrollbar' => $topScrollbar, + 'shrink_vertically_auto' => $auto, ))) { $this->flash->success(t('Settings saved successfully.')); } else { diff --git a/Plugin.php b/Plugin.php index ed49f3b..65a0a2c 100644 --- a/Plugin.php +++ b/Plugin.php @@ -32,6 +32,14 @@ class Plugin extends Base 'template' => 'plugins/ShrinkVertically/Asset/js/top-scrollbar.js', )); } + + // Optional: auto-adjust the collapsed column height to the screen (measured live on the + // board), overriding the static pixel offset so the vertical scrollbar is not needed. + if ((int) $this->configModel->get('shrink_vertically_auto', 0) === 1) { + $this->hook->on('template:layout:js', array( + 'template' => 'plugins/ShrinkVertically/Asset/js/auto-adjust.js', + )); + } } public function getPluginName() @@ -51,7 +59,7 @@ class Plugin extends Base public function getPluginVersion() { - return '1.5.2'; + return '1.6.0'; } public function getPluginHomepage() diff --git a/README.md b/README.md index f478cc1..02daf0d 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,11 @@ These settings are global (per Kanboard instance) and admin-only. Go to in the page head as the `--sv-shrink-offset` CSS variable. Increase it if the scrollbar is still clipped (for example with a taller theme header); decrease it to make the collapsed columns taller. Default: 240. +- **Auto adjust** -- instead of a fixed offset, measure the collapsed board live and size + the columns to fit the screen automatically, so the right-side vertical scrollbar is not + needed. It re-measures on window resize, on collapse/expand, and after a board refresh. + While enabled, the pixel-offset field above is disabled and dimmed (the measured value is + used instead). Loaded as `Asset/js/auto-adjust.js` only when the option is on. Default: off. - **Top Horizontal Scrollbar thickness in pixels** -- thickness of the custom top scrollbar (all browsers). Injected as the `--sv-bar-size` CSS variable. Default: 25. - **Add a top horizontal scrollbar to the board** -- toggles the mirrored top scrollbar diff --git a/Template/config/show.php b/Template/config/show.php index 0f5cacc..2d3d43d 100644 --- a/Template/config/show.php +++ b/Template/config/show.php @@ -11,6 +11,11 @@

+ + form->checkbox('shrink_vertically_auto', t('Auto adjust (fit columns to the screen automatically)'), 1, isset($values['shrink_vertically_auto']) && $values['shrink_vertically_auto'] == 1, '', array('id' => 'form-shrink_vertically_auto')) ?> +

+ +

@@ -32,3 +37,23 @@ + + diff --git a/VERSION b/VERSION index 9d6ef19..9e37a05 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -ShrinkVertically v1.5.2 +ShrinkVertically v1.6