Skip to content

Commit 9552ca2

Browse files
committed
Merge remote
2 parents 50632c5 + fe544f9 commit 9552ca2

39 files changed

Lines changed: 12834 additions & 67 deletions

AutomaticSettings.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/**
22
* Load, save and apply options to HTML options page.
33
*
4-
* @module modules/AutomaticSettings
5-
* @requires internal/Trigger
6-
* @requires internal/LoadAndSave
4+
* @public
5+
* @module AutomaticSettings
6+
* @requires AutomaticSettings/Trigger
77
*/
88

99
// import and expose module parts

MobileOptions.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
* This prevents unnecessary flackering when the CSS is added and the browser needs to
88
* re-parse/render the HTML.
99
*
10-
* @module modules/MobileOptions
10+
* @public
11+
* @module MobileOptions
1112
*/
1213

1314
/**
1415
* Returns whether the current runtime is a mobile one (true) or not (false).
1516
*
16-
* @function
1717
* @private
1818
* @returns {Promise} with Boolean
1919
*/
@@ -33,7 +33,7 @@ async function isMobile() {
3333
* Currently this just adds a CSS class.
3434
* You can e.g. use this to disable all incompatible options on mobile devices.
3535
*
36-
* @private
36+
* @public
3737
* @returns {Promise}
3838
*/
3939
export async function init() {

README.md

Lines changed: 186 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
# TinyWebEx AutomaticSettings
22

3-
A simple module that allows you to specify your add-on settings in HTML-only, so you can focus on adding settings and not care about how to load and save them.
4-
It is also designed to be used with settings pages that save their settings automatically. There is no need for an "OK" button or so. However, it is flexible enough to allow you to not use this feature.
3+
A simple module that allows you to specify your add-on settings in HTML-only, so you can focus on adding settings and not care about how to load and save them. This means you do not have to write any custom JavaScript!
4+
It is also designed to be used with settings pages that save their settings automatically. There is no need for an "OK" button or similar confirmation after the user entered the data.
5+
6+
## Features
7+
* supports ["managed options"](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/storage/managed), i.e. loads options from the managed storage and marks them as "unchangable", i.e. disabled.
8+
* can automatically load all options into your HTML
9+
* can automatically save all options in a useful data format (number values are also saved as numbers, not strings)
10+
* [saving multiple options grouped together in JS objects](#option-groups)
11+
* [MessageHandler integration](https://github.com/TinyWebEx/MessageHandler), e.g. to show errors when saving or loading an option fails, or to show a message if some managed options are used.
12+
* [can automatically let your reset button spring to live](#reset-button)
513

614
## Usage
715

816
It mostly just works with some additions to your HTML code. The HTML code itself can be quite flexible then:
917

10-
* `class="setting"` attached to an `input` HTML tag enables handling of this setting. It is thus required.
11-
* The name (`name="greatSettingsNum"`) must be properly specified and is used.
12-
* Add a class via `class="save-on-change"` if the setting should be automatically saved when it is ["changed"/updated]().
13-
* Otherwise add `class="save-on-input"` if the setting should be automatically saved when it the [input event]() is triggered. This is e.g. useful when the simple change of an element is not enough to trigger a save. See the examples below on where that may be useful.
18+
* `class="setting"` attached to an `input` HTML tag enables the loading of this setting. It is thus required.
19+
* The [name attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#name) (e.g. `name="greatSettingsNum"`) must be properly specified and is used for saving the option in the `sync` storage.
20+
* Add a class via `class="save-on-change"` if the setting should be automatically saved when it is [changed](https://developer.mozilla.org/docs/Web/Events/change).
21+
* Otherwise add `class="save-on-input"` if the setting should be automatically saved when it the [input event](https://developer.mozilla.org/docs/Web/Events/input) is triggered. This is e.g. useful when the simple change of an element is not enough to trigger a save. See the examples below on where that may be useful.
22+
* You can optionally bind to different evens and validate entered data or overwrite loading and saving procedures via JavaScript.
23+
* Note that input fields that are disabled are never saved and their input/update events are ignored. Managed options are set to this disabled state, so that these are ignored.
1424

1525
## Examples
1626

17-
Obviously the examples below are minimal examples. Please anyway use proper HTML markup with `label` and such things. This has just nothing to do with this add-on. :)
27+
Obviously the examples below are minimal examples. Please anyway use proper HTML markup with `label` and so on. You can add almost any elements anywhere. This has just nothing to do with this add-on. 🙂
1828

1929
### Checkbox
2030

@@ -32,7 +42,175 @@ This e.g. changes a numeric value setting as `greatSettingsNum`:
3242
<input class="setting save-on-change" id="testSetting" name="greatSettingsNum" type="number">
3343
```
3444

35-
(This [example is taken from the unit tests](tests/automaticSettings.tests.js#225), BTW.)
45+
### Select element
46+
47+
To select a single value and save it as `select`:
48+
49+
```html
50+
<select id="selection" class="setting save-on-input" name="select" size="0">
51+
<option value="L">Low (7%)</option>
52+
<option value="M">Medium (15%)</option>
53+
<option value="Q">Quartile (25%)</option>
54+
<option value="H">High (30%)</option>
55+
</select>
56+
```
57+
58+
### Radio options
59+
60+
To create [radio buttons](https://developer.mozilla.org/docs/Web/HTML/Element/input/radio) you have follow some special handling.
61+
62+
```html
63+
<fieldset id="sizeGroup" data-type="radiogroup" class="setting save-on-input">
64+
<legend>set mode</legend>
65+
<ul>
66+
<li>
67+
<input id="sizeOne" type="radio" name="sizeType" value="oneValue">
68+
<label for="sizeOne">Size one</label>
69+
</li>
70+
71+
<li>
72+
<input id="sizeTwo" type="radio" name="sizeType" value="twoValue">
73+
<label for="sizeTwo">Size two</label>
74+
</li>
75+
76+
<li>
77+
<input id="sizeThree" type="radio" name="sizeType" value="threeValue">
78+
<label for="sizeThree">Size three</label>
79+
</li>
80+
</ul>
81+
</fieldset>
82+
```
83+
84+
You have to:
85+
* add `data-type="radiogroup"` to mark the container of the radio options as a radiogroup.
86+
* if you use a `fieldset` you can bind the save trigger to this fieldset as shown above, or to each individual `input type="radio"`. It's just easy to forget one element if you specify it individually, that's why the behaviour shown above is recommended.
87+
* Note, however, that it is always required to add the `setting` class to the container (i.e. `fieldset`), to enable the loading of this setting. Note that this is _not_ required for the indidual options.
88+
It can be useful, however, to prevent multiple triggers, if you e.g. have other options inside of the fieldset. These are e.g. also automatically triggered when a chield input is triggered, so this can lead to it being saved multiple times. This usually is not a (noteworthy) problem, but you can see it in the console log messages.
89+
90+
## Option groups
91+
92+
A usual use case is to save multiple options in a JavaScript object, i.e. something like this:
93+
```js
94+
groupName = {
95+
size: 170,
96+
sizeType: "auto",
97+
ignoreUserSize: true
98+
};
99+
```
100+
101+
This is natively supported by this add-on. Just add an attribute `data-optiongroup="groupName"` to all the options that you want to have grouped in an object. This can e.g. be useful if you have a [radio group](#radio-options) with sub-options that you want to have saved with the value of the radio buttons themselves.
102+
For instance, the following HTML would result in the object shown above:
103+
```html
104+
<li>
105+
<fieldset id="sizeType" data-type="radiogroup" data-optiongroup="groupName" class="setting">
106+
<legend>set mode</legend>
107+
<ul>
108+
<li>
109+
<input id="sizeOne" type="radio" name="sizeType" value="auto" class="save-on-input">
110+
<label for="sizeOne">Size auto</label>
111+
112+
<input class="setting save-on-input" type="number" data-optiongroup="groupName" name="size" id="partialSettingId">
113+
<span>px</span>
114+
</li>
115+
116+
<li>
117+
<input id="sizeTwo" type="radio" name="sizeType" value="manual" class="save-on-input">
118+
<label for="sizeTwo">Size manual</label>
119+
</li>
120+
121+
<li>
122+
<input id="sizeThree" type="radio" name="sizeType" value="whatever" class="save-on-input">
123+
<label for="sizeThree">Size whatever</label>
124+
</li>
125+
</ul>
126+
</fieldset>
127+
</li>
128+
<li>
129+
<input class="setting save-on-change" data-optiongroup="groupName" type="checkbox" name="ignoreUserSize" id="anotherOption">
130+
</li>
131+
```
132+
133+
## Loading the settings
134+
135+
To enable this plugin, you still a few lines of JavaScript - respectively one line:
136+
```js
137+
AutomaticSettings.init();
138+
```
139+
140+
This does load the options and registers bindings etc.
141+
142+
Obviously you need to pay attention to the fact to only do this after the DOM has been loaded, i.e. [the script should be deferred](https://developer.mozilla.org/docs/Web/HTML/Element/script#attr-defer).
143+
144+
## Trigger
145+
146+
You can additionally intercept loading and saving some settings or check the validity or similar things of some settings via JavaScript. This is all done via `AutomaticSettings.Trigger`.
147+
In most cases, you always pass the registration functions the name of the option to be saved as a string and the function that you want to register as a callback. Most triggers are valid for a single option, whose name you specify, in order to prevent that
148+
You can register as many triggers, as you want.
149+
150+
Generally, it is recommend to register all triggers _before_ calling the [`init` method](#loading-the-settings) of this module, but it also works to register triggers at any time.
151+
152+
### Update & Change trigger
153+
154+
You can use `AutomaticSettings.Trigger.registerUpdate` or `AutomaticSettings.Trigger.registerChange` to register a custom callback that is executed when the user updates (triggered by [input](https://developer.mozilla.org/docs/Web/Events/input)) or [changes](https://developer.mozilla.org/docs/Web/Events/change) an input option.
155+
156+
In both cases, you get the `optionValue` of the setting, the option name and the original event that triggered the request, so you can also find out the HTML element.
157+
158+
This is mostly useful if some options depend on each other (that happens often when using [option groups](#option-groups) e.g.), so you can interactively disable elements based on the user selection/input; or, if you want top verify the data the user entered and show some warnings or so.
159+
160+
Note however, that this way is separate from the whole loading & saving of the data, so you cannot prevent an invalid value from being saved or so, here. Do [overwrite the loading or saving behaviour](#overwriting-loading-and-saving-behaviour) if you want to do this.
161+
162+
Note that you need to add the additional classes `trigger-on-update` (for the update trigger/`registerUpdate`) or `trigger-on-change` (for the input trigger/`registerChange`) to the respective options, to make this feature work. Without it, the library does not bind to these elements.
163+
164+
### Save trigger
165+
166+
You can use `AutomaticSettings.Trigger.registerSave` to register a "save trigger" that is executed when an option is saved (actually directly before it is saved).
167+
It is thus quite useful to automatically apply the option or send it to other parts of the browser extension, so they are notified that a the value of the option changed. This is a useful feature for your usability, because the `AutomaticSetings` module automatically saves all options, so they should also automatically be applied, so the user immediately sees the difference.
168+
169+
You can also use it to validate the input and cancel saving, you need to throw some errors then. Note that you should then show an appropriate error message yourself, as this error is not catched by the library - in contrast to everything else that happens afterwards, i.e. the saving of the option itself, e.g.
170+
171+
### Triggers before and after loading
172+
173+
When the triggers are used as expected, you usually get to one problem: Directly after your options have been loaded, you may see an inconsistent state, as your [save triggers](#save-trigger) did not yet run and no checks on the previously loaded data is done, etc.
174+
175+
To solve this, there is `AutomaticSettings.Trigger.registerAfterLoad`, which can be used to register a handler that is run after _all_ settings have been loaded. To make it easier to implement you can even pass it the special variable `AutomaticSettings.Trigger.RUN_ALL_SAVE_TRIGGER` that tells it to automatically execute all save triggers, you have registered. This is usually what you want. 🙂
176+
177+
Similarly there is `AutomaticSettings.Trigger.registerBeforeLoad` to let you execute stuff before any option is loaded.
178+
179+
### Overwriting loading and saving behavior
180+
181+
Sometimes it is needed to present data to the user in one way, but save it in another way. Thus, you need to manipulate how data is loaded or saved.
182+
If [option groups](#option-groups) are not enough for you, you can use `AutomaticSettings.Trigger.addCustomLoadOverride` and `AutomaticSettings.Trigger.addCustomSaveOverride` to override the respective features.
183+
184+
As always in these triggers, you get some information about the option that is loaded/saved and can check that. However, in addition you can get the data returned by your [save trigger](#save-trigger) in `saveTriggerValues`, so you can re-use it.
185+
186+
In contrast to the [save triggers](#save-trigger) you can also actually influence/overwrite whether/how the value is loaded/saved. By default, the library assumes you now handle loading and saving by yourself, i.e. you need to interact with the HTML DOM (for loading) or the storage API (for saving) directly. By all means, you are overwriting the loading/saving process...
187+
However, you can also return a special value that is returned by `AutomaticSettings.Trigger.overrideContinue` to indicate you want to continue saving/loading, but use different data for it, i.e. you just modify the data to load/save. You just pass it the value you want to continue the process.
188+
189+
In the end, it can e.g. look like this:
190+
191+
```js
192+
/**
193+
* Saves the option XY.
194+
*
195+
* @private
196+
* @param {Object} param
197+
* @param {Object} param.optionValue the value of the changed option
198+
* @param {string} param.option the name of the option that has been changed
199+
* @param {Array} param.saveTriggerValues all values returned by potentially
200+
* previously run save triggers
201+
* @returns {Promise}
202+
*/
203+
function saveOptionXy(param) {
204+
// our proper data is saved in saveTriggerValues by previously run save trigger
205+
const newOption = param.saveTriggerValues[0];
206+
207+
return AutomaticSettings.Trigger.overrideContinue(newOption);
208+
}
209+
```
210+
211+
## Reset buttons
212+
213+
Doc is TODO…
36214

37215
## API note
38216

docs/AutomaticSettings.js.html

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
5+
<meta charset="utf-8">
6+
<title>AutomaticSettings.js - Documentation</title>
7+
8+
9+
<script src="scripts/prettify/prettify.js"></script>
10+
<script src="scripts/prettify/lang-css.js"></script>
11+
<!--[if lt IE 9]>
12+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13+
<![endif]-->
14+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
15+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
17+
</head>
18+
<body>
19+
20+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
21+
<label for="nav-trigger" class="navicon-button x">
22+
<div class="navicon"></div>
23+
</label>
24+
25+
<label for="nav-trigger" class="overlay"></label>
26+
27+
<nav >
28+
29+
<h2><a href="index.html">Home</a></h2><h2><a href="https://github.com/TinyWebEx/" >All TinyWebExt modules</a></h2><h3>Modules</h3><ul><li><a href="module-AutomaticSettings.html">AutomaticSettings</a><ul class='methods'><li data-type='method'><a href="module-AutomaticSettings.html#.init">init</a></li><li data-type='method'><a href="module-AutomaticSettings.html#.setDefaultOptionProvider">setDefaultOptionProvider</a></li></ul></li><li></li><li></li><li><a href="module-AutomaticSettings_Trigger.html">AutomaticSettings/Trigger</a><ul class='methods'><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~addCustomLoadOverride">addCustomLoadOverride</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~addCustomSaveOverride">addCustomSaveOverride</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~overrideContinue">overrideContinue</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~registerAfterLoad">registerAfterLoad</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~registerBeforeLoad">registerBeforeLoad</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~registerChange">registerChange</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~registerSave">registerSave</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~registerUpdate">registerUpdate</a></li><li data-type='method'><a href="module-AutomaticSettings_Trigger.html#~unregisterAll">unregisterAll</a></li></ul></li><li><a href="module-MobileOptions.html">MobileOptions</a><ul class='methods'><li data-type='method'><a href="module-MobileOptions.html#.init">init</a></li></ul></li></ul>
30+
</nav>
31+
32+
<div id="main">
33+
34+
<h1 class="page-title">AutomaticSettings.js</h1>
35+
36+
37+
38+
39+
40+
41+
42+
<section>
43+
<article>
44+
<pre class="prettyprint source linenums"><code>/**
45+
* Load, save and apply options to HTML options page.
46+
*
47+
* @public
48+
* @module AutomaticSettings
49+
* @requires AutomaticSettings/Trigger
50+
*/
51+
52+
// import and expose module parts
53+
export { default as Trigger } from "./internal/Trigger.js";
54+
export * from "./internal/LoadAndSave.js";
55+
export { setDefaultOptionProvider } from "./internal/OptionsModel.js";
56+
</code></pre>
57+
</article>
58+
</section>
59+
60+
61+
62+
63+
64+
65+
</div>
66+
67+
<br class="clear">
68+
69+
<footer>
70+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sun Jan 20 2019 22:24:02 GMT+0100 (Mitteleuropäische Normalzeit) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
71+
</footer>
72+
73+
<script>prettyPrint();</script>
74+
<script src="scripts/linenumber.js"></script>
75+
76+
77+
</body>
78+
</html>

0 commit comments

Comments
 (0)