plugin settings

This commit is contained in:
antelle 2017-05-19 22:05:35 +02:00
parent a131d7435c
commit 5bfce6c871
7 changed files with 189 additions and 4 deletions

View File

@ -133,6 +133,10 @@ const PluginManager = Backbone.Model.extend({
getStatus(id) {
const plugin = this.get('plugins').get(id);
return plugin ? plugin.get('status') : '';
},
getPlugin(id) {
return this.get('plugins').get(id);
}
});

View File

@ -318,6 +318,7 @@ const Plugin = Backbone.Model.extend(_.extend({}, PluginStatus, {
delete global[id];
if (this.module.exports.uninstall) {
this.logger.debug('Plugin script installed', this.logger.ts(ts));
this.loadPluginSettings();
resolve();
} else {
reject('Plugin script installation failed');
@ -376,6 +377,27 @@ const Plugin = Backbone.Model.extend(_.extend({}, PluginStatus, {
delete BaseLocale[this.getThemeLocaleKey(theme.name)];
},
loadPluginSettings() {
if (!this.module || !this.module.exports || !this.module.exports.setSettings) {
return;
}
const ts = this.logger.ts();
const settingPrefix = this.getSettingPrefix();
let settings = null;
for (const key of Object.keys(AppSettingsModel.instance.attributes)) {
if (key.lastIndexOf(settingPrefix, 0) === 0) {
if (!settings) {
settings = {};
}
settings[key.replace(settingPrefix, '')] = AppSettingsModel.instance.attributes[key];
}
}
if (settings) {
this.setSettings(settings);
}
this.logger.debug('Plugin settings loaded', this.logger.ts(ts));
},
uninstallPluginCode() {
if (this.get('manifest').resources.js && this.module && this.module.exports && this.module.exports.uninstall) {
try {
@ -469,6 +491,46 @@ const Plugin = Backbone.Model.extend(_.extend({}, PluginStatus, {
}
});
});
},
getSettingPrefix() {
return `plugin:${this.id}:`;
},
getSettings() {
if (this.get('status') === PluginStatus.STATUS_ACTIVE && this.module && this.module.exports && this.module.exports.getSettings) {
try {
const settings = this.module.exports.getSettings();
const settingsPrefix = this.getSettingPrefix();
if (settings instanceof Array) {
return settings.map(setting => {
setting = _.clone(setting);
const value = AppSettingsModel.instance.get(settingsPrefix + setting.name);
if (value !== undefined) {
setting.value = value;
}
return setting;
});
}
this.logger.error('getSettings: expected Array, got ', typeof settings);
} catch (e) {
this.logger.error('getSettings error', e);
}
}
},
setSettings(settings) {
for (const key of Object.keys(settings)) {
const value = settings[key];
AppSettingsModel.instance.set(this.getSettingPrefix() + key, value);
}
if (this.module.exports.setSettings) {
try {
this.module.exports.setSettings(settings);
} catch (e) {
this.logger.error('setSettings error', e);
}
}
}
}));

View File

@ -22,7 +22,10 @@ const SettingsPluginsView = Backbone.View.extend({
'click .settings_plugins-use-locale-btn': 'useLocaleClick',
'click .settings_plugins-use-theme-btn': 'useThemeClick',
'click .settings__plugins-gallery-plugin-install-btn': 'galleryInstallClick',
'input .settings__plugins-gallery-search': 'gallerySearchInput'
'input .settings__plugins-gallery-search': 'gallerySearchInput',
'change select.settings__plugins-plugin-input': 'pluginSettingChange',
'change input[type=checkbox].settings__plugins-plugin-input': 'pluginSettingChange',
'input input[type=text].settings__plugins-plugin-input': 'pluginSettingChange'
},
searchStr: null,
@ -33,7 +36,7 @@ const SettingsPluginsView = Backbone.View.extend({
initialize() {
this.listenTo(PluginManager, 'change', this.render.bind(this));
this.listenTo(Backbone, 'plugin-gallery-load-complete', this.render.bind(this));
PluginGallery.loadPlugins();
// PluginGallery.loadPlugins();
},
render() {
@ -47,7 +50,8 @@ const SettingsPluginsView = Backbone.View.extend({
updateError: plugin.get('updateError'),
updateCheckDate: Format.dtStr(plugin.get('updateCheckDate')),
installError: plugin.get('installError'),
official: plugin.get('manifest').publicKey === publicKey
official: plugin.get('manifest').publicKey === publicKey,
settings: plugin.getSettings()
})).sort(Comparators.stringComparator('id', true)),
installingFromUrl: this.installFromUrl && !this.installFromUrl.error,
installUrl: this.installFromUrl ? this.installFromUrl.url : null,
@ -194,6 +198,16 @@ const SettingsPluginsView = Backbone.View.extend({
manifest.locale &&
(manifest.locale.name.toLowerCase().indexOf(searchStr) >= 0 ||
manifest.locale.title.toLowerCase().indexOf(searchStr) >= 0);
},
pluginSettingChange(e) {
const el = e.target;
const settingEl = $(el).closest('.settings__plugins-plugin-setting');
const setting = settingEl.data('setting');
const pluginId = settingEl.data('plugin');
const val = el.type === 'checkbox' ? el.checked : el.value;
const plugin = PluginManager.getPlugin(pluginId);
plugin.setSettings({ [setting]: val });
}
});

View File

@ -29,7 +29,7 @@
{{#res 'setPlLoadTime'}}{{plugin.installTime}}ms{{/res}}
{{else}}
{{#ifeq plugin.status 'error'}}
<span class="error-color">&nbsp;{{res 'setPlLoadError'}}
<span class="error-color">&nbsp;{{res 'setPlLoadError'}}</span>
{{else}}
{{plugin.status}}
{{/ifeq}}
@ -40,6 +40,46 @@
{{#if plugin.installError}}<div class="error-color settings__plugins-install-error"><pre>{{plugin.installError}}</pre></div>{{/if}}
{{#if plugin.updateError}}<div class="error-color settings__plugins-install-error"><pre>{{plugin.updateError}}</pre></div>{{/if}}
</div>
{{#if plugin.settings}}
<div class="settings__plugins-plugin-settings">
{{#each plugin.settings as |setting|}}
<div class="settings__plugins-plugin-setting"
data-setting="{{setting.name}}"
data-plugin="{{../id}}"
>
{{#ifeq setting.type 'checkbox'}}
<input type="checkbox"
class="settings__plugins-plugin-input settings__input input-base"
id="plugin-{{../id}}-setting-{{setting.name}}"
{{#if setting.value}}checked{{/if}}
/>
{{/ifeq}}
<label
class="settings__plugins-plugin-label"
for="plugin-{{../id}}-setting-{{setting.name}}"
>{{setting.label}}</label>
{{#ifeq setting.type 'text'}}
<input type="text"
class="settings__plugins-plugin-input settings__input input-base"
id="plugin-{{../id}}-setting-{{setting.name}}"
{{#if setting.placeholder}}placeholder="{{setting.placeholder}}"{{/if}}
{{#if setting.maxlength}}maxlength="{{setting.maxlength}}"{{/if}}
value="{{setting.value}}"
/>
{{/ifeq}}
{{#ifeq setting.type 'select'}}
<select class="settings__plugins-plugin-input settings__select input-base"
id="plugin-{{../name}}-setting-{{setting.name}}"
>
{{#each setting.options as |opt|}}
<option value="{{opt.value}}" {{#ifeq opt.value ../value}}selected{{/ifeq}}>{{opt.label}}</option>
{{/each}}
</select>
{{/ifeq}}
</div>
{{/each}}
</div>
{{/if}}
<div class="settings__plugins-plugin-buttons">
<button class="settings_plugins-uninstall-btn btn-error" data-plugin="{{plugin.id}}">{{res 'setPlUninstallBtn'}}</button>
{{#ifeq plugin.status 'active'}}<button class="settings_plugins-disable-btn btn-silent" data-plugin="{{plugin.id}}">{{res 'setPlDisableBtn'}}</button>{{/ifeq}}

3
plugins/examples/settings/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.DS_Store
*.log
*.pem

View File

@ -0,0 +1,17 @@
{
"version": "0.0.1",
"manifestVersion": "0.1.0",
"name": "settings-example",
"description": "KeeWeb plugin settings example",
"author": {
"name": "antelle",
"email": "antelle.net@gmail.com",
"url": "http://antelle.net"
},
"licence": "MIT",
"url": "https://keeweb.info",
"resources": {
"js": "m2uoOdP65lfoBp/Orc9cSOd0Yq+AKdtm69N7sqCVTEduZYhFRAJqr+wJPQ+tZuY0JiWPgcLYqYZ7zZRq/XxF21EPb9dnJL8PDtS0u3VgWQN4tuK/ykft8fZMBWJAqSO+kUpliGijj0XjWZouTLpeZ2XqhAsO3+cjhzzL7ICAdPYFARqdsvErwH450YX2PBNXw9HrOWMYPIS46PmkD+I/LeZgF7GRgbRExRR3mk5g4l+F5eJgsGM2U16rlHDilzt3lcoj31VJ+/ubsv8YXkJ62S5xQzAz/+h/NkayhhOmNkIApusD7hdcTNBbYLOyTbnibp5cEBKQraDjXZlZRQyD4A=="
},
"publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1QB+yQofkqIHbHFVAtWhjEFjaxvNekyQx/aK7nEpZzqM8ReoVWbJGVA+7z7MhymwZanbL8uAUrSpNTp5eFWltDksxqHqmXT4UcFU+4reLjYfgwjIaA3c9Q+2JA1Iowqbv3NDcDKm6Ug+dROr04VDCfYE4WRYgGdTYHDbJs5svxUgQ25uc0KKUWAvhYbSKsw43AwmbPbKkHdfZHiS5ZST99HVEJWxn3Kd2zLY9Kk70nu9MzypMLDqxUqjKgdeRCIyZeAYzB75miH3B5vMKhFcdmA8+D6WU2N+6gzKsY5BfqF729uFKSTo4JUKQ5fMU0lKSDHG4qGrkgnURfAUuj9YMQIDAQAB"
}

View File

@ -0,0 +1,45 @@
/**
* KeeWeb plugin: settings-example
* @author antelle
* @license MIT
*/
const AppSettingsModel = require('models/app-settings-model');
// get setting: 'plugin:<plugin-name>:<setting-name>'
const settingValue = AppSettingsModel.instance.get('plugin:settings-example:MyText');
module.exports.getSettings = function() {
return [{
name: 'MyText',
label: 'Text setting',
type: 'text',
maxlength: 20,
placeholder: 'Please enter something',
value: ''
}, {
name: 'MySel',
label: 'Select setting',
type: 'select',
options: [{value: 'apple', label: 'Green apple'}, {value: 'banana', label: 'Yellow banana'}],
value: 'banana'
}, {
name: 'MyCheckbox',
label: 'Checkbox setting',
type: 'checkbox',
value: true
}];
};
module.exports.setSettings = function(changes) {
// apply changed settings in plugin logic
// this method will be called:
// 1. on modifications my user
// 2. during plugin startup
// only changed settings will be passed
// example: { MyText: 'value', MySel: 'selected-value', MyCheckbox: true }
};
module.exports.uninstall = function() {
};