StyleEditorUtil.sys.mjs (5208B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 const PROPERTIES_URL = "chrome://devtools/locale/styleeditor.properties"; 6 7 import { loader } from "resource://devtools/shared/loader/Loader.sys.mjs"; 8 9 const gStringBundle = Services.strings.createBundle(PROPERTIES_URL); 10 11 const lazy = {}; 12 13 loader.lazyRequireGetter( 14 lazy, 15 "Menu", 16 "resource://devtools/client/framework/menu.js" 17 ); 18 loader.lazyRequireGetter( 19 lazy, 20 "MenuItem", 21 "resource://devtools/client/framework/menu-item.js" 22 ); 23 24 const PREF_AT_RULES_SIDEBAR = "devtools.styleeditor.showAtRulesSidebar"; 25 const PREF_ORIG_SOURCES = "devtools.source-map.client-service.enabled"; 26 27 /** 28 * Returns a localized string with the given key name from the string bundle. 29 * 30 * @param name 31 * @param ...rest 32 * Optional arguments to format in the string. 33 * @return string 34 */ 35 export function getString(name) { 36 try { 37 if (arguments.length == 1) { 38 return gStringBundle.GetStringFromName(name); 39 } 40 const rest = Array.prototype.slice.call(arguments, 1); 41 return gStringBundle.formatStringFromName(name, rest); 42 } catch (ex) { 43 console.error(ex); 44 throw new Error( 45 "L10N error. '" + name + "' is missing from " + PROPERTIES_URL 46 ); 47 } 48 } 49 50 /** 51 * Retrieve or set the text content of an element. 52 * 53 * @param DOMElement root 54 * The element to use for querySelector. 55 * @param string selector 56 * Selector string for the element to get/set the text content. 57 * @param string textContent 58 * Optional text to set. 59 * @return string 60 * Text content of matching element or null if there were no element 61 * matching selector. 62 */ 63 export function text(root, selector, textContent) { 64 const element = root.querySelector(selector); 65 if (!element) { 66 return null; 67 } 68 69 if (textContent === undefined) { 70 return element.textContent; 71 } 72 element.textContent = textContent; 73 return textContent; 74 } 75 76 /** 77 * Show file picker and return the file user selected. 78 * 79 * @param mixed file 80 * Optional nsIFile or string representing the filename to auto-select. 81 * @param boolean toSave 82 * If true, the user is selecting a filename to save. 83 * @param nsIWindow parentWindow 84 * Optional parent window. If null the parent window of the file picker 85 * will be the window of the attached input element. 86 * @param callback 87 * The callback method, which will be called passing in the selected 88 * file or null if the user did not pick one. 89 * @param AString suggestedFilename 90 * The suggested filename when toSave is true. 91 */ 92 export function showFilePicker( 93 path, 94 toSave, 95 parentWindow, 96 callback, 97 suggestedFilename 98 ) { 99 if (typeof path == "string") { 100 try { 101 if (Services.io.extractScheme(path) == "file") { 102 const uri = Services.io.newURI(path); 103 const file = uri.QueryInterface(Ci.nsIFileURL).file; 104 callback(file); 105 return; 106 } 107 } catch (ex) { 108 callback(null); 109 return; 110 } 111 try { 112 const file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); 113 file.initWithPath(path); 114 callback(file); 115 return; 116 } catch (ex) { 117 callback(null); 118 return; 119 } 120 } 121 if (path) { 122 // "path" is an nsIFile 123 callback(path); 124 return; 125 } 126 127 const fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); 128 const mode = toSave ? fp.modeSave : fp.modeOpen; 129 const key = toSave ? "saveStyleSheet" : "importStyleSheet"; 130 const fpCallback = function (result) { 131 if (result == Ci.nsIFilePicker.returnCancel) { 132 callback(null); 133 } else { 134 callback(fp.file); 135 } 136 }; 137 138 if (toSave && suggestedFilename) { 139 fp.defaultString = suggestedFilename; 140 } 141 142 fp.init(parentWindow.browsingContext, getString(key + ".title"), mode); 143 fp.appendFilter(getString(key + ".filter"), "*.css"); 144 fp.appendFilters(fp.filterAll); 145 fp.open(fpCallback); 146 } 147 148 /** 149 * Returns a Popup Menu for the Options ("gear") Button 150 * 151 * @param {function} toggleOrigSources 152 * To toggle the original source pref 153 * @param {function} toggleAtRulesSidebar 154 * To toggle the pref to show at-rules side bar 155 * @return {object} popupMenu 156 * A Menu object holding the MenuItems 157 */ 158 export function optionsPopupMenu(toggleOrigSources, toggleAtRulesSidebar) { 159 const popupMenu = new lazy.Menu(); 160 popupMenu.append( 161 new lazy.MenuItem({ 162 id: "options-origsources", 163 label: getString("showOriginalSources.label"), 164 accesskey: getString("showOriginalSources.accesskey"), 165 type: "checkbox", 166 checked: Services.prefs.getBoolPref(PREF_ORIG_SOURCES), 167 click: () => toggleOrigSources(), 168 }) 169 ); 170 popupMenu.append( 171 new lazy.MenuItem({ 172 id: "options-show-at-rules", 173 label: getString("showAtRulesSidebar.label"), 174 accesskey: getString("showAtRulesSidebar.accesskey"), 175 type: "checkbox", 176 checked: Services.prefs.getBoolPref(PREF_AT_RULES_SIDEBAR), 177 click: () => toggleAtRulesSidebar(), 178 }) 179 ); 180 181 return popupMenu; 182 }