| |
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 }; |