|
1 /* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 const {Cc, Cu, Ci} = require("chrome"); |
|
8 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); |
|
9 |
|
10 let ToolDefinitions = require("main").Tools; |
|
11 |
|
12 Cu.import("resource://gre/modules/Services.jsm"); |
|
13 |
|
14 loader.lazyGetter(this, "gDevTools", () => Cu.import("resource:///modules/devtools/gDevTools.jsm", {}).gDevTools); |
|
15 loader.lazyGetter(this, "RuleView", () => require("devtools/styleinspector/rule-view")); |
|
16 loader.lazyGetter(this, "ComputedView", () => require("devtools/styleinspector/computed-view")); |
|
17 loader.lazyGetter(this, "_strings", () => Services.strings |
|
18 .createBundle("chrome://global/locale/devtools/styleinspector.properties")); |
|
19 |
|
20 const { PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils"); |
|
21 |
|
22 // This module doesn't currently export any symbols directly, it only |
|
23 // registers inspector tools. |
|
24 |
|
25 function RuleViewTool(aInspector, aWindow, aIFrame) |
|
26 { |
|
27 this.inspector = aInspector; |
|
28 this.doc = aWindow.document; |
|
29 this.outerIFrame = aIFrame; |
|
30 |
|
31 this.view = new RuleView.CssRuleView(aInspector, this.doc); |
|
32 this.doc.documentElement.appendChild(this.view.element); |
|
33 |
|
34 this._changeHandler = () => { |
|
35 this.inspector.markDirty(); |
|
36 }; |
|
37 |
|
38 this.view.element.addEventListener("CssRuleViewChanged", this._changeHandler); |
|
39 |
|
40 this._refreshHandler = () => { |
|
41 this.inspector.emit("rule-view-refreshed"); |
|
42 }; |
|
43 |
|
44 this.view.element.addEventListener("CssRuleViewRefreshed", this._refreshHandler); |
|
45 |
|
46 this._cssLinkHandler = (aEvent) => { |
|
47 let rule = aEvent.detail.rule; |
|
48 let sheet = rule.parentStyleSheet; |
|
49 |
|
50 // Chrome stylesheets are not listed in the style editor, so show |
|
51 // these sheets in the view source window instead. |
|
52 if (!sheet || sheet.isSystem) { |
|
53 let contentDoc = this.inspector.selection.document; |
|
54 let viewSourceUtils = this.inspector.viewSourceUtils; |
|
55 let href = rule.nodeHref || rule.href; |
|
56 viewSourceUtils.viewSource(href, null, contentDoc, rule.line || 0); |
|
57 return; |
|
58 } |
|
59 |
|
60 let location = promise.resolve(rule.location); |
|
61 if (Services.prefs.getBoolPref(PREF_ORIG_SOURCES)) { |
|
62 location = rule.getOriginalLocation(); |
|
63 } |
|
64 location.then(({ href, line, column }) => { |
|
65 let target = this.inspector.target; |
|
66 if (ToolDefinitions.styleEditor.isTargetSupported(target)) { |
|
67 gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) { |
|
68 toolbox.getCurrentPanel().selectStyleSheet(href, line, column); |
|
69 }); |
|
70 } |
|
71 return; |
|
72 }) |
|
73 } |
|
74 |
|
75 this.view.element.addEventListener("CssRuleViewCSSLinkClicked", |
|
76 this._cssLinkHandler); |
|
77 |
|
78 this._onSelect = this.onSelect.bind(this); |
|
79 this.inspector.selection.on("detached", this._onSelect); |
|
80 this.inspector.selection.on("new-node-front", this._onSelect); |
|
81 this.refresh = this.refresh.bind(this); |
|
82 this.inspector.on("layout-change", this.refresh); |
|
83 |
|
84 this.inspector.selection.on("pseudoclass", this.refresh); |
|
85 |
|
86 this.onSelect(); |
|
87 } |
|
88 |
|
89 exports.RuleViewTool = RuleViewTool; |
|
90 |
|
91 RuleViewTool.prototype = { |
|
92 onSelect: function RVT_onSelect(aEvent) { |
|
93 if (!this.view) { |
|
94 // Skip the event if RuleViewTool has been destroyed. |
|
95 return; |
|
96 } |
|
97 this.view.setPageStyle(this.inspector.pageStyle); |
|
98 |
|
99 if (!this.inspector.selection.isConnected() || |
|
100 !this.inspector.selection.isElementNode()) { |
|
101 this.view.highlight(null); |
|
102 return; |
|
103 } |
|
104 |
|
105 if (!aEvent || aEvent == "new-node-front") { |
|
106 let done = this.inspector.updating("rule-view"); |
|
107 this.view.highlight(this.inspector.selection.nodeFront).then(done, done); |
|
108 } |
|
109 }, |
|
110 |
|
111 refresh: function RVT_refresh() { |
|
112 this.view.nodeChanged(); |
|
113 }, |
|
114 |
|
115 destroy: function RVT_destroy() { |
|
116 this.inspector.off("layout-change", this.refresh); |
|
117 this.inspector.selection.off("pseudoclass", this.refresh); |
|
118 this.inspector.selection.off("new-node-front", this._onSelect); |
|
119 |
|
120 this.view.element.removeEventListener("CssRuleViewCSSLinkClicked", |
|
121 this._cssLinkHandler); |
|
122 |
|
123 this.view.element.removeEventListener("CssRuleViewChanged", |
|
124 this._changeHandler); |
|
125 |
|
126 this.view.element.removeEventListener("CssRuleViewRefreshed", |
|
127 this._refreshHandler); |
|
128 |
|
129 this.doc.documentElement.removeChild(this.view.element); |
|
130 |
|
131 this.view.destroy(); |
|
132 |
|
133 delete this.outerIFrame; |
|
134 delete this.view; |
|
135 delete this.doc; |
|
136 delete this.inspector; |
|
137 } |
|
138 }; |
|
139 |
|
140 function ComputedViewTool(aInspector, aWindow, aIFrame) |
|
141 { |
|
142 this.inspector = aInspector; |
|
143 this.window = aWindow; |
|
144 this.document = aWindow.document; |
|
145 this.outerIFrame = aIFrame; |
|
146 this.view = new ComputedView.CssHtmlTree(this, aInspector.pageStyle); |
|
147 |
|
148 this._onSelect = this.onSelect.bind(this); |
|
149 this.inspector.selection.on("detached", this._onSelect); |
|
150 this.inspector.selection.on("new-node-front", this._onSelect); |
|
151 this.refresh = this.refresh.bind(this); |
|
152 this.inspector.on("layout-change", this.refresh); |
|
153 this.inspector.selection.on("pseudoclass", this.refresh); |
|
154 |
|
155 this.view.highlight(null); |
|
156 |
|
157 this.onSelect(); |
|
158 } |
|
159 |
|
160 exports.ComputedViewTool = ComputedViewTool; |
|
161 |
|
162 ComputedViewTool.prototype = { |
|
163 onSelect: function CVT_onSelect(aEvent) |
|
164 { |
|
165 if (!this.view) { |
|
166 // Skip the event if ComputedViewTool has been destroyed. |
|
167 return; |
|
168 } |
|
169 this.view.setPageStyle(this.inspector.pageStyle); |
|
170 |
|
171 if (!this.inspector.selection.isConnected() || |
|
172 !this.inspector.selection.isElementNode()) { |
|
173 this.view.highlight(null); |
|
174 return; |
|
175 } |
|
176 |
|
177 if (!aEvent || aEvent == "new-node-front") { |
|
178 let done = this.inspector.updating("computed-view"); |
|
179 this.view.highlight(this.inspector.selection.nodeFront).then(() => { |
|
180 done(); |
|
181 }); |
|
182 } |
|
183 }, |
|
184 |
|
185 refresh: function CVT_refresh() { |
|
186 this.view.refreshPanel(); |
|
187 }, |
|
188 |
|
189 destroy: function CVT_destroy(aContext) |
|
190 { |
|
191 this.inspector.off("layout-change", this.refresh); |
|
192 this.inspector.sidebar.off("computedview-selected", this.refresh); |
|
193 this.inspector.selection.off("pseudoclass", this.refresh); |
|
194 this.inspector.selection.off("new-node-front", this._onSelect); |
|
195 |
|
196 this.view.destroy(); |
|
197 delete this.view; |
|
198 |
|
199 delete this.outerIFrame; |
|
200 delete this.cssLogic; |
|
201 delete this.cssHtmlTree; |
|
202 delete this.window; |
|
203 delete this.document; |
|
204 delete this.inspector; |
|
205 } |
|
206 }; |