Emit an event when a configuration setting gets changed
This commit is contained in:
parent
05dcb4e8d7
commit
9e48fdc91c
|
@ -2,6 +2,7 @@
|
|||
|
||||
## 9.0.0 (Unreleased)
|
||||
|
||||
- Emit a `change` event when a configuration setting changes
|
||||
- 3 New configuration settings:
|
||||
- [render_media](https://conversejs.org/docs/html/configuration.html#render-media)
|
||||
- [allowed_audio_domains](https://conversejs.org/docs/html/configuration.html#allowed-audio-domains)
|
||||
|
|
|
@ -35,6 +35,7 @@ module.exports = function(config) {
|
|||
{ pattern: "src/headless/plugins/roster/tests/presence.js", type: 'module' },
|
||||
{ pattern: "src/headless/plugins/smacks/tests/smacks.js", type: 'module' },
|
||||
{ pattern: "src/headless/plugins/status/tests/status.js", type: 'module' },
|
||||
{ pattern: "src/headless/shared/settings/tests/settings.js", type: 'module' },
|
||||
{ pattern: "src/headless/tests/converse.js", type: 'module' },
|
||||
{ pattern: "src/headless/tests/eventemitter.js", type: 'module' },
|
||||
{ pattern: "src/modals/tests/user-details-modal.js", type: 'module' },
|
||||
|
@ -63,7 +64,6 @@ module.exports = function(config) {
|
|||
{ pattern: "src/plugins/mam-views/tests/placeholder.js", type: 'module' },
|
||||
{ pattern: "src/plugins/minimize/tests/minchats.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/autocomplete.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/mep.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/component.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/corrections.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/emojis.js", type: 'module' },
|
||||
|
@ -72,6 +72,7 @@ module.exports = function(config) {
|
|||
{ pattern: "src/plugins/muc-views/tests/markers.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/me-messages.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/mentions.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/mep.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/modtools.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/muc-api.js", type: 'module' },
|
||||
{ pattern: "src/plugins/muc-views/tests/muc-mentions.js", type: 'module' },
|
||||
|
|
|
@ -5,6 +5,8 @@ import {
|
|||
extendAppSettings,
|
||||
getAppSetting,
|
||||
getUserSettings,
|
||||
registerListener,
|
||||
unregisterListener,
|
||||
updateAppSettings,
|
||||
updateUserSettings,
|
||||
} from '@converse/headless/shared/settings/utils.js';
|
||||
|
@ -81,6 +83,40 @@ export const settings_api = {
|
|||
set (key, val) {
|
||||
updateAppSettings(key, val);
|
||||
},
|
||||
|
||||
/**
|
||||
* The `listen` namespace exposes methods for creating event listeners
|
||||
* (aka handlers) for events related to settings.
|
||||
*
|
||||
* @namespace _converse.api.settings.listen
|
||||
* @memberOf _converse.api.settings
|
||||
*/
|
||||
listen: {
|
||||
/**
|
||||
* Register an event listener for the passed in event.
|
||||
* @method _converse.api.settings.listen.on
|
||||
* @param { ('change') } name - The name of the event to listen for.
|
||||
* Currently there is only the 'change' event.
|
||||
* @param { Function } handler - The event handler function
|
||||
* @param { Object } [context] - The context of the `this` attribute of the
|
||||
* handler function.
|
||||
* @example _converse.api.settings.listen.on('change', callback);
|
||||
*/
|
||||
on (name, handler, context) {
|
||||
registerListener(name, handler, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* To stop listening to an event, you can use the `not` method.
|
||||
* @method _converse.api.settings.listen.not
|
||||
* @param { String } name The event's name
|
||||
* @param { Function } callback The callback method that is to no longer be called when the event fires
|
||||
* @example _converse.api.settings.listen.not('change', callback);
|
||||
*/
|
||||
not (name, handler) {
|
||||
unregisterListener(name, handler);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
91
src/headless/shared/settings/tests/settings.js
Normal file
91
src/headless/shared/settings/tests/settings.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*global mock */
|
||||
|
||||
|
||||
describe("The \"settings\" API", function () {
|
||||
it("has methods 'get' and 'set' to set configuration settings",
|
||||
mock.initConverse(null, {'play_sounds': true}, (_converse) => {
|
||||
|
||||
const { api } = _converse;
|
||||
|
||||
expect(Object.keys(api.settings)).toEqual(["extend", "update", "get", "set", "listen"]);
|
||||
expect(api.settings.get("play_sounds")).toBe(true);
|
||||
api.settings.set("play_sounds", false);
|
||||
expect(api.settings.get("play_sounds")).toBe(false);
|
||||
api.settings.set({"play_sounds": true});
|
||||
expect(api.settings.get("play_sounds")).toBe(true);
|
||||
// Only whitelisted settings allowed.
|
||||
expect(typeof api.settings.get("non_existing")).toBe("undefined");
|
||||
api.settings.set("non_existing", true);
|
||||
expect(typeof api.settings.get("non_existing")).toBe("undefined");
|
||||
}));
|
||||
|
||||
it("extended via settings.extend don't override settings passed in via converse.initialize",
|
||||
mock.initConverse([], {'emoji_categories': {"travel": ":rocket:"}}, (_converse) => {
|
||||
|
||||
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
|
||||
|
||||
// Test that the extend command doesn't override user-provided site
|
||||
// settings (i.e. settings passed in via converse.initialize).
|
||||
_converse.api.settings.extend({'emoji_categories': {"travel": ":motorcycle:", "food": ":burger:"}});
|
||||
|
||||
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
|
||||
expect(_converse.api.settings.get('emoji_categories')?.food).toBe(undefined);
|
||||
}));
|
||||
|
||||
it("only overrides the passed in properties",
|
||||
mock.initConverse([],
|
||||
{
|
||||
'root': document.createElement('div').attachShadow({ 'mode': 'open' }),
|
||||
'emoji_categories': { 'travel': ':rocket:' },
|
||||
},
|
||||
(_converse) => {
|
||||
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
|
||||
|
||||
// Test that the extend command doesn't override user-provided site
|
||||
// settings (i.e. settings passed in via converse.initialize).
|
||||
_converse.api.settings.extend({
|
||||
'emoji_categories': { 'travel': ':motorcycle:', 'food': ':burger:' },
|
||||
});
|
||||
|
||||
expect(_converse.api.settings.get('emoji_categories').travel).toBe(':rocket:');
|
||||
expect(_converse.api.settings.get('emoji_categories').food).toBe(undefined);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
describe("Configuration settings", function () {
|
||||
|
||||
describe("when set", function () {
|
||||
|
||||
it("will trigger a change event for which listeners can be registered",
|
||||
mock.initConverse([], {}, function (_converse) {
|
||||
|
||||
const { api } = _converse;
|
||||
let changed;
|
||||
const callback = (o) => {
|
||||
changed = o;
|
||||
}
|
||||
api.settings.listen.on('change', callback);
|
||||
api.settings.set('allowed_image_domains', ['conversejs.org']);
|
||||
expect(changed).toEqual({'allowed_image_domains': ['conversejs.org']});
|
||||
|
||||
api.settings.set('allowed_image_domains', ['conversejs.org', 'opkode.com']);
|
||||
expect(changed).toEqual({'allowed_image_domains': ['conversejs.org', 'opkode.com']});
|
||||
|
||||
api.settings.listen.not('change', callback);
|
||||
|
||||
api.settings.set('allowed_image_domains', ['conversejs.org', 'opkode.com', 'inverse.chat']);
|
||||
expect(changed).toEqual({'allowed_image_domains': ['conversejs.org', 'opkode.com']});
|
||||
|
||||
api.settings.listen.on('change:allowed_image_domains', callback);
|
||||
|
||||
api.settings.set('allowed_video_domains', ['inverse.chat']);
|
||||
expect(changed).toEqual({'allowed_image_domains': ['conversejs.org', 'opkode.com']});
|
||||
|
||||
api.settings.set('allowed_image_domains', ['inverse.chat']);
|
||||
expect(changed).toEqual(['inverse.chat']);
|
||||
}));
|
||||
});
|
||||
});
|
|
@ -1,10 +1,12 @@
|
|||
import _converse from '@converse/headless/shared/_converse';
|
||||
import assignIn from 'lodash-es/assignIn';
|
||||
import isEqual from "lodash-es/isEqual.js";
|
||||
import isObject from 'lodash-es/isObject';
|
||||
import log from '@converse/headless/log';
|
||||
import pick from 'lodash-es/pick';
|
||||
import u from '@converse/headless/utils/core';
|
||||
import { DEFAULT_SETTINGS } from './constants.js';
|
||||
import { Events } from '@converse/skeletor/src/events.js';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { initStorage } from '@converse/headless/utils/storage.js';
|
||||
|
||||
|
@ -12,6 +14,10 @@ let init_settings = {}; // Container for settings passed in via converse.initial
|
|||
let app_settings = {};
|
||||
let user_settings; // User settings, populated via api.users.settings
|
||||
|
||||
const app_settings_emitter = {};
|
||||
Object.assign(app_settings_emitter, Events);
|
||||
|
||||
|
||||
export function getAppSettings () {
|
||||
return app_settings;
|
||||
}
|
||||
|
@ -44,14 +50,36 @@ export function extendAppSettings (settings) {
|
|||
u.merge(app_settings, updated_settings);
|
||||
}
|
||||
|
||||
export function registerListener (name, func, context) {
|
||||
app_settings_emitter.on(name, func, context)
|
||||
}
|
||||
|
||||
export function unregisterListener (name, func) {
|
||||
app_settings_emitter.off(name, func);
|
||||
}
|
||||
|
||||
export function updateAppSettings (key, val) {
|
||||
const o = {};
|
||||
if (key == null) return this; // eslint-disable-line no-eq-null
|
||||
|
||||
let attrs;
|
||||
if (isObject(key)) {
|
||||
assignIn(app_settings, pick(key, Object.keys(DEFAULT_SETTINGS)));
|
||||
attrs = key;
|
||||
} else if (typeof key === 'string') {
|
||||
o[key] = val;
|
||||
assignIn(app_settings, pick(o, Object.keys(DEFAULT_SETTINGS)));
|
||||
attrs = {};
|
||||
attrs[key] = val;
|
||||
}
|
||||
|
||||
const allowed_keys = Object.keys(pick(attrs, Object.keys(DEFAULT_SETTINGS)));
|
||||
const changed = {};
|
||||
allowed_keys.forEach(k => {
|
||||
const val = attrs[k];
|
||||
if (!isEqual(app_settings[k], val)) {
|
||||
changed[k] = val;
|
||||
app_settings[k] = val;
|
||||
}
|
||||
});
|
||||
Object.keys(changed).forEach(k => app_settings_emitter.trigger('change:' + k, changed[k]));
|
||||
app_settings_emitter.trigger('change', changed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -246,59 +246,7 @@ describe("Converse", function() {
|
|||
}));
|
||||
});
|
||||
|
||||
describe("The \"settings\" API", function() {
|
||||
it("has methods 'get' and 'set' to set configuration settings",
|
||||
mock.initConverse(null, {'play_sounds': true}, (_converse) => {
|
||||
|
||||
expect(Object.keys(_converse.api.settings)).toEqual(["extend", "update", "get", "set"]);
|
||||
expect(_converse.api.settings.get("play_sounds")).toBe(true);
|
||||
_converse.api.settings.set("play_sounds", false);
|
||||
expect(_converse.api.settings.get("play_sounds")).toBe(false);
|
||||
_converse.api.settings.set({"play_sounds": true});
|
||||
expect(_converse.api.settings.get("play_sounds")).toBe(true);
|
||||
// Only whitelisted settings allowed.
|
||||
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
|
||||
_converse.api.settings.set("non_existing", true);
|
||||
expect(typeof _converse.api.settings.get("non_existing")).toBe("undefined");
|
||||
}));
|
||||
|
||||
it("extended via settings.extend don't override settings passed in via converse.initialize",
|
||||
mock.initConverse([], {'emoji_categories': {"travel": ":rocket:"}}, (_converse) => {
|
||||
|
||||
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
|
||||
|
||||
// Test that the extend command doesn't override user-provided site
|
||||
// settings (i.e. settings passed in via converse.initialize).
|
||||
_converse.api.settings.extend({'emoji_categories': {"travel": ":motorcycle:", "food": ":burger:"}});
|
||||
|
||||
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
|
||||
expect(_converse.api.settings.get('emoji_categories')?.food).toBe(undefined);
|
||||
}));
|
||||
|
||||
it("only overrides the passed in properties",
|
||||
mock.initConverse([],
|
||||
{
|
||||
'root': document.createElement('div').attachShadow({ 'mode': 'open' }),
|
||||
'emoji_categories': { 'travel': ':rocket:' },
|
||||
},
|
||||
(_converse) => {
|
||||
expect(_converse.api.settings.get('emoji_categories')?.travel).toBe(':rocket:');
|
||||
|
||||
// Test that the extend command doesn't override user-provided site
|
||||
// settings (i.e. settings passed in via converse.initialize).
|
||||
_converse.api.settings.extend({
|
||||
'emoji_categories': { 'travel': ':motorcycle:', 'food': ':burger:' },
|
||||
});
|
||||
|
||||
expect(_converse.api.settings.get('emoji_categories').travel).toBe(':rocket:');
|
||||
expect(_converse.api.settings.get('emoji_categories').food).toBe(undefined);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
describe("The \"plugins\" API", function() {
|
||||
describe("The \"plugins\" API", function () {
|
||||
it("only has a method 'add' for registering plugins", mock.initConverse((_converse) => {
|
||||
expect(Object.keys(converse.plugins)).toEqual(["add"]);
|
||||
// Cheating a little bit. We clear the plugins to test more easily.
|
||||
|
@ -311,7 +259,7 @@ describe("Converse", function() {
|
|||
_converse.pluggable.plugins = _old_plugins;
|
||||
}));
|
||||
|
||||
describe("The \"plugins.add\" method", function() {
|
||||
describe("The \"plugins.add\" method", function () {
|
||||
it("throws an error when multiple plugins attempt to register with the same name",
|
||||
mock.initConverse((_converse) => { // eslint-disable-line no-unused-vars
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user