mirror of https://github.com/keeweb/keeweb.git
desktop plugins
This commit is contained in:
parent
3766a0e1b5
commit
70cbcb5c36
|
@ -3,11 +3,22 @@
|
|||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value>
|
||||
<XML>
|
||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||
</XML>
|
||||
<JSCodeStyleSettings>
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
|
||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||
</codeStyleSettings>
|
||||
</value>
|
||||
</option>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</component>
|
||||
</project>
|
|
@ -56,6 +56,9 @@ const Launcher = {
|
|||
getWorkDirPath: function(fileName) {
|
||||
return this.req('path').join(process.cwd(), fileName || '');
|
||||
},
|
||||
joinPath: function(...parts) {
|
||||
return this.req('path').join(...parts);
|
||||
},
|
||||
writeFile: function(path, data, callback) {
|
||||
this.req('fs').writeFile(path, new window.Buffer(data), callback);
|
||||
},
|
||||
|
|
|
@ -462,6 +462,7 @@
|
|||
"setPlLoc": "language",
|
||||
"setPlCreatedBy": "created by {}",
|
||||
"setPlLoadTime": "took {} to load",
|
||||
"setPlLoadError": "error loading plugin",
|
||||
|
||||
"setAboutTitle": "About",
|
||||
"setAboutBuilt": "This app is built with these awesome tools",
|
||||
|
|
|
@ -67,7 +67,7 @@ const PluginManager = Backbone.Model.extend({
|
|||
const plugin = new Plugin(desc.manifest, desc.url, true);
|
||||
return plugin.install()
|
||||
.then(() => plugin)
|
||||
.catch(() => undefined);
|
||||
.catch(() => plugin);
|
||||
},
|
||||
|
||||
saveState() {
|
||||
|
|
|
@ -18,12 +18,20 @@ const io = new IoCache({
|
|||
const Plugin = Backbone.Model.extend({
|
||||
idAttribute: 'name',
|
||||
|
||||
STATUS_ACTIVE: 'active',
|
||||
STATUS_INACTIVE: 'inactive',
|
||||
STATUS_INSTALLING: 'installing',
|
||||
STATUS_UNINSTALLING: 'uninstalling',
|
||||
STATUS_INVALID: 'invalid',
|
||||
STATUS_ERROR: 'error',
|
||||
|
||||
defaults: {
|
||||
name: '',
|
||||
manifest: '',
|
||||
url: '',
|
||||
status: 'inactive',
|
||||
installTime: null
|
||||
installTime: null,
|
||||
installError: null
|
||||
},
|
||||
|
||||
resources: null,
|
||||
|
@ -41,16 +49,25 @@ const Plugin = Backbone.Model.extend({
|
|||
|
||||
install() {
|
||||
const ts = this.logger.ts();
|
||||
this.set('status', 'installing');
|
||||
this.set('status', this.STATUS_INSTALLING);
|
||||
return Promise.resolve().then(() => {
|
||||
const error = this.validateManifest();
|
||||
if (error) {
|
||||
this.logger.error('Manifest validation error', error);
|
||||
this.set('status', 'invalid');
|
||||
this.set('status', this.STATUS_INVALID);
|
||||
throw 'Plugin validation error: ' + error;
|
||||
}
|
||||
return this.installWithManifest()
|
||||
.then(() => this.set('installTime', this.logger.ts() - ts));
|
||||
.then(() => this.set('installTime', this.logger.ts() - ts))
|
||||
.catch(err => {
|
||||
this.logger.error('Error installing plugin', err);
|
||||
this.set({
|
||||
status: this.STATUS_ERROR,
|
||||
installError: err,
|
||||
installTime: this.logger.ts() - ts
|
||||
});
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -114,6 +131,10 @@ const Plugin = Backbone.Model.extend({
|
|||
}
|
||||
},
|
||||
|
||||
getStorageResourcePath(res) {
|
||||
return this.id + '_' + this.getResourcePath(res);
|
||||
},
|
||||
|
||||
loadResource(type) {
|
||||
let res;
|
||||
if (this.get('local')) {
|
||||
|
@ -156,7 +177,7 @@ const Plugin = Backbone.Model.extend({
|
|||
|
||||
loadLocalResource(type) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const storageKey = this.id + '/' + this.getResourcePath(type);
|
||||
const storageKey = this.getStorageResourcePath(type);
|
||||
io.load(storageKey, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
|
@ -182,7 +203,7 @@ const Plugin = Backbone.Model.extend({
|
|||
}
|
||||
return Promise.all(promises)
|
||||
.then(() => {
|
||||
this.set('status', 'active');
|
||||
this.set('status', this.STATUS_ACTIVE);
|
||||
})
|
||||
.catch(e => {
|
||||
this.logger.info('Install error', e);
|
||||
|
@ -204,7 +225,7 @@ const Plugin = Backbone.Model.extend({
|
|||
|
||||
saveResource(key, value) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const storageKey = this.id + '/' + this.getResourcePath(key);
|
||||
const storageKey = this.getStorageResourcePath(key);
|
||||
io.save(storageKey, value, e => {
|
||||
if (e) {
|
||||
reject(e);
|
||||
|
@ -225,7 +246,7 @@ const Plugin = Backbone.Model.extend({
|
|||
|
||||
deleteResource(key) {
|
||||
return new Promise(resolve => {
|
||||
const storageKey = this.id + '/' + this.getResourcePath(key);
|
||||
const storageKey = this.getStorageResourcePath(key);
|
||||
io.remove(storageKey, () => resolve());
|
||||
});
|
||||
},
|
||||
|
@ -321,7 +342,7 @@ const Plugin = Backbone.Model.extend({
|
|||
uninstall() {
|
||||
const manifest = this.get('manifest');
|
||||
this.logger.info('Uninstalling plugin with resources', Object.keys(manifest.resources).join(', '));
|
||||
this.set('status', 'uninstalling');
|
||||
this.set('status', this.STATUS_UNINSTALLING);
|
||||
const ts = this.logger.ts();
|
||||
return Promise.resolve().then(() => {
|
||||
if (manifest.resources.css) {
|
||||
|
@ -342,7 +363,7 @@ const Plugin = Backbone.Model.extend({
|
|||
this.removeTheme(manifest.theme);
|
||||
}
|
||||
return this.deleteResources().then(() => {
|
||||
this.set('status', 'inactive');
|
||||
this.set('status', this.STATUS_INACTIVE);
|
||||
this.logger.info('Uninstall complete', this.logger.ts(ts));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,8 +8,6 @@ const IoBrowserCache = function(config) {
|
|||
this.logger = config.logger;
|
||||
};
|
||||
|
||||
IoBrowserCache.enabled = !!idb;
|
||||
|
||||
_.extend(IoBrowserCache.prototype, {
|
||||
initDb(callback) {
|
||||
if (this.db) {
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
const Launcher = require('../comp/launcher');
|
||||
|
||||
const IoCache = Launcher ? require('./io-browser-cache') : require('./io-browser-cache'); // TODO: use file cache
|
||||
const IoCache = Launcher ? require('./io-file-cache') : require('./io-browser-cache');
|
||||
|
||||
module.exports = IoCache;
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
'use strict';
|
||||
|
||||
const Launcher = require('../comp/launcher');
|
||||
|
||||
const IoFileCache = function(config) {
|
||||
this.basePath = null;
|
||||
this.cacheName = config.cacheName;
|
||||
this.logger = config.logger;
|
||||
};
|
||||
|
||||
_.extend(IoFileCache.prototype, {
|
||||
initFs(callback) {
|
||||
if (this.basePath) {
|
||||
return callback();
|
||||
}
|
||||
const basePath = Launcher.getUserDataPath(this.cacheName);
|
||||
Launcher.mkdir(basePath, err => {
|
||||
if (err) {
|
||||
this.logger.error('Error creating plugin folder');
|
||||
} else {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
|
||||
resolvePath(path) {
|
||||
return Launcher.joinPath(this.basePath, path);
|
||||
},
|
||||
|
||||
save(id, data, callback) {
|
||||
this.initFs(err => {
|
||||
if (err) {
|
||||
return callback && callback(err, null);
|
||||
}
|
||||
this.logger.debug('Save', id);
|
||||
const ts = this.logger.ts();
|
||||
const path = this.resolvePath(id);
|
||||
Launcher.writeFile(path, data, err => {
|
||||
if (err) {
|
||||
this.logger.error('Error saving file', id, err);
|
||||
if (callback) { callback(err); }
|
||||
} else {
|
||||
this.logger.debug('Saved', id, this.logger.ts(ts));
|
||||
if (callback) { callback(); }
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
load(id, callback) {
|
||||
this.initFs(err => {
|
||||
if (err) {
|
||||
return callback && callback(err, null);
|
||||
}
|
||||
this.logger.debug('Load', id);
|
||||
const ts = this.logger.ts();
|
||||
const path = this.resolvePath(id);
|
||||
Launcher.readFile(path, undefined, (data, err) => {
|
||||
if (err) {
|
||||
this.logger.error('Error loading file', id, err);
|
||||
if (callback) { callback(err); }
|
||||
} else {
|
||||
this.logger.debug('Loaded', id, this.logger.ts(ts));
|
||||
if (callback) { callback(null, data); }
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
remove(id, callback) {
|
||||
this.initFs(err => {
|
||||
if (err) {
|
||||
return callback && callback(err, null);
|
||||
}
|
||||
this.logger.debug('Remove', id);
|
||||
const ts = this.logger.ts();
|
||||
const path = this.resolvePath(id);
|
||||
Launcher.deleteFile(path, err => {
|
||||
if (err) {
|
||||
this.logger.error('Error removing file', id, err);
|
||||
if (callback) { callback(err); }
|
||||
} else {
|
||||
this.logger.debug('Removed', id, this.logger.ts(ts));
|
||||
if (callback) { callback(); }
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = IoFileCache;
|
|
@ -16,6 +16,7 @@
|
|||
<a href="{{plugin.manifest.url}}" target="_blank">{{plugin.manifest.url}}</a>, v{{plugin.manifest.version}},
|
||||
{{#res 'setPlCreatedBy'}}<a href="{{plugin.manifest.author.url}}" target="_blank">{{plugin.manifest.author.name}}</a> ({{plugin.manifest.author.email}}){{/res}},
|
||||
{{#res 'setPlLoadTime'}}{{plugin.installTime}}ms{{/res}}
|
||||
{{#ifeq plugin.status 'error'}}<span class="error-color"> ({{res 'setPlLoadError'}}){{/ifeq}}
|
||||
</div>
|
||||
<div class="settings__plugins-plugin-buttons">
|
||||
<button class="settings_plugins-uninstall-btn btn-silent" data-plugin="{{plugin.id}}">{{res 'setPlUninstallBtn'}}</button>
|
||||
|
|
Loading…
Reference in New Issue