From 93e9d3a88c2edc74fda1a65fb1bd813fabf93fe1 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sat, 4 Apr 2026 11:26:37 -0500 Subject: [PATCH] Auto-enable dev mode when Joomla debug is on; fix TOC heading detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Development mode now activates automatically when Joomla global debug is enabled, so admins don't need to toggle both settings. - Bootstrap TOC now detects the highest heading level present (even if only one exists) and includes up to two levels below it (e.g. h2 → h2, h3, h4). Fixes incorrect top-level detection and adds proper three-level nesting support. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/index.php | 2 +- .../vendor/bootstrap-toc/bootstrap-toc.js | 56 ++++++++++++------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/index.php b/src/index.php index c6ffb4b..5ac9797 100644 --- a/src/index.php +++ b/src/index.php @@ -34,7 +34,7 @@ $params_googleanalyticsid = $this->params->get('googleanalyticsid', null); $params_googlesitekey = $this->params->get('googlesitekey', null); $params_custom_head_start = $this->params->get('custom_head_start', null); $params_custom_head_end = $this->params->get('custom_head_end', null); -$params_developmentmode = $this->params->get('developmentmode', false); +$params_developmentmode = $this->params->get('developmentmode', false) || $app->get('debug', false); $params_favicon_source = (string) $this->params->get('favicon_source', ''); // Theme params diff --git a/src/media/vendor/bootstrap-toc/bootstrap-toc.js b/src/media/vendor/bootstrap-toc/bootstrap-toc.js index 3cc08bf..e1423e1 100644 --- a/src/media/vendor/bootstrap-toc/bootstrap-toc.js +++ b/src/media/vendor/bootstrap-toc/bootstrap-toc.js @@ -83,11 +83,12 @@ return this.generateNavEl(anchor, text); }, - // Find the first heading level (`

`, then `

`, etc.) that has more than one element. Defaults to 1 (for `

`). + // Find the highest (lowest-numbered) heading level present in the scope. + // Returns the tag number of the first heading found (e.g. 2 for

). getTopLevel: function($scope) { for (var i = 1; i <= 6; i++) { var $headings = this.findOrFilter($scope, 'h' + i); - if ($headings.length > 1) { + if ($headings.length >= 1) { return i; } } @@ -95,14 +96,15 @@ return 1; }, - // returns the elements for the top level, and the next below it + // Returns elements for the top level and up to two levels below it. + // e.g. if topLevel is 2 → h2, h3, h4 getHeadings: function($scope, topLevel) { - var topSelector = 'h' + topLevel; + var selectors = []; + for (var i = topLevel; i <= Math.min(topLevel + 2, 6); i++) { + selectors.push('h' + i); + } - var secondaryLevel = topLevel + 1; - var secondarySelector = 'h' + secondaryLevel; - - return this.findOrFilter($scope, topSelector + ',' + secondarySelector); + return this.findOrFilter($scope, selectors.join(',')); }, getNavLevel: function(el) { @@ -110,26 +112,38 @@ }, populateNav: function($topContext, topLevel, $headings) { - var $context = $topContext; - var $prevNav; + var $contexts = {}; + $contexts[topLevel] = $topContext; + var $prevNavByLevel = {}; var helpers = this; $headings.each(function(i, el) { var $newNav = helpers.generateNavItem(el); var navLevel = helpers.getNavLevel(el); - // determine the proper $context if (navLevel === topLevel) { - // use top level - $context = $topContext; - } else if ($prevNav && $context === $topContext) { - // create a new level of the tree and switch to it - $context = helpers.createChildNavList($prevNav); - } // else use the current $context - - $context.append($newNav); - - $prevNav = $newNav; + // Top level — append directly + $topContext.append($newNav); + $prevNavByLevel = {}; + $prevNavByLevel[topLevel] = $newNav; + // Reset deeper contexts so next child creates a fresh sublist + $contexts = {}; + $contexts[topLevel] = $topContext; + } else { + // Child level — ensure parent context exists + var parentLevel = navLevel - 1; + if (!$contexts[navLevel] && $prevNavByLevel[parentLevel]) { + $contexts[navLevel] = helpers.createChildNavList($prevNavByLevel[parentLevel]); + } + var $ctx = $contexts[navLevel] || $topContext; + $ctx.append($newNav); + $prevNavByLevel[navLevel] = $newNav; + // Reset deeper contexts + for (var l = navLevel + 1; l <= 6; l++) { + delete $contexts[l]; + delete $prevNavByLevel[l]; + } + } }); },