michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: 'use strict'; michael@0: michael@0: module.metadata = { michael@0: 'stability': 'experimental', michael@0: 'engines': { michael@0: 'Firefox': '> 28' michael@0: } michael@0: }; michael@0: michael@0: const { Class } = require('../../core/heritage'); michael@0: const { merge } = require('../../util/object'); michael@0: const { Disposable } = require('../../core/disposable'); michael@0: const { on, off, emit, setListeners } = require('../../event/core'); michael@0: const { EventTarget } = require('../../event/target'); michael@0: const { getNodeView } = require('../../view/core'); michael@0: michael@0: const view = require('./view'); michael@0: const { buttonContract, stateContract } = require('./contract'); michael@0: const { properties, render, state, register, unregister, michael@0: getDerivedStateFor } = require('../state'); michael@0: const { events: stateEvents } = require('../state/events'); michael@0: const { events: viewEvents } = require('./view/events'); michael@0: const events = require('../../event/utils'); michael@0: michael@0: const { getActiveTab } = require('../../tabs/utils'); michael@0: michael@0: const { id: addonID } = require('../../self'); michael@0: const { identify } = require('../id'); michael@0: michael@0: const buttons = new Map(); michael@0: michael@0: const toWidgetId = id => michael@0: ('action-button--' + addonID.toLowerCase()+ '-' + id). michael@0: replace(/[^a-z0-9_-]/g, ''); michael@0: michael@0: const ActionButton = Class({ michael@0: extends: EventTarget, michael@0: implements: [ michael@0: properties(stateContract), michael@0: state(stateContract), michael@0: Disposable michael@0: ], michael@0: setup: function setup(options) { michael@0: let state = merge({ michael@0: disabled: false michael@0: }, buttonContract(options)); michael@0: michael@0: let id = toWidgetId(options.id); michael@0: michael@0: register(this, state); michael@0: michael@0: // Setup listeners. michael@0: setListeners(this, options); michael@0: michael@0: buttons.set(id, this); michael@0: michael@0: view.create(merge({}, state, { id: id })); michael@0: }, michael@0: michael@0: dispose: function dispose() { michael@0: let id = toWidgetId(this.id); michael@0: buttons.delete(id); michael@0: michael@0: off(this); michael@0: michael@0: view.dispose(id); michael@0: michael@0: unregister(this); michael@0: }, michael@0: michael@0: get id() this.state().id, michael@0: michael@0: click: function click() { view.click(toWidgetId(this.id)) } michael@0: }); michael@0: exports.ActionButton = ActionButton; michael@0: michael@0: identify.define(ActionButton, ({id}) => toWidgetId(id)); michael@0: michael@0: getNodeView.define(ActionButton, button => michael@0: view.nodeFor(toWidgetId(button.id)) michael@0: ); michael@0: michael@0: let actionButtonStateEvents = events.filter(stateEvents, michael@0: e => e.target instanceof ActionButton); michael@0: michael@0: let actionButtonViewEvents = events.filter(viewEvents, michael@0: e => buttons.has(e.target)); michael@0: michael@0: let clickEvents = events.filter(actionButtonViewEvents, e => e.type === 'click'); michael@0: let updateEvents = events.filter(actionButtonViewEvents, e => e.type === 'update'); michael@0: michael@0: on(clickEvents, 'data', ({target: id, window}) => { michael@0: let button = buttons.get(id); michael@0: let state = getDerivedStateFor(button, getActiveTab(window)); michael@0: michael@0: emit(button, 'click', state); michael@0: }); michael@0: michael@0: on(updateEvents, 'data', ({target: id, window}) => { michael@0: render(buttons.get(id), window); michael@0: }); michael@0: michael@0: on(actionButtonStateEvents, 'data', ({target, window, state}) => { michael@0: let id = toWidgetId(target.id); michael@0: view.setIcon(id, window, state.icon); michael@0: view.setLabel(id, window, state.label); michael@0: view.setDisabled(id, window, state.disabled); michael@0: });