OLD | NEW |
(Empty) | |
| 1 /* Copyright 2016 The Chromium Authors. All Rights Reserved. |
| 2 * |
| 3 * Use of this source code is governed by a BSD-style |
| 4 * license that can be found in the LICENSE file or at |
| 5 * https://developers.google.com/open-source/licenses/bsd |
| 6 */ |
| 7 |
| 8 /** |
| 9 * Functions used by Monorail to control the display of elements on |
| 10 * the page, rollovers, and popup menus. |
| 11 * |
| 12 */ |
| 13 |
| 14 |
| 15 /** |
| 16 * Show a popup menu below a specified element. Optional x and y deltas can be |
| 17 * used to fine-tune placement. |
| 18 * @param {string} id The HTML id of the popup menu. |
| 19 * @param {Element} el The HTML element that the popup should appear near. |
| 20 * @param {number} opt_deltaX Optional X offset to finetune placement. |
| 21 * @param {number} opt_deltaY Optional Y offset to finetune placement. |
| 22 * @param {Element} opt_menuButton The HTML element for a menu button that |
| 23 * was pressed to open the menu. When a button was used, we need to ignore |
| 24 * the first "click" event, otherwise the menu will immediately close. |
| 25 * @returns Always returns false to indicate that the browser should handle the |
| 26 * event normally. |
| 27 */ |
| 28 function TKR_showBelow(id, el, opt_deltaX, opt_deltaY, opt_menuButton) { |
| 29 var popupDiv = $(id); |
| 30 var elBounds = nodeBounds(el) |
| 31 var startX = elBounds.x; |
| 32 var startY = elBounds.y + elBounds.h; |
| 33 if (BR_IsIE()) { |
| 34 startX -= 1; |
| 35 startY -= 2; |
| 36 } |
| 37 if (BR_IsSafari()) { |
| 38 startX += 1; |
| 39 } |
| 40 popupDiv.style.display = 'block'; //needed so that offsetWidth != 0 |
| 41 |
| 42 popupDiv.style.left = '-2000px'; |
| 43 if (id == 'pop_dot' || id == 'redoMenu') { |
| 44 startX = startX - popupDiv.offsetWidth + el.offsetWidth; |
| 45 } |
| 46 if (opt_deltaX) startX += opt_deltaX; |
| 47 if (opt_deltaY) startY += opt_deltaY; |
| 48 popupDiv.style.left = (startX)+'px'; |
| 49 popupDiv.style.top = (startY)+'px'; |
| 50 var popup = new TKR_MyPopup(popupDiv, opt_menuButton); |
| 51 popup.show(); |
| 52 return false; |
| 53 } |
| 54 |
| 55 |
| 56 /** |
| 57 * Show a popup menu to the right of a specified element. If there is not |
| 58 * enough space to the right, then it will open to the left side instead. |
| 59 * Optional x and y deltas can be used to fine-tune placement. |
| 60 * TODO(jrobbins): reduce redundancy with function above. |
| 61 * @param {string} id The HTML id of the popup menu. |
| 62 * @param {Element} el The HTML element that the popup should appear near. |
| 63 * @param {number} opt_deltaX Optional X offset to finetune placement. |
| 64 * @param {number} opt_deltaY Optional Y offset to finetune placement. |
| 65 * @returns Always returns false to indicate that the browser should handle the |
| 66 * event normally. |
| 67 */ |
| 68 function TKR_showRight(id, el, opt_deltaX, opt_deltaY) { |
| 69 var popupDiv = $(id); |
| 70 var elBounds = nodeBounds(el); |
| 71 var startX = elBounds.x + elBounds.w; |
| 72 var startY = elBounds.y; |
| 73 |
| 74 // Calculate pageSize.w and pageSize.h |
| 75 var docElemWidth = document.documentElement.clientWidth; |
| 76 var docElemHeight = document.documentElement.clientHeight; |
| 77 var pageSize = { |
| 78 w: (window.innerWidth || docElemWidth && docElemWidth > 0 ? |
| 79 docElemWidth : document.body.clientWidth) || 1, |
| 80 h: (window.innerHeight || docElemHeight && docElemHeight > 0 ? |
| 81 docElemHeight : document.body.clientHeight) || 1 |
| 82 } |
| 83 |
| 84 // We need to make the popupDiv visible in order to capture its width |
| 85 popupDiv.style.display = 'block'; |
| 86 var popupDivBounds = nodeBounds(popupDiv); |
| 87 |
| 88 // Show popup to the left |
| 89 if (startX + popupDivBounds.w > pageSize.w) { |
| 90 startX = elBounds.x - popupDivBounds.w; |
| 91 if (BR_IsIE()) { |
| 92 startX -= 4; |
| 93 startY -= 2; |
| 94 } |
| 95 if (BR_IsNav()) { |
| 96 startX -= 2; |
| 97 } |
| 98 if (BR_IsSafari()) { |
| 99 startX += -1; |
| 100 } |
| 101 |
| 102 // Show popup to the right |
| 103 } else { |
| 104 if (BR_IsIE()) { |
| 105 startY -= 2; |
| 106 } |
| 107 if (BR_IsNav()) { |
| 108 startX += 2; |
| 109 } |
| 110 if (BR_IsSafari()) { |
| 111 startX += 3; |
| 112 } |
| 113 } |
| 114 |
| 115 popupDiv.style.left = '-2000px'; |
| 116 popupDiv.style.position = 'absolute'; |
| 117 if (opt_deltaX) startX += opt_deltaX; |
| 118 if (opt_deltaY) startY += opt_deltaY; |
| 119 popupDiv.style.left = (startX)+'px'; |
| 120 popupDiv.style.top = (startY)+'px'; |
| 121 var popup = new TKR_MyPopup(popupDiv); |
| 122 popup.show(); |
| 123 return false; |
| 124 } |
| 125 |
| 126 |
| 127 /** |
| 128 * Close the specified popup menu and unregister it with the popup |
| 129 * controller, otherwise old leftover popup instances can mess with |
| 130 * the future display of menus. |
| 131 * @param {string} id The HTML ID of the element to hide. |
| 132 */ |
| 133 function TKR_closePopup(id) { |
| 134 var e = $(id); |
| 135 if (e) { |
| 136 for (var i = 0; i < gPopupController.activePopups_.length; ++i) { |
| 137 if (e === gPopupController.activePopups_[i]._div) { |
| 138 var popup = gPopupController.activePopups_[i]; |
| 139 popup.hide(); |
| 140 gPopupController.activePopups_.splice(i, 1); |
| 141 return; |
| 142 } |
| 143 } |
| 144 } |
| 145 } |
| 146 |
| 147 |
| 148 var TKR_allColumnNames = []; // Will be defined in HTML file. |
| 149 |
| 150 /** |
| 151 * Close all popup menus. Also, reset the hover state of the menu item that |
| 152 * was selected. The list of popup menu names is computed from the list of |
| 153 * columns specified in the HTML for the issue list page. |
| 154 * @param menuItem {Element} The menu item that the user clicked. |
| 155 * @returns Always returns false to indicate that the browser should handle the |
| 156 * event normally. |
| 157 */ |
| 158 function TKR_closeAllPopups(menuItem) { |
| 159 for (var col_index = 0; col_index < TKR_allColumnNames.length; col_index++) { |
| 160 TKR_closePopup('pop_' + col_index); |
| 161 TKR_closePopup('filter_' + col_index); |
| 162 } |
| 163 TKR_closePopup('pop_dot'); |
| 164 TKR_closePopup('redoMenu'); |
| 165 menuItem.classList.remove('hover'); |
| 166 return false; |
| 167 } |
| 168 |
| 169 |
| 170 /** |
| 171 * Close all the submenus (of which, one may be currently open). |
| 172 * @returns Always returns false to indicate that the browser should handle the |
| 173 * event normally. |
| 174 */ |
| 175 function TKR_closeSubmenus() { |
| 176 for (var col_index = 0; col_index < TKR_allColumnNames.length; col_index++) { |
| 177 TKR_closePopup('filter_' + col_index); |
| 178 } |
| 179 return false; |
| 180 } |
| 181 |
| 182 |
| 183 /** |
| 184 * Find the enclosing HTML element that controls this section of the |
| 185 * page and set it to use CSS class "opened". That will make the |
| 186 * section display in the opened state, regardless of what state is |
| 187 * was in before. |
| 188 * @param {Element} el The HTML element that the user clicked on. |
| 189 * @returns Always returns false to indicate that the browser should handle the |
| 190 * event normally. |
| 191 */ |
| 192 function TKR_showHidden(el) { |
| 193 while (el) { |
| 194 if (el.classList.contains('closed')) { |
| 195 el.classList.remove('closed'); |
| 196 el.classList.add('opened'); |
| 197 return false; |
| 198 } |
| 199 if (el.classList.contains('opened')) { |
| 200 return false; |
| 201 } |
| 202 el = el.parentNode; |
| 203 } |
| 204 } |
| 205 |
| 206 |
| 207 /** |
| 208 * Toggle the display of a column in the issue list page. That is |
| 209 * done by adding or removing a CSS class of an enclosing HTML |
| 210 * element, and by CSS rules that trigger based on that CSS class. |
| 211 * @param {string} colName The name of the column to toggle, |
| 212 * corresponds to a CSS class. |
| 213 * @returns Always returns false to indicate that the browser should |
| 214 * handle the event normally. |
| 215 */ |
| 216 function TKR_toggleColumn(colName) { |
| 217 var controlDiv = $('colcontrol'); |
| 218 if (controlDiv.classList.contains(colName)) { |
| 219 controlDiv.classList.remove(colName); |
| 220 } |
| 221 else { |
| 222 controlDiv.classList.add(colName); |
| 223 } |
| 224 return false; |
| 225 } |
| 226 |
| 227 |
| 228 /** |
| 229 * Toggle the display of a set of rows in the issue list page. That is |
| 230 * done by adding or removing a CSS class of an enclosing HTML |
| 231 * element, and by CSS rules that trigger based on that CSS class. |
| 232 * TODO(jrobbins): actually, this automatically hides the other groups. |
| 233 * @param {string} rowClassName The name of the row group to toggle, |
| 234 * corresponds to a CSS class. |
| 235 * @returns Always returns false to indicate that the browser should |
| 236 * handle the event normally. |
| 237 */ |
| 238 function TKR_toggleRows(rowClassName) { |
| 239 var controlDiv = $('colcontrol'); |
| 240 controlDiv.classList.add('hide_pri_groups'); |
| 241 controlDiv.classList.add('hide_mile_groups'); |
| 242 controlDiv.classList.add('hide_stat_groups'); |
| 243 TKR_toggleColumn(rowClassName); |
| 244 return false; |
| 245 } |
| 246 |
| 247 |
| 248 /** |
| 249 * A simple class that can manage the display of a popup menu. Instances |
| 250 * of this class are used by popup_controller.js. |
| 251 * @param {Element} div The div that contains the popup menu. |
| 252 * @param {Element} opt_launcherEl The button that launched the popup menu, |
| 253 * if any. |
| 254 * @constructor |
| 255 */ |
| 256 function TKR_MyPopup(div, opt_launcherEl) { |
| 257 this._div = div; |
| 258 this._launcher = opt_launcherEl; |
| 259 this._isVisible = false; |
| 260 } |
| 261 |
| 262 |
| 263 /** |
| 264 * Show a popup menu. This method registers the popup with popup_controller. |
| 265 */ |
| 266 TKR_MyPopup.prototype.show = function() { |
| 267 this._div.style.display = 'block'; |
| 268 this._isVisible = true; |
| 269 PC_addPopup(this); |
| 270 } |
| 271 |
| 272 |
| 273 /** |
| 274 * Show a popup menu. This method is called from the deactive method, |
| 275 * which is called by popup_controller. |
| 276 */ |
| 277 TKR_MyPopup.prototype.hide = function() { |
| 278 this._div.style.display = 'none'; |
| 279 this._isVisible = false; |
| 280 } |
| 281 |
| 282 |
| 283 /** |
| 284 * When the popup_controller gets a user click, it calls deactive() on |
| 285 * every active popup to check if the click should close that popup. |
| 286 */ |
| 287 TKR_MyPopup.prototype.deactivate = function(e) { |
| 288 if (this._isVisible) { |
| 289 var p = GetMousePosition(e); |
| 290 if (nodeBounds(this._div).contains(p)) { |
| 291 return false; // use clicked on popup, remain visible |
| 292 } else if (this._launcher && nodeBounds(this._launcher).contains(p)) { |
| 293 this._launcher = null; |
| 294 return false; // mouseup element that launched menu, remain visible |
| 295 } else { |
| 296 this.hide(); |
| 297 return true; // clicked outside popup, make invisible |
| 298 } |
| 299 } else { |
| 300 return true; // already deactivated, not visible |
| 301 } |
| 302 } |
| 303 |
| 304 |
| 305 /** |
| 306 * Highlight the issue row on the list page that contains the given |
| 307 * checkbox. |
| 308 * @param {Element} cb The checkbox that the user changed. |
| 309 * @returns Always returns false to indicate that the browser should |
| 310 * handle the event normally. |
| 311 */ |
| 312 function TKR_highlightRow(el) { |
| 313 var checked = el.checked; |
| 314 while (el && el.tagName != 'TR') { |
| 315 el = el.parentNode; |
| 316 } |
| 317 if (checked) { |
| 318 el.classList.add('selected'); |
| 319 } |
| 320 else { |
| 321 el.classList.remove('selected'); |
| 322 } |
| 323 return false; |
| 324 } |
| 325 |
| 326 |
| 327 /** |
| 328 * Floats the metadata section on the LHS of issue/source detail pages. |
| 329 * It assumes that the metadata <div> has id 'meta-float' and its outer |
| 330 * container 'meta-container'. |
| 331 */ |
| 332 function TKR_floatMetadata() { |
| 333 var el = $('meta-float'); |
| 334 var container = $('issuemeta'); |
| 335 |
| 336 window.addEventListener('scroll', function() { |
| 337 TKR_floatVertically(el, container); |
| 338 }, false); |
| 339 } |
| 340 |
| 341 /** |
| 342 * Floats the given element vertically within the provided container as user |
| 343 * scrolls up or down the page. It adjusts the width and padding of the parent |
| 344 * element since it sets the 'position' style of the target element to 'fixed'. |
| 345 * @param {Element} el The HTML element to float. |
| 346 * @param {Element} container The container HTML element. |
| 347 */ |
| 348 function TKR_floatVertically(el, container) { |
| 349 var elBounds = nodeBounds(el); |
| 350 var containerBounds = nodeBounds(container); |
| 351 var scrollTop = GetScrollTop(window); |
| 352 |
| 353 if (!el.style.width) { |
| 354 el.style.width = elBounds.w + 'px'; |
| 355 } |
| 356 |
| 357 if ((scrollTop > containerBounds.y) && |
| 358 (scrollTop - containerBounds.y + elBounds.h <= |
| 359 container.style.top + containerBounds.h) && |
| 360 (GetWindowHeight(window) > elBounds.h)) { |
| 361 if (el.style.position != 'fixed') { |
| 362 el.style.position = 'fixed'; |
| 363 el.style.top = '2px'; |
| 364 if (BR_IsIE()) { |
| 365 el.parentNode.style.paddingRight = elBounds.w + 2 + 'px'; |
| 366 } else { |
| 367 el.parentNode.style.minWidth = elBounds.w + 'px'; |
| 368 } |
| 369 } |
| 370 el.style.left = (6 - GetScrollLeft(window)) + 'px'; |
| 371 } else if (el.style.position != 'relative') { |
| 372 el.style.position = 'relative'; |
| 373 el.style.left = '0'; |
| 374 if (BR_IsIE()) { |
| 375 el.parentNode.style.paddingRight = ''; |
| 376 } |
| 377 } |
| 378 } |
| 379 |
| 380 /** |
| 381 * XMLHTTP object used to remember display preferences on the server. |
| 382 */ |
| 383 var TKR_prefsXmlHttp = undefined; |
| 384 |
| 385 |
| 386 /** |
| 387 * Contact the server to remember a PeopleDetail display preference. |
| 388 * @param {string} projectName The name of the current project. |
| 389 * @param {number} expand Zero or one for the widget hide/show state. |
| 390 * @param {string} token The security token. |
| 391 */ |
| 392 function TKR_setPeoplePrefs(projectName, expand, token) { |
| 393 TKR_prefsXmlHttp = XH_XmlHttpCreate() |
| 394 var prefsURL = '/p/' + projectName + '/people/detailPrefs.do'; |
| 395 var data = 'perms_expanded=' + expand + '&token=' + token; |
| 396 XH_XmlHttpPOST( |
| 397 TKR_prefsXmlHttp, prefsURL, data, TKR_prefsFeedCallback); |
| 398 } |
| 399 |
| 400 |
| 401 /** |
| 402 * The communication with the server has made some progress. If it is |
| 403 * done, then process the response. |
| 404 */ |
| 405 function TKR_prefsFeedCallback() { |
| 406 // Actually, we don't use the return value at all, so do nothing. |
| 407 } |
OLD | NEW |