diff -r 000000000000 -r 6474c204b198 browser/devtools/styleinspector/style-inspector.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browser/devtools/styleinspector/style-inspector.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,206 @@ +/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const {Cc, Cu, Ci} = require("chrome"); +const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); + +let ToolDefinitions = require("main").Tools; + +Cu.import("resource://gre/modules/Services.jsm"); + +loader.lazyGetter(this, "gDevTools", () => Cu.import("resource:///modules/devtools/gDevTools.jsm", {}).gDevTools); +loader.lazyGetter(this, "RuleView", () => require("devtools/styleinspector/rule-view")); +loader.lazyGetter(this, "ComputedView", () => require("devtools/styleinspector/computed-view")); +loader.lazyGetter(this, "_strings", () => Services.strings + .createBundle("chrome://global/locale/devtools/styleinspector.properties")); + +const { PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils"); + +// This module doesn't currently export any symbols directly, it only +// registers inspector tools. + +function RuleViewTool(aInspector, aWindow, aIFrame) +{ + this.inspector = aInspector; + this.doc = aWindow.document; + this.outerIFrame = aIFrame; + + this.view = new RuleView.CssRuleView(aInspector, this.doc); + this.doc.documentElement.appendChild(this.view.element); + + this._changeHandler = () => { + this.inspector.markDirty(); + }; + + this.view.element.addEventListener("CssRuleViewChanged", this._changeHandler); + + this._refreshHandler = () => { + this.inspector.emit("rule-view-refreshed"); + }; + + this.view.element.addEventListener("CssRuleViewRefreshed", this._refreshHandler); + + this._cssLinkHandler = (aEvent) => { + let rule = aEvent.detail.rule; + let sheet = rule.parentStyleSheet; + + // Chrome stylesheets are not listed in the style editor, so show + // these sheets in the view source window instead. + if (!sheet || sheet.isSystem) { + let contentDoc = this.inspector.selection.document; + let viewSourceUtils = this.inspector.viewSourceUtils; + let href = rule.nodeHref || rule.href; + viewSourceUtils.viewSource(href, null, contentDoc, rule.line || 0); + return; + } + + let location = promise.resolve(rule.location); + if (Services.prefs.getBoolPref(PREF_ORIG_SOURCES)) { + location = rule.getOriginalLocation(); + } + location.then(({ href, line, column }) => { + let target = this.inspector.target; + if (ToolDefinitions.styleEditor.isTargetSupported(target)) { + gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) { + toolbox.getCurrentPanel().selectStyleSheet(href, line, column); + }); + } + return; + }) + } + + this.view.element.addEventListener("CssRuleViewCSSLinkClicked", + this._cssLinkHandler); + + this._onSelect = this.onSelect.bind(this); + this.inspector.selection.on("detached", this._onSelect); + this.inspector.selection.on("new-node-front", this._onSelect); + this.refresh = this.refresh.bind(this); + this.inspector.on("layout-change", this.refresh); + + this.inspector.selection.on("pseudoclass", this.refresh); + + this.onSelect(); +} + +exports.RuleViewTool = RuleViewTool; + +RuleViewTool.prototype = { + onSelect: function RVT_onSelect(aEvent) { + if (!this.view) { + // Skip the event if RuleViewTool has been destroyed. + return; + } + this.view.setPageStyle(this.inspector.pageStyle); + + if (!this.inspector.selection.isConnected() || + !this.inspector.selection.isElementNode()) { + this.view.highlight(null); + return; + } + + if (!aEvent || aEvent == "new-node-front") { + let done = this.inspector.updating("rule-view"); + this.view.highlight(this.inspector.selection.nodeFront).then(done, done); + } + }, + + refresh: function RVT_refresh() { + this.view.nodeChanged(); + }, + + destroy: function RVT_destroy() { + this.inspector.off("layout-change", this.refresh); + this.inspector.selection.off("pseudoclass", this.refresh); + this.inspector.selection.off("new-node-front", this._onSelect); + + this.view.element.removeEventListener("CssRuleViewCSSLinkClicked", + this._cssLinkHandler); + + this.view.element.removeEventListener("CssRuleViewChanged", + this._changeHandler); + + this.view.element.removeEventListener("CssRuleViewRefreshed", + this._refreshHandler); + + this.doc.documentElement.removeChild(this.view.element); + + this.view.destroy(); + + delete this.outerIFrame; + delete this.view; + delete this.doc; + delete this.inspector; + } +}; + +function ComputedViewTool(aInspector, aWindow, aIFrame) +{ + this.inspector = aInspector; + this.window = aWindow; + this.document = aWindow.document; + this.outerIFrame = aIFrame; + this.view = new ComputedView.CssHtmlTree(this, aInspector.pageStyle); + + this._onSelect = this.onSelect.bind(this); + this.inspector.selection.on("detached", this._onSelect); + this.inspector.selection.on("new-node-front", this._onSelect); + this.refresh = this.refresh.bind(this); + this.inspector.on("layout-change", this.refresh); + this.inspector.selection.on("pseudoclass", this.refresh); + + this.view.highlight(null); + + this.onSelect(); +} + +exports.ComputedViewTool = ComputedViewTool; + +ComputedViewTool.prototype = { + onSelect: function CVT_onSelect(aEvent) + { + if (!this.view) { + // Skip the event if ComputedViewTool has been destroyed. + return; + } + this.view.setPageStyle(this.inspector.pageStyle); + + if (!this.inspector.selection.isConnected() || + !this.inspector.selection.isElementNode()) { + this.view.highlight(null); + return; + } + + if (!aEvent || aEvent == "new-node-front") { + let done = this.inspector.updating("computed-view"); + this.view.highlight(this.inspector.selection.nodeFront).then(() => { + done(); + }); + } + }, + + refresh: function CVT_refresh() { + this.view.refreshPanel(); + }, + + destroy: function CVT_destroy(aContext) + { + this.inspector.off("layout-change", this.refresh); + this.inspector.sidebar.off("computedview-selected", this.refresh); + this.inspector.selection.off("pseudoclass", this.refresh); + this.inspector.selection.off("new-node-front", this._onSelect); + + this.view.destroy(); + delete this.view; + + delete this.outerIFrame; + delete this.cssLogic; + delete this.cssHtmlTree; + delete this.window; + delete this.document; + delete this.inspector; + } +};