measure.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. /* globals getOuterId, getBrowserForTab */
  5. "use strict";
  6. const EventEmitter = require("devtools/shared/event-emitter");
  7. const eventEmitter = new EventEmitter();
  8. const events = require("sdk/event/core");
  9. loader.lazyRequireGetter(this, "getOuterId", "sdk/window/utils", true);
  10. loader.lazyRequireGetter(this, "getBrowserForTab", "sdk/tabs/utils", true);
  11. const l10n = require("gcli/l10n");
  12. require("devtools/server/actors/inspector");
  13. const { MeasuringToolHighlighter, HighlighterEnvironment } =
  14. require("devtools/server/actors/highlighters");
  15. const highlighters = new WeakMap();
  16. const visibleHighlighters = new Set();
  17. const isCheckedFor = (tab) =>
  18. tab ? visibleHighlighters.has(getBrowserForTab(tab).outerWindowID) : false;
  19. exports.items = [
  20. // The client measure command is used to maintain the toolbar button state
  21. // only and redirects to the server command to actually toggle the measuring
  22. // tool (see `measure_server` below).
  23. {
  24. name: "measure",
  25. runAt: "client",
  26. description: l10n.lookup("measureDesc"),
  27. manual: l10n.lookup("measureManual"),
  28. buttonId: "command-button-measure",
  29. buttonClass: "command-button command-button-invertable",
  30. tooltipText: l10n.lookup("measureTooltip"),
  31. state: {
  32. isChecked: ({_tab}) => isCheckedFor(_tab),
  33. onChange: (target, handler) => eventEmitter.on("changed", handler),
  34. offChange: (target, handler) => eventEmitter.off("changed", handler)
  35. },
  36. exec: function*(args, context) {
  37. let { target } = context.environment;
  38. // Pipe the call to the server command.
  39. let response = yield context.updateExec("measure_server");
  40. let { visible, id } = response.data;
  41. if (visible) {
  42. visibleHighlighters.add(id);
  43. } else {
  44. visibleHighlighters.delete(id);
  45. }
  46. eventEmitter.emit("changed", { target });
  47. // Toggle off the button when the page navigates because the measuring
  48. // tool is removed automatically by the MeasuringToolHighlighter on the
  49. // server then.
  50. let onNavigate = () => {
  51. visibleHighlighters.delete(id);
  52. eventEmitter.emit("changed", { target });
  53. };
  54. target.off("will-navigate", onNavigate);
  55. target.once("will-navigate", onNavigate);
  56. }
  57. },
  58. // The server measure command is hidden by default, it's just used by the
  59. // client command.
  60. {
  61. name: "measure_server",
  62. runAt: "server",
  63. hidden: true,
  64. returnType: "highlighterVisibility",
  65. exec: function(args, context) {
  66. let env = context.environment;
  67. let { document } = env;
  68. let id = getOuterId(env.window);
  69. // Calling the command again after the measuring tool has been shown once,
  70. // hides it.
  71. if (highlighters.has(document)) {
  72. let { highlighter } = highlighters.get(document);
  73. highlighter.destroy();
  74. return {visible: false, id};
  75. }
  76. // Otherwise, display the measuring tool.
  77. let environment = new HighlighterEnvironment();
  78. environment.initFromWindow(env.window);
  79. let highlighter = new MeasuringToolHighlighter(environment);
  80. // Store the instance of the measuring tool highlighter for this document
  81. // so we can hide it later.
  82. highlighters.set(document, { highlighter, environment });
  83. // Listen to the highlighter's destroy event which may happen if the
  84. // window is refreshed or closed with the measuring tool shown.
  85. events.once(highlighter, "destroy", () => {
  86. if (highlighters.has(document)) {
  87. let { environment } = highlighters.get(document);
  88. environment.destroy();
  89. highlighters.delete(document);
  90. }
  91. });
  92. highlighter.show();
  93. return {visible: true, id};
  94. }
  95. }
  96. ];