gecko-dev/browser/devtools/app-manager/content/manifest-editor.js

147 lines
3.9 KiB
JavaScript

/* 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/. */
"use strict";
Cu.import("resource://gre/modules/osfile.jsm");
const {VariablesView} =
Cu.import("resource:///modules/devtools/VariablesView.jsm", {});
const VARIABLES_VIEW_URL =
"chrome://browser/content/devtools/widgets/VariablesView.xul";
function ManifestEditor(project) {
this.project = project;
this._onContainerReady = this._onContainerReady.bind(this);
this._onEval = this._onEval.bind(this);
this._onSwitch = this._onSwitch.bind(this);
this._onDelete = this._onDelete.bind(this);
this._onNew = this._onNew.bind(this);
}
ManifestEditor.prototype = {
get manifest() { return this.project.manifest; },
get editable() { return this.project.type == "packaged"; },
show: function(containerElement) {
let deferred = promise.defer();
let iframe = this._iframe = document.createElement("iframe");
iframe.addEventListener("load", function onIframeLoad() {
iframe.removeEventListener("load", onIframeLoad, true);
deferred.resolve(iframe.contentWindow);
}, true);
iframe.setAttribute("src", VARIABLES_VIEW_URL);
iframe.classList.add("variables-view");
containerElement.appendChild(iframe);
return deferred.promise.then(this._onContainerReady);
},
_onContainerReady: function(varWindow) {
let variablesContainer = varWindow.document.querySelector("#variables");
variablesContainer.classList.add("manifest-editor");
let editor = this.editor = new VariablesView(variablesContainer);
editor.onlyEnumVisible = true;
editor.alignedValues = true;
editor.actionsFirst = true;
if (this.editable) {
editor.eval = this._onEval;
editor.switch = this._onSwitch;
editor.delete = this._onDelete;
editor.new = this._onNew;
}
return this.update();
},
_onEval: function(variable, value) {
let parent = this._descend(variable.ownerView.symbolicPath);
try {
parent[variable.name] = JSON.parse(value);
} catch(e) {
Cu.reportError(e);
}
this.update();
},
_onSwitch: function(variable, newName) {
if (variable.name == newName) {
return;
}
let parent = this._descend(variable.ownerView.symbolicPath);
parent[newName] = parent[variable.name];
delete parent[variable.name];
this.update();
},
_onDelete: function(variable) {
let parent = this._descend(variable.ownerView.symbolicPath);
delete parent[variable.name];
},
_onNew: function(variable, newName, newValue) {
let parent = this._descend(variable.symbolicPath);
try {
parent[newName] = JSON.parse(newValue);
} catch(e) {
Cu.reportError(e);
}
this.update();
},
/**
* Returns the value located at a given path in the manifest.
* @param path array
* A string for each path component: ["developer", "name"]
*/
_descend: function(path) {
let parent = this.manifest;
while (path.length) {
parent = parent[path.shift()];
}
return parent;
},
update: function() {
this.editor.rawObject = this.manifest;
this.editor.commitHierarchy();
// Wait until the animation from commitHierarchy has completed
let deferred = promise.defer();
setTimeout(deferred.resolve, this.editor.lazyEmptyDelay + 1);
return deferred.promise;
},
save: function() {
if (this.editable) {
let validator = new AppValidator(this.project);
let manifestFile = validator._getPackagedManifestFile();
let path = manifestFile.path;
let encoder = new TextEncoder();
let data = encoder.encode(JSON.stringify(this.manifest, null, 2));
return OS.File.writeAtomic(path, data, { tmpPath: path + ".tmp" });
}
return promise.resolve();
},
destroy: function() {
if (this._iframe) {
this._iframe.remove();
}
}
};