diff --git a/defaults/preferences/treestyletab.js b/defaults/preferences/treestyletab.js index 04db6447..82920270 100644 --- a/defaults/preferences/treestyletab.js +++ b/defaults/preferences/treestyletab.js @@ -346,6 +346,7 @@ pref("extensions.treestyletab.tooltip.fullTooltipDelay", 2000); * If true, too many items are shown in multiple columns. */ pref("extensions.treestyletab.tooltip.columnize", true); +pref("extensions.treestyletab.tooltip.columnize.width", "20em"); /** * Visibility of extra menu items for the context menu on tabs, inserted by TST. @@ -662,6 +663,7 @@ pref("extensions.treestyletab.pinnedTab.faviconized", true); * If true, too many items are shown in multiple columns in a dummy (group) tab. */ pref("extensions.treestyletab.groupTab.columnize", true); +pref("extensions.treestyletab.groupTab.columnize.width", "20em"); /** * Compatibility hack flags for other addons. They can be disabled by each diff --git a/history.en.md b/history.en.md index 1c9046a9..68c23ef6 100644 --- a/history.en.md +++ b/history.en.md @@ -2,6 +2,7 @@ - master/HEAD * Implement pseudo tree in `about:treestyletab-group` tabs and the rich tooltip without XHTML. (We don't need to mix XHTML and XUL to apply multi-column properties of CSS.) + * Activate multi-column layout only when it is required, at tooltip of tabs and dummy group tabs. - 0.17.2016030402 * Show rich tooltip with multiple columns even if there are only short title tabs. * Avoid initialization error on newly opened group tabs. diff --git a/history.ja.md b/history.ja.md index 12c7c7fb..35591fd5 100644 --- a/history.ja.md +++ b/history.ja.md @@ -2,6 +2,7 @@ - master/HEAD * `about:treestyletab-group`のタブとツールチップにおけるツリーをXHTML無しで実装するようにした(CSSのマルチカラムレイアウトを使うためだけにXHTMLとXULを混在させる必要はない事が分かったため) + * タブのツールチップとダミーのグループ化用のタブにおいて、内容が1列に収まらないときだけマルチカラム表示するようにした - 0.17.2016030402 * 短いタイトルのタブしかない場合にツールチップの内容が段組表示されない問題を修正 * 新しく開かれた空のグループ化用のタブの初期化処理が失敗するようになっていたのを修正 diff --git a/modules/fullTooltip.js b/modules/fullTooltip.js index 7ad7ac58..e8949391 100644 --- a/modules/fullTooltip.js +++ b/modules/fullTooltip.js @@ -145,38 +145,6 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, { }; }, - getTotalContentSize : function FTM_getTotalContentSize(aContainer) - { - var total = { - width : 0, - height : 0 - }; - var totalHeight = 0; - var orient = this.window.getComputedStyle(aContainer, null).getPropertyValue('orient'); - var isVertical = orient == 'vertical'; - Array.forEach(aContainer.childNodes, function(aNode) { - var width, height; - var box = aNode.boxObject; - if (box) { - width = box.width; - height = box.height; - } - else { - width = aNode.clientWidth; - height = aNode.clientHeight; - } - if (isVertical) { - total.width = Math.max(total.width, width); - total.height += height; - } - else { - total.width += width; - total.height = Math.max(total.height, height); - } - }); - return total; - }, - get currentTooltipMargins() { var tooltip = this.tabFullTooltip; @@ -560,11 +528,6 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, { root.appendChild(container); this.tabFullTooltip.appendChild(root); - - log(' => tree size: ', { - width : tree.clientWidth, - height : tree.clientHeight - }); }, clear : function FTM_clear() @@ -580,36 +543,61 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, { { log('expandTooltip'); var tooltip = this.tabFullTooltip; - var tree = this.tree; { + let tree = this.tree; let basePosition = this.windowBasePosition; let tooltipBox = tooltip.boxObject; - log(' => current tooltip position: ', { + log(' => initial dimension: ', { screenX : tooltipBox.screenX, screenY : tooltipBox.screenY, x : tooltipBox.screenX - basePosition.x, y : tooltipBox.screenY - basePosition.y, width : tooltipBox.width, - height : tooltipBox.height + height : tooltipBox.height, + tree : { + width : tree.clientWidth, + height : tree.clientHeight + } }); } - log(' => tree: ', { - width : tree.clientWidth, - height : tree.clientHeight - }); this.lastScreen = this.getCurrentScreen(tooltip.boxObject); - if (utils.getTreePref('tooltip.columnize')) { + this.determineTreeSize(); + this.expandTooltipInternal(); + }, + determineTreeSize : function FTM_determineTreeSize() + { + var tree = this.tree; + + var columnize = utils.getTreePref('tooltip.columnize'); + if (columnize) { PseudoTreeBuilder.columnizeTree(tree, { - width : this.lastScreen.allowedWidth, - height : this.lastScreen.allowedHeight + columnWidth : utils.getTreePref('tooltip.columnize.width'), + containerBox : { + width : this.lastScreen.allowedWidth, + height : this.lastScreen.allowedHeight + }, + calculateCount : true }); - this.window.setTimeout(this.expandTooltipInternal.bind(this), 0); - } - else { - this.expandTooltipInternal(); } + + var range = this.document.createRange(); + range.selectNodeContents(tree); + if (tree.previousSibling) + range.setStartBefore(tree.previousSibling); + var rect = range.getBoundingClientRect(); + range.detach(); + + var container = this.container; + + var arrowScrollBox = container.parentNode; + var scrollButtonsMargin = (arrowScrollBox.boxObject.width - arrowScrollBox._scrollbox.boxObject.width); + scrollButtonsMargin *= 2; // enough width to deactivate scroll buttons. + + var containerStyle = container.style; + containerStyle.width = (container.width = rect.width + scrollButtonsMargin)+'px'; + containerStyle.height = (container.height = rect.height)+'px'; }, expandTooltipInternal : function FTM_expandTooltipInternal() { @@ -619,30 +607,24 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, { var tooltip = this.tabFullTooltip; tooltip.setAttribute('popup-shown', true); - var requiredSize = this.getTotalContentSize(this.tree.parentNode); - { - // Let's maximize the container box enough to show the tree. - // If the tree is larger thant the tooltip, - // it becomes scrollable by arrowscrollbox. - let containerStyle = this.container.style; - containerStyle.width = requiredSize.width+'px'; - containerStyle.height = requiredSize.height+'px'; - } - var currentScreen = this.lastScreen || this.getCurrentScreen(box); var box = tooltip.boxObject; var currentX = box.screenX - currentScreen.left; var currentY = box.screenY - currentScreen.top; + var container = this.container; + var maxWidth = Math.min(container.width, currentScreen.allowedWidth); + var maxHeight = Math.min(container.height, currentScreen.allowedHeight); + var style = tooltip.style; - style.maxWidth = currentScreen.allowedWidth+'px'; + style.maxWidth = maxWidth+'px'; style.maxHeight = currentScreen.allowedHeight+'px'; style.minWidth = 0; style.minHeight = 0; var margins = this.currentTooltipMargins; - var maxX = currentScreen.width - Math.min(requiredSize.width, currentScreen.allowedWidth); - var maxY = currentScreen.height - Math.min(requiredSize.height, currentScreen.allowedHeight); + var maxX = currentScreen.width - maxWidth; + var maxY = currentScreen.height - maxHeight; log(' => current dimension: ', { margins : margins, @@ -650,7 +632,12 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, { y : currentY, maxX : maxX, maxY : maxY, - required : requiredSize + container : { + width : container.width, + height : container.height + }, + screen : currentScreen, + columnCount : this.tree.columnCount }); if (currentX > maxX) diff --git a/modules/groupTab.js b/modules/groupTab.js index fba531fb..51d38929 100644 --- a/modules/groupTab.js +++ b/modules/groupTab.js @@ -411,7 +411,9 @@ GroupTab.prototype = inherit(TreeStyleTabBase, { return; var container = this.document.getElementById('tree'); var tree = container.firstChild; - PseudoTreeBuilder.columnizeTree(tree); + PseudoTreeBuilder.columnizeTree(tree, { + columnWidth : utils.getTreePref('groupTab.columnize.width') + }); }, onTabAttached : function GT_onTabAttached(aEvent) diff --git a/modules/pseudoTreeBuilder.js b/modules/pseudoTreeBuilder.js index 95e67fe8..f3002c5f 100644 --- a/modules/pseudoTreeBuilder.js +++ b/modules/pseudoTreeBuilder.js @@ -146,45 +146,34 @@ var PseudoTreeBuilder = { return container; }, - columnizeTree : function TB_columnizeTree(aTree, aContainerBox) + columnizeTree : function TB_columnizeTree(aTree, aOptions) { if (!aTree) return; - aContainerBox = aContainerBox || aTree.parentNode.boxObject; + aOptions = aOptions || {}; + aOptions.columnWidth = aOptions.columnWidth || '20em'; var style = aTree.style; - var height = aTree.clientHeight * (aTree.columnCount || 1); - if (height > aContainerBox.height && - aContainerBox.height < aContainerBox.width) { - let maxWidth = aContainerBox.width; - aTree.columnWidth = Math.floor(maxWidth * 0.9 / 2.5); - let count = Math.ceil( - (Math.max(aTree.clientWidth, maxWidth) * aTree.clientHeight) / - (aTree.columnWidth * aTree.clientHeight) - ); - aTree.columnCount = style.columnCount = style.MozColumnCount = count; - style.columnWidth = style.MozColumnWidth = aTree.columnWidth+'px'; - style.columnGap = style.MozColumnGap = '0'; - style.columnFill = style.MozColumnFill = 'auto'; - aTree.ownerDocument.defaultView.setTimeout((function() { - let columnCount = this.getActualColumnCount(aTree); - aTree.columnCount = style.columnCount = - style.MozColumnCount = columnCount; - }).bind(this), 0); - } - else { - aTree.columnCount = 1; - style.columnCount = style.MozColumnCount = - style.columnWidth = style.MozColumnWidth = - style.columnGap = style.MozColumnGap = - style.columnFill = style.MozColumnFill; + style.columnWidth = style.MozColumnWidth = 'calc(' + aOptions.columnWidth + ')'; + { + let computedStyle = aTree.ownerDocument.defaultView.getComputedStyle(aTree, null) + aTree.columnWidth = Number((computedStyle.MozColumnWidth || computedStyle.columnWidth).replace(/px/, '')); } + style.columnGap = style.MozColumnGap = '0'; + style.columnFill = style.MozColumnFill = 'auto'; + style.columnCount = style.MozColumnCount = 'auto'; - if (aTree.columnCount > 1) { + var containerBox = aOptions.containerBox || aTree.parentNode.boxObject; + var maxWidth = containerBox.width; + if (aTree.columnWidth * 2 <= maxWidth || + aOptions.calculateCount) { style.height = style.maxHeight = - Math.floor(aContainerBox.height * 0.9) + 'px'; + Math.floor(containerBox.height * 0.9) + 'px'; + + if (this.getActualColumnCount(aTree) == 1) + style.columnWidth = style.MozColumnWidth = ''; } else { style.height = style.maxHeight = ''; @@ -192,24 +181,10 @@ var PseudoTreeBuilder = { }, getActualColumnCount : function TB_getActualColumnCount(aTree) { - var rows = aTree.querySelectorAll('*|*.' + this.kTREEROW); - if (rows.length <= 1) - return 0; - - var firstRow = rows[0]; - if (rows[0].clientWidth === 0) // ignore hidden item! - firstRow = rows[1]; - var lastRow = rows[rows.length - 1]; - - var firstWidth = firstRow.clientWidth; - var lastWidth = lastRow.clientWidth; - - // We have to see XUL box object's x instead of HTML element's clientLeft - // to get actual position of elements in a multi-column box. - var firstX = firstRow.querySelector('label').boxObject.x; - var lastX = lastRow.querySelector('label').boxObject.x; - - var totalWidth = lastX + lastWidth - firstX; - return Math.floor(totalWidth / firstWidth); + var range = aTree.ownerDocument.createRange(); + range.selectNodeContents(aTree); + var rect = range.getBoundingClientRect(); + range.detach(); + return Math.floor(rect.width / aTree.columnWidth); } };