Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 <?xml version="1.0"?>
2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
3 - License, v. 2.0. If a copy of the MPL was not distributed with this
4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
7 <bindings id="popupBindings"
8 xmlns="http://www.mozilla.org/xbl"
9 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
10 xmlns:xbl="http://www.mozilla.org/xbl">
12 <binding id="popup-base">
13 <resources>
14 <stylesheet src="chrome://global/skin/popup.css"/>
15 </resources>
17 <implementation implements="nsIDOMXULPopupElement">
18 <property name="label" onget="return this.getAttribute('label');"
19 onset="this.setAttribute('label', val); return val;"/>
20 <property name="position" onget="return this.getAttribute('position');"
21 onset="this.setAttribute('position', val); return val;"/>
22 <property name="popupBoxObject">
23 <getter>
24 return this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject);
25 </getter>
26 </property>
28 <property name="state" readonly="true"
29 onget="return this.popupBoxObject.popupState"/>
31 <property name="triggerNode" readonly="true"
32 onget="return this.popupBoxObject.triggerNode"/>
34 <property name="anchorNode" readonly="true"
35 onget="return this.popupBoxObject.anchorNode"/>
37 <method name="openPopup">
38 <parameter name="aAnchorElement"/>
39 <parameter name="aPosition"/>
40 <parameter name="aX"/>
41 <parameter name="aY"/>
42 <parameter name="aIsContextMenu"/>
43 <parameter name="aAttributesOverride"/>
44 <parameter name="aTriggerEvent"/>
45 <body>
46 <![CDATA[
47 try {
48 var popupBox = this.popupBoxObject;
49 if (popupBox)
50 popupBox.openPopup(aAnchorElement, aPosition, aX, aY,
51 aIsContextMenu, aAttributesOverride, aTriggerEvent);
52 } catch(e) {}
53 ]]>
54 </body>
55 </method>
57 <method name="openPopupAtScreen">
58 <parameter name="aX"/>
59 <parameter name="aY"/>
60 <parameter name="aIsContextMenu"/>
61 <parameter name="aTriggerEvent"/>
62 <body>
63 <![CDATA[
64 try {
65 var popupBox = this.popupBoxObject;
66 if (popupBox)
67 popupBox.openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent);
68 } catch(e) {}
69 ]]>
70 </body>
71 </method>
73 <method name="showPopup">
74 <parameter name="element"/>
75 <parameter name="xpos"/>
76 <parameter name="ypos"/>
77 <parameter name="popuptype"/>
78 <parameter name="anchoralignment"/>
79 <parameter name="popupalignment"/>
80 <body>
81 <![CDATA[
82 var popupBox = null;
83 var menuBox = null;
84 try {
85 popupBox = this.popupBoxObject;
86 } catch(e) {}
87 try {
88 menuBox = this.parentNode.boxObject;
89 } catch(e) {}
90 if (menuBox instanceof Components.interfaces.nsIMenuBoxObject)
91 menuBox.openMenu(true);
92 else if (popupBox)
93 popupBox.showPopup(element, this, xpos, ypos, popuptype, anchoralignment, popupalignment);
94 ]]>
95 </body>
96 </method>
98 <method name="hidePopup">
99 <body>
100 <![CDATA[
101 var popupBox = null;
102 var menuBox = null;
103 try {
104 popupBox = this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject);
105 } catch(e) {}
106 try {
107 menuBox = this.parentNode.boxObject;
108 } catch(e) {}
109 if (menuBox instanceof Components.interfaces.nsIMenuBoxObject)
110 menuBox.openMenu(false);
111 else if (popupBox)
112 popupBox.hidePopup();
113 ]]>
114 </body>
115 </method>
117 <property name="autoPosition">
118 <getter>
119 <![CDATA[
120 return this.popupBoxObject.autoPosition;
121 ]]>
122 </getter>
123 <setter>
124 <![CDATA[
125 return this.popupBoxObject.autoPosition = val;
126 ]]>
127 </setter>
128 </property>
130 <property name="alignmentPosition" readonly="true">
131 <getter>
132 <![CDATA[
133 return this.popupBoxObject.alignmentPosition;
134 ]]>
135 </getter>
136 </property>
138 <property name="alignmentOffset" readonly="true">
139 <getter>
140 <![CDATA[
141 return this.popupBoxObject.alignmentOffset;
142 ]]>
143 </getter>
144 </property>
146 <method name="enableKeyboardNavigator">
147 <parameter name="aEnableKeyboardNavigator"/>
148 <body>
149 <![CDATA[
150 this.popupBoxObject.enableKeyboardNavigator(aEnableKeyboardNavigator);
151 ]]>
152 </body>
153 </method>
155 <method name="enableRollup">
156 <parameter name="aEnableRollup"/>
157 <body>
158 <![CDATA[
159 this.popupBoxObject.enableRollup(aEnableRollup);
160 ]]>
161 </body>
162 </method>
164 <method name="sizeTo">
165 <parameter name="aWidth"/>
166 <parameter name="aHeight"/>
167 <body>
168 <![CDATA[
169 this.popupBoxObject.sizeTo(aWidth, aHeight);
170 ]]>
171 </body>
172 </method>
174 <method name="moveTo">
175 <parameter name="aLeft"/>
176 <parameter name="aTop"/>
177 <body>
178 <![CDATA[
179 this.popupBoxObject.moveTo(aLeft, aTop);
180 ]]>
181 </body>
182 </method>
184 <method name="moveToAnchor">
185 <parameter name="aAnchorElement"/>
186 <parameter name="aPosition"/>
187 <parameter name="aX"/>
188 <parameter name="aY"/>
189 <parameter name="aAttributesOverride"/>
190 <body>
191 <![CDATA[
192 this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride);
193 ]]>
194 </body>
195 </method>
197 <method name="getOuterScreenRect">
198 <body>
199 <![CDATA[
200 return this.popupBoxObject.getOuterScreenRect();
201 ]]>
202 </body>
203 </method>
204 </implementation>
206 </binding>
208 <binding id="popup" role="xul:menupopup"
209 extends="chrome://global/content/bindings/popup.xml#popup-base">
211 <content>
212 <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
213 smoothscroll="false">
214 <children/>
215 </xul:arrowscrollbox>
216 </content>
218 <handlers>
219 <handler event="popupshowing" phase="target">
220 <![CDATA[
221 var array = [];
222 var width = 0;
223 for (var menuitem = this.firstChild; menuitem; menuitem = menuitem.nextSibling) {
224 if (menuitem.localName == "menuitem" && menuitem.hasAttribute("acceltext")) {
225 var accel = document.getAnonymousElementByAttribute(menuitem, "anonid", "accel");
226 if (accel && accel.boxObject) {
227 array.push(accel);
228 if (accel.boxObject.width > width)
229 width = accel.boxObject.width;
230 }
231 }
232 }
233 for (var i = 0; i < array.length; i++)
234 array[i].width = width;
235 ]]>
236 </handler>
237 </handlers>
238 </binding>
240 <binding id="panel" role="xul:panel"
241 extends="chrome://global/content/bindings/popup.xml#popup-base">
242 <implementation implements="nsIDOMXULPopupElement">
243 <field name="_prevFocus">0</field>
244 <field name="_dragBindingAlive">true</field>
245 <constructor>
246 <![CDATA[
247 if (this.getAttribute("backdrag") == "true" && !this._draggableStarted) {
248 this._draggableStarted = true;
249 try {
250 let tmp = {};
251 Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
252 let draghandle = new tmp.WindowDraggingElement(this);
253 draghandle.mouseDownCheck = function () this._dragBindingAlive;
254 } catch (e) {}
255 }
256 ]]>
257 </constructor>
258 </implementation>
260 <handlers>
261 <handler event="popupshowing"><![CDATA[
262 // Capture the previous focus before has a chance to get set inside the panel
263 try {
264 this._prevFocus = document.commandDispatcher.focusedElement;
265 if (!this._prevFocus) // Content window has focus
266 this._prevFocus = document.commandDispatcher.focusedWindow;
267 } catch (ex) {
268 this._prevFocus = document.activeElement;
269 }
270 ]]></handler>
271 <handler event="popupshown"><![CDATA[
272 // Fire event for accessibility APIs
273 var alertEvent = document.createEvent("Events");
274 alertEvent.initEvent("AlertActive", true, true);
275 this.dispatchEvent(alertEvent);
276 ]]></handler>
277 <handler event="popuphiding"><![CDATA[
278 try {
279 this._currentFocus = document.commandDispatcher.focusedElement;
280 } catch (e) {
281 this._currentFocus = document.activeElement;
282 }
283 ]]></handler>
284 <handler event="popuphidden"><![CDATA[
285 var currentFocus = this._currentFocus;
286 var prevFocus = this._prevFocus;
287 this._currentFocus = null;
288 this._prevFocus = null;
289 if (prevFocus && currentFocus && this.getAttribute("norestorefocus") != "true") {
290 // Try to restore focus
291 try {
292 if (document.commandDispatcher.focusedWindow != window)
293 return; // Focus has already been set to a window outside of this panel
294 } catch(ex) {}
295 while (currentFocus) {
296 if (currentFocus == this) {
297 // Focus was set on an element inside this panel,
298 // so we need to move it back to where it was previously
299 try {
300 let fm = Components.classes["@mozilla.org/focus-manager;1"]
301 .getService(Components.interfaces.nsIFocusManager);
302 fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
303 } catch(e) {
304 prevFocus.focus();
305 }
306 return;
307 }
308 currentFocus = currentFocus.parentNode;
309 }
310 }
311 ]]></handler>
312 </handlers>
313 </binding>
315 <binding id="arrowpanel" extends="chrome://global/content/bindings/popup.xml#panel">
316 <content flip="both" side="top" position="bottomcenter topleft" consumeoutsideclicks="false">
317 <xul:vbox anonid="container" class="panel-arrowcontainer" flex="1"
318 xbl:inherits="side,panelopen">
319 <xul:box anonid="arrowbox" class="panel-arrowbox">
320 <xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/>
321 </xul:box>
322 <xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1">
323 <children/>
324 <xul:box class="panel-inner-arrowcontentfooter" xbl:inherits="footertype" hidden="true"/>
325 </xul:box>
326 </xul:vbox>
327 </content>
328 <implementation>
329 <field name="_fadeTimer">null</field>
330 <method name="sizeTo">
331 <parameter name="aWidth"/>
332 <parameter name="aHeight"/>
333 <body>
334 <![CDATA[
335 this.popupBoxObject.sizeTo(aWidth, aHeight);
336 if (this.state == "open")
337 this.adjustArrowPosition();
338 ]]>
339 </body>
340 </method>
341 <method name="moveTo">
342 <parameter name="aLeft"/>
343 <parameter name="aTop"/>
344 <body>
345 <![CDATA[
346 this.popupBoxObject.moveTo(aLeft, aTop);
347 if (this.state == "open")
348 this.adjustArrowPosition();
349 ]]>
350 </body>
351 </method>
352 <method name="moveToAnchor">
353 <parameter name="aAnchorElement"/>
354 <parameter name="aPosition"/>
355 <parameter name="aX"/>
356 <parameter name="aY"/>
357 <parameter name="aAttributesOverride"/>
358 <body>
359 <![CDATA[
360 this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride);
361 if (this.state == "open")
362 this.adjustArrowPosition();
363 ]]>
364 </body>
365 </method>
366 <method name="adjustArrowPosition">
367 <body>
368 <![CDATA[
369 var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
371 var anchor = this.anchorNode;
372 if (!anchor) {
373 arrow.hidden = true;
374 return;
375 }
377 var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
378 var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
380 var position = this.alignmentPosition;
381 var offset = this.alignmentOffset;
383 // if this panel has a "sliding" arrow, we may have previously set margins...
384 arrowbox.style.removeProperty("transform");
385 if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
386 container.orient = "horizontal";
387 arrowbox.orient = "vertical";
388 if (position.indexOf("_after") > 0) {
389 arrowbox.pack = "end";
390 } else {
391 arrowbox.pack = "start";
392 }
393 arrowbox.style.transform = "translate(0, " + -offset + "px)";
395 // The assigned side stays the same regardless of direction.
396 var isRTL = (window.getComputedStyle(this).direction == "rtl");
398 if (position.indexOf("start_") == 0) {
399 container.dir = "reverse";
400 this.setAttribute("side", isRTL ? "left" : "right");
401 }
402 else {
403 container.dir = "";
404 this.setAttribute("side", isRTL ? "right" : "left");
405 }
406 }
407 else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) {
408 container.orient = "";
409 arrowbox.orient = "";
410 if (position.indexOf("_end") > 0) {
411 arrowbox.pack = "end";
412 } else {
413 arrowbox.pack = "start";
414 }
415 arrowbox.style.transform = "translate(" + -offset + "px, 0)";
417 if (position.indexOf("before_") == 0) {
418 container.dir = "reverse";
419 this.setAttribute("side", "bottom");
420 }
421 else {
422 container.dir = "";
423 this.setAttribute("side", "top");
424 }
425 }
427 arrow.hidden = false;
428 ]]>
429 </body>
430 </method>
431 </implementation>
432 <handlers>
433 <handler event="popupshowing" phase="target">
434 <![CDATA[
435 this.adjustArrowPosition();
437 // set fading
438 var fade = this.getAttribute("fade");
439 var fadeDelay = (fade == "fast") ? 1 : fade == "slow" ? 4000 : 0;
440 if (fadeDelay) {
441 this._fadeTimer = setTimeout(function (self) {
442 self.style.opacity = 0.2;
443 }, fadeDelay, this);
444 }
445 ]]>
446 </handler>
447 <handler event="popuphiding" phase="target">
448 clearTimeout(this._fadeTimer);
449 this.style.removeProperty("opacity");
450 </handler>
451 <handler event="transitionend" phase="target">
452 <![CDATA[
453 if (event.propertyName == "opacity" &&
454 event.originalTarget == this) {
455 this.hidePopup();
456 this.style.removeProperty("opacity");
457 }
458 ]]>
459 </handler>
460 <handler event="popupshown" phase="target">
461 this.setAttribute("panelopen", "true");
462 </handler>
463 <handler event="popuphidden" phase="target">
464 this.removeAttribute("panelopen");
465 </handler>
466 </handlers>
467 </binding>
469 <binding id="tooltip" role="xul:tooltip"
470 extends="chrome://global/content/bindings/popup.xml#popup-base">
471 <content>
472 <children>
473 <xul:label class="tooltip-label" xbl:inherits="xbl:text=label" flex="1"/>
474 </children>
475 </content>
477 <implementation>
478 <field name="_mouseOutCount">0</field>
479 <field name="_isMouseOver">false</field>
481 <property name="label"
482 onget="return this.getAttribute('label');"
483 onset="this.setAttribute('label', val); return val;"/>
485 <property name="page" onset="if (val) this.setAttribute('page', 'true');
486 else this.removeAttribute('page');
487 return val;"
488 onget="return this.getAttribute('page') == 'true';"/>
490 <!-- Given the supplied element within a page, set the tooltip's text to the text
491 for that element. Returns true if text was assigned, and false if the no text
492 is set, which normally would be used to cancel tooltip display.
494 Note that DefaultTooltipTextProvider::GetNodeText() from nsDocShellTreeOwner.cpp
495 also performs the same function, but for embedded clients that don't use a XUL/JS
496 layer. These two should be kept synchronized.
497 -->
498 <method name="fillInPageTooltip">
499 <parameter name="tipElement"/>
500 <body>
501 <![CDATA[
502 // Don't show the tooltip if the tooltip node is a document or disconnected.
503 if (!tipElement || !tipElement.ownerDocument ||
504 (tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED)) {
505 return false;
506 }
508 var defView = tipElement.ownerDocument.defaultView;
509 // XXX Work around bug 350679:
510 // "Tooltips can be fired in documents with no view".
511 if (!defView)
512 return false;
514 const XLinkNS = "http://www.w3.org/1999/xlink";
515 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
517 var titleText = null;
518 var XLinkTitleText = null;
519 var SVGTitleText = null;
520 var XULtooltiptextText = null;
521 var lookingForSVGTitle = true;
522 var direction = tipElement.ownerDocument.dir;
524 // If the element is invalid per HTML5 Forms specifications and has no title,
525 // show the constraint validation error message.
526 if ((tipElement instanceof HTMLInputElement ||
527 tipElement instanceof HTMLTextAreaElement ||
528 tipElement instanceof HTMLSelectElement ||
529 tipElement instanceof HTMLButtonElement) &&
530 !tipElement.hasAttribute('title') &&
531 (!tipElement.form || !tipElement.form.noValidate)) {
532 // If the element is barred from constraint validation or valid,
533 // the validation message will be the empty string.
534 titleText = tipElement.validationMessage || null;
535 }
537 // If the element is an <input type='file'> without a title, we should show
538 // the current file selection.
539 if (!titleText &&
540 tipElement instanceof HTMLInputElement &&
541 tipElement.type == 'file' &&
542 !tipElement.hasAttribute('title')) {
543 let files = tipElement.files;
545 try {
546 var bundle = Components.classes['@mozilla.org/intl/stringbundle;1']
547 .getService(Components.interfaces.nsIStringBundleService)
548 .createBundle("chrome://global/locale/layout/HtmlForm.properties");
549 if (files.length == 0) {
550 if (tipElement.multiple) {
551 titleText = bundle.GetStringFromName("NoFilesSelected");
552 } else {
553 titleText = bundle.GetStringFromName("NoFileSelected");
554 }
555 } else {
556 titleText = files[0].name;
557 // For UX and performance (jank) reasons we cap the number of
558 // files that we list in the tooltip to 20 plus a "and xxx more"
559 // line, or to 21 if exactly 21 files were picked.
560 const TRUNCATED_FILE_COUNT = 20;
561 let count = Math.min(files.length, TRUNCATED_FILE_COUNT);
562 for (let i = 1; i < count; ++i) {
563 titleText += "\n" + files[i].name;
564 }
565 if (files.length == TRUNCATED_FILE_COUNT + 1) {
566 titleText += "\n" + files[TRUNCATED_FILE_COUNT].name;
567 } else if (files.length > TRUNCATED_FILE_COUNT + 1) {
568 let xmoreStr = bundle.GetStringFromName("AndNMoreFiles");
569 let xmoreNum = files.length - TRUNCATED_FILE_COUNT;
570 let tmp = {};
571 Components.utils.import("resource://gre/modules/PluralForm.jsm", tmp);
572 let andXMoreStr = tmp.PluralForm.get(xmoreNum, xmoreStr).replace("#1", xmoreNum);
573 titleText += "\n" + andXMoreStr;
574 }
575 }
576 } catch(e) {}
577 }
579 // Check texts against null so that title="" can be used to undefine a
580 // title on a child element.
581 while (tipElement &&
582 (titleText == null) && (XLinkTitleText == null) &&
583 (SVGTitleText == null) && (XULtooltiptextText == null)) {
585 if (tipElement.nodeType == Node.ELEMENT_NODE) {
586 if (tipElement.namespaceURI == XULNS)
587 XULtooltiptextText = tipElement.getAttribute("tooltiptext");
588 else
589 titleText = tipElement.getAttribute("title");
591 if ((tipElement instanceof HTMLAnchorElement ||
592 tipElement instanceof HTMLAreaElement ||
593 tipElement instanceof HTMLLinkElement ||
594 tipElement instanceof SVGAElement) && tipElement.href) {
595 XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
596 }
597 if (lookingForSVGTitle &&
598 (!(tipElement instanceof SVGElement) ||
599 tipElement.parentNode.nodeType == Node.DOCUMENT_NODE)) {
600 lookingForSVGTitle = false;
601 }
602 if (lookingForSVGTitle) {
603 for (let childNode of tipElement.childNodes) {
604 if (childNode instanceof SVGTitleElement) {
605 SVGTitleText = childNode.textContent;
606 break;
607 }
608 }
609 }
611 direction = defView.getComputedStyle(tipElement, "")
612 .getPropertyValue("direction");
613 }
615 tipElement = tipElement.parentNode;
616 }
618 this.style.direction = direction;
620 return [titleText, XLinkTitleText, SVGTitleText, XULtooltiptextText].some(function (t) {
621 if (t && /\S/.test(t)) {
622 // Make CRLF and CR render one line break each.
623 this.label = t.replace(/\r\n?/g, '\n');
624 return true;
625 }
627 return false;
628 }, this);
630 return false;
631 ]]>
632 </body>
633 </method>
634 </implementation>
636 <handlers>
637 <handler event="mouseover"><![CDATA[
638 var rel = event.relatedTarget;
639 //dump("ENTERING " + (rel ? rel.localName : "null") + "\n");
640 if (!rel)
641 return;
643 // find out if the node we entered from is one of our anonymous children
644 while (rel) {
645 if (rel == this)
646 break;
647 rel = rel.parentNode;
648 }
650 // if the exited node is not a descendant of ours, we are entering for the first time
651 if (rel != this)
652 this._isMouseOver = true;
653 ]]></handler>
655 <handler event="mouseout"><![CDATA[
656 var rel = event.relatedTarget;
657 //dump("LEAVING " + (rel ? rel.localName : "null") + "\n");
659 // relatedTarget is null when the titletip is first shown: a mouseout event fires
660 // because the mouse is exiting the main window and entering the titletip "window".
661 // relatedTarget is also null when the mouse exits the main window completely,
662 // so count how many times relatedTarget was null after titletip is first shown
663 // and hide popup the 2nd time
664 if (!rel) {
665 ++this._mouseOutCount;
666 if (this._mouseOutCount > 1)
667 this.hidePopup();
668 return;
669 }
671 // find out if the node we are entering is one of our anonymous children
672 while (rel) {
673 if (rel == this)
674 break;
675 rel = rel.parentNode;
676 }
678 // if the entered node is not a descendant of ours, hide the tooltip
679 if (rel != this && this._isMouseOver) {
680 this.hidePopup();
681 }
682 ]]></handler>
684 <handler event="popupshowing"><![CDATA[
685 if (this.page && !this.fillInPageTooltip(this.triggerNode)) {
686 event.preventDefault();
687 }
688 ]]></handler>
690 <handler event="popuphiding"><![CDATA[
691 this._isMouseOver = false;
692 this._mouseOutCount = 0;
693 ]]></handler>
694 </handlers>
695 </binding>
697 <binding id="popup-scrollbars" extends="chrome://global/content/bindings/popup.xml#popup">
698 <content>
699 <xul:hbox class="popup-internal-box" flex="1" orient="vertical" style="overflow: auto;">
700 <children/>
701 </xul:hbox>
702 </content>
703 </binding>
705 </bindings>