1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/widgets/popup.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,705 @@ 1.4 +<?xml version="1.0"?> 1.5 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.6 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.8 + 1.9 + 1.10 +<bindings id="popupBindings" 1.11 + xmlns="http://www.mozilla.org/xbl" 1.12 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 1.13 + xmlns:xbl="http://www.mozilla.org/xbl"> 1.14 + 1.15 + <binding id="popup-base"> 1.16 + <resources> 1.17 + <stylesheet src="chrome://global/skin/popup.css"/> 1.18 + </resources> 1.19 + 1.20 + <implementation implements="nsIDOMXULPopupElement"> 1.21 + <property name="label" onget="return this.getAttribute('label');" 1.22 + onset="this.setAttribute('label', val); return val;"/> 1.23 + <property name="position" onget="return this.getAttribute('position');" 1.24 + onset="this.setAttribute('position', val); return val;"/> 1.25 + <property name="popupBoxObject"> 1.26 + <getter> 1.27 + return this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject); 1.28 + </getter> 1.29 + </property> 1.30 + 1.31 + <property name="state" readonly="true" 1.32 + onget="return this.popupBoxObject.popupState"/> 1.33 + 1.34 + <property name="triggerNode" readonly="true" 1.35 + onget="return this.popupBoxObject.triggerNode"/> 1.36 + 1.37 + <property name="anchorNode" readonly="true" 1.38 + onget="return this.popupBoxObject.anchorNode"/> 1.39 + 1.40 + <method name="openPopup"> 1.41 + <parameter name="aAnchorElement"/> 1.42 + <parameter name="aPosition"/> 1.43 + <parameter name="aX"/> 1.44 + <parameter name="aY"/> 1.45 + <parameter name="aIsContextMenu"/> 1.46 + <parameter name="aAttributesOverride"/> 1.47 + <parameter name="aTriggerEvent"/> 1.48 + <body> 1.49 + <![CDATA[ 1.50 + try { 1.51 + var popupBox = this.popupBoxObject; 1.52 + if (popupBox) 1.53 + popupBox.openPopup(aAnchorElement, aPosition, aX, aY, 1.54 + aIsContextMenu, aAttributesOverride, aTriggerEvent); 1.55 + } catch(e) {} 1.56 + ]]> 1.57 + </body> 1.58 + </method> 1.59 + 1.60 + <method name="openPopupAtScreen"> 1.61 + <parameter name="aX"/> 1.62 + <parameter name="aY"/> 1.63 + <parameter name="aIsContextMenu"/> 1.64 + <parameter name="aTriggerEvent"/> 1.65 + <body> 1.66 + <![CDATA[ 1.67 + try { 1.68 + var popupBox = this.popupBoxObject; 1.69 + if (popupBox) 1.70 + popupBox.openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent); 1.71 + } catch(e) {} 1.72 + ]]> 1.73 + </body> 1.74 + </method> 1.75 + 1.76 + <method name="showPopup"> 1.77 + <parameter name="element"/> 1.78 + <parameter name="xpos"/> 1.79 + <parameter name="ypos"/> 1.80 + <parameter name="popuptype"/> 1.81 + <parameter name="anchoralignment"/> 1.82 + <parameter name="popupalignment"/> 1.83 + <body> 1.84 + <![CDATA[ 1.85 + var popupBox = null; 1.86 + var menuBox = null; 1.87 + try { 1.88 + popupBox = this.popupBoxObject; 1.89 + } catch(e) {} 1.90 + try { 1.91 + menuBox = this.parentNode.boxObject; 1.92 + } catch(e) {} 1.93 + if (menuBox instanceof Components.interfaces.nsIMenuBoxObject) 1.94 + menuBox.openMenu(true); 1.95 + else if (popupBox) 1.96 + popupBox.showPopup(element, this, xpos, ypos, popuptype, anchoralignment, popupalignment); 1.97 + ]]> 1.98 + </body> 1.99 + </method> 1.100 + 1.101 + <method name="hidePopup"> 1.102 + <body> 1.103 + <![CDATA[ 1.104 + var popupBox = null; 1.105 + var menuBox = null; 1.106 + try { 1.107 + popupBox = this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject); 1.108 + } catch(e) {} 1.109 + try { 1.110 + menuBox = this.parentNode.boxObject; 1.111 + } catch(e) {} 1.112 + if (menuBox instanceof Components.interfaces.nsIMenuBoxObject) 1.113 + menuBox.openMenu(false); 1.114 + else if (popupBox) 1.115 + popupBox.hidePopup(); 1.116 + ]]> 1.117 + </body> 1.118 + </method> 1.119 + 1.120 + <property name="autoPosition"> 1.121 + <getter> 1.122 + <![CDATA[ 1.123 + return this.popupBoxObject.autoPosition; 1.124 + ]]> 1.125 + </getter> 1.126 + <setter> 1.127 + <![CDATA[ 1.128 + return this.popupBoxObject.autoPosition = val; 1.129 + ]]> 1.130 + </setter> 1.131 + </property> 1.132 + 1.133 + <property name="alignmentPosition" readonly="true"> 1.134 + <getter> 1.135 + <![CDATA[ 1.136 + return this.popupBoxObject.alignmentPosition; 1.137 + ]]> 1.138 + </getter> 1.139 + </property> 1.140 + 1.141 + <property name="alignmentOffset" readonly="true"> 1.142 + <getter> 1.143 + <![CDATA[ 1.144 + return this.popupBoxObject.alignmentOffset; 1.145 + ]]> 1.146 + </getter> 1.147 + </property> 1.148 + 1.149 + <method name="enableKeyboardNavigator"> 1.150 + <parameter name="aEnableKeyboardNavigator"/> 1.151 + <body> 1.152 + <![CDATA[ 1.153 + this.popupBoxObject.enableKeyboardNavigator(aEnableKeyboardNavigator); 1.154 + ]]> 1.155 + </body> 1.156 + </method> 1.157 + 1.158 + <method name="enableRollup"> 1.159 + <parameter name="aEnableRollup"/> 1.160 + <body> 1.161 + <![CDATA[ 1.162 + this.popupBoxObject.enableRollup(aEnableRollup); 1.163 + ]]> 1.164 + </body> 1.165 + </method> 1.166 + 1.167 + <method name="sizeTo"> 1.168 + <parameter name="aWidth"/> 1.169 + <parameter name="aHeight"/> 1.170 + <body> 1.171 + <![CDATA[ 1.172 + this.popupBoxObject.sizeTo(aWidth, aHeight); 1.173 + ]]> 1.174 + </body> 1.175 + </method> 1.176 + 1.177 + <method name="moveTo"> 1.178 + <parameter name="aLeft"/> 1.179 + <parameter name="aTop"/> 1.180 + <body> 1.181 + <![CDATA[ 1.182 + this.popupBoxObject.moveTo(aLeft, aTop); 1.183 + ]]> 1.184 + </body> 1.185 + </method> 1.186 + 1.187 + <method name="moveToAnchor"> 1.188 + <parameter name="aAnchorElement"/> 1.189 + <parameter name="aPosition"/> 1.190 + <parameter name="aX"/> 1.191 + <parameter name="aY"/> 1.192 + <parameter name="aAttributesOverride"/> 1.193 + <body> 1.194 + <![CDATA[ 1.195 + this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride); 1.196 + ]]> 1.197 + </body> 1.198 + </method> 1.199 + 1.200 + <method name="getOuterScreenRect"> 1.201 + <body> 1.202 + <![CDATA[ 1.203 + return this.popupBoxObject.getOuterScreenRect(); 1.204 + ]]> 1.205 + </body> 1.206 + </method> 1.207 + </implementation> 1.208 + 1.209 + </binding> 1.210 + 1.211 + <binding id="popup" role="xul:menupopup" 1.212 + extends="chrome://global/content/bindings/popup.xml#popup-base"> 1.213 + 1.214 + <content> 1.215 + <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical" 1.216 + smoothscroll="false"> 1.217 + <children/> 1.218 + </xul:arrowscrollbox> 1.219 + </content> 1.220 + 1.221 + <handlers> 1.222 + <handler event="popupshowing" phase="target"> 1.223 + <![CDATA[ 1.224 + var array = []; 1.225 + var width = 0; 1.226 + for (var menuitem = this.firstChild; menuitem; menuitem = menuitem.nextSibling) { 1.227 + if (menuitem.localName == "menuitem" && menuitem.hasAttribute("acceltext")) { 1.228 + var accel = document.getAnonymousElementByAttribute(menuitem, "anonid", "accel"); 1.229 + if (accel && accel.boxObject) { 1.230 + array.push(accel); 1.231 + if (accel.boxObject.width > width) 1.232 + width = accel.boxObject.width; 1.233 + } 1.234 + } 1.235 + } 1.236 + for (var i = 0; i < array.length; i++) 1.237 + array[i].width = width; 1.238 + ]]> 1.239 + </handler> 1.240 + </handlers> 1.241 + </binding> 1.242 + 1.243 + <binding id="panel" role="xul:panel" 1.244 + extends="chrome://global/content/bindings/popup.xml#popup-base"> 1.245 + <implementation implements="nsIDOMXULPopupElement"> 1.246 + <field name="_prevFocus">0</field> 1.247 + <field name="_dragBindingAlive">true</field> 1.248 + <constructor> 1.249 + <![CDATA[ 1.250 + if (this.getAttribute("backdrag") == "true" && !this._draggableStarted) { 1.251 + this._draggableStarted = true; 1.252 + try { 1.253 + let tmp = {}; 1.254 + Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp); 1.255 + let draghandle = new tmp.WindowDraggingElement(this); 1.256 + draghandle.mouseDownCheck = function () this._dragBindingAlive; 1.257 + } catch (e) {} 1.258 + } 1.259 + ]]> 1.260 + </constructor> 1.261 + </implementation> 1.262 + 1.263 + <handlers> 1.264 + <handler event="popupshowing"><![CDATA[ 1.265 + // Capture the previous focus before has a chance to get set inside the panel 1.266 + try { 1.267 + this._prevFocus = document.commandDispatcher.focusedElement; 1.268 + if (!this._prevFocus) // Content window has focus 1.269 + this._prevFocus = document.commandDispatcher.focusedWindow; 1.270 + } catch (ex) { 1.271 + this._prevFocus = document.activeElement; 1.272 + } 1.273 + ]]></handler> 1.274 + <handler event="popupshown"><![CDATA[ 1.275 + // Fire event for accessibility APIs 1.276 + var alertEvent = document.createEvent("Events"); 1.277 + alertEvent.initEvent("AlertActive", true, true); 1.278 + this.dispatchEvent(alertEvent); 1.279 + ]]></handler> 1.280 + <handler event="popuphiding"><![CDATA[ 1.281 + try { 1.282 + this._currentFocus = document.commandDispatcher.focusedElement; 1.283 + } catch (e) { 1.284 + this._currentFocus = document.activeElement; 1.285 + } 1.286 + ]]></handler> 1.287 + <handler event="popuphidden"><![CDATA[ 1.288 + var currentFocus = this._currentFocus; 1.289 + var prevFocus = this._prevFocus; 1.290 + this._currentFocus = null; 1.291 + this._prevFocus = null; 1.292 + if (prevFocus && currentFocus && this.getAttribute("norestorefocus") != "true") { 1.293 + // Try to restore focus 1.294 + try { 1.295 + if (document.commandDispatcher.focusedWindow != window) 1.296 + return; // Focus has already been set to a window outside of this panel 1.297 + } catch(ex) {} 1.298 + while (currentFocus) { 1.299 + if (currentFocus == this) { 1.300 + // Focus was set on an element inside this panel, 1.301 + // so we need to move it back to where it was previously 1.302 + try { 1.303 + let fm = Components.classes["@mozilla.org/focus-manager;1"] 1.304 + .getService(Components.interfaces.nsIFocusManager); 1.305 + fm.setFocus(prevFocus, fm.FLAG_NOSCROLL); 1.306 + } catch(e) { 1.307 + prevFocus.focus(); 1.308 + } 1.309 + return; 1.310 + } 1.311 + currentFocus = currentFocus.parentNode; 1.312 + } 1.313 + } 1.314 + ]]></handler> 1.315 + </handlers> 1.316 + </binding> 1.317 + 1.318 + <binding id="arrowpanel" extends="chrome://global/content/bindings/popup.xml#panel"> 1.319 + <content flip="both" side="top" position="bottomcenter topleft" consumeoutsideclicks="false"> 1.320 + <xul:vbox anonid="container" class="panel-arrowcontainer" flex="1" 1.321 + xbl:inherits="side,panelopen"> 1.322 + <xul:box anonid="arrowbox" class="panel-arrowbox"> 1.323 + <xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/> 1.324 + </xul:box> 1.325 + <xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1"> 1.326 + <children/> 1.327 + <xul:box class="panel-inner-arrowcontentfooter" xbl:inherits="footertype" hidden="true"/> 1.328 + </xul:box> 1.329 + </xul:vbox> 1.330 + </content> 1.331 + <implementation> 1.332 + <field name="_fadeTimer">null</field> 1.333 + <method name="sizeTo"> 1.334 + <parameter name="aWidth"/> 1.335 + <parameter name="aHeight"/> 1.336 + <body> 1.337 + <![CDATA[ 1.338 + this.popupBoxObject.sizeTo(aWidth, aHeight); 1.339 + if (this.state == "open") 1.340 + this.adjustArrowPosition(); 1.341 + ]]> 1.342 + </body> 1.343 + </method> 1.344 + <method name="moveTo"> 1.345 + <parameter name="aLeft"/> 1.346 + <parameter name="aTop"/> 1.347 + <body> 1.348 + <![CDATA[ 1.349 + this.popupBoxObject.moveTo(aLeft, aTop); 1.350 + if (this.state == "open") 1.351 + this.adjustArrowPosition(); 1.352 + ]]> 1.353 + </body> 1.354 + </method> 1.355 + <method name="moveToAnchor"> 1.356 + <parameter name="aAnchorElement"/> 1.357 + <parameter name="aPosition"/> 1.358 + <parameter name="aX"/> 1.359 + <parameter name="aY"/> 1.360 + <parameter name="aAttributesOverride"/> 1.361 + <body> 1.362 + <![CDATA[ 1.363 + this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride); 1.364 + if (this.state == "open") 1.365 + this.adjustArrowPosition(); 1.366 + ]]> 1.367 + </body> 1.368 + </method> 1.369 + <method name="adjustArrowPosition"> 1.370 + <body> 1.371 + <![CDATA[ 1.372 + var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow"); 1.373 + 1.374 + var anchor = this.anchorNode; 1.375 + if (!anchor) { 1.376 + arrow.hidden = true; 1.377 + return; 1.378 + } 1.379 + 1.380 + var container = document.getAnonymousElementByAttribute(this, "anonid", "container"); 1.381 + var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox"); 1.382 + 1.383 + var position = this.alignmentPosition; 1.384 + var offset = this.alignmentOffset; 1.385 + 1.386 + // if this panel has a "sliding" arrow, we may have previously set margins... 1.387 + arrowbox.style.removeProperty("transform"); 1.388 + if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) { 1.389 + container.orient = "horizontal"; 1.390 + arrowbox.orient = "vertical"; 1.391 + if (position.indexOf("_after") > 0) { 1.392 + arrowbox.pack = "end"; 1.393 + } else { 1.394 + arrowbox.pack = "start"; 1.395 + } 1.396 + arrowbox.style.transform = "translate(0, " + -offset + "px)"; 1.397 + 1.398 + // The assigned side stays the same regardless of direction. 1.399 + var isRTL = (window.getComputedStyle(this).direction == "rtl"); 1.400 + 1.401 + if (position.indexOf("start_") == 0) { 1.402 + container.dir = "reverse"; 1.403 + this.setAttribute("side", isRTL ? "left" : "right"); 1.404 + } 1.405 + else { 1.406 + container.dir = ""; 1.407 + this.setAttribute("side", isRTL ? "right" : "left"); 1.408 + } 1.409 + } 1.410 + else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) { 1.411 + container.orient = ""; 1.412 + arrowbox.orient = ""; 1.413 + if (position.indexOf("_end") > 0) { 1.414 + arrowbox.pack = "end"; 1.415 + } else { 1.416 + arrowbox.pack = "start"; 1.417 + } 1.418 + arrowbox.style.transform = "translate(" + -offset + "px, 0)"; 1.419 + 1.420 + if (position.indexOf("before_") == 0) { 1.421 + container.dir = "reverse"; 1.422 + this.setAttribute("side", "bottom"); 1.423 + } 1.424 + else { 1.425 + container.dir = ""; 1.426 + this.setAttribute("side", "top"); 1.427 + } 1.428 + } 1.429 + 1.430 + arrow.hidden = false; 1.431 + ]]> 1.432 + </body> 1.433 + </method> 1.434 + </implementation> 1.435 + <handlers> 1.436 + <handler event="popupshowing" phase="target"> 1.437 + <![CDATA[ 1.438 + this.adjustArrowPosition(); 1.439 + 1.440 + // set fading 1.441 + var fade = this.getAttribute("fade"); 1.442 + var fadeDelay = (fade == "fast") ? 1 : fade == "slow" ? 4000 : 0; 1.443 + if (fadeDelay) { 1.444 + this._fadeTimer = setTimeout(function (self) { 1.445 + self.style.opacity = 0.2; 1.446 + }, fadeDelay, this); 1.447 + } 1.448 + ]]> 1.449 + </handler> 1.450 + <handler event="popuphiding" phase="target"> 1.451 + clearTimeout(this._fadeTimer); 1.452 + this.style.removeProperty("opacity"); 1.453 + </handler> 1.454 + <handler event="transitionend" phase="target"> 1.455 + <![CDATA[ 1.456 + if (event.propertyName == "opacity" && 1.457 + event.originalTarget == this) { 1.458 + this.hidePopup(); 1.459 + this.style.removeProperty("opacity"); 1.460 + } 1.461 + ]]> 1.462 + </handler> 1.463 + <handler event="popupshown" phase="target"> 1.464 + this.setAttribute("panelopen", "true"); 1.465 + </handler> 1.466 + <handler event="popuphidden" phase="target"> 1.467 + this.removeAttribute("panelopen"); 1.468 + </handler> 1.469 + </handlers> 1.470 + </binding> 1.471 + 1.472 + <binding id="tooltip" role="xul:tooltip" 1.473 + extends="chrome://global/content/bindings/popup.xml#popup-base"> 1.474 + <content> 1.475 + <children> 1.476 + <xul:label class="tooltip-label" xbl:inherits="xbl:text=label" flex="1"/> 1.477 + </children> 1.478 + </content> 1.479 + 1.480 + <implementation> 1.481 + <field name="_mouseOutCount">0</field> 1.482 + <field name="_isMouseOver">false</field> 1.483 + 1.484 + <property name="label" 1.485 + onget="return this.getAttribute('label');" 1.486 + onset="this.setAttribute('label', val); return val;"/> 1.487 + 1.488 + <property name="page" onset="if (val) this.setAttribute('page', 'true'); 1.489 + else this.removeAttribute('page'); 1.490 + return val;" 1.491 + onget="return this.getAttribute('page') == 'true';"/> 1.492 + 1.493 + <!-- Given the supplied element within a page, set the tooltip's text to the text 1.494 + for that element. Returns true if text was assigned, and false if the no text 1.495 + is set, which normally would be used to cancel tooltip display. 1.496 + 1.497 + Note that DefaultTooltipTextProvider::GetNodeText() from nsDocShellTreeOwner.cpp 1.498 + also performs the same function, but for embedded clients that don't use a XUL/JS 1.499 + layer. These two should be kept synchronized. 1.500 + --> 1.501 + <method name="fillInPageTooltip"> 1.502 + <parameter name="tipElement"/> 1.503 + <body> 1.504 + <![CDATA[ 1.505 + // Don't show the tooltip if the tooltip node is a document or disconnected. 1.506 + if (!tipElement || !tipElement.ownerDocument || 1.507 + (tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED)) { 1.508 + return false; 1.509 + } 1.510 + 1.511 + var defView = tipElement.ownerDocument.defaultView; 1.512 + // XXX Work around bug 350679: 1.513 + // "Tooltips can be fired in documents with no view". 1.514 + if (!defView) 1.515 + return false; 1.516 + 1.517 + const XLinkNS = "http://www.w3.org/1999/xlink"; 1.518 + const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.519 + 1.520 + var titleText = null; 1.521 + var XLinkTitleText = null; 1.522 + var SVGTitleText = null; 1.523 + var XULtooltiptextText = null; 1.524 + var lookingForSVGTitle = true; 1.525 + var direction = tipElement.ownerDocument.dir; 1.526 + 1.527 + // If the element is invalid per HTML5 Forms specifications and has no title, 1.528 + // show the constraint validation error message. 1.529 + if ((tipElement instanceof HTMLInputElement || 1.530 + tipElement instanceof HTMLTextAreaElement || 1.531 + tipElement instanceof HTMLSelectElement || 1.532 + tipElement instanceof HTMLButtonElement) && 1.533 + !tipElement.hasAttribute('title') && 1.534 + (!tipElement.form || !tipElement.form.noValidate)) { 1.535 + // If the element is barred from constraint validation or valid, 1.536 + // the validation message will be the empty string. 1.537 + titleText = tipElement.validationMessage || null; 1.538 + } 1.539 + 1.540 + // If the element is an <input type='file'> without a title, we should show 1.541 + // the current file selection. 1.542 + if (!titleText && 1.543 + tipElement instanceof HTMLInputElement && 1.544 + tipElement.type == 'file' && 1.545 + !tipElement.hasAttribute('title')) { 1.546 + let files = tipElement.files; 1.547 + 1.548 + try { 1.549 + var bundle = Components.classes['@mozilla.org/intl/stringbundle;1'] 1.550 + .getService(Components.interfaces.nsIStringBundleService) 1.551 + .createBundle("chrome://global/locale/layout/HtmlForm.properties"); 1.552 + if (files.length == 0) { 1.553 + if (tipElement.multiple) { 1.554 + titleText = bundle.GetStringFromName("NoFilesSelected"); 1.555 + } else { 1.556 + titleText = bundle.GetStringFromName("NoFileSelected"); 1.557 + } 1.558 + } else { 1.559 + titleText = files[0].name; 1.560 + // For UX and performance (jank) reasons we cap the number of 1.561 + // files that we list in the tooltip to 20 plus a "and xxx more" 1.562 + // line, or to 21 if exactly 21 files were picked. 1.563 + const TRUNCATED_FILE_COUNT = 20; 1.564 + let count = Math.min(files.length, TRUNCATED_FILE_COUNT); 1.565 + for (let i = 1; i < count; ++i) { 1.566 + titleText += "\n" + files[i].name; 1.567 + } 1.568 + if (files.length == TRUNCATED_FILE_COUNT + 1) { 1.569 + titleText += "\n" + files[TRUNCATED_FILE_COUNT].name; 1.570 + } else if (files.length > TRUNCATED_FILE_COUNT + 1) { 1.571 + let xmoreStr = bundle.GetStringFromName("AndNMoreFiles"); 1.572 + let xmoreNum = files.length - TRUNCATED_FILE_COUNT; 1.573 + let tmp = {}; 1.574 + Components.utils.import("resource://gre/modules/PluralForm.jsm", tmp); 1.575 + let andXMoreStr = tmp.PluralForm.get(xmoreNum, xmoreStr).replace("#1", xmoreNum); 1.576 + titleText += "\n" + andXMoreStr; 1.577 + } 1.578 + } 1.579 + } catch(e) {} 1.580 + } 1.581 + 1.582 + // Check texts against null so that title="" can be used to undefine a 1.583 + // title on a child element. 1.584 + while (tipElement && 1.585 + (titleText == null) && (XLinkTitleText == null) && 1.586 + (SVGTitleText == null) && (XULtooltiptextText == null)) { 1.587 + 1.588 + if (tipElement.nodeType == Node.ELEMENT_NODE) { 1.589 + if (tipElement.namespaceURI == XULNS) 1.590 + XULtooltiptextText = tipElement.getAttribute("tooltiptext"); 1.591 + else 1.592 + titleText = tipElement.getAttribute("title"); 1.593 + 1.594 + if ((tipElement instanceof HTMLAnchorElement || 1.595 + tipElement instanceof HTMLAreaElement || 1.596 + tipElement instanceof HTMLLinkElement || 1.597 + tipElement instanceof SVGAElement) && tipElement.href) { 1.598 + XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title"); 1.599 + } 1.600 + if (lookingForSVGTitle && 1.601 + (!(tipElement instanceof SVGElement) || 1.602 + tipElement.parentNode.nodeType == Node.DOCUMENT_NODE)) { 1.603 + lookingForSVGTitle = false; 1.604 + } 1.605 + if (lookingForSVGTitle) { 1.606 + for (let childNode of tipElement.childNodes) { 1.607 + if (childNode instanceof SVGTitleElement) { 1.608 + SVGTitleText = childNode.textContent; 1.609 + break; 1.610 + } 1.611 + } 1.612 + } 1.613 + 1.614 + direction = defView.getComputedStyle(tipElement, "") 1.615 + .getPropertyValue("direction"); 1.616 + } 1.617 + 1.618 + tipElement = tipElement.parentNode; 1.619 + } 1.620 + 1.621 + this.style.direction = direction; 1.622 + 1.623 + return [titleText, XLinkTitleText, SVGTitleText, XULtooltiptextText].some(function (t) { 1.624 + if (t && /\S/.test(t)) { 1.625 + // Make CRLF and CR render one line break each. 1.626 + this.label = t.replace(/\r\n?/g, '\n'); 1.627 + return true; 1.628 + } 1.629 + 1.630 + return false; 1.631 + }, this); 1.632 + 1.633 + return false; 1.634 + ]]> 1.635 + </body> 1.636 + </method> 1.637 + </implementation> 1.638 + 1.639 + <handlers> 1.640 + <handler event="mouseover"><![CDATA[ 1.641 + var rel = event.relatedTarget; 1.642 + //dump("ENTERING " + (rel ? rel.localName : "null") + "\n"); 1.643 + if (!rel) 1.644 + return; 1.645 + 1.646 + // find out if the node we entered from is one of our anonymous children 1.647 + while (rel) { 1.648 + if (rel == this) 1.649 + break; 1.650 + rel = rel.parentNode; 1.651 + } 1.652 + 1.653 + // if the exited node is not a descendant of ours, we are entering for the first time 1.654 + if (rel != this) 1.655 + this._isMouseOver = true; 1.656 + ]]></handler> 1.657 + 1.658 + <handler event="mouseout"><![CDATA[ 1.659 + var rel = event.relatedTarget; 1.660 + //dump("LEAVING " + (rel ? rel.localName : "null") + "\n"); 1.661 + 1.662 + // relatedTarget is null when the titletip is first shown: a mouseout event fires 1.663 + // because the mouse is exiting the main window and entering the titletip "window". 1.664 + // relatedTarget is also null when the mouse exits the main window completely, 1.665 + // so count how many times relatedTarget was null after titletip is first shown 1.666 + // and hide popup the 2nd time 1.667 + if (!rel) { 1.668 + ++this._mouseOutCount; 1.669 + if (this._mouseOutCount > 1) 1.670 + this.hidePopup(); 1.671 + return; 1.672 + } 1.673 + 1.674 + // find out if the node we are entering is one of our anonymous children 1.675 + while (rel) { 1.676 + if (rel == this) 1.677 + break; 1.678 + rel = rel.parentNode; 1.679 + } 1.680 + 1.681 + // if the entered node is not a descendant of ours, hide the tooltip 1.682 + if (rel != this && this._isMouseOver) { 1.683 + this.hidePopup(); 1.684 + } 1.685 + ]]></handler> 1.686 + 1.687 + <handler event="popupshowing"><![CDATA[ 1.688 + if (this.page && !this.fillInPageTooltip(this.triggerNode)) { 1.689 + event.preventDefault(); 1.690 + } 1.691 + ]]></handler> 1.692 + 1.693 + <handler event="popuphiding"><![CDATA[ 1.694 + this._isMouseOver = false; 1.695 + this._mouseOutCount = 0; 1.696 + ]]></handler> 1.697 + </handlers> 1.698 + </binding> 1.699 + 1.700 + <binding id="popup-scrollbars" extends="chrome://global/content/bindings/popup.xml#popup"> 1.701 + <content> 1.702 + <xul:hbox class="popup-internal-box" flex="1" orient="vertical" style="overflow: auto;"> 1.703 + <children/> 1.704 + </xul:hbox> 1.705 + </content> 1.706 + </binding> 1.707 + 1.708 +</bindings>