Merge pull request #143 from samuelthomas2774/add-custom-settings
Add custom settings and content reloading
This commit is contained in:
commit
6380f9fc33
|
@ -85,8 +85,9 @@ export default class {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh locally stored content
|
* Refresh locally stored content
|
||||||
|
* @param {bool} suppressErrors Suppress any errors that occur during loading of content
|
||||||
*/
|
*/
|
||||||
static async refreshContent() {
|
static async refreshContent(suppressErrors = false) {
|
||||||
if (!this.localContent.length) return this.loadAllContent();
|
if (!this.localContent.length) return this.loadAllContent();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -102,18 +103,44 @@ export default class {
|
||||||
await this.preloadContent(dir);
|
await this.preloadContent(dir);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// We don't want every plugin/theme to fail loading when one does
|
// We don't want every plugin/theme to fail loading when one does
|
||||||
|
this.errors.push(new ErrorEvent({
|
||||||
|
module: this.moduleName,
|
||||||
|
message: `Failed to load ${dir}`,
|
||||||
|
err
|
||||||
|
}));
|
||||||
|
|
||||||
Logger.err(this.moduleName, err);
|
Logger.err(this.moduleName, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let content of this.localContent) {
|
for (let content of this.localContent) {
|
||||||
if (directories.includes(content.dirName)) continue;
|
if (directories.includes(content.dirName)) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
// Plugin/theme was deleted manually, stop it and remove any reference
|
// Plugin/theme was deleted manually, stop it and remove any reference
|
||||||
this.unloadContent(content);
|
await this.unloadContent(content);
|
||||||
|
} catch (err) {
|
||||||
|
this.errors.push(new ErrorEvent({
|
||||||
|
module: this.moduleName,
|
||||||
|
message: `Failed to unload ${content.dirName}`,
|
||||||
|
err
|
||||||
|
}));
|
||||||
|
|
||||||
|
Logger.err(this.moduleName, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.errors.length && !suppressErrors) {
|
||||||
|
Modals.error({
|
||||||
|
header: `${this.moduleName} - ${this.errors.length} ${this.contentType}${this.errors.length !== 1 ? 's' : ''} failed to load`,
|
||||||
|
module: this.moduleName,
|
||||||
|
type: 'err',
|
||||||
|
content: this.errors
|
||||||
|
});
|
||||||
|
this._errors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.localContent;
|
return this.localContent;
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
@ -151,19 +178,20 @@ export default class {
|
||||||
try {
|
try {
|
||||||
const readUserConfig = await this.readUserConfig(contentPath);
|
const readUserConfig = await this.readUserConfig(contentPath);
|
||||||
userConfig.enabled = readUserConfig.enabled || false;
|
userConfig.enabled = readUserConfig.enabled || false;
|
||||||
userConfig.config = readConfig.defaultConfig.map(config => {
|
userConfig.config = readConfig.defaultConfig.map(category => {
|
||||||
const userSet = readUserConfig.config.find(c => c.category === config.category);
|
let newCategory = readUserConfig.config.find(c => c.category === category.category);
|
||||||
// return userSet || config;
|
// return userSet || config;
|
||||||
if (!userSet) return config;
|
if (!newCategory) newCategory = {settings: []};
|
||||||
|
|
||||||
config.settings = config.settings.map(setting => {
|
category.settings = category.settings.map(setting => {
|
||||||
const userSetting = userSet.settings.find(s => s.id === setting.id);
|
if (setting.type === 'array' || setting.type === 'custom') setting.path = contentPath;
|
||||||
if (!userSetting) return setting;
|
const newSetting = newCategory.settings.find(s => s.id === setting.id);
|
||||||
|
if (!newSetting) return setting;
|
||||||
|
|
||||||
setting.value = userSetting.value;
|
setting.value = newSetting.value;
|
||||||
return setting;
|
return setting;
|
||||||
});
|
});
|
||||||
return config;
|
return category;
|
||||||
});
|
});
|
||||||
userConfig.css = readUserConfig.css || null;
|
userConfig.css = readUserConfig.css || null;
|
||||||
// userConfig.config = readUserConfig.config;
|
// userConfig.config = readUserConfig.config;
|
||||||
|
@ -175,15 +203,18 @@ export default class {
|
||||||
defaultConfig: readConfig.defaultConfig,
|
defaultConfig: readConfig.defaultConfig,
|
||||||
schemes: readConfig.configSchemes,
|
schemes: readConfig.configSchemes,
|
||||||
userConfig
|
userConfig
|
||||||
}
|
};
|
||||||
|
|
||||||
const paths = {
|
const paths = {
|
||||||
contentPath,
|
contentPath,
|
||||||
dirName,
|
dirName,
|
||||||
mainPath
|
mainPath
|
||||||
}
|
};
|
||||||
|
|
||||||
const content = await this.loadContent(paths, configs, readConfig.info, readConfig.main, readConfig.dependencies);
|
const content = await this.loadContent(paths, configs, readConfig.info, readConfig.main, readConfig.dependencies);
|
||||||
|
if (!reload && this.getContentById(content.id))
|
||||||
|
throw {message: `A ${this.contentType} with the ID ${content.id} already exists.`};
|
||||||
|
|
||||||
if (reload) this.localContent[index] = content;
|
if (reload) this.localContent[index] = content;
|
||||||
else this.localContent.push(content);
|
else this.localContent.push(content);
|
||||||
return content;
|
return content;
|
||||||
|
@ -193,6 +224,43 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload content
|
||||||
|
* @param {any} content Content to unload
|
||||||
|
* @param {bool} reload Whether to reload the content after
|
||||||
|
*/
|
||||||
|
static async unloadContent(content, reload) {
|
||||||
|
content = this.findContent(content);
|
||||||
|
if (!content) throw {message: `Could not find a ${this.contentType} from ${content}.`};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (content.enabled && content.disable) content.disable(false);
|
||||||
|
if (content.enabled && content.stop) content.stop(false);
|
||||||
|
if (content.onunload) content.onunload(reload);
|
||||||
|
if (content.onUnload) content.onUnload(reload);
|
||||||
|
const index = this.getContentIndex(content);
|
||||||
|
|
||||||
|
delete window.require.cache[window.require.resolve(content.paths.mainPath)];
|
||||||
|
|
||||||
|
if (reload) {
|
||||||
|
const newcontent = await this.preloadContent(content.dirName, true, index);
|
||||||
|
if (newcontent.enabled && newcontent.start) newcontent.start(false);
|
||||||
|
return newcontent;
|
||||||
|
} else this.localContent.splice(index, 1);
|
||||||
|
} catch (err) {
|
||||||
|
Logger.err(this.moduleName, err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reload content
|
||||||
|
* @param {any} content Content to reload
|
||||||
|
*/
|
||||||
|
static async reloadContent(content) {
|
||||||
|
return this.unloadContent(content, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read content config file
|
* Read content config file
|
||||||
* @param {any} configPath Config file path
|
* @param {any} configPath Config file path
|
||||||
|
@ -211,19 +279,26 @@ export default class {
|
||||||
return FileUtils.readJsonFromFile(configPath);
|
return FileUtils.readJsonFromFile(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the passed object is an instance of this content type.
|
||||||
|
* @param {any} content Object to check
|
||||||
|
*/
|
||||||
|
static isThisContent(content) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wildcard content finder
|
* Wildcard content finder
|
||||||
* @param {any} wild Content name | id | path | dirname
|
* @param {any} wild Content name | id | path | dirname
|
||||||
|
* @param {bool} nonunique Allow searching attributes that may not be unique
|
||||||
*/
|
*/
|
||||||
//TODO make this nicer
|
static findContent(wild, nonunique) {
|
||||||
static findContent(wild) {
|
if (this.isThisContent(wild)) return wild;
|
||||||
let content = this.getContentByName(wild);
|
let content;
|
||||||
if (content) return content;
|
content = this.getContentById(wild); if (content) return content;
|
||||||
content = this.getContentById(wild);
|
content = this.getContentByDirName(wild); if (content) return content;
|
||||||
if (content) return content;
|
content = this.getContentByPath(wild); if (content) return content;
|
||||||
content = this.getContentByPath(wild);
|
content = this.getContentByName(wild); if (content && nonunique) return content;
|
||||||
if (content) return content;
|
|
||||||
return this.getContentByDirName(wild);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getContentIndex(content) { return this.localContent.findIndex(c => c === content) }
|
static getContentIndex(content) { return this.localContent.findIndex(c => c === content) }
|
||||||
|
|
|
@ -45,11 +45,12 @@ export default class ExtModule {
|
||||||
get main() { return this.__pluginInternals.main }
|
get main() { return this.__pluginInternals.main }
|
||||||
get defaultConfig() { return this.configs.defaultConfig }
|
get defaultConfig() { return this.configs.defaultConfig }
|
||||||
get userConfig() { return this.configs.userConfig }
|
get userConfig() { return this.configs.userConfig }
|
||||||
get id() { return this.info.id || this.info.name.replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-') }
|
get id() { return this.info.id || this.info.name.toLowerCase().replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-') }
|
||||||
get name() { return this.info.name }
|
get name() { return this.info.name }
|
||||||
get authors() { return this.info.authors }
|
get authors() { return this.info.authors }
|
||||||
get version() { return this.info.version }
|
get version() { return this.info.version }
|
||||||
get pluginPath() { return this.paths.contentPath }
|
get contentPath() { return this.paths.contentPath }
|
||||||
|
get modulePath() { return this.paths.contentPath }
|
||||||
get dirName() { return this.paths.dirName }
|
get dirName() { return this.paths.dirName }
|
||||||
get enabled() { return true }
|
get enabled() { return true }
|
||||||
get config() { return this.userConfig.config || [] }
|
get config() { return this.userConfig.config || [] }
|
||||||
|
|
|
@ -39,7 +39,19 @@ export default class extends ContentManager {
|
||||||
|
|
||||||
static get loadContent() { return this.loadModule }
|
static get loadContent() { return this.loadModule }
|
||||||
static async loadModule(paths, configs, info, main) {
|
static async loadModule(paths, configs, info, main) {
|
||||||
return new ExtModule({ configs, info, main, paths: { contentPath: paths.contentPath, dirName: paths.dirName, mainPath: paths.mainPath } });
|
return new ExtModule({
|
||||||
|
configs, info, main,
|
||||||
|
paths: {
|
||||||
|
contentPath: paths.contentPath,
|
||||||
|
dirName: paths.dirName,
|
||||||
|
mainPath: paths.mainPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get isExtModule() { return this.isThisContent }
|
||||||
|
static isThisContent(module) {
|
||||||
|
return module instanceof ExtModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get findModule() { return this.findContent }
|
static get findModule() { return this.findContent }
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
import { Utils, FileUtils } from 'common';
|
import { Utils, FileUtils } from 'common';
|
||||||
import { Modals } from 'ui';
|
import { Modals } from 'ui';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
import PluginManager from './pluginmanager';
|
||||||
import ContentConfig from './contentconfig';
|
import ContentConfig from './contentconfig';
|
||||||
import { SettingUpdatedEvent, SettingsUpdatedEvent } from 'structs';
|
import { SettingUpdatedEvent, SettingsUpdatedEvent } from 'structs';
|
||||||
|
|
||||||
|
@ -52,10 +53,11 @@ export default class Plugin {
|
||||||
get defaultConfig() { return this.configs.defaultConfig }
|
get defaultConfig() { return this.configs.defaultConfig }
|
||||||
get userConfig() { return this.configs.userConfig }
|
get userConfig() { return this.configs.userConfig }
|
||||||
get configSchemes() { return this.configs.schemes }
|
get configSchemes() { return this.configs.schemes }
|
||||||
get id() { return this.info.id || this.name.replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-') }
|
get id() { return this.info.id || this.name.toLowerCase().replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-') }
|
||||||
get name() { return this.info.name }
|
get name() { return this.info.name }
|
||||||
get authors() { return this.info.authors }
|
get authors() { return this.info.authors }
|
||||||
get version() { return this.info.version }
|
get version() { return this.info.version }
|
||||||
|
get contentPath() { return this.paths.contentPath }
|
||||||
get pluginPath() { return this.paths.contentPath }
|
get pluginPath() { return this.paths.contentPath }
|
||||||
get dirName() { return this.paths.dirName }
|
get dirName() { return this.paths.dirName }
|
||||||
get enabled() { return this.userConfig.enabled }
|
get enabled() { return this.userConfig.enabled }
|
||||||
|
@ -122,25 +124,32 @@ export default class Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start(save = true) {
|
||||||
if (this.onstart && !this.onstart()) return false;
|
if (this.onstart && !this.onstart()) return false;
|
||||||
if (this.onStart && !this.onStart()) return false;
|
if (this.onStart && !this.onStart()) return false;
|
||||||
|
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
this.userConfig.enabled = true;
|
this.userConfig.enabled = true;
|
||||||
this.saveConfiguration();
|
if (save) this.saveConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop(save = true) {
|
||||||
if (this.onstop && !this.onstop()) return false;
|
if (this.onstop && !this.onstop()) return false;
|
||||||
if (this.onStop && !this.onStop()) return false;
|
if (this.onStop && !this.onStop()) return false;
|
||||||
|
|
||||||
|
if (this.enabled) {
|
||||||
this.userConfig.enabled = false;
|
this.userConfig.enabled = false;
|
||||||
this.saveConfiguration();
|
if (save) this.saveConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unload() {
|
||||||
|
PluginManager.unloadPlugin(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,12 @@ export default class extends ContentManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async loadAllPlugins(suppressErrors) {
|
static async loadAllPlugins(suppressErrors) {
|
||||||
|
this.loaded = false;
|
||||||
const loadAll = await this.loadAllContent(suppressErrors);
|
const loadAll = await this.loadAllContent(suppressErrors);
|
||||||
this.localPlugins.forEach(plugin => {
|
this.loaded = true;
|
||||||
|
for (let plugin of this.localPlugins) {
|
||||||
if (plugin.enabled) plugin.start();
|
if (plugin.enabled) plugin.start();
|
||||||
});
|
}
|
||||||
|
|
||||||
return loadAll;
|
return loadAll;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +48,6 @@ export default class extends ContentManager {
|
||||||
|
|
||||||
static get loadContent() { return this.loadPlugin }
|
static get loadContent() { return this.loadPlugin }
|
||||||
static async loadPlugin(paths, configs, info, main, dependencies) {
|
static async loadPlugin(paths, configs, info, main, dependencies) {
|
||||||
|
|
||||||
const deps = [];
|
const deps = [];
|
||||||
if (dependencies) {
|
if (dependencies) {
|
||||||
for (const [key, value] of Object.entries(dependencies)) {
|
for (const [key, value] of Object.entries(dependencies)) {
|
||||||
|
@ -61,36 +62,21 @@ export default class extends ContentManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugin = window.require(paths.mainPath)(Plugin, new PluginApi(info), Vendor, deps);
|
const plugin = window.require(paths.mainPath)(Plugin, new PluginApi(info), Vendor, deps);
|
||||||
const instance = new plugin({ configs, info, main, paths: { contentPath: paths.contentPath, dirName: paths.dirName, mainPath: paths.mainPath } });
|
const instance = new plugin({
|
||||||
|
configs, info, main,
|
||||||
|
paths: {
|
||||||
|
contentPath: paths.contentPath,
|
||||||
|
dirName: paths.dirName,
|
||||||
|
mainPath: paths.mainPath
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (instance.enabled && this.loaded) instance.start();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get unloadContent() { return this.unloadPlugin }
|
static get unloadPlugin() { return this.unloadContent }
|
||||||
static async unloadPlugin(plugin) {
|
static get reloadPlugin() { return this.reloadContent }
|
||||||
try {
|
|
||||||
if (plugin.enabled) plugin.stop();
|
|
||||||
const { pluginPath } = plugin;
|
|
||||||
const index = this.getPluginIndex(plugin);
|
|
||||||
|
|
||||||
delete window.require.cache[window.require.resolve(pluginPath)];
|
|
||||||
this.localPlugins.splice(index, 1);
|
|
||||||
} catch (err) {
|
|
||||||
//This might fail but we don't have any other option at this point
|
|
||||||
Logger.err('PluginManager', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async reloadPlugin(plugin) {
|
|
||||||
const _plugin = plugin instanceof Plugin ? plugin : this.findPlugin(plugin);
|
|
||||||
if (!_plugin) throw { 'message': 'Attempted to reload a plugin that is not loaded?' };
|
|
||||||
if (!_plugin.stop()) throw { 'message': 'Plugin failed to stop!' };
|
|
||||||
const index = this.getPluginIndex(_plugin);
|
|
||||||
const { pluginPath, dirName } = _plugin;
|
|
||||||
|
|
||||||
delete window.require.cache[window.require.resolve(pluginPath)];
|
|
||||||
|
|
||||||
return this.preloadContent(dirName, true, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static stopPlugin(name) {
|
static stopPlugin(name) {
|
||||||
const plugin = name instanceof Plugin ? name : this.getPluginByName(name);
|
const plugin = name instanceof Plugin ? name : this.getPluginByName(name);
|
||||||
|
@ -112,6 +98,11 @@ export default class extends ContentManager {
|
||||||
return true; //Return true anyways since plugin doesn't exist
|
return true; //Return true anyways since plugin doesn't exist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get isPlugin() { return this.isThisContent }
|
||||||
|
static isThisContent(plugin) {
|
||||||
|
return plugin instanceof Plugin;
|
||||||
|
}
|
||||||
|
|
||||||
static get findPlugin() { return this.findContent }
|
static get findPlugin() { return this.findContent }
|
||||||
static get getPluginIndex() { return this.getContentIndex }
|
static get getPluginIndex() { return this.getContentIndex }
|
||||||
static get getPluginByName() { return this.getContentByName }
|
static get getPluginByName() { return this.getContentByName }
|
||||||
|
|
|
@ -49,6 +49,7 @@ export default class Theme {
|
||||||
get icon() { return this.info.icon }
|
get icon() { return this.info.icon }
|
||||||
get paths() { return this.__themeInternals.paths }
|
get paths() { return this.__themeInternals.paths }
|
||||||
get main() { return this.__themeInternals.main }
|
get main() { return this.__themeInternals.main }
|
||||||
|
get loaded() { return this.__themeInternals.loaded }
|
||||||
get defaultConfig() { return this.configs.defaultConfig }
|
get defaultConfig() { return this.configs.defaultConfig }
|
||||||
get userConfig() { return this.configs.userConfig }
|
get userConfig() { return this.configs.userConfig }
|
||||||
get configSchemes() { return this.configs.schemes }
|
get configSchemes() { return this.configs.schemes }
|
||||||
|
@ -56,6 +57,7 @@ export default class Theme {
|
||||||
get name() { return this.info.name }
|
get name() { return this.info.name }
|
||||||
get authors() { return this.info.authors }
|
get authors() { return this.info.authors }
|
||||||
get version() { return this.info.version }
|
get version() { return this.info.version }
|
||||||
|
get contentPath() { return this.paths.contentPath }
|
||||||
get themePath() { return this.paths.contentPath }
|
get themePath() { return this.paths.contentPath }
|
||||||
get dirName() { return this.paths.dirName }
|
get dirName() { return this.paths.dirName }
|
||||||
get enabled() { return this.userConfig.enabled }
|
get enabled() { return this.userConfig.enabled }
|
||||||
|
@ -115,17 +117,17 @@ export default class Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enable() {
|
enable(save = true) {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
this.userConfig.enabled = true;
|
this.userConfig.enabled = true;
|
||||||
this.saveConfiguration();
|
if (save) this.saveConfiguration();
|
||||||
}
|
}
|
||||||
DOM.injectTheme(this.css, this.id);
|
DOM.injectTheme(this.css, this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
disable() {
|
disable(save = true) {
|
||||||
this.userConfig.enabled = false;
|
this.userConfig.enabled = false;
|
||||||
this.saveConfiguration();
|
if (save) this.saveConfiguration();
|
||||||
DOM.deleteTheme(this.id);
|
DOM.deleteTheme(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,8 @@ export default class ThemeManager extends ContentManager {
|
||||||
return 'themes';
|
return 'themes';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get loadAllThemes() {
|
static get loadAllThemes() { return this.loadAllContent }
|
||||||
return this.loadAllContent;
|
static get refreshThemes() { return this.refreshContent }
|
||||||
}
|
|
||||||
|
|
||||||
static get loadContent() { return this.loadTheme }
|
static get loadContent() { return this.loadTheme }
|
||||||
static async loadTheme(paths, configs, info, main) {
|
static async loadTheme(paths, configs, info, main) {
|
||||||
|
@ -53,6 +52,12 @@ export default class ThemeManager extends ContentManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get unloadTheme() { return this.unloadContent }
|
||||||
|
static async reloadTheme(theme) {
|
||||||
|
theme = await this.reloadContent(theme);
|
||||||
|
theme.recompile();
|
||||||
|
}
|
||||||
|
|
||||||
static enableTheme(theme) {
|
static enableTheme(theme) {
|
||||||
theme.enable();
|
theme.enable();
|
||||||
}
|
}
|
||||||
|
@ -61,8 +66,9 @@ export default class ThemeManager extends ContentManager {
|
||||||
theme.disable();
|
theme.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static reloadTheme(theme) {
|
static get isTheme() { return this.isThisContent }
|
||||||
theme.recompile();
|
static isThisContent(theme) {
|
||||||
|
return theme instanceof Theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getConfigAsSCSS(config) {
|
static async getConfigAsSCSS(config) {
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
.bd-drawer {
|
.bd-drawer {
|
||||||
border-bottom: 1px solid rgba(114, 118, 126, 0.3);
|
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.bd-settings-category > & {
|
||||||
|
border-bottom: 1px solid rgba(114, 118, 126, 0.3);
|
||||||
|
|
||||||
|
.bd-drawer-contents > .bd-form-item:last-child > .bd-form-divider:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.bd-form-header {
|
.bd-form-header {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -31,24 +38,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-drawer-contents {
|
.bd-drawer-contents {
|
||||||
|
// margin-top is set in JavaScript when the drawer is animating
|
||||||
|
// It still needs to be set here for it to animate
|
||||||
transition: transform 0.2s ease, margin-top 0.2s ease, opacity 0.2s ease;
|
transition: transform 0.2s ease, margin-top 0.2s ease, opacity 0.2s ease;
|
||||||
transform: scaleY(0) translateY(0%);
|
transform: scaleY(0) translateY(0%);
|
||||||
margin-top: -50%;
|
margin-top: -100%;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
||||||
> .bd-form-item:last-child > .bd-form-divider:last-child {
|
> .bd-form-item:last-child > .bd-form-divider:last-child {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bd-drawer-open {
|
&.bd-drawer-open {
|
||||||
.bd-drawer-open-button {
|
> .bd-drawer-header .bd-drawer-open-button {
|
||||||
.bd-chevron-1 {
|
.bd-chevron-1 {
|
||||||
svg {
|
svg {
|
||||||
transform: rotate(90deg)
|
transform: rotate(90deg)
|
||||||
|
@ -63,10 +66,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-drawer-contents {
|
> .bd-drawer-contents-wrap > .bd-drawer-contents {
|
||||||
transform: scaleY(1) translateY(0%);
|
transform: scaleY(1) translateY(0%);
|
||||||
margin-top: 0%;
|
margin-top: 0%;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,3 +38,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bd-form-customsetting {
|
||||||
|
&.bd-form-customsetting-debug + .bd-form-divider {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .bd-drawer {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,3 +6,4 @@
|
||||||
@import './forms/index.scss';
|
@import './forms/index.scss';
|
||||||
@import './material-buttons.scss';
|
@import './material-buttons.scss';
|
||||||
@import './drawers.scss';
|
@import './drawers.scss';
|
||||||
|
@import './preformatted.scss';
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
.bd-pre-wrap {
|
||||||
|
background: rgba(0, 0, 0, 0.1);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #b9bbbe;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-family: monospace;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
color: #fff;
|
||||||
|
border-color: #040405;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include scrollbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bd-pre {
|
||||||
|
padding: 11px;
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
<Button v-tooltip="'Settings'" v-if="plugin.hasSettings" :onClick="() => showSettings(plugin)"><MiSettings size="18" /></Button>
|
<Button v-tooltip="'Settings'" v-if="plugin.hasSettings" :onClick="() => showSettings(plugin)"><MiSettings size="18" /></Button>
|
||||||
<Button v-tooltip="'Reload'" :onClick="reloadPlugin"><MiRefresh size="18" /></Button>
|
<Button v-tooltip="'Reload'" :onClick="reloadPlugin"><MiRefresh size="18" /></Button>
|
||||||
<Button v-tooltip="'Edit'" :onClick="editPlugin"><MiPencil size="18" /></Button>
|
<Button v-tooltip="'Edit'" :onClick="editPlugin"><MiPencil size="18" /></Button>
|
||||||
<Button v-tooltip="'Uninstall'" type="err"><MiDelete size="18" /></Button>
|
<Button v-tooltip="'Uninstall (shift + click to unload)'" :onClick="deletePlugin" type="err"><MiDelete size="18" /></Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
settingsOpen: false
|
settingsOpen: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: ['plugin', 'togglePlugin', 'reloadPlugin', 'showSettings'],
|
props: ['plugin', 'togglePlugin', 'reloadPlugin', 'deletePlugin', 'showSettings'],
|
||||||
components: {
|
components: {
|
||||||
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<div class="bd-flex bd-flex-col bd-pluginsView">
|
<div class="bd-flex bd-flex-col bd-pluginsView">
|
||||||
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-plugins-container bd-local-plugins">
|
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-plugins-container bd-local-plugins">
|
||||||
<PluginCard v-for="plugin in localPlugins" :plugin="plugin" :key="plugin.id" :togglePlugin="() => togglePlugin(plugin)" :reloadPlugin="() => reloadPlugin(plugin)" :showSettings="() => showSettings(plugin)" />
|
<PluginCard v-for="plugin in localPlugins" :plugin="plugin" :key="plugin.id" :togglePlugin="() => togglePlugin(plugin)" :reloadPlugin="() => reloadPlugin(plugin)" :deletePlugin="e => deletePlugin(plugin, e.shiftKey)" :showSettings="() => showSettings(plugin)" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!local" class="bd-spinner-container">
|
<div v-if="!local" class="bd-spinner-container">
|
||||||
<div class="bd-spinner-2"></div>
|
<div class="bd-spinner-2"></div>
|
||||||
|
@ -67,11 +67,8 @@
|
||||||
async togglePlugin(plugin) {
|
async togglePlugin(plugin) {
|
||||||
// TODO Display error if plugin fails to start/stop
|
// TODO Display error if plugin fails to start/stop
|
||||||
try {
|
try {
|
||||||
if (plugin.enabled) {
|
await plugin.enabled ? PluginManager.stopPlugin(plugin) : PluginManager.startPlugin(plugin);
|
||||||
await PluginManager.stopPlugin(plugin);
|
this.$forceUpdate();
|
||||||
} else {
|
|
||||||
await PluginManager.startPlugin(plugin);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -84,6 +81,15 @@
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async deletePlugin(plugin, unload) {
|
||||||
|
try {
|
||||||
|
if (unload) await PluginManager.unloadPlugin(plugin);
|
||||||
|
else await PluginManager.deletePlugin(plugin);
|
||||||
|
this.$forceUpdate();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
showSettings(plugin) {
|
showSettings(plugin) {
|
||||||
return Modals.contentSettings(plugin);
|
return Modals.contentSettings(plugin);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
<SettingSwitch slot="toggle" :checked="theme.enabled" :change="toggleTheme" />
|
<SettingSwitch slot="toggle" :checked="theme.enabled" :change="toggleTheme" />
|
||||||
<ButtonGroup slot="controls">
|
<ButtonGroup slot="controls">
|
||||||
<Button v-tooltip="'Settings'" v-if="theme.hasSettings" :onClick="showSettings"><MiSettings size="18" /></Button>
|
<Button v-tooltip="'Settings'" v-if="theme.hasSettings" :onClick="showSettings"><MiSettings size="18" /></Button>
|
||||||
<Button v-tooltip="'Reload'" :onClick="reloadTheme"><MiRefresh size="18" /></Button>
|
<Button v-tooltip="'Recompile (shift + click to reload)'" :onClick="reloadTheme"><MiRefresh size="18" /></Button>
|
||||||
<Button v-tooltip="'Edit'" :onClick="editTheme"><MiPencil size="18" /></Button>
|
<Button v-tooltip="'Edit'" :onClick="editTheme"><MiPencil size="18" /></Button>
|
||||||
<Button v-tooltip="'Uninstall'" type="err"><MiDelete size="18" /></Button>
|
<Button v-tooltip="'Uninstall (shift + click to unload)'" :onClick="deleteTheme" type="err"><MiDelete size="18" /></Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
settingsOpen: false
|
settingsOpen: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: ['theme', 'toggleTheme', 'reloadTheme', 'showSettings'],
|
props: ['theme', 'toggleTheme', 'reloadTheme', 'deleteTheme', 'showSettings'],
|
||||||
components: {
|
components: {
|
||||||
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<div class="bd-flex bd-flex-col bd-themesView">
|
<div class="bd-flex bd-flex-col bd-themesView">
|
||||||
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-themes-container bd-local-themes">
|
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-themes-container bd-local-themes">
|
||||||
<ThemeCard v-for="theme in localThemes" :theme="theme" :key="theme.id" :toggleTheme="() => toggleTheme(theme)" :reloadTheme="() => reloadTheme(theme)" :showSettings="() => showSettings(theme)" />
|
<ThemeCard v-for="theme in localThemes" :theme="theme" :key="theme.id" :toggleTheme="() => toggleTheme(theme)" :reloadTheme="e => reloadTheme(theme, e.shiftKey)" :showSettings="() => showSettings(theme)" :deleteTheme="e => deleteTheme(theme, e.shiftKey)" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!local" class="bd-spinner-container">
|
<div v-if="!local" class="bd-spinner-container">
|
||||||
<div class="bd-spinner-2"></div>
|
<div class="bd-spinner-2"></div>
|
||||||
|
@ -59,31 +59,38 @@
|
||||||
this.local = false;
|
this.local = false;
|
||||||
},
|
},
|
||||||
async refreshLocal() {
|
async refreshLocal() {
|
||||||
await ThemeManager.refreshTheme();
|
await ThemeManager.refreshThemes();
|
||||||
},
|
},
|
||||||
async refreshOnline() {
|
async refreshOnline() {
|
||||||
|
|
||||||
},
|
},
|
||||||
toggleTheme(theme) {
|
async toggleTheme(theme) {
|
||||||
// TODO Display error if theme fails to enable/disable
|
// TODO Display error if theme fails to enable/disable
|
||||||
try {
|
try {
|
||||||
if (theme.enabled) {
|
await theme.enabled ? ThemeManager.disableTheme(theme) : ThemeManager.enableTheme(theme);
|
||||||
ThemeManager.disableTheme(theme);
|
this.$forceUpdate();
|
||||||
} else {
|
|
||||||
ThemeManager.enableTheme(theme);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async reloadTheme(theme) {
|
async reloadTheme(theme, reload) {
|
||||||
try {
|
try {
|
||||||
await ThemeManager.reloadTheme(theme);
|
if (reload) await ThemeManager.reloadTheme(theme);
|
||||||
|
else await theme.recompile();
|
||||||
this.$forceUpdate();
|
this.$forceUpdate();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async deleteTheme(theme, unload) {
|
||||||
|
try {
|
||||||
|
if (unload) await ThemeManager.unloadTheme(theme);
|
||||||
|
else await ThemeManager.deleteTheme(theme);
|
||||||
|
this.$forceUpdate();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
showSettings(theme) {
|
showSettings(theme) {
|
||||||
return Modals.contentSettings(theme);
|
return Modals.contentSettings(theme);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,8 +104,10 @@
|
||||||
|
|
||||||
for (let newCategory of newSettings) {
|
for (let newCategory of newSettings) {
|
||||||
const category = settings.find(c => c.category === newCategory.category);
|
const category = settings.find(c => c.category === newCategory.category);
|
||||||
|
if (!category) continue;
|
||||||
for (let newSetting of newCategory.settings) {
|
for (let newSetting of newCategory.settings) {
|
||||||
const setting = category.settings.find(s => s.id === newSetting.id);
|
const setting = category.settings.find(s => s.id === newSetting.id);
|
||||||
|
if (!setting) continue;
|
||||||
setting.value = setting.old_value = newSetting.value;
|
setting.value = setting.old_value = newSetting.value;
|
||||||
setting.changed = false;
|
setting.changed = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Custom Setting Component
|
||||||
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bd-form-customsetting" :class="{'bd-form-customsetting-debug': setting.debug}">
|
||||||
|
<component :is="component" :setting="setting" :change="change"></component>
|
||||||
|
<Drawer class="bd-form-customsetting-value" label="Custom setting data" v-if="setting.debug">
|
||||||
|
<pre class="bd-pre-wrap"><div class="bd-pre">{{ JSON.stringify(setting, null, 4) }}</div></pre>
|
||||||
|
</Drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { PluginManager } from 'modules';
|
||||||
|
import SettingsPanel from '../SettingsPanel.vue';
|
||||||
|
import Drawer from '../../common/Drawer.vue';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['setting', 'change'],
|
||||||
|
components: {
|
||||||
|
Drawer
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
component() {
|
||||||
|
if (typeof this.setting.file === 'string') {
|
||||||
|
const component = window.require(path.join(this.setting.path, this.setting.file));
|
||||||
|
return this.setting.component ? component[this.setting.component] : component.default ? component.default : component;
|
||||||
|
}
|
||||||
|
if (typeof this.setting.function === 'string') {
|
||||||
|
const plugin = PluginManager.getPluginByPath(this.setting.path);
|
||||||
|
if (!plugin) return;
|
||||||
|
const component = plugin[this.setting.function](this.setting, this.change);
|
||||||
|
if (component instanceof HTMLElement)
|
||||||
|
return this.componentFromHTMLElement(component, this.setting, this.change);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
if (typeof this.setting.component === 'string') {
|
||||||
|
const plugin = PluginManager.getPluginByPath(this.setting.path);
|
||||||
|
if (!plugin) return;
|
||||||
|
const component = plugin[this.setting.component];
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
if (typeof this.setting.component === 'object') {
|
||||||
|
return this.setting.component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
componentFromHTMLElement(htmlelement, setting, change) {
|
||||||
|
return {
|
||||||
|
template: '<div></div>',
|
||||||
|
props: ['setting', 'change'],
|
||||||
|
mounted() {
|
||||||
|
this.$el.appendChild(htmlelement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -19,6 +19,7 @@
|
||||||
<SliderSetting v-if="setting.type === 'slider'" :setting="setting" :change="change"/>
|
<SliderSetting v-if="setting.type === 'slider'" :setting="setting" :change="change"/>
|
||||||
<FileSetting v-if="setting.type === 'file'" :setting="setting" :change="change"/>
|
<FileSetting v-if="setting.type === 'file'" :setting="setting" :change="change"/>
|
||||||
<ArraySetting v-if="setting.type === 'array'" :setting="setting" :change="change" />
|
<ArraySetting v-if="setting.type === 'array'" :setting="setting" :change="change" />
|
||||||
|
<CustomSetting v-if="setting.type === 'custom'" :setting="setting" :change="change" />
|
||||||
<div class="bd-form-divider"></div>
|
<div class="bd-form-divider"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
import SliderSetting from './Slider.vue';
|
import SliderSetting from './Slider.vue';
|
||||||
import FileSetting from './File.vue';
|
import FileSetting from './File.vue';
|
||||||
import ArraySetting from './Array.vue';
|
import ArraySetting from './Array.vue';
|
||||||
|
import CustomSetting from './Custom.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
@ -48,7 +50,8 @@
|
||||||
MultilineTextSetting,
|
MultilineTextSetting,
|
||||||
SliderSetting,
|
SliderSetting,
|
||||||
FileSetting,
|
FileSetting,
|
||||||
ArraySetting
|
ArraySetting,
|
||||||
|
CustomSetting
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
changed() {
|
changed() {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bd-button" :class="[{'bd-disabled': disabled}, {'bd-err': type === 'err'}]" @click="!disabled && !loading ? onClick() : null">
|
<div class="bd-button" :class="[{'bd-disabled': disabled}, {'bd-err': type === 'err'}]" @click="!disabled && !loading ? onClick($event) : null">
|
||||||
<div v-if="loading" class="bd-spinner-7"></div>
|
<div v-if="loading" class="bd-spinner-7"></div>
|
||||||
<slot v-else />
|
<slot v-else />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="['bd-drawer', {'bd-drawer-open': open}]">
|
<div :class="['bd-drawer', {'bd-drawer-open': open, 'bd-animating': animating}]">
|
||||||
<div class="bd-form-header bd-drawer-header" @click="() => open = !open">
|
<div class="bd-form-header bd-drawer-header" @click="() => open = !open">
|
||||||
<span class="bd-form-header-text">{{ label }}</span>
|
<span class="bd-form-header-text">{{ label }}</span>
|
||||||
<span class="bd-form-header-button bd-drawer-open-button">
|
<span class="bd-form-header-button bd-drawer-open-button">
|
||||||
|
@ -18,8 +18,8 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="bd-drawer-contents-wrap">
|
<div class="bd-drawer-contents-wrap">
|
||||||
<div class="bd-drawer-contents">
|
<div class="bd-drawer-contents" ref="contents">
|
||||||
<slot />
|
<slot v-if="open || animating" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,7 +37,21 @@
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
open: false
|
open: false,
|
||||||
|
animating: false,
|
||||||
|
timeout: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
async open(open) {
|
||||||
|
this.animating = true;
|
||||||
|
const contents = this.$refs.contents;
|
||||||
|
contents.style.marginTop = 0 - contents.offsetHeight + 'px';
|
||||||
|
if (this.timeout) clearTimeout(this.timeout);
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
contents.style.marginTop = null;
|
||||||
|
this.animating = false;
|
||||||
|
}, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,10 +85,11 @@ export default class {
|
||||||
return this.add({ event }, ErrorModal);
|
return this.add({ event }, ErrorModal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static showContentManagerErrors() {
|
static showContentManagerErrors(clear = true) {
|
||||||
// Get any errors from PluginManager and ThemeManager
|
// Get any errors from PluginManager and ThemeManager
|
||||||
const errors = ([]).concat(PluginManager.errors).concat(ThemeManager.errors);
|
const errors = ([]).concat(PluginManager.errors).concat(ThemeManager.errors);
|
||||||
if (errors.length) return this.error({
|
if (errors.length) {
|
||||||
|
const modal = this.error({
|
||||||
header:
|
header:
|
||||||
(PluginManager.errors.length && ThemeManager.errors.length ? '' :
|
(PluginManager.errors.length && ThemeManager.errors.length ? '' :
|
||||||
(PluginManager.errors.length ? PluginManager.moduleName : ThemeManager.moduleName) + ' - ') +
|
(PluginManager.errors.length ? PluginManager.moduleName : ThemeManager.moduleName) + ' - ') +
|
||||||
|
@ -101,6 +102,14 @@ export default class {
|
||||||
type: 'err',
|
type: 'err',
|
||||||
content: errors
|
content: errors
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (clear) {
|
||||||
|
PluginManager._errors = [];
|
||||||
|
ThemeManager._errors = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return modal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static settings(headertext, settings, schemes, settingsUpdated, settingUpdated, saveSettings) {
|
static settings(headertext, settings, schemes, settingsUpdated, settingUpdated, saveSettings) {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports.default = {
|
||||||
|
template: "<div style=\"margin-bottom: 15px; background-color: rgba(0, 0, 0, 0.2); border: 1px dashed rgba(255, 255, 255, 0.2); padding: 10px; color: #f6f6f7; font-weight: 500; font-size: 15px;\">Test custom setting {{ setting.id }}. This is from component.js in the plugin/theme's directory. (It can use functions.)</div>",
|
||||||
|
props: ['setting', 'change']
|
||||||
|
};
|
|
@ -194,6 +194,51 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"category": "custom-settings",
|
||||||
|
"category_name": "Custom settings",
|
||||||
|
"type": "drawer",
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"id": "custom-1",
|
||||||
|
"type": "custom",
|
||||||
|
"value": false,
|
||||||
|
"component": {
|
||||||
|
"template": "<div style=\"margin-bottom: 15px; background-color: rgba(0, 0, 0, 0.2); border: 1px dashed rgba(255, 255, 255, 0.2); padding: 10px; color: #f6f6f7; font-weight: 500; font-size: 15px;\">Test custom setting {{ setting.id }}. This is included inline with the plugin/theme's config. (Which means it can't use any functions, but can still bind functions to events.) <button class=\"bd-button bd-button-primary\" style=\"display: inline-block; margin-left: 10px;\" @click=\"change(1)\">Set value to 1</button> <button class=\"bd-button bd-button-primary\" style=\"display: inline-block; margin-left: 10px;\" @click=\"change(2)\">Set value to 2</button></div>",
|
||||||
|
"props": [
|
||||||
|
"setting",
|
||||||
|
"change"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"debug": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom-2",
|
||||||
|
"type": "custom",
|
||||||
|
"value": false,
|
||||||
|
"file": "component.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom-3",
|
||||||
|
"type": "custom",
|
||||||
|
"value": false,
|
||||||
|
"component": "settingscomponent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom-4",
|
||||||
|
"type": "custom",
|
||||||
|
"value": false,
|
||||||
|
"function": "getSettingsComponent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom-5",
|
||||||
|
"type": "custom",
|
||||||
|
"value": false,
|
||||||
|
"function": "getSettingsComponentHTMLElement",
|
||||||
|
"debug": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"category_header_comment": "Setting a category other than default has a header with category name as the text",
|
"category_header_comment": "Setting a category other than default has a header with category name as the text",
|
||||||
"category": "test-category",
|
"category": "test-category",
|
||||||
|
|
|
@ -33,6 +33,11 @@ module.exports = (Plugin, Api, Vendor, Dependencies) => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUnload(reload) {
|
||||||
|
Logger.log('Unloading plugin');
|
||||||
|
delete require.cache[require.resolve('./component')];
|
||||||
|
}
|
||||||
|
|
||||||
eventTest(e) {
|
eventTest(e) {
|
||||||
Logger.log(e);
|
Logger.log(e);
|
||||||
}
|
}
|
||||||
|
@ -56,6 +61,44 @@ module.exports = (Plugin, Api, Vendor, Dependencies) => {
|
||||||
if (!this.enabled) return;
|
if (!this.enabled) return;
|
||||||
Logger.log([ 'Settings updated', settings ]);
|
Logger.log([ 'Settings updated', settings ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get settingscomponent() {
|
||||||
|
const plugin = this;
|
||||||
|
return this._settingscomponent ? this._settingscomponent : this._settingscomponent = {
|
||||||
|
template: "<div style=\"margin-bottom: 15px; background-color: rgba(0, 0, 0, 0.2); border: 1px dashed rgba(255, 255, 255, 0.2); padding: 10px; color: #f6f6f7; font-weight: 500; font-size: 15px;\">Test custom setting {{ setting.id }}. This is from Plugin.settingscomponent.<br />Plugin ID: {{ plugin.id }}</div>",
|
||||||
|
props: ['setting', 'change'],
|
||||||
|
data() { return { plugin }; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsComponent(setting, change) {
|
||||||
|
return this._settingscomponent2 ? this._settingscomponent2 : this.settingscomponent2 = {
|
||||||
|
template: "<div style=\"margin-bottom: 15px; background-color: rgba(0, 0, 0, 0.2); border: 1px dashed rgba(255, 255, 255, 0.2); padding: 10px; color: #f6f6f7; font-weight: 500; font-size: 15px;\">Test custom setting {{ setting.id }}. This is from Plugin.getSettingsComponent().</div>",
|
||||||
|
props: ['setting', 'change']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsComponentHTMLElement(setting, change) {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.setAttribute('style', 'margin-bottom: 15px; background-color: rgba(0, 0, 0, 0.2); border: 1px dashed rgba(255, 255, 255, 0.2); padding: 10px; color: #f6f6f7; font-weight: 500; font-size: 15px;');
|
||||||
|
el.textContent = `Test custom setting ${setting.id}. This is from Plugin.getSettingsComponentHTMLElement(). Current value: ${setting.value}.`;
|
||||||
|
|
||||||
|
const button1 = document.createElement('button');
|
||||||
|
button1.setAttribute('class', 'bd-button bd-button-primary');
|
||||||
|
button1.setAttribute('style', 'display: inline-block; margin-left: 10px;');
|
||||||
|
button1.addEventListener('click', () => change(1));
|
||||||
|
button1.textContent = 'Set value to 1';
|
||||||
|
el.appendChild(button1);
|
||||||
|
|
||||||
|
const button2 = document.createElement('button');
|
||||||
|
button2.setAttribute('class', 'bd-button bd-button-primary');
|
||||||
|
button2.setAttribute('style', 'display: inline-block; margin-left: 10px;');
|
||||||
|
button2.addEventListener('click', () => change(2));
|
||||||
|
button2.textContent = 'Set value to 2';
|
||||||
|
el.appendChild(button2);
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue