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