browser/devtools/styleeditor/StyleEditorUtil.jsm

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:950bf43ddee7
1 /* vim:set ts=2 sw=2 sts=2 et: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 "use strict";
7
8 this.EXPORTED_SYMBOLS = [
9 "_",
10 "assert",
11 "log",
12 "text",
13 "wire",
14 "showFilePicker"
15 ];
16
17 const Cc = Components.classes;
18 const Ci = Components.interfaces;
19 const Cu = Components.utils;
20
21 Cu.import("resource://gre/modules/Services.jsm");
22
23 const PROPERTIES_URL = "chrome://browser/locale/devtools/styleeditor.properties";
24
25 const console = Services.console;
26 const gStringBundle = Services.strings.createBundle(PROPERTIES_URL);
27
28
29 /**
30 * Returns a localized string with the given key name from the string bundle.
31 *
32 * @param aName
33 * @param ...rest
34 * Optional arguments to format in the string.
35 * @return string
36 */
37 this._ = function _(aName)
38 {
39
40 if (arguments.length == 1) {
41 return gStringBundle.GetStringFromName(aName);
42 }
43 let rest = Array.prototype.slice.call(arguments, 1);
44 return gStringBundle.formatStringFromName(aName, rest, rest.length);
45 }
46
47 /**
48 * Assert an expression is true or throw if false.
49 *
50 * @param aExpression
51 * @param aMessage
52 * Optional message.
53 * @return aExpression
54 */
55 this.assert = function assert(aExpression, aMessage)
56 {
57 if (!!!(aExpression)) {
58 let msg = aMessage ? "ASSERTION FAILURE:" + aMessage : "ASSERTION FAILURE";
59 log(msg);
60 throw new Error(msg);
61 }
62 return aExpression;
63 }
64
65 /**
66 * Retrieve or set the text content of an element.
67 *
68 * @param DOMElement aRoot
69 * The element to use for querySelector.
70 * @param string aSelector
71 * Selector string for the element to get/set the text content.
72 * @param string aText
73 * Optional text to set.
74 * @return string
75 * Text content of matching element or null if there were no element
76 * matching aSelector.
77 */
78 this.text = function text(aRoot, aSelector, aText)
79 {
80 let element = aRoot.querySelector(aSelector);
81 if (!element) {
82 return null;
83 }
84
85 if (aText === undefined) {
86 return element.textContent;
87 }
88 element.textContent = aText;
89 return aText;
90 }
91
92 /**
93 * Iterates _own_ properties of an object.
94 *
95 * @param aObject
96 * The object to iterate.
97 * @param function aCallback(aKey, aValue)
98 */
99 function forEach(aObject, aCallback)
100 {
101 for (let key in aObject) {
102 if (aObject.hasOwnProperty(key)) {
103 aCallback(key, aObject[key]);
104 }
105 }
106 }
107
108 /**
109 * Log a message to the console.
110 *
111 * @param ...rest
112 * One or multiple arguments to log.
113 * If multiple arguments are given, they will be joined by " " in the log.
114 */
115 this.log = function log()
116 {
117 console.logStringMessage(Array.prototype.slice.call(arguments).join(" "));
118 }
119
120 /**
121 * Wire up element(s) matching selector with attributes, event listeners, etc.
122 *
123 * @param DOMElement aRoot
124 * The element to use for querySelectorAll.
125 * Can be null if aSelector is a DOMElement.
126 * @param string|DOMElement aSelectorOrElement
127 * Selector string or DOMElement for the element(s) to wire up.
128 * @param object aDescriptor
129 * An object describing how to wire matching selector, supported properties
130 * are "events" and "attributes" taking objects themselves.
131 * Each key of properties above represents the name of the event or
132 * attribute, with the value being a function used as an event handler or
133 * string to use as attribute value.
134 * If aDescriptor is a function, the argument is equivalent to :
135 * {events: {'click': aDescriptor}}
136 */
137 this.wire = function wire(aRoot, aSelectorOrElement, aDescriptor)
138 {
139 let matches;
140 if (typeof(aSelectorOrElement) == "string") { // selector
141 matches = aRoot.querySelectorAll(aSelectorOrElement);
142 if (!matches.length) {
143 return;
144 }
145 } else {
146 matches = [aSelectorOrElement]; // element
147 }
148
149 if (typeof(aDescriptor) == "function") {
150 aDescriptor = {events: {click: aDescriptor}};
151 }
152
153 for (let i = 0; i < matches.length; i++) {
154 let element = matches[i];
155 forEach(aDescriptor.events, function (aName, aHandler) {
156 element.addEventListener(aName, aHandler, false);
157 });
158 forEach(aDescriptor.attributes, element.setAttribute);
159 }
160 }
161
162 /**
163 * Show file picker and return the file user selected.
164 *
165 * @param mixed file
166 * Optional nsIFile or string representing the filename to auto-select.
167 * @param boolean toSave
168 * If true, the user is selecting a filename to save.
169 * @param nsIWindow parentWindow
170 * Optional parent window. If null the parent window of the file picker
171 * will be the window of the attached input element.
172 * @param callback
173 * The callback method, which will be called passing in the selected
174 * file or null if the user did not pick one.
175 * @param AString suggestedFilename
176 * The suggested filename when toSave is true.
177 */
178 this.showFilePicker = function showFilePicker(path, toSave, parentWindow,
179 callback, suggestedFilename)
180 {
181 if (typeof(path) == "string") {
182 try {
183 if (Services.io.extractScheme(path) == "file") {
184 let uri = Services.io.newURI(path, null, null);
185 let file = uri.QueryInterface(Ci.nsIFileURL).file;
186 callback(file);
187 return;
188 }
189 } catch (ex) {
190 callback(null);
191 return;
192 }
193 try {
194 let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
195 file.initWithPath(path);
196 callback(file);
197 return;
198 } catch (ex) {
199 callback(null);
200 return;
201 }
202 }
203 if (path) { // "path" is an nsIFile
204 callback(path);
205 return;
206 }
207
208 let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
209 let mode = toSave ? fp.modeSave : fp.modeOpen;
210 let key = toSave ? "saveStyleSheet" : "importStyleSheet";
211 let fpCallback = function(result) {
212 if (result == Ci.nsIFilePicker.returnCancel) {
213 callback(null);
214 } else {
215 callback(fp.file);
216 }
217 };
218
219 if (toSave && suggestedFilename) {
220 fp.defaultString = suggestedFilename;
221 }
222
223 fp.init(parentWindow, _(key + ".title"), mode);
224 fp.appendFilters(_(key + ".filter"), "*.css");
225 fp.appendFilters(fp.filterAll);
226 fp.open(fpCallback);
227 return;
228 }

mercurial