feat: add old about:configs
This commit is contained in:
@@ -16,6 +16,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||||||
TabFeatures: "resource:///modules/TabFeatures.sys.mjs",
|
TabFeatures: "resource:///modules/TabFeatures.sys.mjs",
|
||||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
UICustomizations: "resource:///modules/UICustomizations.sys.mjs",
|
UICustomizations: "resource:///modules/UICustomizations.sys.mjs",
|
||||||
|
AboutCfg: "resource:///modules/AboutCfg.sys.mjs",
|
||||||
});
|
});
|
||||||
|
|
||||||
const WATERFOX_CUSTOMIZATIONS_PREF =
|
const WATERFOX_CUSTOMIZATIONS_PREF =
|
||||||
@@ -72,6 +73,8 @@ export const WaterfoxGlue = {
|
|||||||
Services.obs.addObserver(this, "quit-application-granted");
|
Services.obs.addObserver(this, "quit-application-granted");
|
||||||
// Listen for addon events
|
// Listen for addon events
|
||||||
this.addAddonListener();
|
this.addAddonListener();
|
||||||
|
// Register about:cfg
|
||||||
|
lazy.AboutCfg.init();
|
||||||
},
|
},
|
||||||
|
|
||||||
async _setPrefObservers() {
|
async _setPrefObservers() {
|
||||||
|
|||||||
57
waterfox/browser/components/aboutcfg/AboutCfg.sys.mjs
Normal file
57
waterfox/browser/components/aboutcfg/AboutCfg.sys.mjs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
// https://github.com/earthlng/aboutconfig/blob/main/aboutcfg.jsm
|
||||||
|
const registrar = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||||
|
|
||||||
|
// generate a unique ID on every app launch. protection against the very unlikely possibility that a
|
||||||
|
// future update adds a component with the same class ID, which would break the script.
|
||||||
|
function generateFreeCID() {
|
||||||
|
let uuid = Components.ID(Services.uuid.generateUUID().toString());
|
||||||
|
// I can't tell whether generateUUID is guaranteed to produce a unique ID, or just a random ID.
|
||||||
|
// so I add this loop to regenerate it in the extremely unlikely (or potentially impossible)
|
||||||
|
// event that the UUID is already registered as a CID.
|
||||||
|
while (registrar.isCIDRegistered(uuid)) {
|
||||||
|
uuid = Components.ID(Services.uuid.generateUUID().toString());
|
||||||
|
}
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function VintageAboutConfig() {}
|
||||||
|
VintageAboutConfig.prototype = {
|
||||||
|
get uri() {
|
||||||
|
const urlString = 'chrome://browser/content/aboutcfg/aboutcfg.xhtml';
|
||||||
|
return this._uri || (this._uri = Services.io.newURI(urlString));
|
||||||
|
},
|
||||||
|
newChannel: function (_uri, loadInfo) {
|
||||||
|
const ch = Services.io.newChannelFromURIWithLoadInfo(this.uri, loadInfo);
|
||||||
|
ch.owner = Services.scriptSecurityManager.getSystemPrincipal();
|
||||||
|
return ch;
|
||||||
|
},
|
||||||
|
getURIFlags: function (_uri) {
|
||||||
|
return Components.interfaces.nsIAboutModule.ALLOW_SCRIPT | Components.interfaces.nsIAboutModule.IS_SECURE_CHROME_UI;
|
||||||
|
},
|
||||||
|
getChromeURI: function (_uri) {
|
||||||
|
return this.uri;
|
||||||
|
},
|
||||||
|
QueryInterface: ChromeUtils.generateQI(['nsIAboutModule']),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AboutCfg = {
|
||||||
|
init() {
|
||||||
|
const AboutModuleFactory = {
|
||||||
|
createInstance(aIID) {
|
||||||
|
return new VintageAboutConfig().QueryInterface(aIID);
|
||||||
|
},
|
||||||
|
QueryInterface: ChromeUtils.generateQI(['nsIFactory']),
|
||||||
|
};
|
||||||
|
|
||||||
|
registrar.registerFactory(
|
||||||
|
generateFreeCID(),
|
||||||
|
'about:cfg',
|
||||||
|
'@mozilla.org/network/protocol/about;1?what=cfg',
|
||||||
|
AboutModuleFactory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
63
waterfox/browser/components/aboutcfg/aboutcfg.css
Normal file
63
waterfox/browser/components/aboutcfg/aboutcfg.css
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#warningScreen {
|
||||||
|
font-size: 15px;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
padding-inline-start: calc(48px + 4.6em);
|
||||||
|
padding-inline-end: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
background-image: url("chrome://global/skin/icons/warning.svg");
|
||||||
|
fill: #fcd100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warningTitle {
|
||||||
|
font-weight: lighter;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warningText {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warningButton {
|
||||||
|
margin-top: 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filterRow {
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-inline-start: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configTree {
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configTreeBody::-moz-tree-cell-text(user) {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configTreeBody::-moz-tree-cell-text(locked) {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
#prefCol,
|
||||||
|
#valueCol {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#lockCol,
|
||||||
|
#typeCol {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deck-selected {
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
783
waterfox/browser/components/aboutcfg/aboutcfg.js
Normal file
783
waterfox/browser/components/aboutcfg/aboutcfg.js
Normal file
@@ -0,0 +1,783 @@
|
|||||||
|
/* 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 nsIPrefLocalizedString = Ci.nsIPrefLocalizedString;
|
||||||
|
const _nsISupportsString = Ci.nsISupportsString;
|
||||||
|
const nsIPrefBranch = Ci.nsIPrefBranch;
|
||||||
|
const nsIClipboardHelper = Ci.nsIClipboardHelper;
|
||||||
|
|
||||||
|
const nsClipboardHelper_CONTRACTID = "@mozilla.org/widget/clipboardhelper;1";
|
||||||
|
|
||||||
|
const gPrefBranch = Services.prefs;
|
||||||
|
const gClipboardHelper =
|
||||||
|
Cc[nsClipboardHelper_CONTRACTID].getService(nsIClipboardHelper);
|
||||||
|
|
||||||
|
const gLockProps = ["default", "user", "locked"];
|
||||||
|
// we get these from a string bundle
|
||||||
|
const gLockStrs = [];
|
||||||
|
const gTypeStrs = [];
|
||||||
|
|
||||||
|
const PREF_IS_DEFAULT_VALUE = 0;
|
||||||
|
const PREF_IS_MODIFIED = 1;
|
||||||
|
const PREF_IS_LOCKED = 2;
|
||||||
|
|
||||||
|
const gPrefHash = {};
|
||||||
|
const gPrefArray = [];
|
||||||
|
let gPrefView = gPrefArray; // share the JS array
|
||||||
|
let gSortedColumn = "prefCol";
|
||||||
|
let gSortFunction = null;
|
||||||
|
let gSortDirection = 1; // 1 is ascending; -1 is descending
|
||||||
|
let gFilter = null;
|
||||||
|
|
||||||
|
const view = {
|
||||||
|
get rowCount() {
|
||||||
|
return gPrefView.length;
|
||||||
|
},
|
||||||
|
getCellText(index, col) {
|
||||||
|
if (!(index in gPrefView)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = gPrefView[index][col.id];
|
||||||
|
|
||||||
|
switch (col.id) {
|
||||||
|
case "lockCol":
|
||||||
|
return gLockStrs[value];
|
||||||
|
case "typeCol":
|
||||||
|
return gTypeStrs[value];
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getRowProperties(_index) {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
getCellProperties(index, _col) {
|
||||||
|
if (index in gPrefView) {
|
||||||
|
return gLockProps[gPrefView[index].lockCol];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
getColumnProperties(_col) {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
treebox: null,
|
||||||
|
selection: null,
|
||||||
|
isContainer(_index) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
isContainerOpen(_index) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
isContainerEmpty(_index) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
isSorted() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
canDrop(_index, _orientation) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
drop(_row, _orientation) {},
|
||||||
|
setTree(out) {
|
||||||
|
this.treebox = out;
|
||||||
|
},
|
||||||
|
getParentIndex(_rowIndex) {
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
|
hasNextSibling(_rowIndex, _afterIndex) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
getLevel(_index) {
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
getImageSrc(_row, _col) {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
toggleOpenState(_index) {},
|
||||||
|
cycleHeader(col) {
|
||||||
|
let index = this.selection.currentIndex;
|
||||||
|
if (col.id === gSortedColumn) {
|
||||||
|
gSortDirection = -gSortDirection;
|
||||||
|
gPrefArray.reverse();
|
||||||
|
if (gPrefView !== gPrefArray) {
|
||||||
|
gPrefView.reverse();
|
||||||
|
}
|
||||||
|
if (index >= 0) {
|
||||||
|
index = gPrefView.length - index - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let pref = null;
|
||||||
|
if (index >= 0) {
|
||||||
|
pref = gPrefView[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const old = document.getElementById(gSortedColumn);
|
||||||
|
old.removeAttribute("sortDirection");
|
||||||
|
gSortFunction = gSortFunctions[col.id];
|
||||||
|
gPrefArray.sort(gSortFunction);
|
||||||
|
if (gPrefView !== gPrefArray) {
|
||||||
|
gPrefView.sort(gSortFunction);
|
||||||
|
}
|
||||||
|
gSortedColumn = col.id;
|
||||||
|
if (pref) {
|
||||||
|
index = getViewIndexOfPref(pref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col.element.setAttribute(
|
||||||
|
"sortDirection",
|
||||||
|
gSortDirection > 0 ? "ascending" : "descending"
|
||||||
|
);
|
||||||
|
this.treebox.invalidate();
|
||||||
|
if (index >= 0) {
|
||||||
|
this.selection.select(index);
|
||||||
|
this.treebox.ensureRowIsVisible(index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectionChanged() {},
|
||||||
|
cycleCell(_row, _col) {},
|
||||||
|
isEditable(_row, _col) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
setCellValue(_row, _col, _value) {},
|
||||||
|
setCellText(_row, _col, _value) {},
|
||||||
|
isSeparator(_index) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// find the index in gPrefView of a pref object
|
||||||
|
// or -1 if it does not exist in the filtered view
|
||||||
|
function getViewIndexOfPref(pref) {
|
||||||
|
let low = -1;
|
||||||
|
let high = gPrefView.length;
|
||||||
|
let index = (low + high) >> 1;
|
||||||
|
while (index > low) {
|
||||||
|
const mid = gPrefView[index];
|
||||||
|
if (mid === pref) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
if (gSortFunction(mid, pref) < 0) {
|
||||||
|
low = index;
|
||||||
|
} else {
|
||||||
|
high = index;
|
||||||
|
}
|
||||||
|
index = (low + high) >> 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the index in gPrefView where a pref object belongs
|
||||||
|
function getNearestViewIndexOfPref(pref) {
|
||||||
|
let low = -1;
|
||||||
|
let high = gPrefView.length;
|
||||||
|
let index = (low + high) >> 1;
|
||||||
|
while (index > low) {
|
||||||
|
if (gSortFunction(gPrefView[index], pref) < 0) {
|
||||||
|
low = index;
|
||||||
|
} else {
|
||||||
|
high = index;
|
||||||
|
}
|
||||||
|
index = (low + high) >> 1;
|
||||||
|
}
|
||||||
|
return high;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the index in gPrefArray of a pref object
|
||||||
|
function getIndexOfPref(pref) {
|
||||||
|
let low = -1;
|
||||||
|
let high = gPrefArray.length;
|
||||||
|
let index = (low + high) >> 1;
|
||||||
|
while (index > low) {
|
||||||
|
const mid = gPrefArray[index];
|
||||||
|
if (mid === pref) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
if (gSortFunction(mid, pref) < 0) {
|
||||||
|
low = index;
|
||||||
|
} else {
|
||||||
|
high = index;
|
||||||
|
}
|
||||||
|
index = (low + high) >> 1;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNearestIndexOfPref(pref) {
|
||||||
|
let low = -1;
|
||||||
|
let high = gPrefArray.length;
|
||||||
|
let index = (low + high) >> 1;
|
||||||
|
while (index > low) {
|
||||||
|
if (gSortFunction(gPrefArray[index], pref) < 0) {
|
||||||
|
low = index;
|
||||||
|
} else {
|
||||||
|
high = index;
|
||||||
|
}
|
||||||
|
index = (low + high) >> 1;
|
||||||
|
}
|
||||||
|
return high;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gPrefListener = {
|
||||||
|
observe(_subject, topic, prefName) {
|
||||||
|
if (topic !== "nsPref:changed") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let arrayIndex = gPrefArray.length;
|
||||||
|
let viewIndex = arrayIndex;
|
||||||
|
let selectedIndex = view.selection.currentIndex;
|
||||||
|
let pref;
|
||||||
|
let updateView = false;
|
||||||
|
let updateArray = false;
|
||||||
|
let addedRow = false;
|
||||||
|
if (prefName in gPrefHash) {
|
||||||
|
pref = gPrefHash[prefName];
|
||||||
|
viewIndex = getViewIndexOfPref(pref);
|
||||||
|
arrayIndex = getIndexOfPref(pref);
|
||||||
|
fetchPref(prefName, arrayIndex);
|
||||||
|
// fetchPref replaces the existing pref object
|
||||||
|
pref = gPrefHash[prefName];
|
||||||
|
if (viewIndex >= 0) {
|
||||||
|
// Might need to update the filtered view
|
||||||
|
gPrefView[viewIndex] = gPrefHash[prefName];
|
||||||
|
view.treebox.invalidateRow(viewIndex);
|
||||||
|
}
|
||||||
|
if (gSortedColumn === "lockCol" || gSortedColumn === "valueCol") {
|
||||||
|
updateArray = true;
|
||||||
|
gPrefArray.splice(arrayIndex, 1);
|
||||||
|
if (gFilter?.test(`${pref.prefCol};${pref.valueCol}`)) {
|
||||||
|
updateView = true;
|
||||||
|
gPrefView.splice(viewIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fetchPref(prefName, arrayIndex);
|
||||||
|
pref = gPrefArray.pop();
|
||||||
|
updateArray = true;
|
||||||
|
addedRow = true;
|
||||||
|
if (gFilter?.test(`${pref.prefCol};${pref.valueCol}`)) {
|
||||||
|
updateView = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (updateArray) {
|
||||||
|
// Reinsert in the data array
|
||||||
|
let newIndex = getNearestIndexOfPref(pref);
|
||||||
|
gPrefArray.splice(newIndex, 0, pref);
|
||||||
|
|
||||||
|
if (updateView) {
|
||||||
|
// View is filtered, reinsert in the view separately
|
||||||
|
newIndex = getNearestViewIndexOfPref(pref);
|
||||||
|
gPrefView.splice(newIndex, 0, pref);
|
||||||
|
} else if (gFilter) {
|
||||||
|
// View is filtered, but nothing to update
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addedRow) {
|
||||||
|
view.treebox.rowCountChanged(newIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate the changed range in the view
|
||||||
|
const low = Math.min(viewIndex, newIndex);
|
||||||
|
const high = Math.max(viewIndex, newIndex);
|
||||||
|
view.treebox.invalidateRange(low, high);
|
||||||
|
|
||||||
|
if (selectedIndex === viewIndex) {
|
||||||
|
selectedIndex = newIndex;
|
||||||
|
} else if (selectedIndex >= low && selectedIndex <= high) {
|
||||||
|
selectedIndex += newIndex > viewIndex ? -1 : 1;
|
||||||
|
}
|
||||||
|
if (selectedIndex >= 0) {
|
||||||
|
view.selection.select(selectedIndex);
|
||||||
|
if (selectedIndex === newIndex) {
|
||||||
|
view.treebox.ensureRowIsVisible(selectedIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
class prefObject {
|
||||||
|
constructor(prefName, _prefIndex) {
|
||||||
|
this.prefCol = prefName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prefObject.prototype = {
|
||||||
|
lockCol: PREF_IS_DEFAULT_VALUE,
|
||||||
|
typeCol: nsIPrefBranch.PREF_STRING,
|
||||||
|
valueCol: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
function fetchPref(prefName, prefIndex) {
|
||||||
|
const pref = new prefObject(prefName);
|
||||||
|
|
||||||
|
gPrefHash[prefName] = pref;
|
||||||
|
gPrefArray[prefIndex] = pref;
|
||||||
|
|
||||||
|
if (gPrefBranch.prefIsLocked(prefName)) {
|
||||||
|
pref.lockCol = PREF_IS_LOCKED;
|
||||||
|
} else if (gPrefBranch.prefHasUserValue(prefName)) {
|
||||||
|
pref.lockCol = PREF_IS_MODIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (gPrefBranch.getPrefType(prefName)) {
|
||||||
|
case gPrefBranch.PREF_BOOL:
|
||||||
|
pref.typeCol = gPrefBranch.PREF_BOOL;
|
||||||
|
// convert to a string
|
||||||
|
pref.valueCol = gPrefBranch.getBoolPref(prefName).toString();
|
||||||
|
break;
|
||||||
|
case gPrefBranch.PREF_INT:
|
||||||
|
pref.typeCol = gPrefBranch.PREF_INT;
|
||||||
|
// convert to a string
|
||||||
|
pref.valueCol = gPrefBranch.getIntPref(prefName).toString();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pref.valueCol = gPrefBranch.getStringPref(prefName);
|
||||||
|
// Try in case it's a localized string (will throw an exception if not)
|
||||||
|
if (
|
||||||
|
pref.lockCol === PREF_IS_DEFAULT_VALUE &&
|
||||||
|
/^chrome:\/\/.+\/locale\/.+\.properties/.test(pref.valueCol)
|
||||||
|
) {
|
||||||
|
pref.valueCol = gPrefBranch.getComplexValue(
|
||||||
|
prefName,
|
||||||
|
nsIPrefLocalizedString
|
||||||
|
).data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
// Also catch obscure cases in which you can't tell in advance
|
||||||
|
// that the pref exists but has no user or default value...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onConfigLoad() {
|
||||||
|
const configContext = document.getElementById("configContext");
|
||||||
|
configContext.addEventListener("popupshowing", function (event) {
|
||||||
|
if (event.target === this) {
|
||||||
|
updateContextMenu();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const commandListeners = {
|
||||||
|
toggleSelected: ModifySelected,
|
||||||
|
modifySelected: ModifySelected,
|
||||||
|
copyPref,
|
||||||
|
copyName,
|
||||||
|
copyValue,
|
||||||
|
resetSelected: ResetSelected,
|
||||||
|
};
|
||||||
|
|
||||||
|
configContext.addEventListener("command", (e) => {
|
||||||
|
if (e.target.id in commandListeners) {
|
||||||
|
commandListeners[e.target.id]();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const configString = document.getElementById("configString");
|
||||||
|
configString.addEventListener("command", () => {
|
||||||
|
NewPref(nsIPrefBranch.PREF_STRING);
|
||||||
|
});
|
||||||
|
|
||||||
|
const configInt = document.getElementById("configInt");
|
||||||
|
configInt.addEventListener("command", () => {
|
||||||
|
NewPref(nsIPrefBranch.PREF_INT);
|
||||||
|
});
|
||||||
|
|
||||||
|
const configBool = document.getElementById("configBool");
|
||||||
|
configBool.addEventListener("command", () => {
|
||||||
|
NewPref(nsIPrefBranch.PREF_BOOL);
|
||||||
|
});
|
||||||
|
|
||||||
|
const keyVKReturn = document.getElementById("keyVKReturn");
|
||||||
|
keyVKReturn.addEventListener("command", ModifySelected);
|
||||||
|
|
||||||
|
const textBox = document.getElementById("textbox");
|
||||||
|
textBox.addEventListener("command", FilterPrefs);
|
||||||
|
|
||||||
|
const configFocuSearch = document.getElementById("configFocuSearch");
|
||||||
|
configFocuSearch.addEventListener("command", () => {
|
||||||
|
textBox.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
const configFocuSearch2 = document.getElementById("configFocuSearch2");
|
||||||
|
configFocuSearch2.addEventListener("command", () => {
|
||||||
|
textBox.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
const warningButton = document.getElementById("warningButton");
|
||||||
|
warningButton.addEventListener("command", ShowPrefs);
|
||||||
|
|
||||||
|
const configTree = document.getElementById("configTree");
|
||||||
|
configTree.addEventListener("select", () => {
|
||||||
|
window.updateCommands("select");
|
||||||
|
});
|
||||||
|
|
||||||
|
const configTreeBody = document.getElementById("configTreeBody");
|
||||||
|
configTreeBody.addEventListener("dblclick", (event) => {
|
||||||
|
if (event.button === 0) {
|
||||||
|
ModifySelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
gLockStrs[PREF_IS_DEFAULT_VALUE] = "default";
|
||||||
|
gLockStrs[PREF_IS_MODIFIED] = "modified";
|
||||||
|
gLockStrs[PREF_IS_LOCKED] = "locked";
|
||||||
|
gTypeStrs[nsIPrefBranch.PREF_STRING] = "string";
|
||||||
|
gTypeStrs[nsIPrefBranch.PREF_INT] = "integer";
|
||||||
|
gTypeStrs[nsIPrefBranch.PREF_BOOL] = "boolean";
|
||||||
|
|
||||||
|
const showWarning = gPrefBranch.getBoolPref("general.warnOnAboutConfig");
|
||||||
|
|
||||||
|
if (showWarning) {
|
||||||
|
document.getElementById("warningButton").focus();
|
||||||
|
} else {
|
||||||
|
ShowPrefs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unhide the warning message
|
||||||
|
function ShowPrefs() {
|
||||||
|
document.getElementById("configDeck").lastElementChild.style.visibility =
|
||||||
|
"visible";
|
||||||
|
gPrefBranch.getChildList("").forEach(fetchPref);
|
||||||
|
|
||||||
|
const descending = document.getElementsByAttribute(
|
||||||
|
"sortDirection",
|
||||||
|
"descending"
|
||||||
|
);
|
||||||
|
if (descending.item(0)) {
|
||||||
|
gSortedColumn = descending[0].id;
|
||||||
|
gSortDirection = -1;
|
||||||
|
} else {
|
||||||
|
const ascending = document.getElementsByAttribute(
|
||||||
|
"sortDirection",
|
||||||
|
"ascending"
|
||||||
|
);
|
||||||
|
if (ascending.item(0)) {
|
||||||
|
gSortedColumn = ascending[0].id;
|
||||||
|
} else {
|
||||||
|
document
|
||||||
|
.getElementById(gSortedColumn)
|
||||||
|
.setAttribute("sortDirection", "ascending");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gSortFunction = gSortFunctions[gSortedColumn];
|
||||||
|
gPrefArray.sort(gSortFunction);
|
||||||
|
|
||||||
|
gPrefBranch.addObserver("", gPrefListener);
|
||||||
|
|
||||||
|
const configTree = document.getElementById("configTree");
|
||||||
|
configTree.view = view;
|
||||||
|
configTree.controllers.insertControllerAt(0, configController);
|
||||||
|
|
||||||
|
document.getElementById("configDeck").setAttribute("selectedIndex", 1);
|
||||||
|
document.getElementById("configTreeKeyset").removeAttribute("disabled");
|
||||||
|
if (!document.getElementById("showWarningNextTime").checked) {
|
||||||
|
gPrefBranch.setBoolPref("general.warnOnAboutConfig", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process about:config?filter=<string>
|
||||||
|
const textbox = document.getElementById("textbox");
|
||||||
|
// About URIs don't support query params, so do this manually
|
||||||
|
const loc = document.location.href;
|
||||||
|
const matches = /[?&]filter=([^&]+)/i.exec(loc);
|
||||||
|
if (matches) {
|
||||||
|
textbox.value = decodeURIComponent(matches[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even if we did not set the filter string via the URL query,
|
||||||
|
// textbox might have been set via some other mechanism
|
||||||
|
if (textbox.value) {
|
||||||
|
FilterPrefs();
|
||||||
|
}
|
||||||
|
textbox.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onConfigUnload() {
|
||||||
|
if (
|
||||||
|
document.getElementById("configDeck").getAttribute("selectedIndex") === 1
|
||||||
|
) {
|
||||||
|
gPrefBranch.removeObserver("", gPrefListener);
|
||||||
|
const configTree = document.getElementById("configTree");
|
||||||
|
configTree.view = null;
|
||||||
|
configTree.controllers.removeController(configController);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function FilterPrefs() {
|
||||||
|
if (
|
||||||
|
document.getElementById("configDeck").getAttribute("selectedIndex") !== 1
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const substring = document.getElementById("textbox").value;
|
||||||
|
// Check for "/regex/[i]"
|
||||||
|
if (substring.charAt(0) === "/") {
|
||||||
|
const r = substring.match(/^\/(.*)\/(i?)$/);
|
||||||
|
try {
|
||||||
|
gFilter = RegExp(r[1], r[2]);
|
||||||
|
} catch (_e) {
|
||||||
|
return; // Do nothing on incomplete or bad RegExp
|
||||||
|
}
|
||||||
|
} else if (substring) {
|
||||||
|
gFilter = RegExp(
|
||||||
|
substring
|
||||||
|
.replace(/([^* \w])/g, "\\$1")
|
||||||
|
.replace(/^\*+/, "")
|
||||||
|
.replace(/\*+/g, ".*"),
|
||||||
|
"i"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
gFilter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefCol =
|
||||||
|
view.selection && view.selection.currentIndex < 0
|
||||||
|
? null
|
||||||
|
: gPrefView[view.selection.currentIndex].prefCol;
|
||||||
|
const oldlen = gPrefView.length;
|
||||||
|
gPrefView = gPrefArray;
|
||||||
|
if (gFilter) {
|
||||||
|
gPrefView = [];
|
||||||
|
for (let i = 0; i < gPrefArray.length; ++i) {
|
||||||
|
if (gFilter.test(`${gPrefArray[i].prefCol};${gPrefArray[i].valueCol}`)) {
|
||||||
|
gPrefView.push(gPrefArray[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view.treebox.invalidate();
|
||||||
|
view.treebox.rowCountChanged(oldlen, gPrefView.length - oldlen);
|
||||||
|
gotoPref(prefCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
function prefColSortFunction(x, y) {
|
||||||
|
if (x.prefCol > y.prefCol) {
|
||||||
|
return gSortDirection;
|
||||||
|
}
|
||||||
|
if (x.prefCol < y.prefCol) {
|
||||||
|
return -gSortDirection;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lockColSortFunction(x, y) {
|
||||||
|
if (x.lockCol !== y.lockCol) {
|
||||||
|
return gSortDirection * (y.lockCol - x.lockCol);
|
||||||
|
}
|
||||||
|
return prefColSortFunction(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeColSortFunction(x, y) {
|
||||||
|
if (x.typeCol !== y.typeCol) {
|
||||||
|
return gSortDirection * (y.typeCol - x.typeCol);
|
||||||
|
}
|
||||||
|
return prefColSortFunction(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function valueColSortFunction(x, y) {
|
||||||
|
if (x.valueCol > y.valueCol) {
|
||||||
|
return gSortDirection;
|
||||||
|
}
|
||||||
|
if (x.valueCol < y.valueCol) {
|
||||||
|
return -gSortDirection;
|
||||||
|
}
|
||||||
|
return prefColSortFunction(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gSortFunctions = {
|
||||||
|
prefCol: prefColSortFunction,
|
||||||
|
lockCol: lockColSortFunction,
|
||||||
|
typeCol: typeColSortFunction,
|
||||||
|
valueCol: valueColSortFunction,
|
||||||
|
};
|
||||||
|
|
||||||
|
const _gCategoryLabelForSortColumn = {
|
||||||
|
prefCol: "SortByName",
|
||||||
|
lockCol: "SortByStatus",
|
||||||
|
typeCol: "SortByType",
|
||||||
|
valueCol: "SortByValue",
|
||||||
|
};
|
||||||
|
|
||||||
|
const configController = {
|
||||||
|
supportsCommand: function supportsCommand(command) {
|
||||||
|
return command === "cmd_copy";
|
||||||
|
},
|
||||||
|
isCommandEnabled: function isCommandEnabled(_command) {
|
||||||
|
return view.selection && view.selection.currentIndex >= 0;
|
||||||
|
},
|
||||||
|
doCommand: function doCommand(_command) {
|
||||||
|
copyPref();
|
||||||
|
},
|
||||||
|
onEvent: function onEvent(_event) {},
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateContextMenu() {
|
||||||
|
let lockCol = PREF_IS_LOCKED;
|
||||||
|
let typeCol = nsIPrefBranch.PREF_STRING;
|
||||||
|
let valueCol = "";
|
||||||
|
let copyDisabled = true;
|
||||||
|
const prefSelected = view.selection.currentIndex >= 0;
|
||||||
|
|
||||||
|
if (prefSelected) {
|
||||||
|
const prefRow = gPrefView[view.selection.currentIndex];
|
||||||
|
lockCol = prefRow.lockCol;
|
||||||
|
typeCol = prefRow.typeCol;
|
||||||
|
valueCol = prefRow.valueCol;
|
||||||
|
copyDisabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyPref = document.getElementById("copyPref");
|
||||||
|
copyPref.setAttribute("disabled", copyDisabled);
|
||||||
|
|
||||||
|
const copyName = document.getElementById("copyName");
|
||||||
|
copyName.setAttribute("disabled", copyDisabled);
|
||||||
|
|
||||||
|
const copyValue = document.getElementById("copyValue");
|
||||||
|
copyValue.setAttribute("disabled", copyDisabled);
|
||||||
|
|
||||||
|
const resetSelected = document.getElementById("resetSelected");
|
||||||
|
resetSelected.setAttribute("disabled", lockCol !== PREF_IS_MODIFIED);
|
||||||
|
|
||||||
|
const canToggle = typeCol === nsIPrefBranch.PREF_BOOL && valueCol !== "";
|
||||||
|
// indicates that a pref is locked or no pref is selected at all
|
||||||
|
const isLocked = lockCol === PREF_IS_LOCKED;
|
||||||
|
|
||||||
|
const modifySelected = document.getElementById("modifySelected");
|
||||||
|
modifySelected.setAttribute("disabled", isLocked);
|
||||||
|
modifySelected.hidden = canToggle;
|
||||||
|
|
||||||
|
const toggleSelected = document.getElementById("toggleSelected");
|
||||||
|
toggleSelected.setAttribute("disabled", isLocked);
|
||||||
|
toggleSelected.hidden = !canToggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyPref() {
|
||||||
|
const pref = gPrefView[view.selection.currentIndex];
|
||||||
|
gClipboardHelper.copyString(`${pref.prefCol};${pref.valueCol}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyName() {
|
||||||
|
gClipboardHelper.copyString(gPrefView[view.selection.currentIndex].prefCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyValue() {
|
||||||
|
gClipboardHelper.copyString(gPrefView[view.selection.currentIndex].valueCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ModifySelected() {
|
||||||
|
if (view.selection.currentIndex >= 0) {
|
||||||
|
ModifyPref(gPrefView[view.selection.currentIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ResetSelected() {
|
||||||
|
const entry = gPrefView[view.selection.currentIndex];
|
||||||
|
gPrefBranch.clearUserPref(entry.prefCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function NewPref(type) {
|
||||||
|
const result = { value: "" };
|
||||||
|
const dummy = { value: 0 };
|
||||||
|
|
||||||
|
const [newTitle, newPrompt] = [
|
||||||
|
`New ${gTypeStrs[type]} value`,
|
||||||
|
"Enter the preference name",
|
||||||
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
Services.prompt.prompt(window, newTitle, newPrompt, result, null, dummy)
|
||||||
|
) {
|
||||||
|
result.value = result.value.trim();
|
||||||
|
if (!result.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pref;
|
||||||
|
if (result.value in gPrefHash) {
|
||||||
|
pref = gPrefHash[result.value];
|
||||||
|
} else {
|
||||||
|
pref = {
|
||||||
|
prefCol: result.value,
|
||||||
|
lockCol: PREF_IS_DEFAULT_VALUE,
|
||||||
|
typeCol: type,
|
||||||
|
valueCol: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (ModifyPref(pref)) {
|
||||||
|
setTimeout(gotoPref, 0, result.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoPref(pref) {
|
||||||
|
// make sure the pref exists and is displayed in the current view
|
||||||
|
const index = pref in gPrefHash ? getViewIndexOfPref(gPrefHash[pref]) : -1;
|
||||||
|
if (index >= 0) {
|
||||||
|
view.selection.select(index);
|
||||||
|
view.treebox.ensureRowIsVisible(index);
|
||||||
|
} else {
|
||||||
|
view.selection.clearSelection();
|
||||||
|
view.selection.currentIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ModifyPref(entry) {
|
||||||
|
if (entry.lockCol === PREF_IS_LOCKED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [title] = [`Enter ${gTypeStrs[entry.typeCol]} value`];
|
||||||
|
|
||||||
|
if (entry.typeCol === nsIPrefBranch.PREF_BOOL) {
|
||||||
|
const check = { value: entry.valueCol === "false" };
|
||||||
|
if (
|
||||||
|
!entry.valueCol &&
|
||||||
|
!Services.prompt.select(
|
||||||
|
window,
|
||||||
|
title,
|
||||||
|
entry.prefCol,
|
||||||
|
[false, true],
|
||||||
|
check
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
gPrefBranch.setBoolPref(entry.prefCol, check.value);
|
||||||
|
} else {
|
||||||
|
const result = window.prompt(entry.prefCol, entry.valueCol);
|
||||||
|
if (result === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (entry.typeCol === nsIPrefBranch.PREF_INT) {
|
||||||
|
// | 0 converts to integer or 0; - 0 to float or NaN.
|
||||||
|
// Thus, this check should catch all cases.
|
||||||
|
const numResult = Number.parseInt(result);
|
||||||
|
const val = numResult | 0;
|
||||||
|
if (val !== numResult - 0) {
|
||||||
|
const [err_title, err_text] = [
|
||||||
|
"Invalid value",
|
||||||
|
"The text you entered is not a number.",
|
||||||
|
];
|
||||||
|
|
||||||
|
Services.prompt.alert(window, err_title, err_text);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
gPrefBranch.setIntPref(entry.prefCol, val);
|
||||||
|
} else {
|
||||||
|
gPrefBranch.setStringPref(entry.prefCol, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Services.prefs.savePrefFile(null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = onConfigLoad;
|
||||||
|
window.addEventListener("unload", onConfigUnload);
|
||||||
104
waterfox/browser/components/aboutcfg/aboutcfg.xhtml
Normal file
104
waterfox/browser/components/aboutcfg/aboutcfg.xhtml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<!-- 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/. -->
|
||||||
|
|
||||||
|
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
|
||||||
|
<?xml-stylesheet href="chrome://global/skin/in-content/info-pages.css" type="text/css"?>
|
||||||
|
<?xml-stylesheet href="chrome://browser/content/aboutcfg/aboutcfg.css" type="text/css"?>
|
||||||
|
|
||||||
|
<window id="config"
|
||||||
|
title="about:cfg"
|
||||||
|
csp="default-src chrome:; object-src 'none'"
|
||||||
|
data-l10n-id="config-window"
|
||||||
|
aria-describedby="warningTitle warningText"
|
||||||
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||||
|
windowtype="Preferences:ConfigManager"
|
||||||
|
role="application"
|
||||||
|
width="750"
|
||||||
|
height="500">
|
||||||
|
|
||||||
|
<html:link rel="icon" href="chrome://global/skin/icons/settings.svg"/>
|
||||||
|
|
||||||
|
<script src="chrome://browser/content/aboutcfg/aboutcfg.js"/>
|
||||||
|
<script src="chrome://global/content/editMenuOverlay.js"/>
|
||||||
|
<script src="chrome://global/content/globalOverlay.js"/>
|
||||||
|
|
||||||
|
<menupopup id="configContext">
|
||||||
|
<menuitem id="toggleSelected" label="Toggle" accesskey="T" default="true"/>
|
||||||
|
<menuitem id="modifySelected" label="Modify" accesskey="M" default="true"/>
|
||||||
|
<menuseparator/>
|
||||||
|
<menuitem id="copyPref" label="Copy" accesskey="C"/>
|
||||||
|
<menuitem id="copyName" label="Copy Name" accesskey="N"/>
|
||||||
|
<menuitem id="copyValue" label="Copy Value" accesskey="V"/>
|
||||||
|
<menu label="New" accesskey="w">
|
||||||
|
<menupopup>
|
||||||
|
<menuitem id="configString" label="String" accesskey="S"/>
|
||||||
|
<menuitem id="configInt" label="Integer" accesskey="I"/>
|
||||||
|
<menuitem id="configBool" label="Boolean" accesskey="B"/>
|
||||||
|
</menupopup>
|
||||||
|
</menu>
|
||||||
|
<menuitem id="resetSelected" label="Reset" accesskey="R"/>
|
||||||
|
</menupopup>
|
||||||
|
|
||||||
|
<keyset id="configTreeKeyset" disabled="true">
|
||||||
|
<key id="keyVKReturn" keycode="VK_RETURN"/>
|
||||||
|
<key id="configFocuSearch" modifiers="accel" key="r"/>
|
||||||
|
<key id="configFocuSearch2" modifiers="accel" key="f"/>
|
||||||
|
</keyset>
|
||||||
|
<deck id="configDeck" flex="1">
|
||||||
|
<vbox id="warningScreen" flex="1" align="center" style="overflow: auto;">
|
||||||
|
<spacer flex="1"/>
|
||||||
|
<vbox id="warningBox" class="container">
|
||||||
|
<hbox class="title" flex="1">
|
||||||
|
<label id="warningTitle" value="This might void your warranty!" class="title-text" flex="1"></label>
|
||||||
|
</hbox>
|
||||||
|
<vbox class="description" flex="1">
|
||||||
|
<label id="warningText">Changing these advanced settings can be harmful to the stability, security, and performance of this application. You should only continue if you are sure of what you are doing.</label>
|
||||||
|
<checkbox id="showWarningNextTime" label="Show this warning next time" checked="true"/>
|
||||||
|
<hbox class="button-container">
|
||||||
|
<button id="warningButton" label="I accept the risk!" class="primary"/>
|
||||||
|
</hbox>
|
||||||
|
</vbox>
|
||||||
|
</vbox>
|
||||||
|
<spacer flex="2"/>
|
||||||
|
</vbox>
|
||||||
|
<vbox flex="1">
|
||||||
|
<hbox id="filterRow" align="center">
|
||||||
|
<label value="Search:" accesskey="r" control="textbox"/>
|
||||||
|
<search-textbox id="textbox" flex="1"
|
||||||
|
aria-controls="configTree"/>
|
||||||
|
</hbox>
|
||||||
|
<tree id="configTree" flex="1" seltype="single"
|
||||||
|
enableColumnDrag="true" context="configContext">
|
||||||
|
<treecols>
|
||||||
|
<!--
|
||||||
|
The below code may suggest that 'ordinal' is still a supported XUL
|
||||||
|
attribute. It is not. This is a crutch so that we can continue
|
||||||
|
persisting the CSS -moz-box-ordinal-group attribute, which is the
|
||||||
|
appropriate replacement for the ordinal attribute but cannot yet
|
||||||
|
be easily persisted. The code that synchronizes the attribute with
|
||||||
|
the CSS lives in toolkit/content/widget/tree.js and is specific to
|
||||||
|
tree elements.
|
||||||
|
-->
|
||||||
|
<treecol id="prefCol" label="Preference Name" flex="7"
|
||||||
|
ignoreincolumnpicker="true"
|
||||||
|
persist="hidden width ordinal sortDirection"/>
|
||||||
|
<splitter class="tree-splitter" />
|
||||||
|
<treecol id="lockCol" label="Status" flex="1"
|
||||||
|
persist="hidden width ordinal sortDirection"/>
|
||||||
|
<splitter class="tree-splitter" />
|
||||||
|
<treecol id="typeCol" label="Type" flex="1"
|
||||||
|
persist="hidden width ordinal sortDirection"/>
|
||||||
|
<splitter class="tree-splitter" />
|
||||||
|
<treecol id="valueCol" label="Value" flex="10"
|
||||||
|
persist="hidden width ordinal sortDirection"/>
|
||||||
|
</treecols>
|
||||||
|
|
||||||
|
<treechildren id="configTreeBody"/>
|
||||||
|
</tree>
|
||||||
|
</vbox>
|
||||||
|
</deck>
|
||||||
|
</window>
|
||||||
8
waterfox/browser/components/aboutcfg/jar.mn
Normal file
8
waterfox/browser/components/aboutcfg/jar.mn
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# 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/.
|
||||||
|
|
||||||
|
browser.jar:
|
||||||
|
content/browser/aboutcfg/aboutcfg.css (aboutcfg.css)
|
||||||
|
content/browser/aboutcfg/aboutcfg.js (aboutcfg.js)
|
||||||
|
content/browser/aboutcfg/aboutcfg.xhtml (aboutcfg.xhtml)
|
||||||
11
waterfox/browser/components/aboutcfg/moz.build
Normal file
11
waterfox/browser/components/aboutcfg/moz.build
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
|
# vim: set filetype=python:
|
||||||
|
# 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/.
|
||||||
|
|
||||||
|
EXTRA_JS_MODULES += [
|
||||||
|
"AboutCfg.sys.mjs",
|
||||||
|
]
|
||||||
|
|
||||||
|
JAR_MANIFESTS += ["jar.mn"]
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
DIRS += [
|
DIRS += [
|
||||||
|
"aboutcfg",
|
||||||
"aboutwelcome",
|
"aboutwelcome",
|
||||||
"aboutpasswords",
|
"aboutpasswords",
|
||||||
"addonstores",
|
"addonstores",
|
||||||
|
|||||||
Reference in New Issue
Block a user