michael@0: /* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set 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, Cu, Ci} = require("chrome"); michael@0: const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); michael@0: michael@0: let ToolDefinitions = require("main").Tools; michael@0: michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: loader.lazyGetter(this, "gDevTools", () => Cu.import("resource:///modules/devtools/gDevTools.jsm", {}).gDevTools); michael@0: loader.lazyGetter(this, "RuleView", () => require("devtools/styleinspector/rule-view")); michael@0: loader.lazyGetter(this, "ComputedView", () => require("devtools/styleinspector/computed-view")); michael@0: loader.lazyGetter(this, "_strings", () => Services.strings michael@0: .createBundle("chrome://global/locale/devtools/styleinspector.properties")); michael@0: michael@0: const { PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils"); michael@0: michael@0: // This module doesn't currently export any symbols directly, it only michael@0: // registers inspector tools. michael@0: michael@0: function RuleViewTool(aInspector, aWindow, aIFrame) michael@0: { michael@0: this.inspector = aInspector; michael@0: this.doc = aWindow.document; michael@0: this.outerIFrame = aIFrame; michael@0: michael@0: this.view = new RuleView.CssRuleView(aInspector, this.doc); michael@0: this.doc.documentElement.appendChild(this.view.element); michael@0: michael@0: this._changeHandler = () => { michael@0: this.inspector.markDirty(); michael@0: }; michael@0: michael@0: this.view.element.addEventListener("CssRuleViewChanged", this._changeHandler); michael@0: michael@0: this._refreshHandler = () => { michael@0: this.inspector.emit("rule-view-refreshed"); michael@0: }; michael@0: michael@0: this.view.element.addEventListener("CssRuleViewRefreshed", this._refreshHandler); michael@0: michael@0: this._cssLinkHandler = (aEvent) => { michael@0: let rule = aEvent.detail.rule; michael@0: let sheet = rule.parentStyleSheet; michael@0: michael@0: // Chrome stylesheets are not listed in the style editor, so show michael@0: // these sheets in the view source window instead. michael@0: if (!sheet || sheet.isSystem) { michael@0: let contentDoc = this.inspector.selection.document; michael@0: let viewSourceUtils = this.inspector.viewSourceUtils; michael@0: let href = rule.nodeHref || rule.href; michael@0: viewSourceUtils.viewSource(href, null, contentDoc, rule.line || 0); michael@0: return; michael@0: } michael@0: michael@0: let location = promise.resolve(rule.location); michael@0: if (Services.prefs.getBoolPref(PREF_ORIG_SOURCES)) { michael@0: location = rule.getOriginalLocation(); michael@0: } michael@0: location.then(({ href, line, column }) => { michael@0: let target = this.inspector.target; michael@0: if (ToolDefinitions.styleEditor.isTargetSupported(target)) { michael@0: gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) { michael@0: toolbox.getCurrentPanel().selectStyleSheet(href, line, column); michael@0: }); michael@0: } michael@0: return; michael@0: }) michael@0: } michael@0: michael@0: this.view.element.addEventListener("CssRuleViewCSSLinkClicked", michael@0: this._cssLinkHandler); michael@0: michael@0: this._onSelect = this.onSelect.bind(this); michael@0: this.inspector.selection.on("detached", this._onSelect); michael@0: this.inspector.selection.on("new-node-front", this._onSelect); michael@0: this.refresh = this.refresh.bind(this); michael@0: this.inspector.on("layout-change", this.refresh); michael@0: michael@0: this.inspector.selection.on("pseudoclass", this.refresh); michael@0: michael@0: this.onSelect(); michael@0: } michael@0: michael@0: exports.RuleViewTool = RuleViewTool; michael@0: michael@0: RuleViewTool.prototype = { michael@0: onSelect: function RVT_onSelect(aEvent) { michael@0: if (!this.view) { michael@0: // Skip the event if RuleViewTool has been destroyed. michael@0: return; michael@0: } michael@0: this.view.setPageStyle(this.inspector.pageStyle); michael@0: michael@0: if (!this.inspector.selection.isConnected() || michael@0: !this.inspector.selection.isElementNode()) { michael@0: this.view.highlight(null); michael@0: return; michael@0: } michael@0: michael@0: if (!aEvent || aEvent == "new-node-front") { michael@0: let done = this.inspector.updating("rule-view"); michael@0: this.view.highlight(this.inspector.selection.nodeFront).then(done, done); michael@0: } michael@0: }, michael@0: michael@0: refresh: function RVT_refresh() { michael@0: this.view.nodeChanged(); michael@0: }, michael@0: michael@0: destroy: function RVT_destroy() { michael@0: this.inspector.off("layout-change", this.refresh); michael@0: this.inspector.selection.off("pseudoclass", this.refresh); michael@0: this.inspector.selection.off("new-node-front", this._onSelect); michael@0: michael@0: this.view.element.removeEventListener("CssRuleViewCSSLinkClicked", michael@0: this._cssLinkHandler); michael@0: michael@0: this.view.element.removeEventListener("CssRuleViewChanged", michael@0: this._changeHandler); michael@0: michael@0: this.view.element.removeEventListener("CssRuleViewRefreshed", michael@0: this._refreshHandler); michael@0: michael@0: this.doc.documentElement.removeChild(this.view.element); michael@0: michael@0: this.view.destroy(); michael@0: michael@0: delete this.outerIFrame; michael@0: delete this.view; michael@0: delete this.doc; michael@0: delete this.inspector; michael@0: } michael@0: }; michael@0: michael@0: function ComputedViewTool(aInspector, aWindow, aIFrame) michael@0: { michael@0: this.inspector = aInspector; michael@0: this.window = aWindow; michael@0: this.document = aWindow.document; michael@0: this.outerIFrame = aIFrame; michael@0: this.view = new ComputedView.CssHtmlTree(this, aInspector.pageStyle); michael@0: michael@0: this._onSelect = this.onSelect.bind(this); michael@0: this.inspector.selection.on("detached", this._onSelect); michael@0: this.inspector.selection.on("new-node-front", this._onSelect); michael@0: this.refresh = this.refresh.bind(this); michael@0: this.inspector.on("layout-change", this.refresh); michael@0: this.inspector.selection.on("pseudoclass", this.refresh); michael@0: michael@0: this.view.highlight(null); michael@0: michael@0: this.onSelect(); michael@0: } michael@0: michael@0: exports.ComputedViewTool = ComputedViewTool; michael@0: michael@0: ComputedViewTool.prototype = { michael@0: onSelect: function CVT_onSelect(aEvent) michael@0: { michael@0: if (!this.view) { michael@0: // Skip the event if ComputedViewTool has been destroyed. michael@0: return; michael@0: } michael@0: this.view.setPageStyle(this.inspector.pageStyle); michael@0: michael@0: if (!this.inspector.selection.isConnected() || michael@0: !this.inspector.selection.isElementNode()) { michael@0: this.view.highlight(null); michael@0: return; michael@0: } michael@0: michael@0: if (!aEvent || aEvent == "new-node-front") { michael@0: let done = this.inspector.updating("computed-view"); michael@0: this.view.highlight(this.inspector.selection.nodeFront).then(() => { michael@0: done(); michael@0: }); michael@0: } michael@0: }, michael@0: michael@0: refresh: function CVT_refresh() { michael@0: this.view.refreshPanel(); michael@0: }, michael@0: michael@0: destroy: function CVT_destroy(aContext) michael@0: { michael@0: this.inspector.off("layout-change", this.refresh); michael@0: this.inspector.sidebar.off("computedview-selected", this.refresh); michael@0: this.inspector.selection.off("pseudoclass", this.refresh); michael@0: this.inspector.selection.off("new-node-front", this._onSelect); michael@0: michael@0: this.view.destroy(); michael@0: delete this.view; michael@0: michael@0: delete this.outerIFrame; michael@0: delete this.cssLogic; michael@0: delete this.cssHtmlTree; michael@0: delete this.window; michael@0: delete this.document; michael@0: delete this.inspector; michael@0: } michael@0: };