toggle.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. 'use strict';
  5. module.metadata = {
  6. 'stability': 'experimental',
  7. 'engines': {
  8. 'Firefox': '> 28'
  9. }
  10. };
  11. // Because Firefox Holly, we still need to check if `CustomizableUI` is
  12. // available. Once Australis will officially land, we can safely remove it.
  13. // See Bug 959142
  14. try {
  15. require('chrome').Cu.import('resource:///modules/CustomizableUI.jsm', {});
  16. }
  17. catch (e) {
  18. throw Error('Unsupported Application: The module ' + module.id +
  19. ' does not support this application.');
  20. }
  21. const { Class } = require('../../core/heritage');
  22. const { merge } = require('../../util/object');
  23. const { Disposable } = require('../../core/disposable');
  24. const { on, off, emit, setListeners } = require('../../event/core');
  25. const { EventTarget } = require('../../event/target');
  26. const view = require('./view');
  27. const { toggleButtonContract, toggleStateContract } = require('./contract');
  28. const { properties, render, state, register, unregister,
  29. setStateFor, getStateFor, getDerivedStateFor } = require('../state');
  30. const { events: stateEvents } = require('../state/events');
  31. const { events: viewEvents } = require('./view/events');
  32. const events = require('../../event/utils');
  33. const { getActiveTab } = require('../../tabs/utils');
  34. const buttons = new Map();
  35. const ToggleButton = Class({
  36. extends: EventTarget,
  37. implements: [
  38. properties(toggleStateContract),
  39. state(toggleStateContract),
  40. Disposable
  41. ],
  42. setup: function setup(options) {
  43. let state = merge({
  44. disabled: false,
  45. checked: false
  46. }, toggleButtonContract(options));
  47. register(this, state);
  48. // Setup listeners.
  49. setListeners(this, options);
  50. buttons.set(options.id, this);
  51. view.create(merge({ type: 'checkbox' }, state));
  52. },
  53. dispose: function dispose() {
  54. buttons.delete(this.id);
  55. off(this);
  56. view.dispose(this.id);
  57. unregister(this);
  58. },
  59. get id() this.state().id,
  60. click: function click() view.click(this.id)
  61. });
  62. exports.ToggleButton = ToggleButton;
  63. let toggleButtonStateEvents = events.filter(stateEvents,
  64. e => e.target instanceof ToggleButton);
  65. let toggleButtonViewEvents = events.filter(viewEvents,
  66. e => buttons.has(e.target));
  67. let clickEvents = events.filter(toggleButtonViewEvents, e => e.type === 'click');
  68. let updateEvents = events.filter(toggleButtonViewEvents, e => e.type === 'update');
  69. on(toggleButtonStateEvents, 'data', ({target, window, state}) => {
  70. let { id } = target;
  71. view.setIcon(id, window, state.icon);
  72. view.setLabel(id, window, state.label);
  73. view.setDisabled(id, window, state.disabled);
  74. view.setChecked(id, window, state.checked);
  75. });
  76. on(clickEvents, 'data', ({target: id, window, checked }) => {
  77. let button = buttons.get(id);
  78. let windowState = getStateFor(button, window);
  79. let newWindowState = merge({}, windowState, { checked: checked });
  80. setStateFor(button, window, newWindowState);
  81. let state = getDerivedStateFor(button, getActiveTab(window));
  82. emit(button, 'click', state);
  83. emit(button, 'change', state);
  84. });
  85. on(updateEvents, 'data', ({target: id, window}) => {
  86. render(buttons.get(id), window);
  87. });