Implement options page (#38)

This commit is contained in:
Maxim Baz
2019-03-11 12:33:24 +01:00
committed by GitHub
parent b1abed2f2b
commit 0b908f8ef9
9 changed files with 435 additions and 34 deletions

193
src/options/interface.js Normal file
View File

@@ -0,0 +1,193 @@
module.exports = Interface;
var m = require("mithril");
/**
* Options main interface
*
* @since 3.0.0
*
* @param object settings Settings object
* @param function saveSettings Function to save settings
* @return void
*/
function Interface(settings, saveSettings) {
// public methods
this.attach = attach;
this.view = view;
// fields
this.settings = settings;
this.saveSettings = saveSettings;
this.saveEnabled = false;
// 'default' store must not be displayed or later attempted to be saved
delete this.settings.stores.default;
}
/**
* Attach the interface on the given element
*
* @since 3.0.0
*
* @param DOMElement element Target element
* @return void
*/
function attach(element) {
m.mount(element, this);
}
/**
* Generates vnodes for render
*
* @since 3.0.0
*
* @param function ctl Controller
* @param object params Runtime params
* @return []Vnode
*/
function view(ctl, params) {
var nodes = [];
nodes.push(m("h3", "Basic settings"));
nodes.push(createCheckbox.call(this, "autoSubmit", "Automatically submit forms after filling"));
nodes.push(m("h3", "Custom store locations"));
nodes.push(
m("div", { class: "notice" }, "(this overrides default store and $PASSWORD_STORE_DIR)")
);
for (var storeId in this.settings.stores) {
nodes.push(createCustomStore.call(this, storeId));
}
nodes.push(
m(
"a.add-store",
{
onclick: () => {
addEmptyStore(this.settings.stores);
this.saveEnabled = true;
}
},
"Add store"
)
);
if (typeof this.error !== "undefined") {
nodes.push(m("div.error", this.error.message));
}
nodes.push(
m(
"button.save",
{
disabled: !this.saveEnabled,
onclick: async () => {
try {
await this.saveSettings(this.settings);
this.error = undefined;
} catch (e) {
this.error = e;
}
this.saveEnabled = false;
m.redraw();
}
},
"Save"
)
);
return nodes;
}
/**
* Generates vnode for a checkbox setting
*
* @since 3.0.0
*
* @param string key Settings key
* @param string title Label for the checkbox
* @return Vnode
*/
function createCheckbox(key, title) {
return m("div.option", { class: key }, [
m("label", [
m("input[type=checkbox]", {
title: title,
checked: this.settings[key],
onchange: e => {
this.settings[key] = e.target.checked;
this.saveEnabled = true;
}
}),
title
])
]);
}
/**
* Generates vnode for a custom store configuration
*
* @since 3.0.0
*
* @param string storeId Store ID
* @return Vnode
*/
function createCustomStore(storeId) {
let store = this.settings.stores[storeId];
return m("div.option.custom-store", { class: "store-" + store.name }, [
m("input[type=text].name", {
title: "The name for this password store",
value: store.name,
placeholder: "name",
onchange: e => {
store.name = e.target.value;
this.saveEnabled = true;
}
}),
m("input[type=text].path", {
title: "The full path to this password store",
value: store.path,
placeholder: "/path/to/store",
onchange: e => {
store.path = e.target.value;
this.saveEnabled = true;
}
}),
m(
"a.remove",
{
title: "Remove this password store",
onclick: () => {
delete this.settings.stores[storeId];
this.saveEnabled = true;
}
},
"[X]"
)
]);
}
/**
* Generates new store ID
*
* @since 3.0.0
*
* @return string new store ID
*/
function newId() {
return Math.random()
.toString(36)
.substr(2, 9);
}
/**
* Generates a new empty store
*
* @since 3.0.0
*
* @param []object stores List of stores to add a new store to
* @return void
*/
function addEmptyStore(stores) {
let store = { id: newId(), name: "", path: "" };
stores[store.id] = store;
}