blob: 23b9dcf7107f2362542d65c9999ebdafcb720b7f [file] [log] [blame]
/* Copyright 2016 The Chromium Authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://developers.google.com/open-source/licenses/bsd
*/
/**
* Functions used by Monorail to control the display of elements on
* the page, rollovers, and popup menus.
*
*/
/**
* Show a popup menu below a specified element. Optional x and y deltas can be
* used to fine-tune placement.
* @param {string} id The HTML id of the popup menu.
* @param {Element} el The HTML element that the popup should appear near.
* @param {number} opt_deltaX Optional X offset to finetune placement.
* @param {number} opt_deltaY Optional Y offset to finetune placement.
* @param {Element} opt_menuButton The HTML element for a menu button that
* was pressed to open the menu. When a button was used, we need to ignore
* the first "click" event, otherwise the menu will immediately close.
* @return Always returns false to indicate that the browser should handle the
* event normally.
*/
function TKR_showBelow(id, el, opt_deltaX, opt_deltaY, opt_menuButton) {
let popupDiv = $(id);
let elBounds = nodeBounds(el);
let startX = elBounds.x;
let startY = elBounds.y + elBounds.h;
if (BR_IsIE()) {
startX -= 1;
startY -= 2;
}
if (BR_IsSafari()) {
startX += 1;
}
popupDiv.style.display = 'block'; // needed so that offsetWidth != 0
popupDiv.style.left = '-2000px';
if (id == 'pop_dot' || id == 'redoMenu') {
startX = startX - popupDiv.offsetWidth + el.offsetWidth;
}
if (opt_deltaX) startX += opt_deltaX;
if (opt_deltaY) startY += opt_deltaY;
popupDiv.style.left = (startX)+'px';
popupDiv.style.top = (startY)+'px';
let popup = new TKR_MyPopup(popupDiv, opt_menuButton);
popup.show();
return false;
}
/**
* Show a popup menu to the right of a specified element. If there is not
* enough space to the right, then it will open to the left side instead.
* Optional x and y deltas can be used to fine-tune placement.
* TODO(jrobbins): reduce redundancy with function above.
* @param {string} id The HTML id of the popup menu.
* @param {Element} el The HTML element that the popup should appear near.
* @param {number} opt_deltaX Optional X offset to finetune placement.
* @param {number} opt_deltaY Optional Y offset to finetune placement.
* @return Always returns false to indicate that the browser should handle the
* event normally.
*/
function TKR_showRight(id, el, opt_deltaX, opt_deltaY) {
let popupDiv = $(id);
let elBounds = nodeBounds(el);
let startX = elBounds.x + elBounds.w;
let startY = elBounds.y;
// Calculate pageSize.w and pageSize.h
let docElemWidth = document.documentElement.clientWidth;
let docElemHeight = document.documentElement.clientHeight;
let pageSize = {
w: (window.innerWidth || docElemWidth && docElemWidth > 0 ?
docElemWidth : document.body.clientWidth) || 1,
h: (window.innerHeight || docElemHeight && docElemHeight > 0 ?
docElemHeight : document.body.clientHeight) || 1,
};
// We need to make the popupDiv visible in order to capture its width
popupDiv.style.display = 'block';
let popupDivBounds = nodeBounds(popupDiv);
// Show popup to the left
if (startX + popupDivBounds.w > pageSize.w) {
startX = elBounds.x - popupDivBounds.w;
if (BR_IsIE()) {
startX -= 4;
startY -= 2;
}
if (BR_IsNav()) {
startX -= 2;
}
if (BR_IsSafari()) {
startX += -1;
}
// Show popup to the right
} else {
if (BR_IsIE()) {
startY -= 2;
}
if (BR_IsNav()) {
startX += 2;
}
if (BR_IsSafari()) {
startX += 3;
}
}
popupDiv.style.left = '-2000px';
popupDiv.style.position = 'absolute';
if (opt_deltaX) startX += opt_deltaX;
if (opt_deltaY) startY += opt_deltaY;
popupDiv.style.left = (startX)+'px';
popupDiv.style.top = (startY)+'px';
let popup = new TKR_MyPopup(popupDiv);
popup.show();
return false;
}
/**
* Close the specified popup menu and unregister it with the popup
* controller, otherwise old leftover popup instances can mess with
* the future display of menus.
* @param {string} id The HTML ID of the element to hide.
*/
function TKR_closePopup(id) {
let e = $(id);
if (e) {
for (let i = 0; i < gPopupController.activePopups_.length; ++i) {
if (e === gPopupController.activePopups_[i]._div) {
let popup = gPopupController.activePopups_[i];
popup.hide();
gPopupController.activePopups_.splice(i, 1);
return;
}
}
}
}
var TKR_allColumnNames = []; // Will be defined in HTML file.
/**
* Close all popup menus. Also, reset the hover state of the menu item that
* was selected. The list of popup menu names is computed from the list of
* columns specified in the HTML for the issue list page.
* @param menuItem {Element} The menu item that the user clicked.
* @return Always returns false to indicate that the browser should handle the
* event normally.
*/
function TKR_closeAllPopups(menuItem) {
for (let col_index = 0; col_index < TKR_allColumnNames.length; col_index++) {
TKR_closePopup('pop_' + col_index);
TKR_closePopup('filter_' + col_index);
}
TKR_closePopup('pop_dot');
TKR_closePopup('redoMenu');
menuItem.classList.remove('hover');
return false;
}
/**
* Close all the submenus (of which, one may be currently open).
* @return Always returns false to indicate that the browser should handle the
* event normally.
*/
function TKR_closeSubmenus() {
for (let col_index = 0; col_index < TKR_allColumnNames.length; col_index++) {
TKR_closePopup('filter_' + col_index);
}
return false;
}
/**
* Find the enclosing HTML element that controls this section of the
* page and set it to use CSS class "opened". That will make the
* section display in the opened state, regardless of what state is
* was in before.
* @param {Element} el The HTML element that the user clicked on.
* @return Always returns false to indicate that the browser should handle the
* event normally.
*/
function TKR_showHidden(el) {
while (el) {
if (el.classList.contains('closed')) {
el.classList.remove('closed');
el.classList.add('opened');
return false;
}
if (el.classList.contains('opened')) {
return false;
}
el = el.parentNode;
}
}
/**
* Toggle the display of a column in the issue list page. That is
* done by adding or removing a CSS class of an enclosing HTML
* element, and by CSS rules that trigger based on that CSS class.
* @param {string} colName The name of the column to toggle,
* corresponds to a CSS class.
* @return Always returns false to indicate that the browser should
* handle the event normally.
*/
function TKR_toggleColumn(colName) {
let controlDiv = $('colcontrol');
if (controlDiv.classList.contains(colName)) {
controlDiv.classList.remove(colName);
} else {
controlDiv.classList.add(colName);
}
return false;
}
/**
* Toggle the display of a set of rows in the issue list page. That is
* done by adding or removing a CSS class of an enclosing HTML
* element, and by CSS rules that trigger based on that CSS class.
* TODO(jrobbins): actually, this automatically hides the other groups.
* @param {string} rowClassName The name of the row group to toggle,
* corresponds to a CSS class.
* @return Always returns false to indicate that the browser should
* handle the event normally.
*/
function TKR_toggleRows(rowClassName) {
let controlDiv = $('colcontrol');
controlDiv.classList.add('hide_pri_groups');
controlDiv.classList.add('hide_mile_groups');
controlDiv.classList.add('hide_stat_groups');
TKR_toggleColumn(rowClassName);
return false;
}
/**
* A simple class that can manage the display of a popup menu. Instances
* of this class are used by popup_controller.js.
* @param {Element} div The div that contains the popup menu.
* @param {Element} opt_launcherEl The button that launched the popup menu,
* if any.
* @constructor
*/
function TKR_MyPopup(div, opt_launcherEl) {
this._div = div;
this._launcher = opt_launcherEl;
this._isVisible = false;
}
/**
* Show a popup menu. This method registers the popup with popup_controller.
*/
TKR_MyPopup.prototype.show = function() {
this._div.style.display = 'block';
this._isVisible = true;
PC_addPopup(this);
};
/**
* Show a popup menu. This method is called from the deactive method,
* which is called by popup_controller.
*/
TKR_MyPopup.prototype.hide = function() {
this._div.style.display = 'none';
this._isVisible = false;
};
/**
* When the popup_controller gets a user click, it calls deactive() on
* every active popup to check if the click should close that popup.
*/
TKR_MyPopup.prototype.deactivate = function(e) {
if (this._isVisible) {
let p = GetMousePosition(e);
if (nodeBounds(this._div).contains(p)) {
return false; // use clicked on popup, remain visible
} else if (this._launcher && nodeBounds(this._launcher).contains(p)) {
this._launcher = null;
return false; // mouseup element that launched menu, remain visible
} else {
this.hide();
return true; // clicked outside popup, make invisible
}
} else {
return true; // already deactivated, not visible
}
};
/**
* Highlight the issue row on the list page that contains the given
* checkbox.
* @param {Element} cb The checkbox that the user changed.
* @return Always returns false to indicate that the browser should
* handle the event normally.
*/
function TKR_highlightRow(el) {
let checked = el.checked;
while (el && el.tagName != 'TR') {
el = el.parentNode;
}
if (checked) {
el.classList.add('selected');
} else {
el.classList.remove('selected');
}
return false;
}