/toolkit/content/widgets/popup.xml

http://github.com/zpao/v8monkey · XML · 552 lines · 496 code · 53 blank · 3 comment · 0 complexity · b74c3a2054b6d8987bda064125610dce MD5 · raw file

  1. <?xml version="1.0"?>
  2. <bindings id="popupBindings"
  3. xmlns="http://www.mozilla.org/xbl"
  4. xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  5. xmlns:xbl="http://www.mozilla.org/xbl">
  6. <binding id="popup-base">
  7. <resources>
  8. <stylesheet src="chrome://global/skin/popup.css"/>
  9. </resources>
  10. <implementation implements="nsIDOMXULPopupElement">
  11. <property name="label" onget="return this.getAttribute('label');"
  12. onset="this.setAttribute('label', val); return val;"/>
  13. <property name="position" onget="return this.getAttribute('position');"
  14. onset="this.setAttribute('position', val); return val;"/>
  15. <property name="popupBoxObject">
  16. <getter>
  17. return this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject);
  18. </getter>
  19. </property>
  20. <property name="state" readonly="true"
  21. onget="return this.popupBoxObject.popupState"/>
  22. <property name="triggerNode" readonly="true"
  23. onget="return this.popupBoxObject.triggerNode"/>
  24. <property name="anchorNode" readonly="true"
  25. onget="return this.popupBoxObject.anchorNode"/>
  26. <method name="openPopup">
  27. <parameter name="aAnchorElement"/>
  28. <parameter name="aPosition"/>
  29. <parameter name="aX"/>
  30. <parameter name="aY"/>
  31. <parameter name="aIsContextMenu"/>
  32. <parameter name="aAttributesOverride"/>
  33. <parameter name="aTriggerEvent"/>
  34. <body>
  35. <![CDATA[
  36. try {
  37. var popupBox = this.popupBoxObject;
  38. if (popupBox)
  39. popupBox.openPopup(aAnchorElement, aPosition, aX, aY,
  40. aIsContextMenu, aAttributesOverride, aTriggerEvent);
  41. } catch(e) {}
  42. ]]>
  43. </body>
  44. </method>
  45. <method name="openPopupAtScreen">
  46. <parameter name="aX"/>
  47. <parameter name="aY"/>
  48. <parameter name="aIsContextMenu"/>
  49. <parameter name="aTriggerEvent"/>
  50. <body>
  51. <![CDATA[
  52. try {
  53. var popupBox = this.popupBoxObject;
  54. if (popupBox)
  55. popupBox.openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent);
  56. } catch(e) {}
  57. ]]>
  58. </body>
  59. </method>
  60. <method name="showPopup">
  61. <parameter name="element"/>
  62. <parameter name="xpos"/>
  63. <parameter name="ypos"/>
  64. <parameter name="popuptype"/>
  65. <parameter name="anchoralignment"/>
  66. <parameter name="popupalignment"/>
  67. <body>
  68. <![CDATA[
  69. var popupBox = null;
  70. var menuBox = null;
  71. try {
  72. popupBox = this.popupBoxObject;
  73. } catch(e) {}
  74. try {
  75. menuBox = this.parentNode.boxObject;
  76. } catch(e) {}
  77. if (menuBox instanceof Components.interfaces.nsIMenuBoxObject)
  78. menuBox.openMenu(true);
  79. else if (popupBox)
  80. popupBox.showPopup(element, this, xpos, ypos, popuptype, anchoralignment, popupalignment);
  81. ]]>
  82. </body>
  83. </method>
  84. <method name="hidePopup">
  85. <body>
  86. <![CDATA[
  87. var popupBox = null;
  88. var menuBox = null;
  89. try {
  90. popupBox = this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject);
  91. } catch(e) {}
  92. try {
  93. menuBox = this.parentNode.boxObject;
  94. } catch(e) {}
  95. if (menuBox instanceof Components.interfaces.nsIMenuBoxObject)
  96. menuBox.openMenu(false);
  97. else if (popupBox)
  98. popupBox.hidePopup();
  99. ]]>
  100. </body>
  101. </method>
  102. <property name="autoPosition">
  103. <getter>
  104. <![CDATA[
  105. return this.popupBoxObject.autoPosition;
  106. ]]>
  107. </getter>
  108. <setter>
  109. <![CDATA[
  110. return this.popupBoxObject.autoPosition = val;
  111. ]]>
  112. </setter>
  113. </property>
  114. <method name="enableKeyboardNavigator">
  115. <parameter name="aEnableKeyboardNavigator"/>
  116. <body>
  117. <![CDATA[
  118. this.popupBoxObject.enableKeyboardNavigator(aEnableKeyboardNavigator);
  119. ]]>
  120. </body>
  121. </method>
  122. <method name="enableRollup">
  123. <parameter name="aEnableRollup"/>
  124. <body>
  125. <![CDATA[
  126. this.popupBoxObject.enableRollup(aEnableRollup);
  127. ]]>
  128. </body>
  129. </method>
  130. <method name="sizeTo">
  131. <parameter name="aWidth"/>
  132. <parameter name="aHeight"/>
  133. <body>
  134. <![CDATA[
  135. this.popupBoxObject.sizeTo(aWidth, aHeight);
  136. ]]>
  137. </body>
  138. </method>
  139. <method name="moveTo">
  140. <parameter name="aLeft"/>
  141. <parameter name="aTop"/>
  142. <body>
  143. <![CDATA[
  144. this.popupBoxObject.moveTo(aLeft, aTop);
  145. ]]>
  146. </body>
  147. </method>
  148. <method name="getOuterScreenRect">
  149. <body>
  150. <![CDATA[
  151. return this.popupBoxObject.getOuterScreenRect();
  152. ]]>
  153. </body>
  154. </method>
  155. </implementation>
  156. </binding>
  157. <binding id="popup"
  158. extends="chrome://global/content/bindings/popup.xml#popup-base">
  159. <content>
  160. <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
  161. smoothscroll="false">
  162. <children/>
  163. </xul:arrowscrollbox>
  164. </content>
  165. <implementation implements="nsIAccessibleProvider">
  166. <property name="accessibleType" readonly="true">
  167. <getter>
  168. <![CDATA[
  169. return Components.interfaces.nsIAccessibleProvider.XULMenupopup;
  170. ]]>
  171. </getter>
  172. </property>
  173. </implementation>
  174. <handlers>
  175. <handler event="popupshowing" phase="target">
  176. <![CDATA[
  177. var array = [];
  178. var width = 0;
  179. for (var menuitem = this.firstChild; menuitem; menuitem = menuitem.nextSibling) {
  180. if (menuitem.localName == "menuitem" && menuitem.hasAttribute("acceltext")) {
  181. var accel = document.getAnonymousElementByAttribute(menuitem, "anonid", "accel");
  182. if (accel && accel.boxObject) {
  183. array.push(accel);
  184. if (accel.boxObject.width > width)
  185. width = accel.boxObject.width;
  186. }
  187. }
  188. }
  189. for (var i = 0; i < array.length; i++)
  190. array[i].width = width;
  191. ]]>
  192. </handler>
  193. </handlers>
  194. </binding>
  195. <binding id="panel"
  196. extends="chrome://global/content/bindings/popup.xml#popup-base">
  197. <!-- This separate binding for dialog-like panels - not menu, list or autocomplete popups
  198. exposes the popup as an alert or a pane, depending on whether it is always intended
  199. to get keyboard navigation when it opens -->
  200. <implementation implements="nsIDOMXULPopupElement, nsIAccessibleProvider">
  201. <property name="accessibleType" readonly="true">
  202. <getter>
  203. <![CDATA[
  204. return (this.getAttribute("noautofocus") == "true") ?
  205. Components.interfaces.nsIAccessibleProvider.XULAlert :
  206. Components.interfaces.nsIAccessibleProvider.XULPane;
  207. ]]></getter>
  208. </property>
  209. <field name="_prevFocus">0</field>
  210. <field name="_dragBindingAlive">true</field>
  211. <constructor>
  212. <![CDATA[
  213. if (this.getAttribute("backdrag") == "true" && !this._draggableStarted) {
  214. this._draggableStarted = true;
  215. try {
  216. let tmp = {};
  217. Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
  218. let draghandle = new tmp.WindowDraggingElement(this);
  219. draghandle.mouseDownCheck = function () this._dragBindingAlive;
  220. } catch (e) {}
  221. }
  222. ]]>
  223. </constructor>
  224. </implementation>
  225. <handlers>
  226. <handler event="popupshowing"><![CDATA[
  227. // Capture the previous focus before has a chance to get set inside the panel
  228. try {
  229. this._prevFocus = document.commandDispatcher.focusedElement;
  230. if (!this._prevFocus) // Content window has focus
  231. this._prevFocus = document.commandDispatcher.focusedWindow;
  232. } catch (ex) {
  233. this._prevFocus = document.activeElement;
  234. }
  235. ]]></handler>
  236. <handler event="popupshown"><![CDATA[
  237. // Fire event for accessibility APIs
  238. var alertEvent = document.createEvent("Events");
  239. alertEvent.initEvent("AlertActive", true, true);
  240. this.dispatchEvent(alertEvent);
  241. ]]></handler>
  242. <handler event="popuphiding"><![CDATA[
  243. try {
  244. this._currentFocus = document.commandDispatcher.focusedElement;
  245. } catch (e) {
  246. this._currentFocus = document.activeElement;
  247. }
  248. ]]></handler>
  249. <handler event="popuphidden"><![CDATA[
  250. var currentFocus = this._currentFocus;
  251. var prevFocus = this._prevFocus;
  252. this._currentFocus = null;
  253. this._prevFocus = null;
  254. if (prevFocus && currentFocus && this.getAttribute("norestorefocus") != "true") {
  255. // Try to restore focus
  256. try {
  257. if (document.commandDispatcher.focusedWindow != window)
  258. return; // Focus has already been set to a window outside of this panel
  259. } catch(ex) {}
  260. while (currentFocus) {
  261. if (currentFocus == this) {
  262. // Focus was set on an element inside this panel,
  263. // so we need to move it back to where it was previously
  264. try {
  265. let fm = Components.classes["@mozilla.org/focus-manager;1"]
  266. .getService(Components.interfaces.nsIFocusManager);
  267. fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
  268. } catch(e) {
  269. prevFocus.focus();
  270. }
  271. return;
  272. }
  273. currentFocus = currentFocus.parentNode;
  274. }
  275. }
  276. ]]></handler>
  277. </handlers>
  278. </binding>
  279. <binding id="arrowpanel" extends="chrome://global/content/bindings/popup.xml#panel">
  280. <content flip="both" side="top" position="bottomcenter topleft">
  281. <xul:box anonid="container" class="panel-arrowcontainer" flex="1">
  282. <xul:box anonid="arrowbox" class="panel-arrowbox">
  283. <xul:image anonid="arrow" class="panel-arrow"/>
  284. </xul:box>
  285. <xul:box class="panel-arrowcontent" flex="1">
  286. <xul:box class="panel-inner-arrowcontent" xbl:inherits="align,dir,orient,pack" flex="1">
  287. <children/>
  288. <xul:box class="panel-inner-arrowcontentfooter" xbl:inherits="footertype" hidden="true"/>
  289. </xul:box>
  290. </xul:box>
  291. </xul:box>
  292. </content>
  293. <implementation>
  294. <field name="_fadeTimer">null</field>
  295. </implementation>
  296. <handlers>
  297. <handler event="popupshowing">
  298. <![CDATA[
  299. var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
  300. var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
  301. var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
  302. var anchor = this.anchorNode;
  303. if (!anchor) {
  304. arrow.hidden = true;
  305. return;
  306. }
  307. // Returns whether the first float is smaller than the second float or
  308. // equals to it in a range of epsilon.
  309. function smallerTo(aFloat1, aFloat2, aEpsilon)
  310. {
  311. return aFloat1 <= (aFloat2 + aEpsilon);
  312. }
  313. let popupRect = this.getBoundingClientRect();
  314. let popupLeft = window.mozInnerScreenX + popupRect.left;
  315. let popupTop = window.mozInnerScreenY + popupRect.top;
  316. let popupRight = popupLeft + popupRect.width;
  317. let popupBottom = popupTop + popupRect.height;
  318. let anchorRect = anchor.getBoundingClientRect();
  319. let anchorLeft = anchor.ownerDocument.defaultView.mozInnerScreenX + anchorRect.left;
  320. let anchorTop = anchor.ownerDocument.defaultView.mozInnerScreenY + anchorRect.top;
  321. let anchorRight = anchorLeft + anchorRect.width;
  322. let anchorBottom = anchorTop + anchorRect.height;
  323. try {
  324. let anchorWindow = anchor.ownerDocument.defaultView;
  325. if (anchorWindow != window) {
  326. let utils = anchorWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
  327. getInterface(Components.interfaces.nsIDOMWindowUtils);
  328. let spp = utils.screenPixelsPerCSSPixel;
  329. anchorLeft *= spp;
  330. anchorRight *= spp;
  331. anchorTop *= spp;
  332. anchorBottom *= spp;
  333. }
  334. } catch(ex) { }
  335. const epsilon = 0.2;
  336. var horizPos = smallerTo(popupRight, anchorLeft, epsilon) ? -1 : smallerTo(anchorRight, popupLeft, epsilon) ? 1 : 0;
  337. var vertPos = smallerTo(popupBottom, anchorTop, epsilon) ? -1 : smallerTo(anchorBottom, popupTop, epsilon) ? 1 : 0;
  338. var anchorClass = "";
  339. var hideAnchor = false;
  340. if (horizPos == 0) {
  341. container.orient = "vertical";
  342. arrowbox.orient = "";
  343. if (vertPos == 0) {
  344. hideAnchor = true;
  345. }
  346. else {
  347. let pack = "";
  348. // We have to guess where to position the arrow given that we don't
  349. // have access to the parameters passed to |openPopup|.
  350. // If the popup is on the left of the anchor.
  351. if (smallerTo(popupLeft, anchorLeft, epsilon) && smallerTo(popupRight, anchorRight, epsilon)) {
  352. pack = "end";
  353. // If the popup is on the right of the anchor.
  354. } else if (smallerTo(anchorLeft, popupLeft, epsilon) && smallerTo(anchorRight, popupRight, epsilon)) {
  355. pack = "start"; //(popupLeft + popupRect.width / 2 > anchorRight) ? "start" : "end";
  356. // If the popup is not on the right nor on the left.
  357. // Basically, that means one is above the other and one is bigger
  358. // than the other.
  359. // In that case, we can't easily choose a position for the arrow so
  360. // we have to guess depending on which side the popup is more close to.
  361. } else {
  362. pack = (Math.abs(popupLeft - anchorLeft) < Math.abs(popupRight - anchorRight)) ? "start" : "end";
  363. }
  364. // In RTL, everything should be inverted.
  365. if (window.getComputedStyle(this).direction == "rtl") {
  366. pack = (pack == "start") ? "end" : "start";
  367. }
  368. arrowbox.pack = pack;
  369. if (vertPos == 1) {
  370. container.dir = "";
  371. anchorClass = "top";
  372. }
  373. else if (vertPos == -1) {
  374. container.dir = "reverse";
  375. anchorClass = "bottom";
  376. }
  377. }
  378. }
  379. else if (vertPos == 0) {
  380. container.orient = "";
  381. arrowbox.orient = "vertical";
  382. if (horizPos == 0) {
  383. hideAnchor = true;
  384. }
  385. else {
  386. arrowbox.pack = popupTop + popupRect.height / 2 < anchorTop ? "end" : "start";
  387. if (horizPos == 1) {
  388. container.dir = "";
  389. anchorClass = "left";
  390. }
  391. else if (horizPos == -1) {
  392. container.dir = "reverse";
  393. anchorClass = "right";
  394. }
  395. }
  396. }
  397. else {
  398. hideAnchor = true;
  399. }
  400. arrow.hidden = hideAnchor;
  401. arrow.setAttribute("side", anchorClass);
  402. this.setAttribute("side", anchorClass);
  403. // set fading
  404. var fade = this.getAttribute("fade");
  405. var fadeDelay = (fade == "fast") ? 1 : fade == "slow" ? 4000 : 0;
  406. if (fadeDelay) {
  407. this._fadeTimer = setTimeout(function (self) {
  408. self.style.opacity = 0.2;
  409. }, fadeDelay, this);
  410. }
  411. ]]>
  412. </handler>
  413. <handler event="popuphiding" phase="target">
  414. clearTimeout(this._fadeTimer);
  415. this.style.removeProperty("opacity");
  416. </handler>
  417. <handler event="transitionend" phase="target">
  418. <![CDATA[
  419. if (event.propertyName == "opacity") {
  420. this.hidePopup();
  421. this.style.removeProperty("opacity");
  422. }
  423. ]]>
  424. </handler>
  425. </handlers>
  426. </binding>
  427. <binding id="tooltip" extends="chrome://global/content/bindings/popup.xml#popup-base">
  428. <content>
  429. <children>
  430. <xul:label class="tooltip-label" xbl:inherits="xbl:text=label" flex="1"/>
  431. </children>
  432. </content>
  433. <implementation implements="nsIAccessibleProvider">
  434. <property name="accessibleType" readonly="true">
  435. <getter>
  436. return Components.interfaces.nsIAccessibleProvider.XULTooltip;
  437. </getter>
  438. </property>
  439. <field name="_mouseOutCount">0</field>
  440. <field name="_isMouseOver">false</field>
  441. <property name="label"
  442. onget="return this.getAttribute('label');"
  443. onset="this.setAttribute('label', val); return val;"/>
  444. </implementation>
  445. <handlers>
  446. <handler event="mouseover"><![CDATA[
  447. var rel = event.relatedTarget;
  448. //dump("ENTERING " + (rel ? rel.localName : "null") + "\n");
  449. if (!rel)
  450. return;
  451. // find out if the node we entered from is one of our anonymous children
  452. while (rel) {
  453. if (rel == this)
  454. break;
  455. rel = rel.parentNode;
  456. }
  457. // if the exited node is not a descendant of ours, we are entering for the first time
  458. if (rel != this)
  459. this._isMouseOver = true;
  460. ]]></handler>
  461. <handler event="mouseout"><![CDATA[
  462. var rel = event.relatedTarget;
  463. //dump("LEAVING " + (rel ? rel.localName : "null") + "\n");
  464. // relatedTarget is null when the titletip is first shown: a mouseout event fires
  465. // because the mouse is exiting the main window and entering the titletip "window".
  466. // relatedTarget is also null when the mouse exits the main window completely,
  467. // so count how many times relatedTarget was null after titletip is first shown
  468. // and hide popup the 2nd time
  469. if (!rel) {
  470. ++this._mouseOutCount;
  471. if (this._mouseOutCount > 1)
  472. this.hidePopup();
  473. return;
  474. }
  475. // find out if the node we are entering is one of our anonymous children
  476. while (rel) {
  477. if (rel == this)
  478. break;
  479. rel = rel.parentNode;
  480. }
  481. // if the entered node is not a descendant of ours, hide the tooltip
  482. if (rel != this && this._isMouseOver) {
  483. this.hidePopup();
  484. }
  485. ]]></handler>
  486. <handler event="popuphiding"><![CDATA[
  487. this._isMouseOver = false;
  488. this._mouseOutCount = 0;
  489. ]]></handler>
  490. </handlers>
  491. </binding>
  492. <binding id="popup-scrollbars" extends="chrome://global/content/bindings/popup.xml#popup">
  493. <content>
  494. <xul:hbox class="popup-internal-box" flex="1" orient="vertical" style="overflow: auto;">
  495. <children/>
  496. </xul:hbox>
  497. </content>
  498. </binding>
  499. </bindings>