2014-09-30 07:09:27 -04:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Tree Style Tab.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
|
2016-02-15 10:10:59 -05:00
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2011-2016
|
2014-09-30 07:09:27 -04:00
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex@gmail.com>
|
|
|
|
* Tetsuharu OHZEKI <https://github.com/saneyuki>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ******/
|
|
|
|
|
2015-10-10 23:40:17 -04:00
|
|
|
var EXPORTED_SYMBOLS = ['FullTooltipManager'];
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
|
|
|
|
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
|
|
|
|
|
|
|
Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm');
|
|
|
|
Components.utils.import('resource://treestyletab-modules/base.js');
|
|
|
|
Components.utils.import('resource://treestyletab-modules/pseudoTreeBuilder.js');
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, 'ScreenManager',
|
|
|
|
'@mozilla.org/gfx/screenmanager;1', 'nsIScreenManager');
|
|
|
|
|
2016-02-18 09:12:24 -05:00
|
|
|
function log(...aArgs) {
|
|
|
|
utils.log.apply(utils, ['fullTooltip'].concat(aArgs));
|
|
|
|
}
|
|
|
|
function logWithStackTrace(...aArgs) {
|
|
|
|
utils.logWithStackTrace.apply(utils, ['fullTooltip'].concat(aArgs));
|
|
|
|
}
|
|
|
|
|
2014-09-30 07:09:27 -04:00
|
|
|
function FullTooltipManager(aOwner)
|
|
|
|
{
|
|
|
|
this.init(aOwner);
|
|
|
|
}
|
|
|
|
FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
|
|
|
|
|
|
|
|
kTOOLTIP_MODE_DEFAULT : 0,
|
|
|
|
kTOOLTIP_MODE_COLLAPSED : 1,
|
|
|
|
kTOOLTIP_MODE_ALWAYS : 2,
|
|
|
|
|
|
|
|
get window()
|
|
|
|
{
|
|
|
|
return this.owner.window;
|
|
|
|
},
|
|
|
|
|
|
|
|
get document()
|
|
|
|
{
|
|
|
|
return this.owner.document;
|
|
|
|
},
|
|
|
|
|
|
|
|
get tabTooltip()
|
|
|
|
{
|
|
|
|
return this.document.getElementById('tabbrowser-tab-tooltip');
|
|
|
|
},
|
|
|
|
|
|
|
|
get tabFullTooltip()
|
|
|
|
{
|
|
|
|
return this.document.getElementById('treestyletab-full-tree-tooltip');
|
|
|
|
},
|
2016-02-18 09:59:44 -05:00
|
|
|
get container()
|
|
|
|
{
|
|
|
|
return this.tabFullTooltip.lastChild._scrollbox;
|
|
|
|
},
|
|
|
|
get tree()
|
|
|
|
{
|
|
|
|
return this.tabFullTooltip.lastChild.lastChild.lastChild;
|
|
|
|
},
|
2014-09-30 07:09:27 -04:00
|
|
|
|
2016-02-18 10:24:57 -05:00
|
|
|
/**
|
|
|
|
* If the window is maximized, screenX and screenY can be out of
|
|
|
|
* visible screen rect. On the other hand,
|
|
|
|
* PopupBoxObject#openPopupAtScreen() automatically reposition
|
|
|
|
* the popup if it is going to be shown out of the visible screen
|
|
|
|
* rect. As the result, the popup will be repositioned unexpectedly
|
|
|
|
* if I use the raw screenX and screenY.
|
|
|
|
* https://github.com/piroor/treestyletab/issues/302
|
|
|
|
* To prevent such a result, I have to calculate valid base position
|
|
|
|
* for the popup.
|
|
|
|
*/
|
|
|
|
get windowBasePosition() {
|
|
|
|
var screen = ScreenManager.screenForRect(
|
|
|
|
this.window.screenX,
|
|
|
|
this.window.screenY,
|
|
|
|
this.window.outerWidth,
|
|
|
|
this.window.outerHeight
|
|
|
|
);
|
|
|
|
var screenMinX = {},
|
|
|
|
screenMinY = {},
|
|
|
|
screenMaxX = {},
|
|
|
|
screenMaxY = {};
|
|
|
|
screen.GetAvailRect(screenMinX, screenMinY, screenMaxX, screenMaxY);
|
|
|
|
|
|
|
|
return {
|
|
|
|
x: Math.max(this.window.screenX, screenMinX.value),
|
|
|
|
y: Math.max(this.window.screenY, screenMinY.value)
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
getCurrentScreen : function FTM_getCurrentScreen(aBox)
|
|
|
|
{
|
|
|
|
var currentScreen = Cc['@mozilla.org/gfx/screenmanager;1']
|
|
|
|
.getService(Ci.nsIScreenManager)
|
|
|
|
.screenForRect(aBox.screenX, aBox.screenY, aBox.width, aBox.height);
|
|
|
|
var screenLeft = {},
|
|
|
|
screenTop = {},
|
|
|
|
screenWidth = {},
|
|
|
|
screenHeight = {};
|
|
|
|
currentScreen.GetRect(screenLeft, screenTop, screenWidth, screenHeight);
|
|
|
|
return {
|
|
|
|
left : screenLeft.value,
|
|
|
|
top : screenTop.value,
|
|
|
|
width : screenWidth.value,
|
|
|
|
height : screenHeight.value,
|
|
|
|
allowedWidth : Math.ceil(screenWidth.value * 0.8),
|
|
|
|
allowedHeight : Math.ceil(screenHeight.value * 0.7)
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2016-02-19 12:15:45 -05:00
|
|
|
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;
|
|
|
|
var style = this.window.getComputedStyle(tooltip, null);
|
|
|
|
return {
|
|
|
|
left : Number(style.getPropertyValue('margin-left').replace(/px/, '')),
|
|
|
|
top : Number(style.getPropertyValue('margin-top').replace(/px/, ''))
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2016-02-18 10:24:57 -05:00
|
|
|
getFullTooltipFromEvent : function FTM_getFullTooltipFromEvent(aEvent)
|
|
|
|
{
|
|
|
|
return utils.evaluateXPath(
|
|
|
|
'ancestor-or-self::xul:tooltip[@id="'+this.tabFullTooltip.id+'"]',
|
|
|
|
aEvent.target,
|
|
|
|
Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
|
|
|
|
).singleNodeValue;
|
|
|
|
},
|
|
|
|
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
init : function FTM_init(aOwner)
|
|
|
|
{
|
|
|
|
this.owner = aOwner;
|
|
|
|
|
|
|
|
this.tabTooltip.addEventListener('popupshowing', this, true);
|
|
|
|
this.tabTooltip.addEventListener('popuphiding', this, true);
|
|
|
|
|
|
|
|
this.tabFullTooltip.addEventListener('click', this, false);
|
|
|
|
this.tabFullTooltip.addEventListener(PseudoTreeBuilder.kTAB_LINK_CLICK, this, true);
|
|
|
|
this.tabFullTooltip.addEventListener('popupshown', this, true);
|
|
|
|
this.tabFullTooltip.addEventListener('popuphidden', this, true);
|
2016-02-18 09:59:44 -05:00
|
|
|
this.tabFullTooltip.addEventListener('transitionend', this, true);
|
2014-09-30 07:09:27 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
destroy : function FTM_destroy()
|
|
|
|
{
|
|
|
|
this.cancel();
|
|
|
|
this.stopListenTooltipEvents();
|
|
|
|
|
|
|
|
this.tabTooltip.removeEventListener('popupshowing', this, true);
|
|
|
|
this.tabTooltip.removeEventListener('popuphiding', this, true);
|
|
|
|
|
|
|
|
this.tabFullTooltip.removeEventListener('click', this, false);
|
|
|
|
this.tabFullTooltip.removeEventListener(PseudoTreeBuilder.kTAB_LINK_CLICK, this, true);
|
|
|
|
this.tabFullTooltip.removeEventListener('popupshown', this, true);
|
|
|
|
this.tabFullTooltip.removeEventListener('popuphidden', this, true);
|
2016-02-18 09:59:44 -05:00
|
|
|
this.tabFullTooltip.removeEventListener('transitionend', this, true);
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
delete this.owner;
|
|
|
|
},
|
|
|
|
|
|
|
|
handleEvent : function FTM_handleEvent(aEvent)
|
|
|
|
{
|
|
|
|
switch (aEvent.type)
|
|
|
|
{
|
|
|
|
case 'click':
|
|
|
|
return this.onClick(aEvent);
|
|
|
|
|
|
|
|
case PseudoTreeBuilder.kTAB_LINK_CLICK:
|
|
|
|
return this.onItemClick(aEvent);
|
|
|
|
|
|
|
|
case 'popupshowing':
|
|
|
|
return this.onDefaultTooltipShowing(aEvent);
|
|
|
|
|
|
|
|
case 'popuphiding':
|
|
|
|
return this.onDefaultTooltipHiding(aEvent);
|
|
|
|
|
|
|
|
case 'popupshown':
|
|
|
|
return this.onShown(aEvent);
|
|
|
|
|
|
|
|
case 'popuphidden':
|
|
|
|
return this.onHidden(aEvent);
|
|
|
|
|
|
|
|
case 'mousemove':
|
2016-02-19 06:16:09 -05:00
|
|
|
if (this.changingPropertiesCount === 0)
|
2016-02-19 04:37:18 -05:00
|
|
|
this.onTooltipMouseMove(aEvent);
|
|
|
|
return;
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
case 'mouseover':
|
2016-02-19 06:16:09 -05:00
|
|
|
if (this.changingPropertiesCount === 0)
|
2016-02-19 04:37:18 -05:00
|
|
|
this.cancelDelayedHide();
|
|
|
|
return;
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
case 'mouseout':
|
2016-02-19 06:16:09 -05:00
|
|
|
if (this.changingPropertiesCount === 0)
|
2016-02-19 04:37:18 -05:00
|
|
|
this.hideWithDelay();
|
|
|
|
return;
|
2014-09-30 07:09:27 -04:00
|
|
|
|
2016-02-18 09:59:44 -05:00
|
|
|
case 'transitionend':
|
2016-02-19 06:16:09 -05:00
|
|
|
return this.onExpanded(aEvent);
|
2016-02-18 09:59:44 -05:00
|
|
|
|
2014-09-30 07:09:27 -04:00
|
|
|
default:
|
2016-02-19 06:48:03 -05:00
|
|
|
if (this.changingPropertiesCount === 0)
|
|
|
|
this.onTooltipEvent(aEvent);
|
|
|
|
return;
|
2014-09-30 07:09:27 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
onClick : function FTM_onClick(aEvent)
|
|
|
|
{
|
|
|
|
this.tabFullTooltip.hidePopup();
|
|
|
|
},
|
|
|
|
|
|
|
|
onItemClick : function FTM_onItemClick(aEvent)
|
|
|
|
{
|
|
|
|
var id = aEvent.detail.id;
|
|
|
|
if (id) {
|
|
|
|
let tab = this.getTabById(id, this.owner.browser);
|
|
|
|
if (tab) {
|
|
|
|
let event = aEvent.detail.sourceEvent;
|
|
|
|
if (event.button == 1 ||
|
|
|
|
(event.button == 0 && this.isAccelKeyPressed(event)))
|
|
|
|
this.owner.browser.removeTab(tab);
|
|
|
|
else if (event.button != 2)
|
|
|
|
this.owner.browser.selectedTab = tab;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.tabFullTooltip.hidePopup();
|
|
|
|
},
|
|
|
|
|
|
|
|
onDefaultTooltipShowing : function FTM_onDefaultTooltipShowing(aEvent)
|
|
|
|
{
|
|
|
|
this.cancel();
|
|
|
|
this.handleDefaultTooltip(aEvent);
|
|
|
|
},
|
|
|
|
|
|
|
|
onDefaultTooltipHiding : function FTM_onDefaultTooltipHiding(aEvent)
|
|
|
|
{
|
|
|
|
this.cancel();
|
|
|
|
},
|
|
|
|
|
|
|
|
onShown : function FTM_onShown(aEvent)
|
|
|
|
{
|
2016-02-18 09:12:24 -05:00
|
|
|
log('onShown');
|
2014-09-30 07:09:27 -04:00
|
|
|
this.startListenTooltipEvents();
|
2016-02-18 10:24:57 -05:00
|
|
|
this.expandTooltip();
|
2014-09-30 07:09:27 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
onHidden : function FTM_onHidden(aEvent)
|
|
|
|
{
|
|
|
|
this.tabFullTooltip.removeAttribute('popup-shown');
|
|
|
|
this.stopListenTooltipEvents();
|
2016-02-18 10:08:09 -05:00
|
|
|
this.clear();
|
2014-09-30 07:09:27 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
onTooltipMouseMove : function FTM_onTooltipMouseMove(aEvent)
|
|
|
|
{
|
|
|
|
if (this.getFullTooltipFromEvent(aEvent))
|
|
|
|
this.cancelDelayedHide();
|
|
|
|
else
|
|
|
|
this.hideWithDelay();
|
|
|
|
},
|
|
|
|
|
|
|
|
onTooltipEvent : function FTM_onTooltipEvent(aEvent)
|
|
|
|
{
|
|
|
|
if (!this.getFullTooltipFromEvent(aEvent))
|
|
|
|
this.hide();
|
|
|
|
},
|
|
|
|
|
|
|
|
startListenTooltipEvents : function FTM_startListenTooltipEvents()
|
|
|
|
{
|
|
|
|
if (this.listening)
|
|
|
|
return;
|
|
|
|
this.window.addEventListener('DOMMouseScroll', this, true);
|
|
|
|
this.window.addEventListener('keydown', this, true);
|
|
|
|
this.window.addEventListener('mousedown', this, true);
|
|
|
|
this.window.addEventListener('mouseup', this, true);
|
|
|
|
this.window.addEventListener('dragstart', this, true);
|
|
|
|
this.window.addEventListener('mousemove', this, true);
|
|
|
|
this.tabFullTooltip.addEventListener('mouseover', this, false);
|
|
|
|
this.tabFullTooltip.addEventListener('mouseout', this, false);
|
|
|
|
this.listening = true;
|
|
|
|
},
|
|
|
|
|
|
|
|
stopListenTooltipEvents : function FTM_stopListenTooltipEvents()
|
|
|
|
{
|
|
|
|
if (!this.listening)
|
|
|
|
return;
|
|
|
|
this.window.removeEventListener('DOMMouseScroll', this, true);
|
|
|
|
this.window.removeEventListener('keydown', this, true);
|
|
|
|
this.window.removeEventListener('mousedown', this, true);
|
|
|
|
this.window.removeEventListener('mouseup', this, true);
|
|
|
|
this.window.removeEventListener('dragstart', this, true);
|
|
|
|
this.window.removeEventListener('mousemove', this, true);
|
|
|
|
this.tabFullTooltip.removeEventListener('mouseover', this, false);
|
|
|
|
this.tabFullTooltip.removeEventListener('mouseout', this, false);
|
|
|
|
this.listening = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
handleDefaultTooltip : function FTM_handleDefaultTooltip(aEvent)
|
|
|
|
{
|
2016-02-18 09:12:24 -05:00
|
|
|
log('handleDefaultTooltip');
|
2014-09-30 07:09:27 -04:00
|
|
|
var tab = this.getTabFromChild(this.document.tooltipNode);
|
|
|
|
if (!tab || tab.localName != 'tab')
|
|
|
|
return;
|
|
|
|
|
|
|
|
var label;
|
|
|
|
var collapsed = this.isSubtreeCollapsed(tab);
|
|
|
|
var mode = utils.getTreePref('tooltip.mode');
|
|
|
|
|
|
|
|
var base = parseInt(tab.getAttribute(this.kNEST) || 0);
|
|
|
|
var descendant = this.getDescendantTabs(tab);
|
|
|
|
var indentPart = ' ';
|
|
|
|
var tree = null;
|
|
|
|
var fullTooltipExtraLabel = '';
|
|
|
|
if (mode > this.kTOOLTIP_MODE_DEFAULT &&
|
|
|
|
descendant.length) {
|
|
|
|
let tabs = [tab].concat(descendant);
|
|
|
|
let tabsToBeListed = tabs.slice(0, Math.max(1, utils.getTreePref('tooltip.maxCount')));
|
|
|
|
tree = tabsToBeListed
|
|
|
|
.map(function(aTab) {
|
|
|
|
let label = aTab.getAttribute('label');
|
|
|
|
let indent = '';
|
|
|
|
let nest = parseInt(aTab.getAttribute(this.kNEST) || 0) - base;
|
|
|
|
for (let i = 0; i < nest; i++)
|
|
|
|
{
|
|
|
|
indent += indentPart;
|
|
|
|
}
|
|
|
|
return utils.treeBundle.getFormattedString('tooltip.item.label', [label, indent]);
|
|
|
|
}, this)
|
|
|
|
.join('\n');
|
|
|
|
if (tabs.length != tabsToBeListed.length) {
|
|
|
|
tree += '\n'+indentPart+utils.treeBundle.getFormattedString('tooltip.more', [tabs.length-tabsToBeListed.length]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var shouldShowTree = mode != this.kTOOLTIP_MODE_DEFAULT && (collapsed || mode == this.kTOOLTIP_MODE_ALWAYS);
|
|
|
|
if ('mOverCloseButton' in tab && tab.mOverCloseButton) {
|
|
|
|
if (descendant.length &&
|
|
|
|
(collapsed || utils.getTreePref('closeParentBehavior') == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN)) {
|
|
|
|
label = tree || tab.getAttribute('label');
|
|
|
|
label = label && shouldShowTree ?
|
|
|
|
utils.treeBundle.getFormattedString('tooltip.closeTree.labeled', [label]) :
|
|
|
|
utils.treeBundle.getString('tooltip.closeTree') ;
|
|
|
|
fullTooltipExtraLabel = utils.treeBundle.getFormattedString('tooltip.closeTree.labeled', ['%TREE%']).split(/\s*%TREE%\s*/);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tab.getAttribute(this.kTWISTY_HOVER) == 'true') {
|
|
|
|
let key = collapsed ?
|
|
|
|
'tooltip.expandSubtree' :
|
|
|
|
'tooltip.collapseSubtree' ;
|
|
|
|
label = tree || tab.getAttribute('label');
|
|
|
|
label = label && shouldShowTree ?
|
|
|
|
utils.treeBundle.getFormattedString(key+'.labeled', [label]) :
|
|
|
|
utils.treeBundle.getString(key) ;
|
|
|
|
fullTooltipExtraLabel = utils.treeBundle.getFormattedString(key+'.labeled', ['%TREE%']).split(/\s*%TREE%\s*/);
|
|
|
|
}
|
|
|
|
else if (shouldShowTree) {
|
|
|
|
label = tree;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!label)
|
|
|
|
return;
|
|
|
|
|
|
|
|
aEvent.target.setAttribute('label', label);
|
|
|
|
aEvent.stopPropagation();
|
|
|
|
|
|
|
|
if (shouldShowTree)
|
|
|
|
this.setup(aEvent.target, tab, fullTooltipExtraLabel);
|
|
|
|
},
|
|
|
|
|
|
|
|
setup : function FTM_setup(aBaseTooltip, aTab, aExtraLabels)
|
|
|
|
{
|
2016-02-18 09:12:24 -05:00
|
|
|
log('setup');
|
2014-09-30 07:09:27 -04:00
|
|
|
this.cancel();
|
|
|
|
|
|
|
|
var delay = utils.getTreePref('tooltip.fullTooltipDelay');
|
|
|
|
if (delay < 0)
|
|
|
|
return;
|
|
|
|
|
2016-02-18 09:59:44 -05:00
|
|
|
this._fullTooltipTimer = this.window.setTimeout((function() {
|
|
|
|
log('setup:delayed');
|
2016-02-19 03:45:13 -05:00
|
|
|
|
2016-02-18 09:59:44 -05:00
|
|
|
var basePosition = this.windowBasePosition;
|
2016-02-19 03:45:13 -05:00
|
|
|
log(' => window position: ', basePosition);
|
|
|
|
|
2014-09-30 07:09:27 -04:00
|
|
|
var box = aBaseTooltip.boxObject;
|
|
|
|
var x = box.screenX - basePosition.x;
|
|
|
|
var y = box.screenY - basePosition.y;
|
|
|
|
var w = box.width;
|
|
|
|
var h = box.height;
|
2016-02-18 09:59:44 -05:00
|
|
|
log(' => base tooltip: ', {
|
|
|
|
screenX : box.screenX,
|
|
|
|
screenY : box.screenY,
|
|
|
|
x : x,
|
|
|
|
y : y,
|
|
|
|
width : w,
|
|
|
|
height : h
|
|
|
|
});
|
2016-02-19 03:45:13 -05:00
|
|
|
|
|
|
|
aBaseTooltip.hidePopup();
|
2014-09-30 07:09:27 -04:00
|
|
|
|
2016-02-18 09:59:44 -05:00
|
|
|
this.fill(aTab, aExtraLabels);
|
2014-09-30 07:09:27 -04:00
|
|
|
|
2016-02-18 09:59:44 -05:00
|
|
|
var tooltip = this.tabFullTooltip;
|
2015-02-26 10:59:31 -05:00
|
|
|
{
|
2016-02-19 06:48:39 -05:00
|
|
|
this.setTooltipPosition(x, y);
|
2015-02-26 10:59:31 -05:00
|
|
|
let style = tooltip.style;
|
2016-02-18 09:59:44 -05:00
|
|
|
style.maxWidth = style.minWidth = w+'px';
|
2014-09-30 07:09:27 -04:00
|
|
|
style.maxHeight = style.minHeight = h+'px';
|
|
|
|
}
|
|
|
|
tooltip.openPopupAtScreen(basePosition.x, basePosition.y, false);
|
2016-02-18 09:59:44 -05:00
|
|
|
}).bind(this), Math.max(delay, 0), this);
|
2014-09-30 07:09:27 -04:00
|
|
|
},
|
2016-02-19 06:48:39 -05:00
|
|
|
setTooltipPosition : function FTM_setTooltipPosition(aX, aY, aScreen)
|
|
|
|
{
|
|
|
|
var tooltip = this.tabFullTooltip;
|
|
|
|
var style = tooltip.style;
|
|
|
|
var box = tooltip.boxObject;
|
2016-02-19 12:15:45 -05:00
|
|
|
var aScreen = aScreen || this.lastScreen || this.getCurrentScreen(box);
|
2016-02-19 06:48:39 -05:00
|
|
|
style.marginLeft = aX+'px';
|
|
|
|
style.marginTop = aY+'px';
|
|
|
|
},
|
2014-09-30 07:09:27 -04:00
|
|
|
|
2016-02-18 10:24:57 -05:00
|
|
|
cancel : function FTM_cancel()
|
2014-09-30 07:09:27 -04:00
|
|
|
{
|
|
|
|
if (this._fullTooltipTimer) {
|
|
|
|
this.window.clearTimeout(this._fullTooltipTimer);
|
|
|
|
this._fullTooltipTimer = null;
|
|
|
|
}
|
|
|
|
this.hide();
|
|
|
|
},
|
|
|
|
|
|
|
|
hide : function FTM_hide()
|
|
|
|
{
|
2016-02-19 06:49:03 -05:00
|
|
|
logWithStackTrace('hide');
|
2014-09-30 07:09:27 -04:00
|
|
|
this.cancelDelayedHide();
|
|
|
|
this.tabFullTooltip.hidePopup();
|
2016-02-19 06:16:09 -05:00
|
|
|
this.changingPropertiesCount = 0;
|
2016-02-19 12:15:45 -05:00
|
|
|
this.lastScreen = null;
|
2014-09-30 07:09:27 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
hideWithDelay : function FTM_hideWithDelay()
|
|
|
|
{
|
|
|
|
this.cancelDelayedHide();
|
|
|
|
this._delayedHideTimer = this.window.setTimeout(function(aSelf) {
|
|
|
|
aSelf.hide();
|
|
|
|
}, 500, this);
|
|
|
|
},
|
|
|
|
|
|
|
|
cancelDelayedHide : function FTM_cancelDelayedHide()
|
|
|
|
{
|
|
|
|
if (this._delayedHideTimer) {
|
|
|
|
this.window.clearTimeout(this._delayedHideTimer);
|
|
|
|
this._delayedHideTimer = null;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
fill : function FTM_fill(aTab, aExtraLabels)
|
|
|
|
{
|
2016-02-18 09:12:24 -05:00
|
|
|
log('fill');
|
2014-09-30 07:09:27 -04:00
|
|
|
this.clear();
|
|
|
|
|
|
|
|
var root = this.document.createElement('arrowscrollbox');
|
2016-02-15 11:32:56 -05:00
|
|
|
var orient = utils.getTreePref('tooltip.columnize') ? 'horizontal' : 'vertical' ;
|
|
|
|
root.setAttribute('orient', orient);
|
2014-09-30 07:09:27 -04:00
|
|
|
root.setAttribute('flex', 1);
|
|
|
|
|
2016-02-15 11:24:36 -05:00
|
|
|
var container = root.appendChild(this.document.createElement('vbox'));
|
|
|
|
|
2014-09-30 07:09:27 -04:00
|
|
|
if (aExtraLabels) {
|
|
|
|
if (typeof aExtraLabels == 'string')
|
|
|
|
aExtraLabels = [aExtraLabels];
|
|
|
|
for (let i = 0, maxi = aExtraLabels.length; i < maxi; i++)
|
|
|
|
{
|
|
|
|
let label = aExtraLabels[i];
|
|
|
|
label = label.trim();
|
|
|
|
if (!label)
|
|
|
|
continue;
|
2016-02-19 06:55:04 -05:00
|
|
|
let caption = this.document.createElement('description');
|
|
|
|
caption.appendChild(this.document.createTextNode(label));
|
|
|
|
container.appendChild(caption)
|
2014-09-30 07:09:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 09:12:24 -05:00
|
|
|
var tree = PseudoTreeBuilder.build(aTab);
|
2016-02-15 11:24:36 -05:00
|
|
|
container.insertBefore(tree, container.firstChild && container.firstChild.nextSibling);
|
|
|
|
root.appendChild(container);
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
this.tabFullTooltip.appendChild(root);
|
2016-02-18 09:59:44 -05:00
|
|
|
|
|
|
|
log(' => tree size: ', {
|
|
|
|
width : tree.clientWidth,
|
|
|
|
height : tree.clientHeight
|
|
|
|
});
|
2014-09-30 07:09:27 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
clear : function FTM_clear()
|
|
|
|
{
|
|
|
|
var range = this.document.createRange();
|
|
|
|
range.selectNodeContents(this.tabFullTooltip);
|
|
|
|
range.deleteContents();
|
|
|
|
range.detach();
|
2016-02-18 10:24:57 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
expandTooltip : function FTM_expandTooltip()
|
|
|
|
{
|
|
|
|
log('expandTooltip');
|
|
|
|
var tooltip = this.tabFullTooltip;
|
|
|
|
var tree = this.tree;
|
2016-02-19 03:45:13 -05:00
|
|
|
{
|
|
|
|
let basePosition = this.windowBasePosition;
|
|
|
|
let tooltipBox = tooltip.boxObject;
|
|
|
|
log(' => current tooltip position: ', {
|
|
|
|
screenX : tooltipBox.screenX,
|
|
|
|
screenY : tooltipBox.screenY,
|
|
|
|
x : tooltipBox.screenX - basePosition.x,
|
|
|
|
y : tooltipBox.screenY - basePosition.y,
|
|
|
|
width : tooltipBox.width,
|
|
|
|
height : tooltipBox.height
|
|
|
|
});
|
|
|
|
}
|
2016-02-18 10:24:57 -05:00
|
|
|
log(' => tree: ', {
|
|
|
|
width : tree.clientWidth,
|
|
|
|
height : tree.clientHeight
|
|
|
|
});
|
|
|
|
|
2016-02-19 12:15:45 -05:00
|
|
|
this.lastScreen = this.getCurrentScreen(tooltip.boxObject);
|
|
|
|
|
2016-02-18 10:24:57 -05:00
|
|
|
if (utils.getTreePref('tooltip.columnize')) {
|
|
|
|
PseudoTreeBuilder.columnizeTree(tree, {
|
2016-03-04 08:26:26 -05:00
|
|
|
containerBox : {
|
2016-03-04 08:26:51 -05:00
|
|
|
width : this.lastScreen.allowedWidth,
|
|
|
|
height : this.lastScreen.allowedHeight
|
2016-03-04 08:26:26 -05:00
|
|
|
},
|
|
|
|
calculateCount : true
|
2016-02-18 10:24:57 -05:00
|
|
|
});
|
|
|
|
this.window.setTimeout(this.expandTooltipInternal.bind(this), 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.expandTooltipInternal();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
expandTooltipInternal : function FTM_expandTooltipInternal()
|
|
|
|
{
|
|
|
|
log('expandTooltipInternal');
|
2016-02-19 06:16:09 -05:00
|
|
|
this.changingPropertiesCount = 2;
|
2016-02-19 04:37:18 -05:00
|
|
|
|
2016-02-18 10:24:57 -05:00
|
|
|
var tooltip = this.tabFullTooltip;
|
|
|
|
tooltip.setAttribute('popup-shown', true);
|
|
|
|
|
2016-02-19 12:15:45 -05:00
|
|
|
var requiredSize = this.getTotalContentSize(this.tree.parentNode);
|
2016-02-19 04:36:42 -05:00
|
|
|
{
|
|
|
|
// Let's maximize the container box enough to show the tree.
|
|
|
|
// If the tree is larger thant the tooltip,
|
|
|
|
// it becomes scrollable by arrowscrollbox.
|
2016-02-19 06:16:41 -05:00
|
|
|
let containerStyle = this.container.style;
|
2016-02-19 12:15:45 -05:00
|
|
|
containerStyle.width = requiredSize.width+'px';
|
|
|
|
containerStyle.height = requiredSize.height+'px';
|
2016-02-19 04:36:42 -05:00
|
|
|
}
|
|
|
|
|
2016-02-19 12:15:45 -05:00
|
|
|
var currentScreen = this.lastScreen || this.getCurrentScreen(box);
|
2016-02-18 10:24:57 -05:00
|
|
|
var box = tooltip.boxObject;
|
2016-02-19 12:15:45 -05:00
|
|
|
var currentX = box.screenX - currentScreen.left;
|
|
|
|
var currentY = box.screenY - currentScreen.top;
|
2016-02-18 10:24:57 -05:00
|
|
|
|
|
|
|
var style = tooltip.style;
|
|
|
|
style.maxWidth = currentScreen.allowedWidth+'px';
|
|
|
|
style.maxHeight = currentScreen.allowedHeight+'px';
|
|
|
|
style.minWidth = 0;
|
|
|
|
style.minHeight = 0;
|
|
|
|
|
2016-02-19 12:15:45 -05:00
|
|
|
var margins = this.currentTooltipMargins;
|
|
|
|
var maxX = currentScreen.width - Math.min(requiredSize.width, currentScreen.allowedWidth);
|
|
|
|
var maxY = currentScreen.height - Math.min(requiredSize.height, currentScreen.allowedHeight);
|
|
|
|
|
|
|
|
log(' => current dimension: ', {
|
|
|
|
margins : margins,
|
|
|
|
x : currentX,
|
|
|
|
y : currentY,
|
|
|
|
maxX : maxX,
|
|
|
|
maxY : maxY,
|
|
|
|
required : requiredSize
|
2016-02-19 04:36:42 -05:00
|
|
|
});
|
2016-02-19 12:15:45 -05:00
|
|
|
|
|
|
|
if (currentX > maxX)
|
|
|
|
margins.left -= currentX - maxX + Math.ceil(currentScreen.width * 0.05);
|
|
|
|
if (currentY > maxY)
|
|
|
|
margins.top -= currentY - maxY + Math.ceil(currentScreen.height * 0.05);
|
|
|
|
|
|
|
|
this.setTooltipPosition(margins.left, margins.top, currentScreen);
|
|
|
|
log(' => updated margins: ', margins);
|
2016-02-19 06:16:09 -05:00
|
|
|
},
|
|
|
|
onExpanded : function FTM_onExpanded(aEvent)
|
|
|
|
{
|
|
|
|
let tooltipBox = this.tabFullTooltip.boxObject;
|
|
|
|
let tree = this.tree;
|
|
|
|
log('transitionend: ', {
|
|
|
|
target : aEvent.target,
|
|
|
|
property : aEvent.propertyName,
|
|
|
|
value : this.window.getComputedStyle(aEvent.target, null)
|
|
|
|
.getPropertyValue(aEvent.propertyName),
|
|
|
|
tooltipSize : {
|
|
|
|
width : tooltipBox.width,
|
|
|
|
height : tooltipBox.height
|
|
|
|
},
|
|
|
|
treeSize : {
|
|
|
|
width : tree.clientWidth,
|
|
|
|
height : tree.clientHeight
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (this.changingPropertiesCount > 0 &&
|
|
|
|
/width|height/.test(aEvent.propertyName))
|
|
|
|
this.changingPropertiesCount--;
|
2014-09-30 07:09:27 -04:00
|
|
|
}
|
|
|
|
});
|