browser/components/places/content/menu.xml

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 <?xml version="1.0"?>
michael@0 2
michael@0 3 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 6
michael@0 7 <bindings id="placesMenuBindings"
michael@0 8 xmlns="http://www.mozilla.org/xbl"
michael@0 9 xmlns:xbl="http://www.mozilla.org/xbl"
michael@0 10 xmlns:html="http://www.w3.org/1999/xhtml"
michael@0 11 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
michael@0 12
michael@0 13 <binding id="places-popup-base"
michael@0 14 extends="chrome://global/content/bindings/popup.xml#popup">
michael@0 15 <content>
michael@0 16 <xul:hbox flex="1">
michael@0 17 <xul:vbox class="menupopup-drop-indicator-bar" hidden="true">
michael@0 18 <xul:image class="menupopup-drop-indicator" mousethrough="always"/>
michael@0 19 </xul:vbox>
michael@0 20 <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
michael@0 21 smoothscroll="false">
michael@0 22 <children/>
michael@0 23 </xul:arrowscrollbox>
michael@0 24 </xul:hbox>
michael@0 25 </content>
michael@0 26
michael@0 27 <implementation>
michael@0 28
michael@0 29 <field name="_indicatorBar">
michael@0 30 document.getAnonymousElementByAttribute(this, "class",
michael@0 31 "menupopup-drop-indicator-bar");
michael@0 32 </field>
michael@0 33
michael@0 34 <field name="_scrollBox">
michael@0 35 document.getAnonymousElementByAttribute(this, "class",
michael@0 36 "popup-internal-box");
michael@0 37 </field>
michael@0 38
michael@0 39 <!-- This is the view that manage the popup -->
michael@0 40 <field name="_rootView">PlacesUIUtils.getViewForNode(this);</field>
michael@0 41
michael@0 42 <!-- Check if we should hide the drop indicator for the target -->
michael@0 43 <method name="_hideDropIndicator">
michael@0 44 <parameter name="aEvent"/>
michael@0 45 <body><![CDATA[
michael@0 46 let target = aEvent.target;
michael@0 47
michael@0 48 // Don't draw the drop indicator outside of markers.
michael@0 49 // The markers are hidden, since otherwise sometimes popups acquire
michael@0 50 // scrollboxes on OS X, so we can't use them directly.
michael@0 51 let firstChildTop = this._startMarker.nextSibling.boxObject.y;
michael@0 52 let lastChildBottom = this._endMarker.previousSibling.boxObject.y +
michael@0 53 this._endMarker.previousSibling.boxObject.height;
michael@0 54 let betweenMarkers = target.boxObject.y >= firstChildTop ||
michael@0 55 target.boxObject.y <= lastChildBottom;
michael@0 56
michael@0 57 // Hide the dropmarker if current node is not a Places node.
michael@0 58 return !(target && target._placesNode && betweenMarkers);
michael@0 59 ]]></body>
michael@0 60 </method>
michael@0 61
michael@0 62 <!-- This function returns information about where to drop when
michael@0 63 dragging over this popup insertion point -->
michael@0 64 <method name="_getDropPoint">
michael@0 65 <parameter name="aEvent"/>
michael@0 66 <body><![CDATA[
michael@0 67 // Can't drop if the menu isn't a folder
michael@0 68 let resultNode = this._placesNode;
michael@0 69
michael@0 70 if (!PlacesUtils.nodeIsFolder(resultNode) ||
michael@0 71 PlacesControllerDragHelper.disallowInsertion(resultNode)) {
michael@0 72 return null;
michael@0 73 }
michael@0 74
michael@0 75 var dropPoint = { ip: null, folderElt: null };
michael@0 76
michael@0 77 // The element we are dragging over
michael@0 78 let elt = aEvent.target;
michael@0 79 if (elt.localName == "menupopup")
michael@0 80 elt = elt.parentNode;
michael@0 81
michael@0 82 // Calculate positions taking care of arrowscrollbox
michael@0 83 let scrollbox = this._scrollBox;
michael@0 84 let eventY = aEvent.layerY + (scrollbox.boxObject.y - this.boxObject.y);
michael@0 85 let scrollboxOffset = scrollbox.scrollBoxObject.y -
michael@0 86 (scrollbox.boxObject.y - this.boxObject.y);
michael@0 87 let eltY = elt.boxObject.y - scrollboxOffset;
michael@0 88 let eltHeight = elt.boxObject.height;
michael@0 89
michael@0 90 if (!elt._placesNode) {
michael@0 91 // If we are dragging over a non places node drop at the end.
michael@0 92 dropPoint.ip = new InsertionPoint(
michael@0 93 PlacesUtils.getConcreteItemId(resultNode),
michael@0 94 -1,
michael@0 95 Ci.nsITreeView.DROP_ON);
michael@0 96 // We can set folderElt if we are dropping over a static menu that
michael@0 97 // has an internal placespopup.
michael@0 98 let isMenu = elt.localName == "menu" ||
michael@0 99 (elt.localName == "toolbarbutton" &&
michael@0 100 elt.getAttribute("type") == "menu");
michael@0 101 if (isMenu && elt.lastChild &&
michael@0 102 elt.lastChild.hasAttribute("placespopup"))
michael@0 103 dropPoint.folderElt = elt;
michael@0 104 return dropPoint;
michael@0 105 }
michael@0 106 else if ((PlacesUtils.nodeIsFolder(elt._placesNode) ||
michael@0 107 PlacesUtils.nodeIsTagQuery(elt._placesNode)) &&
michael@0 108 !PlacesUtils.nodeIsReadOnly(elt._placesNode)) {
michael@0 109 // This is a folder or a tag container.
michael@0 110 if (eventY - eltY < eltHeight * 0.20) {
michael@0 111 // If mouse is in the top part of the element, drop above folder.
michael@0 112 dropPoint.ip = new InsertionPoint(
michael@0 113 PlacesUtils.getConcreteItemId(resultNode),
michael@0 114 -1,
michael@0 115 Ci.nsITreeView.DROP_BEFORE,
michael@0 116 PlacesUtils.nodeIsTagQuery(elt._placesNode),
michael@0 117 elt._placesNode.itemId);
michael@0 118 return dropPoint;
michael@0 119 }
michael@0 120 else if (eventY - eltY < eltHeight * 0.80) {
michael@0 121 // If mouse is in the middle of the element, drop inside folder.
michael@0 122 dropPoint.ip = new InsertionPoint(
michael@0 123 PlacesUtils.getConcreteItemId(elt._placesNode),
michael@0 124 -1,
michael@0 125 Ci.nsITreeView.DROP_ON,
michael@0 126 PlacesUtils.nodeIsTagQuery(elt._placesNode));
michael@0 127 dropPoint.folderElt = elt;
michael@0 128 return dropPoint;
michael@0 129 }
michael@0 130 }
michael@0 131 else if (eventY - eltY <= eltHeight / 2) {
michael@0 132 // This is a non-folder node or a readonly folder.
michael@0 133 // If the mouse is above the middle, drop above this item.
michael@0 134 dropPoint.ip = new InsertionPoint(
michael@0 135 PlacesUtils.getConcreteItemId(resultNode),
michael@0 136 -1,
michael@0 137 Ci.nsITreeView.DROP_BEFORE,
michael@0 138 PlacesUtils.nodeIsTagQuery(elt._placesNode),
michael@0 139 elt._placesNode.itemId);
michael@0 140 return dropPoint;
michael@0 141 }
michael@0 142
michael@0 143 // Drop below the item.
michael@0 144 dropPoint.ip = new InsertionPoint(
michael@0 145 PlacesUtils.getConcreteItemId(resultNode),
michael@0 146 -1,
michael@0 147 Ci.nsITreeView.DROP_AFTER,
michael@0 148 PlacesUtils.nodeIsTagQuery(elt._placesNode),
michael@0 149 elt._placesNode.itemId);
michael@0 150 return dropPoint;
michael@0 151 ]]></body>
michael@0 152 </method>
michael@0 153
michael@0 154 <!-- Sub-menus should be opened when the mouse drags over them, and closed
michael@0 155 when the mouse drags off. The overFolder object manages opening and
michael@0 156 closing of folders when the mouse hovers. -->
michael@0 157 <field name="_overFolder"><![CDATA[({
michael@0 158 _self: this,
michael@0 159 _folder: {elt: null,
michael@0 160 openTimer: null,
michael@0 161 hoverTime: 350,
michael@0 162 closeTimer: null},
michael@0 163 _closeMenuTimer: null,
michael@0 164
michael@0 165 get elt() {
michael@0 166 return this._folder.elt;
michael@0 167 },
michael@0 168 set elt(val) {
michael@0 169 return this._folder.elt = val;
michael@0 170 },
michael@0 171
michael@0 172 get openTimer() {
michael@0 173 return this._folder.openTimer;
michael@0 174 },
michael@0 175 set openTimer(val) {
michael@0 176 return this._folder.openTimer = val;
michael@0 177 },
michael@0 178
michael@0 179 get hoverTime() {
michael@0 180 return this._folder.hoverTime;
michael@0 181 },
michael@0 182 set hoverTime(val) {
michael@0 183 return this._folder.hoverTime = val;
michael@0 184 },
michael@0 185
michael@0 186 get closeTimer() {
michael@0 187 return this._folder.closeTimer;
michael@0 188 },
michael@0 189 set closeTimer(val) {
michael@0 190 return this._folder.closeTimer = val;
michael@0 191 },
michael@0 192
michael@0 193 get closeMenuTimer() {
michael@0 194 return this._closeMenuTimer;
michael@0 195 },
michael@0 196 set closeMenuTimer(val) {
michael@0 197 return this._closeMenuTimer = val;
michael@0 198 },
michael@0 199
michael@0 200 setTimer: function OF__setTimer(aTime) {
michael@0 201 var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
michael@0 202 timer.initWithCallback(this, aTime, timer.TYPE_ONE_SHOT);
michael@0 203 return timer;
michael@0 204 },
michael@0 205
michael@0 206 notify: function OF__notify(aTimer) {
michael@0 207 // Function to process all timer notifications.
michael@0 208
michael@0 209 if (aTimer == this._folder.openTimer) {
michael@0 210 // Timer to open a submenu that's being dragged over.
michael@0 211 this._folder.elt.lastChild.setAttribute("autoopened", "true");
michael@0 212 this._folder.elt.lastChild.showPopup(this._folder.elt);
michael@0 213 this._folder.openTimer = null;
michael@0 214 }
michael@0 215
michael@0 216 else if (aTimer == this._folder.closeTimer) {
michael@0 217 // Timer to close a submenu that's been dragged off of.
michael@0 218 // Only close the submenu if the mouse isn't being dragged over any
michael@0 219 // of its child menus.
michael@0 220 var draggingOverChild = PlacesControllerDragHelper
michael@0 221 .draggingOverChildNode(this._folder.elt);
michael@0 222 if (draggingOverChild)
michael@0 223 this._folder.elt = null;
michael@0 224 this.clear();
michael@0 225
michael@0 226 // Close any parent folders which aren't being dragged over.
michael@0 227 // (This is necessary because of the above code that keeps a folder
michael@0 228 // open while its children are being dragged over.)
michael@0 229 if (!draggingOverChild)
michael@0 230 this.closeParentMenus();
michael@0 231 }
michael@0 232
michael@0 233 else if (aTimer == this.closeMenuTimer) {
michael@0 234 // Timer to close this menu after the drag exit.
michael@0 235 var popup = this._self;
michael@0 236 // if we are no more dragging we can leave the menu open to allow
michael@0 237 // for better D&D bookmark organization
michael@0 238 if (PlacesControllerDragHelper.getSession() &&
michael@0 239 !PlacesControllerDragHelper.draggingOverChildNode(popup.parentNode)) {
michael@0 240 popup.hidePopup();
michael@0 241 // Close any parent menus that aren't being dragged over;
michael@0 242 // otherwise they'll stay open because they couldn't close
michael@0 243 // while this menu was being dragged over.
michael@0 244 this.closeParentMenus();
michael@0 245 }
michael@0 246 this._closeMenuTimer = null;
michael@0 247 }
michael@0 248 },
michael@0 249
michael@0 250 // Helper function to close all parent menus of this menu,
michael@0 251 // as long as none of the parent's children are currently being
michael@0 252 // dragged over.
michael@0 253 closeParentMenus: function OF__closeParentMenus() {
michael@0 254 var popup = this._self;
michael@0 255 var parent = popup.parentNode;
michael@0 256 while (parent) {
michael@0 257 if (parent.localName == "menupopup" && parent._placesNode) {
michael@0 258 if (PlacesControllerDragHelper.draggingOverChildNode(parent.parentNode))
michael@0 259 break;
michael@0 260 parent.hidePopup();
michael@0 261 }
michael@0 262 parent = parent.parentNode;
michael@0 263 }
michael@0 264 },
michael@0 265
michael@0 266 // The mouse is no longer dragging over the stored menubutton.
michael@0 267 // Close the menubutton, clear out drag styles, and clear all
michael@0 268 // timers for opening/closing it.
michael@0 269 clear: function OF__clear() {
michael@0 270 if (this._folder.elt && this._folder.elt.lastChild) {
michael@0 271 if (!this._folder.elt.lastChild.hasAttribute("dragover"))
michael@0 272 this._folder.elt.lastChild.hidePopup();
michael@0 273 // remove menuactive style
michael@0 274 this._folder.elt.removeAttribute("_moz-menuactive");
michael@0 275 this._folder.elt = null;
michael@0 276 }
michael@0 277 if (this._folder.openTimer) {
michael@0 278 this._folder.openTimer.cancel();
michael@0 279 this._folder.openTimer = null;
michael@0 280 }
michael@0 281 if (this._folder.closeTimer) {
michael@0 282 this._folder.closeTimer.cancel();
michael@0 283 this._folder.closeTimer = null;
michael@0 284 }
michael@0 285 }
michael@0 286 })]]></field>
michael@0 287
michael@0 288 <method name="_cleanupDragDetails">
michael@0 289 <body><![CDATA[
michael@0 290 // Called on dragend and drop.
michael@0 291 PlacesControllerDragHelper.currentDropTarget = null;
michael@0 292 this._rootView._draggedElt = null;
michael@0 293 this.removeAttribute("dragover");
michael@0 294 this.removeAttribute("dragstart");
michael@0 295 this._indicatorBar.hidden = true;
michael@0 296 ]]></body>
michael@0 297 </method>
michael@0 298
michael@0 299 </implementation>
michael@0 300
michael@0 301 <handlers>
michael@0 302 <handler event="DOMMenuItemActive"><![CDATA[
michael@0 303 let elt = event.target;
michael@0 304 if (elt.parentNode != this)
michael@0 305 return;
michael@0 306
michael@0 307 #ifdef XP_MACOSX
michael@0 308 // XXX: The following check is a temporary hack until bug 420033 is
michael@0 309 // resolved.
michael@0 310 let parentElt = elt.parent;
michael@0 311 while (parentElt) {
michael@0 312 if (parentElt.id == "bookmarksMenuPopup" ||
michael@0 313 parentElt.id == "goPopup")
michael@0 314 return;
michael@0 315
michael@0 316 parentElt = parentElt.parentNode;
michael@0 317 }
michael@0 318 #endif
michael@0 319
michael@0 320 if (window.XULBrowserWindow) {
michael@0 321 let elt = event.target;
michael@0 322 let placesNode = elt._placesNode;
michael@0 323
michael@0 324 var linkURI;
michael@0 325 if (placesNode && PlacesUtils.nodeIsURI(placesNode))
michael@0 326 linkURI = placesNode.uri;
michael@0 327 else if (elt.hasAttribute("targetURI"))
michael@0 328 linkURI = elt.getAttribute("targetURI");
michael@0 329
michael@0 330 if (linkURI)
michael@0 331 window.XULBrowserWindow.setOverLink(linkURI, null);
michael@0 332 }
michael@0 333 ]]></handler>
michael@0 334
michael@0 335 <handler event="DOMMenuItemInactive"><![CDATA[
michael@0 336 let elt = event.target;
michael@0 337 if (elt.parentNode != this)
michael@0 338 return;
michael@0 339
michael@0 340 if (window.XULBrowserWindow)
michael@0 341 window.XULBrowserWindow.setOverLink("", null);
michael@0 342 ]]></handler>
michael@0 343
michael@0 344 <handler event="dragstart"><![CDATA[
michael@0 345 if (!event.target._placesNode)
michael@0 346 return;
michael@0 347
michael@0 348 let draggedElt = event.target._placesNode;
michael@0 349
michael@0 350 // Force a copy action if parent node is a query or we are dragging a
michael@0 351 // not-removable node.
michael@0 352 if (!PlacesControllerDragHelper.canMoveNode(draggedElt))
michael@0 353 event.dataTransfer.effectAllowed = "copyLink";
michael@0 354
michael@0 355 // Activate the view and cache the dragged element.
michael@0 356 this._rootView._draggedElt = draggedElt;
michael@0 357 this._rootView.controller.setDataTransfer(event);
michael@0 358 this.setAttribute("dragstart", "true");
michael@0 359 event.stopPropagation();
michael@0 360 ]]></handler>
michael@0 361
michael@0 362 <handler event="drop"><![CDATA[
michael@0 363 PlacesControllerDragHelper.currentDropTarget = event.target;
michael@0 364
michael@0 365 let dropPoint = this._getDropPoint(event);
michael@0 366 if (dropPoint && dropPoint.ip) {
michael@0 367 PlacesControllerDragHelper.onDrop(dropPoint.ip, event.dataTransfer);
michael@0 368 event.preventDefault();
michael@0 369 }
michael@0 370
michael@0 371 this._cleanupDragDetails();
michael@0 372 event.stopPropagation();
michael@0 373 ]]></handler>
michael@0 374
michael@0 375 <handler event="dragover"><![CDATA[
michael@0 376 PlacesControllerDragHelper.currentDropTarget = event.target;
michael@0 377 let dt = event.dataTransfer;
michael@0 378
michael@0 379 let dropPoint = this._getDropPoint(event);
michael@0 380 if (!dropPoint || !dropPoint.ip ||
michael@0 381 !PlacesControllerDragHelper.canDrop(dropPoint.ip, dt)) {
michael@0 382 this._indicatorBar.hidden = true;
michael@0 383 event.stopPropagation();
michael@0 384 return;
michael@0 385 }
michael@0 386
michael@0 387 // Mark this popup as being dragged over.
michael@0 388 this.setAttribute("dragover", "true");
michael@0 389
michael@0 390 if (dropPoint.folderElt) {
michael@0 391 // We are dragging over a folder.
michael@0 392 // _overFolder should take the care of opening it on a timer.
michael@0 393 if (this._overFolder.elt &&
michael@0 394 this._overFolder.elt != dropPoint.folderElt) {
michael@0 395 // We are dragging over a new folder, let's clear old values
michael@0 396 this._overFolder.clear();
michael@0 397 }
michael@0 398 if (!this._overFolder.elt) {
michael@0 399 this._overFolder.elt = dropPoint.folderElt;
michael@0 400 // Create the timer to open this folder.
michael@0 401 this._overFolder.openTimer = this._overFolder
michael@0 402 .setTimer(this._overFolder.hoverTime);
michael@0 403 }
michael@0 404 // Since we are dropping into a folder set the corresponding style.
michael@0 405 dropPoint.folderElt.setAttribute("_moz-menuactive", true);
michael@0 406 }
michael@0 407 else {
michael@0 408 // We are not dragging over a folder.
michael@0 409 // Clear out old _overFolder information.
michael@0 410 this._overFolder.clear();
michael@0 411 }
michael@0 412
michael@0 413 // Autoscroll the popup strip if we drag over the scroll buttons.
michael@0 414 let anonid = event.originalTarget.getAttribute('anonid');
michael@0 415 let scrollDir = anonid == "scrollbutton-up" ? -1 :
michael@0 416 anonid == "scrollbutton-down" ? 1 : 0;
michael@0 417 if (scrollDir != 0) {
michael@0 418 this._scrollBox.scrollByIndex(scrollDir, false);
michael@0 419 }
michael@0 420
michael@0 421 // Check if we should hide the drop indicator for this target.
michael@0 422 if (dropPoint.folderElt || this._hideDropIndicator(event)) {
michael@0 423 this._indicatorBar.hidden = true;
michael@0 424 event.preventDefault();
michael@0 425 event.stopPropagation();
michael@0 426 return;
michael@0 427 }
michael@0 428
michael@0 429 // We should display the drop indicator relative to the arrowscrollbox.
michael@0 430 let sbo = this._scrollBox.scrollBoxObject;
michael@0 431 let newMarginTop = 0;
michael@0 432 if (scrollDir == 0) {
michael@0 433 let elt = this.firstChild;
michael@0 434 while (elt && event.screenY > elt.boxObject.screenY +
michael@0 435 elt.boxObject.height / 2)
michael@0 436 elt = elt.nextSibling;
michael@0 437 newMarginTop = elt ? elt.boxObject.screenY - sbo.screenY :
michael@0 438 sbo.height;
michael@0 439 }
michael@0 440 else if (scrollDir == 1)
michael@0 441 newMarginTop = sbo.height;
michael@0 442
michael@0 443 // Set the new marginTop based on arrowscrollbox.
michael@0 444 newMarginTop += sbo.y - this._scrollBox.boxObject.y;
michael@0 445 this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
michael@0 446 this._indicatorBar.hidden = false;
michael@0 447
michael@0 448 event.preventDefault();
michael@0 449 event.stopPropagation();
michael@0 450 ]]></handler>
michael@0 451
michael@0 452 <handler event="dragexit"><![CDATA[
michael@0 453 PlacesControllerDragHelper.currentDropTarget = null;
michael@0 454 this.removeAttribute("dragover");
michael@0 455
michael@0 456 // If we have not moved to a valid new target clear the drop indicator
michael@0 457 // this happens when moving out of the popup.
michael@0 458 let target = event.relatedTarget;
michael@0 459 if (!target || !this.contains(target))
michael@0 460 this._indicatorBar.hidden = true;
michael@0 461
michael@0 462 // Close any folder being hovered over
michael@0 463 if (this._overFolder.elt) {
michael@0 464 this._overFolder.closeTimer = this._overFolder
michael@0 465 .setTimer(this._overFolder.hoverTime);
michael@0 466 }
michael@0 467
michael@0 468 // The autoopened attribute is set when this folder was automatically
michael@0 469 // opened after the user dragged over it. If this attribute is set,
michael@0 470 // auto-close the folder on drag exit.
michael@0 471 // We should also try to close this popup if the drag has started
michael@0 472 // from here, the timer will check if we are dragging over a child.
michael@0 473 if (this.hasAttribute("autoopened") ||
michael@0 474 this.hasAttribute("dragstart")) {
michael@0 475 this._overFolder.closeMenuTimer = this._overFolder
michael@0 476 .setTimer(this._overFolder.hoverTime);
michael@0 477 }
michael@0 478
michael@0 479 event.stopPropagation();
michael@0 480 ]]></handler>
michael@0 481
michael@0 482 <handler event="dragend"><![CDATA[
michael@0 483 this._cleanupDragDetails();
michael@0 484 ]]></handler>
michael@0 485
michael@0 486 </handlers>
michael@0 487 </binding>
michael@0 488
michael@0 489 <!-- Most of this is copied from the arrowpanel binding in popup.xml -->
michael@0 490 <binding id="places-popup-arrow"
michael@0 491 extends="chrome://browser/content/places/menu.xml#places-popup-base">
michael@0 492 <content flip="both" side="top" position="bottomcenter topright">
michael@0 493 <xul:vbox anonid="container" class="panel-arrowcontainer" flex="1"
michael@0 494 xbl:inherits="side,panelopen">
michael@0 495 <xul:box anonid="arrowbox" class="panel-arrowbox">
michael@0 496 <xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/>
michael@0 497 </xul:box>
michael@0 498 <xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1">
michael@0 499 <xul:vbox class="menupopup-drop-indicator-bar" hidden="true">
michael@0 500 <xul:image class="menupopup-drop-indicator" mousethrough="always"/>
michael@0 501 </xul:vbox>
michael@0 502 <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
michael@0 503 smoothscroll="false">
michael@0 504 <children/>
michael@0 505 </xul:arrowscrollbox>
michael@0 506 </xul:box>
michael@0 507 </xul:vbox>
michael@0 508 </content>
michael@0 509
michael@0 510 <implementation>
michael@0 511 <constructor><![CDATA[
michael@0 512 this.style.pointerEvents = 'none';
michael@0 513 ]]></constructor>
michael@0 514 <method name="adjustArrowPosition">
michael@0 515 <body><![CDATA[
michael@0 516 var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
michael@0 517
michael@0 518 var anchor = this.anchorNode;
michael@0 519 if (!anchor) {
michael@0 520 arrow.hidden = true;
michael@0 521 return;
michael@0 522 }
michael@0 523
michael@0 524 var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
michael@0 525 var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
michael@0 526
michael@0 527 var position = this.alignmentPosition;
michael@0 528 var offset = this.alignmentOffset;
michael@0 529
michael@0 530 // if this panel has a "sliding" arrow, we may have previously set margins...
michael@0 531 arrowbox.style.removeProperty("transform");
michael@0 532 if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
michael@0 533 container.orient = "horizontal";
michael@0 534 arrowbox.orient = "vertical";
michael@0 535 if (position.indexOf("_after") > 0) {
michael@0 536 arrowbox.pack = "end";
michael@0 537 } else {
michael@0 538 arrowbox.pack = "start";
michael@0 539 }
michael@0 540 arrowbox.style.transform = "translate(0, " + -offset + "px)";
michael@0 541
michael@0 542 // The assigned side stays the same regardless of direction.
michael@0 543 var isRTL = (window.getComputedStyle(this).direction == "rtl");
michael@0 544
michael@0 545 if (position.indexOf("start_") == 0) {
michael@0 546 container.dir = "reverse";
michael@0 547 this.setAttribute("side", isRTL ? "left" : "right");
michael@0 548 }
michael@0 549 else {
michael@0 550 container.dir = "";
michael@0 551 this.setAttribute("side", isRTL ? "right" : "left");
michael@0 552 }
michael@0 553 }
michael@0 554 else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) {
michael@0 555 container.orient = "";
michael@0 556 arrowbox.orient = "";
michael@0 557 if (position.indexOf("_end") > 0) {
michael@0 558 arrowbox.pack = "end";
michael@0 559 } else {
michael@0 560 arrowbox.pack = "start";
michael@0 561 }
michael@0 562 arrowbox.style.transform = "translate(" + -offset + "px, 0)";
michael@0 563
michael@0 564 if (position.indexOf("before_") == 0) {
michael@0 565 container.dir = "reverse";
michael@0 566 this.setAttribute("side", "bottom");
michael@0 567 }
michael@0 568 else {
michael@0 569 container.dir = "";
michael@0 570 this.setAttribute("side", "top");
michael@0 571 }
michael@0 572 }
michael@0 573
michael@0 574 arrow.hidden = false;
michael@0 575 ]]></body>
michael@0 576 </method>
michael@0 577 </implementation>
michael@0 578
michael@0 579 <handlers>
michael@0 580 <handler event="popupshowing" phase="target"><![CDATA[
michael@0 581 this.adjustArrowPosition();
michael@0 582 ]]></handler>
michael@0 583 <handler event="popupshown" phase="target"><![CDATA[
michael@0 584 this.setAttribute("panelopen", "true");
michael@0 585 let disablePointerEvents;
michael@0 586 if (!this.hasAttribute("disablepointereventsfortransition")) {
michael@0 587 let container = document.getAnonymousElementByAttribute(this, "anonid", "container");
michael@0 588 let cs = getComputedStyle(container);
michael@0 589 let transitionProp = cs.transitionProperty;
michael@0 590 let transitionTime = parseFloat(cs.transitionDuration);
michael@0 591 disablePointerEvents = (transitionProp.contains("transform") ||
michael@0 592 transitionProp == "all") &&
michael@0 593 transitionTime > 0;
michael@0 594 this.setAttribute("disablepointereventsfortransition", disablePointerEvents);
michael@0 595 } else {
michael@0 596 disablePointerEvents = this.getAttribute("disablepointereventsfortransition") == "true";
michael@0 597 }
michael@0 598 if (!disablePointerEvents) {
michael@0 599 this.style.removeProperty("pointer-events");
michael@0 600 }
michael@0 601 ]]></handler>
michael@0 602 <handler event="transitionend"><![CDATA[
michael@0 603 if (event.originalTarget.getAttribute("anonid") == "container" &&
michael@0 604 event.propertyName == "transform") {
michael@0 605 this.style.removeProperty("pointer-events");
michael@0 606 }
michael@0 607 ]]></handler>
michael@0 608 <handler event="popuphidden" phase="target"><![CDATA[
michael@0 609 this.removeAttribute("panelopen");
michael@0 610 if (this.getAttribute("disablepointereventsfortransition") == "true") {
michael@0 611 this.style.pointerEvents = 'none';
michael@0 612 }
michael@0 613 ]]></handler>
michael@0 614 </handlers>
michael@0 615 </binding>
michael@0 616 </bindings>

mercurial