michael@0: /* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ 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: michael@0: const {Cc, Ci, Cu, Cr} = require("chrome"); michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); michael@0: let EventEmitter = require("devtools/toolkit/event-emitter"); michael@0: michael@0: Cu.import("resource:///modules/devtools/StyleEditorUI.jsm"); michael@0: Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm"); michael@0: michael@0: loader.lazyGetter(this, "StyleSheetsFront", michael@0: () => require("devtools/server/actors/stylesheets").StyleSheetsFront); michael@0: michael@0: loader.lazyGetter(this, "StyleEditorFront", michael@0: () => require("devtools/server/actors/styleeditor").StyleEditorFront); michael@0: michael@0: this.StyleEditorPanel = function StyleEditorPanel(panelWin, toolbox) { michael@0: EventEmitter.decorate(this); michael@0: michael@0: this._toolbox = toolbox; michael@0: this._target = toolbox.target; michael@0: this._panelWin = panelWin; michael@0: this._panelDoc = panelWin.document; michael@0: michael@0: this.destroy = this.destroy.bind(this); michael@0: this._showError = this._showError.bind(this); michael@0: } michael@0: michael@0: exports.StyleEditorPanel = StyleEditorPanel; michael@0: michael@0: StyleEditorPanel.prototype = { michael@0: get target() this._toolbox.target, michael@0: michael@0: get panelWindow() this._panelWin, michael@0: michael@0: /** michael@0: * open is effectively an asynchronous constructor michael@0: */ michael@0: open: function() { michael@0: let deferred = promise.defer(); michael@0: michael@0: let targetPromise; michael@0: // We always interact with the target as if it were remote michael@0: if (!this.target.isRemote) { michael@0: targetPromise = this.target.makeRemote(); michael@0: } else { michael@0: targetPromise = promise.resolve(this.target); michael@0: } michael@0: michael@0: targetPromise.then(() => { michael@0: this.target.on("close", this.destroy); michael@0: michael@0: if (this.target.form.styleSheetsActor) { michael@0: this._debuggee = StyleSheetsFront(this.target.client, this.target.form); michael@0: } michael@0: else { michael@0: /* We're talking to a pre-Firefox 29 server-side */ michael@0: this._debuggee = StyleEditorFront(this.target.client, this.target.form); michael@0: } michael@0: this.UI = new StyleEditorUI(this._debuggee, this.target, this._panelDoc); michael@0: this.UI.initialize().then(() => { michael@0: this.UI.on("error", this._showError); michael@0: michael@0: this.isReady = true; michael@0: michael@0: deferred.resolve(this); michael@0: }); michael@0: }, console.error); michael@0: michael@0: return deferred.promise; michael@0: }, michael@0: michael@0: /** michael@0: * Show an error message from the style editor in the toolbox michael@0: * notification box. michael@0: * michael@0: * @param {string} event michael@0: * Type of event michael@0: * @param {string} code michael@0: * Error code of error to report michael@0: * @param {string} message michael@0: * Extra message to append to error message michael@0: */ michael@0: _showError: function(event, code, message) { michael@0: if (!this._toolbox) { michael@0: // could get an async error after we've been destroyed michael@0: return; michael@0: } michael@0: michael@0: let errorMessage = _(code); michael@0: if (message) { michael@0: errorMessage += " " + message; michael@0: } michael@0: michael@0: let notificationBox = this._toolbox.getNotificationBox(); michael@0: let notification = notificationBox.getNotificationWithValue("styleeditor-error"); michael@0: if (!notification) { michael@0: notificationBox.appendNotification(errorMessage, michael@0: "styleeditor-error", "", notificationBox.PRIORITY_CRITICAL_LOW); michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Select a stylesheet. michael@0: * michael@0: * @param {string} href michael@0: * Url of stylesheet to find and select in editor michael@0: * @param {number} line michael@0: * Line number to jump to after selecting. One-indexed michael@0: * @param {number} col michael@0: * Column number to jump to after selecting. One-indexed michael@0: */ michael@0: selectStyleSheet: function(href, line, col) { michael@0: if (!this._debuggee || !this.UI) { michael@0: return; michael@0: } michael@0: this.UI.selectStyleSheet(href, line - 1, col ? col - 1 : 0); michael@0: }, michael@0: michael@0: /** michael@0: * Destroy the style editor. michael@0: */ michael@0: destroy: function() { michael@0: if (!this._destroyed) { michael@0: this._destroyed = true; michael@0: michael@0: this._target.off("close", this.destroy); michael@0: this._target = null; michael@0: this._toolbox = null; michael@0: this._panelDoc = null; michael@0: this._debuggee.destroy(); michael@0: this._debuggee = null; michael@0: michael@0: this.UI.destroy(); michael@0: } michael@0: michael@0: return promise.resolve(null); michael@0: }, michael@0: } michael@0: michael@0: XPCOMUtils.defineLazyGetter(StyleEditorPanel.prototype, "strings", michael@0: function () { michael@0: return Services.strings.createBundle( michael@0: "chrome://browser/locale/devtools/styleeditor.properties"); michael@0: });