modules/luci-compat/src/contrib/lemon
modules/luci-compat/src/plural_formula.c
modules/luci-compat/src/plural_formula.h
-docs/jsapi/*
-!docs/jsapi/README.md
+docs/**/*.*
**eslint.config**
!eslint.config.mjs
```
To install all its package definitions, run:
-```
+```sh
./scripts/feeds update luci
./scripts/feeds install -a -p luci
```
You can browse the generated API documentation directly on Github.
- - [Server side Lua APIs](http://openwrt.github.io/luci/api/index.html); Note: deprecated - Lua will be removed in future. Use ucode rpcd for server side operations.
+Use [ucode](https://ucode.mein.io/) and rpcd for server side operations.
+
- [Client side JavaScript APIs](http://openwrt.github.io/luci/jsapi/index.html)
## Development
--- /dev/null
+# LMO - Lua Machine Objects
+
+See [online wiki](https://github.com/openwrt/luci/wiki/LMO) for latest version.
+
+LMO is a simple binary format to pack language strings into a more efficient form.
+Although it's suitable to store any kind of key-value table, it's only used for the LuCI \*.po based translation system at the moment.
+The abbreviation "LMO" stands for "Lua Machine Objects" in the style of the GNU gettext \*.mo format.
+
+## Format Specification
+
+A LMO file is divided into two parts: the payload and the index lookup table.
+All segments of the file are 4 Byte aligned to ease reading and processing of the format.
+Only unsigned 32bit integers are used and stored in network byte order, so an implementation has to use htonl() to properly read them.
+
+Schema:
+
+ <file:
+ <payload:
+ <entry #1: 4 byte aligned data>
+
+ <entry #2: 4 byte aligned data>
+
+ ...
+
+ <entry #N: 4 byte aligned data>
+ >
+
+ <index table:
+ <entry #1:
+ <uint32_t: hash of the first key>
+ <uint32_t: hash of the first value>
+ <uint32_t: file offset of the first value>
+ <uint32_t: length of the first value>
+ >
+
+ <entry #2:
+ <uint32_t: hash of the second key>
+ <uint32_t: hash of the second value>
+ <uint32_t: file offset of the second value>
+ <uint32_t: length of the second value>
+ >
+
+ ...
+
+ <entry #N:
+ <uint32_t: hash of the Nth key>
+ <uint32_t: hash of the Nth value>
+ <uint32_t: file offset of the Nth value>
+ <uint32_t: length of the Nth value>
+ >
+ >
+
+ <uint32_t: offset of the begin of index table>
+ >
+
+
+
+## Processing
+
+In order to process a LMO file, an implementation would have to do the following steps:
+
+### Read Index
+
+1. Locate and open the archive file
+2. Seek to end of file - 4 bytes (sizeof(uint32_t))
+3. Read 32bit index offset and swap from network to native byte order
+4. Seek to index offset, calculate index length: filesize - index offset - 4
+5. Initialize a linked list for index table entries
+6. Read each index entry until the index length is reached, read and byteswap 4 * uint32_t for each step
+7. Seek to begin of file
+
+### Read Entry
+
+1. Calculate the unsigned 32bit hash of the entries key value (see "Hash Function" section below)
+2. Obtain the archive index
+3. Iterate through the linked index list, perform the following steps for each entry:
+ 1. Compare the entry hash value with the calculated hash from step 1
+ 2. If the hash values are equal proceed with step 4
+ 3. Select the next entry and repeat from step 3.1
+4. Seek to the file offset specified in the selected entry
+5. Read as much bytes as specified in the entry length into a buffer
+6. Return the buffer value
+
+## Hash Function
+
+The current LuCI-LMO implementation uses the "Super Fast Hash" function which was kindly put in the public domain by its original author. See http://www.azillionmonkeys.com/qed/hash.html for details. Below is the C-Implementation of this function:
+
+```c
+#if (defined(__GNUC__) && defined(__i386__))
+#define sfh_get16(d) (*((const uint16_t *) (d)))
+#else
+#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t sfh_hash(const char * data, int len)
+{
+ uint32_t hash = len, tmp;
+ int rem;
+
+ if (len <= 0 || data == NULL) return 0;
+
+ rem = len & 3;
+ len >>= 2;
+
+ /* Main loop */
+ for (;len > 0; len--) {
+ hash += sfh_get16(data);
+ tmp = (sfh_get16(data+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ data += 2*sizeof(uint16_t);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem) {
+ case 3: hash += sfh_get16(data);
+ hash ^= hash << 16;
+ hash ^= data[sizeof(uint16_t)] << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += sfh_get16(data);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += *data;
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
+```
+
+## Reference Implementation
+
+A reference implementation can be found here:
+https://github.com/openwrt/luci/blob/master/modules/luci-lua-runtime/src/template_lmo.c
+
+The `po2lmo.c` executable implements a `*.po` to `*.lmo` conversation utility.
+Lua bindings for lmo are defined in `template_lualib.c` and associated headers.
--- /dev/null
+# LuCI Documentation
+
+Start with the [LuCI Client side JavaScript APIs](LuCI.html)
+
+
+
+
+## Historical
+
+The older [Lua API docs](api/index.html) are available for historical reference.
\ No newline at end of file
--- /dev/null
+.navbar-item.github-home a {
+ background-image: url("data:image/svg+xml,%3Csvg width='98' height='96' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z' fill='%2324292f'/%3E%3C/svg%3E");
+ background-repeat: no-repeat;
+ background-size: 1.5em;
+ background-position: 1rem center;
+ padding-left: 3rem;
+}
+
+.signature-attributes {
+ font-style:italic;
+ font-weight:lighter;
+ font-variant:sub;
+}
+
+span.param-type {
+ color:#00918e;
+}
+
+.type-signature {
+ display: inline-block;
+ color:#00918e;
+}
+
+.type-signature::after {
+ content: ' ';
+}
+
+span.signature::after {
+ content: ' ';
+}
+
+table.props tbody td,
+table.params tbody td {
+ padding: 0.5rem;
+}
--- /dev/null
+# Using the JSON-RPC API
+
+LuCI provides some of its libraries to external applications through a [JSON-RPC](https://en.wikipedia.org/wiki/JSON-RPC) API.
+This Howto shows how to use it and provides information about available functions.
+
+See also
+* wiki [rpcd](https://openwrt.org/docs/techref/rpcd)
+* wiki [ubus](https://openwrt.org/docs/techref/ubus)
+
+## Basics
+The API is installed by default.
+
+LuCI comes with an efficient JSON De-/Encoder together with a JSON-RPC-Server which implements the JSON-RPC 1.0 and 2.0 (partly) specifications.
+The LuCI JSON-RPC server offers several independent APIs.
+Therefore you have to use **different URLs for every exported library**.
+Assuming your LuCI-Installation can be reached through `/cgi-bin/luci`, any exported library can be reached via `/cgi-bin/luci/rpc/LIBRARY`.
+
+
+## Authentication
+Most exported libraries will require a valid authentication to be called with.
+If you get an `HTTP 403 Forbidden` status code you are probably missing a valid authentication token.
+To get such a token you have to call the `login` method of the RPC-Library `auth`.
+Following our example from above this login function would be provided at `/cgi-bin/luci/rpc/auth`.
+The function accepts 2 parameters: `username` and `password` (of a valid user account on the host system) and returns an authentication token.
+
+Example:
+```sh
+curl http://<hostname>/cgi-bin/luci/rpc/auth --data '
+{
+ "id": 1,
+ "method": "login",
+ "params": [
+ "youruser",
+ "somepassword"
+ ]
+}'
+```
+
+response:
+```json
+{"id":1,"result":"65e60c5a93b2f2c05e61681bf5e94b49","error":null}
+```
+
+If you want to call any exported library which requires an authentication token you have to append it as a URL parameter auth to the RPC-Server URL.
+E.g. instead of calling `/cgi-bin/luci/rpc/LIBRARY` you should call `/cgi-bin/luci/rpc/LIBRARY?auth=TOKEN`.
+
+If your JSON-RPC client is Cookie-aware (like most browsers are) you will receive the authentication token also with a session cookie and probably don't have to append it to the RPC-Server URL.
+
+
+## Exported Libraries
+### uci
+The UCI-Library `/rpc/uci` offers functionality to interact with the Universal Configuration Interface.
+
+**Exported Functions:**
+
+See [LuCI API](LuCI.uci.html)
+
+Example:
+```sh
+curl http://<hostname>/cgi-bin/luci/rpc/uci?auth=yourtoken --data '
+{
+ "method": "get_all",
+ "params": [ "network" ]
+}'
+```
+
+### fs
+The Filesystem library `/rpc/fs` offers functionality to interact with the filesystem on the host machine.
+
+**Exported Functions:**
+
+See [fs API](LuCI.fs.html)
+
+
+**Note:** All functions are exported as they are except for `readfile` which encodes its return value in [Base64](https://en.wikipedia.org/wiki/Base64) and `writefile` which only accepts Base64 encoded data as second argument.
+
+
--- /dev/null
+# Authoring LuCI Modules
+
+## Categories
+
+The LuCI modules are divided into several category directories, namely:
+* applications - Single applications or plugins for other modules
+* i18n - Translation files
+* libs - libraries of Luci
+* modules - main modules of Luci itself
+* protocols - network related plugins
+* themes - Frontend themes
+
+Each module goes into a subdirectory of its respective category-directories.
+
+## Module directory
+The contents of a module directory are as follows:
+
+### Makefile
+This is the module's makefile. If the module just contains JS sourcecode or resources then the following Makefile should suffice.
+
+```Makefile
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=Title of my example applications
+LUCI_DEPENDS:=+some-package +libsome-library +luci-app-anotherthing
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
+```
+
+If you have C(++) code in your module you should include a `src/` subdirectory containing another Makefile supporting a `clean`, a `compile` and an `install` target.
+The `install` target should deploy its files relative to the predefined `$(DESTDIR)` variable, e.g.
+
+```sh
+mkdir -p $(DESTDIR)/usr/bin; cp myexecutable $(DESTDIR)/usr/bin/myexecutable
+```
+
+### src
+The `src` directory is reserved for C sourcecode.
+
+### htdocs
+All files under `htdocs` will be copied to the document root of the target webserver.
+
+### root
+All directories and files under `root` will be copied to the installation target as they are.
+
+### dist
+`dist` is reserved for the builder to create a working installation tree that will represent the filesystem on the target machine.
+**DO NOT** put any files there as they will get deleted.
+
+### ipkg
+`ipkg` contains IPKG package control files, like `preinst`, `posinst`, `prerm`, `postrm`. `conffiles`.
+See IPKG documentation for details.
+
+
+## OpenWRT feed integration
+If you want to add your module to the LuCI OpenWRT feed, you have to add several sections to the `contrib/package/luci/Makefile`.
+
+For a Web UI applications this is:
+
+A package description:
+```Makefile
+define Package/luci-app-YOURMODULE
+ $(call Package/luci/webtemplate)
+ DEPENDS+=+some-package +some-other-package
+ TITLE:=SHORT DESCRIPTION OF YOURMODULE
+endef
+```
+
+A package installation target:
+```Makefile
+define Package/luci-app-YOURMODULE/install
+ $(call Package/luci/install/template,$(1),applications/YOURMODULE)
+endef
+```
+
+A module build instruction:
+```Makefile
+ifneq ($(CONFIG_PACKAGE_luci-app-YOURMODULE),)
+ PKG_SELECTED_MODULES+=applications/YOURMODULE
+endif
+```
+
+A build package call:
+```Makefile
+$(eval $(call BuildPackage,luci-app-YOURMODULE))
+```
--- /dev/null
+# Creating Themes
+**Note:** You have already read the [Module Reference](./Modules.md).
+
+We assume you want to call your new theme `mytheme`.
+Replace `mytheme` with your module name every time this is mentioned in this Howto.
+
+## Creating the structure
+At first create a new theme directory `themes/luci-theme-mytheme`.
+
+Create a `Makefile` inside your theme directory with the following content:
+```Makefile
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=Title of mytheme
+
+include ../../luci.mk
+# call BuildPackage - OpenWrt buildroot signature
+```
+
+Create the following directory structure inside your theme directory.
+* htdocs
+ * luci-static
+ * `mytheme`
+ * resources
+* root
+ * etc
+ * uci-defaults
+* ucode
+ * template
+ * themes
+ * `mytheme`
+
+
+## Designing
+Create two LuCI ucode Templates named `header.ut` and `footer.ut` under `ucode/template/themes/mytheme`.
+The `header.ut` will be included at the beginning of each rendered page and the `footer.ut` at the end.
+So your `header.ut` will probably contain a DOCTYPE description, headers,
+the menu and layout of the page and the `footer.ut` will close all remaining open tags and may add a footer bar.
+But hey that's your choice: you are the designer ;-).
+
+Just make sure your `header.ut` begins with the following lines:
+```
+{%
+ import { getuid, getspnam } from 'luci.core';
+
+ const boardinfo = ubus.call('system', 'board');
+
+ http.prepare_content('text/html; charset=UTF-8');
+-%}
+```
+
+This ensures your content is sent to the client with the right content type.
+Of course you can adapt `text/html` to your needs.
+
+
+Put any stylesheets, Javascripts, images, ... into `htdocs/luci-static/mytheme`.
+Refer to this directory in your header and footer templates as: `{{ media }}`.
+That means for an icon `htdocs/luci-static/mytheme/logo.svg` you would write:
+
+```html
+<link rel="icon" href="{{ media }}/logo.svg" sizes="any">
+```
+
+## Making the theme selectable
+If you are done with your work there are two last steps to do.
+To make your theme OpenWrt-capable and selectable on the settings page, create a file `root/etc/uci-defaults/luci-theme-mytheme` with the following contents:
+
+```sh
+#!/bin/sh
+uci batch <<-EOF
+ set luci.themes.MyTheme=/luci-static/mytheme
+ set luci.main.mediaurlbase=/luci-static/mytheme
+ commit luci
+EOF
+exit 0
+```
+
+and another file `ipkg/postinst` with the following content:
+```sh
+#!/bin/sh
+[ -n "${IPKG_INSTROOT}" ] || {
+ ( . /etc/uci-defaults/luci-theme-mytheme ) && rm -f /etc/uci-defaults/luci-theme-mytheme
+}
+```
+
+This correctly registers the template with LuCI when it gets installed.
+
+That's all. Now send your theme to the LuCI developers to get it into the development repository - if you like.
--- /dev/null
+# Internationalisation (i18n)
+
+## Use translation function
+
+### Translations in JavaScript
+
+Wrap translatable strings with `_()` e.g. `_('string to translate')` and the `i18n-scan.pl` and friends will correctly identify these strings for translation.
+
+If you have multi line strings you can split them with concatenation:
+```js
+var mystr = _('this string will translate ' +
+ 'correctly even though it is ' +
+ 'a multi line string!');
+```
+
+You may also use line continuations `\` syntax:
+
+```js
+var mystr = _('this string will translate \
+ correctly even though it is \
+ a multi line string');
+```
+
+Usually if you have multiple sentences you may need to use a line break. Use the `<br />` HTML tag like so:
+```js
+var mystr = _('Port number.') + '<br />' +
+ _('E.g. 80 for HTTP');
+```
+Use `<br />` and **not** `<br>` or `<br/>`.
+
+If you have a link inside a translation, move its attributes out of a translation key:
+```js
+var mystr = _('For further information <a %s>check the wiki</a>')
+ .format('href="https://openwrt.org/docs/" target="_blank" rel="noreferrer"')
+```
+This will generate a full link with HTML `For further information <a href="https://openwrt.org/docs/" target="_blank" rel="noreferrer">check the wiki</a>`. The `noreferrer` is important so that it is opened in a new tab (`target="_blank"`).
+
+
+### Translations in Lua controller code and Lua CBIs
+As hinted at in the Templates doc, the `%:` invokes a `translate()` function.
+In most controller contexts, this is already available for you, but if necessary, is available for include in `luci.i18n.translate`
+
+
+## Translation files
+Translations are saved in the folder `po/` within each individual LuCI component directory, e.g. `applications/luci-app-acl/po/`.
+The template is in `po/templates/<package>.pot`.
+The individual language translation files can be found at `po/[lang]/[package].po`.
+
+In order to use the commands below you need to have the `gettext` utilities (`msgcat`, `msgfmt`, `msgmerge`) installed on your system.
+On Debian/Ubuntu, install them with `sudo apt install gettext`.
+
+
+### Initialize po files
+
+When you add or update an app, run from your `applications/luci-app-acl/` app folder:
+```sh
+../../build/i18n-add-language.sh
+```
+This creates the skeleton .po files for all available languages open for translation for your app.
+
+Or from the luci repo root:
+```sh
+./build/i18n-add-language.sh
+```
+This creates the skeleton .po files for all existing languages open for translation for all sub-folders.
+
+### Rebuild po files (for existing languages)
+After you make changes to a package, run:
+
+```sh
+./build/i18n-sync.sh applications/[application]
+```
+
+Example:
+```sh
+./build/i18n-sync.sh applications/luci-app-acl
+```
+
+This only updates those language .po files that already exist in `applications/luci-app-acl/po/`. See the previous step to add a new language.
+
+Note: the directory argument can be omitted to update all po template and po files.
+
+
+Some packages share translation files, in this case you need to scan through all their folders:
+
+```sh
+./build/i18n-scan.pl applications/[package-1] applications/[package-2] applications/[package-n] > [location of shared template]/[application].pot
+```
+This is what the `mkbasepot.sh` script does for the `luci-base` module:
+
+```sh
+./build/i18n-scan.pl \
+ modules/luci-base modules/luci-compat modules/luci-lua-runtime \
+ modules/luci-mod-network modules/luci-mod-status modules/luci-mod-system \
+ protocols themes \
+> modules/luci-base/po/templates/base.pot
+```
+
+*Note:* The translation catalog for the base system covers multiple components. Use the following commands to update it:
+
+```sh
+./build/mkbasepot.sh
+./build/i18n-update.pl
+```
+
+### Finally
+
+You can change languages in [System /Language and Style](http://192.168.1.1/cgi-bin/luci/admin/system/system) and check the translation.
--- /dev/null
+{
+ "i18n": {
+ "title": "Internationalisation - i18n"
+ },
+ "JsonRpcHowTo": {
+ "title": "Using JSON RPC daemon"
+ },
+ "ThemesHowTo": {
+ "title": "Making Themes"
+ }
+}
+++ /dev/null
-# HowTo: Using the JSON-RPC API
-
-See [online wiki](https://github.com/openwrt/luci/wiki/JsonRpcHowTo) for latest version.
-
-LuCI provides some of its libraries to external applications through a [JSON-RPC](https://en.wikipedia.org/wiki/JSON-RPC) API.
-This Howto shows how to use it and provides information about available functions.
-
-See also
-* wiki [rpcd](https://openwrt.org/docs/techref/rpcd)
-* wiki [ubus](https://openwrt.org/docs/techref/ubus)
-
-## Basics
-To enable the API, install the following package and restart `uhttpd`:
-
-```bash
-opkg install luci-mod-rpc luci-lib-ipkg luci-compat
-/etc/init.d/uhttpd restart
-```
-
-LuCI comes with an efficient JSON De-/Encoder together with a JSON-RPC-Server which implements the JSON-RPC 1.0 and 2.0 (partly) specifications.
-The LuCI JSON-RPC server offers several independent APIs.
-Therefore you have to use **different URLs for every exported library**.
-Assuming your LuCI-Installation can be reached through `/cgi-bin/luci`, any exported library can be reached via `/cgi-bin/luci/rpc/LIBRARY`.
-
-
-## Authentication
-Most exported libraries will require a valid authentication to be called with.
-If you get an `HTTP 403 Forbidden` status code you are probably missing a valid authentication token.
-To get such a token you have to call the `login` method of the RPC-Library `auth`.
-Following our example from above this login function would be provided at `/cgi-bin/luci/rpc/auth`.
-The function accepts 2 parameters: `username` and `password` (of a valid user account on the host system) and returns an authentication token.
-
-Example:
-```sh
-curl http://<hostname>/cgi-bin/luci/rpc/auth --data '
-{
- "id": 1,
- "method": "login",
- "params": [
- "youruser",
- "somepassword"
- ]
-}'
-```
-
-response:
-```json
-{"id":1,"result":"65e60c5a93b2f2c05e61681bf5e94b49","error":null}
-```
-
-If you want to call any exported library which requires an authentication token you have to append it as an URL parameter auth to the RPC-Server URL.
-E.g. instead of calling `/cgi-bin/luci/rpc/LIBRARY` you should call `/cgi-bin/luci/rpc/LIBRARY?auth=TOKEN`.
-
-If your JSON-RPC client is Cookie-aware (like most browsers are) you will receive the authentication token also with a session cookie and probably don't have to append it to the RPC-Server URL.
-
-
-## Exported Libraries
-### uci
-The UCI-Library `/rpc/uci` offers functionality to interact with the Universal Configuration Interface.
-
-**Exported Functions:**
-* [(string) add(config, type)](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.add)
-* [(integer) apply(config)](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.apply)
-* [(object) changes([config])](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.changes)
-* [(boolean) commit(config)](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.commit)
-* [(boolean) delete(config, section[, option])](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.delete)
-* [(boolean) delete_all(config[, type])](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.delete_all)
-* [(array) foreach(config[, type])](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.foreach)
-* [(mixed) get(config, section[, option])](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.get)
-* [(object) get_all(config[, section])](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.get_all)
-* [(mixed) get_state(config, section[, option])](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.get)
-* [(boolean) revert(config)](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.revert)
-* [(name) section(config, type, name, values)](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.section)
-* [(boolean) set(config, section, option, value)](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.set)
-* [(boolean) tset(config, section, values)](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.uci.html#Cursor.tset)
-
-Example:
-```sh
-curl http://<hostname>/cgi-bin/luci/rpc/uci?auth=yourtoken --data '
-{
- "method": "get_all",
- "params": [ "network" ]
-}'
-```
-
-### fs
-The Filesystem library `/rpc/fs` offers functionality to interact with the filesystem on the host machine.
-
-**Exported Functions:**
-
-* [Complete luci.fs library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.fs.html)
-
-**Note:** All functions are exported as they are except for `readfile` which encodes its return value in [Base64](https://en.wikipedia.org/wiki/Base64) and `writefile` which only accepts Base64 encoded data as second argument.
-Note that both functions will only be available when the `luasocket` packet is installed on the host system.
-
-### sys
-The System library `/rpc/sys` offers functionality to interact with the operating system on the host machine.
-
-**Exported Functions:**
-* [Complete luci.sys library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.sys.html)
-* [Complete luci.sys.group library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.sys.group.html) prefixing the method name with `group.methodname`.
-* [Complete luci.sys.net library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.sys.net.html) prefixing the method name with `net.methodname`.
-* [Complete luci.sys.process library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.sys.process.html) prefixing the method name with `process.methodname`.
-* [Complete luci.sys.user library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.sys.user.html) with prefix `user`.
-* [Complete luci.sys.wifi library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.sys.wifi.html) with prefix `wifi`.
-
-Example:
-```sh
-curl http://<hostname>/cgi-bin/luci/rpc/sys?auth=yourtoken --data '
-{
- "method": "net.conntrack"
-}'
-```
-
-### ipkg
-The IPKG library `/rpc/ipkg` offers functionality to interact with the package manager (IPKG or OPKG) on the host machine.
-
-**Exported Functions:**
-* [Complete luci.model.ipkg library](https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/docs/api/modules/luci.model.ipkg.html)
-
+++ /dev/null
-# LMO - Lua Machine Objects
-
-See [online wiki](https://github.com/openwrt/luci/wiki/LMO) for latest version.
-
-LMO is a simple binary format to pack language strings into a more efficient form.
-Although it's suitable to store any kind of key-value table, it's only used for the LuCI \*.po based translation system at the moment.
-The abbreviation "LMO" stands for "Lua Machine Objects" in the style of the GNU gettext \*.mo format.
-
-## Format Specification
-
-A LMO file is divided into two parts: the payload and the index lookup table.
-All segments of the file are 4 Byte aligned to ease reading and processing of the format.
-Only unsigned 32bit integers are used and stored in network byte order, so an implementation has to use htonl() to properly read them.
-
-Schema:
-
- <file:
- <payload:
- <entry #1: 4 byte aligned data>
-
- <entry #2: 4 byte aligned data>
-
- ...
-
- <entry #N: 4 byte aligned data>
- >
-
- <index table:
- <entry #1:
- <uint32_t: hash of the first key>
- <uint32_t: hash of the first value>
- <uint32_t: file offset of the first value>
- <uint32_t: length of the first value>
- >
-
- <entry #2:
- <uint32_t: hash of the second key>
- <uint32_t: hash of the second value>
- <uint32_t: file offset of the second value>
- <uint32_t: length of the second value>
- >
-
- ...
-
- <entry #N:
- <uint32_t: hash of the Nth key>
- <uint32_t: hash of the Nth value>
- <uint32_t: file offset of the Nth value>
- <uint32_t: length of the Nth value>
- >
- >
-
- <uint32_t: offset of the begin of index table>
- >
-
-
-
-## Processing
-
-In order to process a LMO file, an implementation would have to do the following steps:
-
-### Read Index
-
-1. Locate and open the archive file
-2. Seek to end of file - 4 bytes (sizeof(uint32_t))
-3. Read 32bit index offset and swap from network to native byte order
-4. Seek to index offset, calculate index length: filesize - index offset - 4
-5. Initialize a linked list for index table entries
-6. Read each index entry until the index length is reached, read and byteswap 4 * uint32_t for each step
-7. Seek to begin of file
-
-### Read Entry
-
-1. Calculate the unsigned 32bit hash of the entries key value (see "Hash Function" section below)
-2. Obtain the archive index
-3. Iterate through the linked index list, perform the following steps for each entry:
- 1. Compare the entry hash value with the calculated hash from step 1
- 2. If the hash values are equal proceed with step 4
- 3. Select the next entry and repeat from step 3.1
-4. Seek to the file offset specified in the selected entry
-5. Read as much bytes as specified in the entry length into a buffer
-6. Return the buffer value
-
-## Hash Function
-
-The current LuCI-LMO implementation uses the "Super Fast Hash" function which was kindly put in the public domain by its original author. See http://www.azillionmonkeys.com/qed/hash.html for details. Below is the C-Implementation of this function:
-
-```c
-#if (defined(__GNUC__) && defined(__i386__))
-#define sfh_get16(d) (*((const uint16_t *) (d)))
-#else
-#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
- +(uint32_t)(((const uint8_t *)(d))[0]) )
-#endif
-
-uint32_t sfh_hash(const char * data, int len)
-{
- uint32_t hash = len, tmp;
- int rem;
-
- if (len <= 0 || data == NULL) return 0;
-
- rem = len & 3;
- len >>= 2;
-
- /* Main loop */
- for (;len > 0; len--) {
- hash += sfh_get16(data);
- tmp = (sfh_get16(data+2) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- data += 2*sizeof(uint16_t);
- hash += hash >> 11;
- }
-
- /* Handle end cases */
- switch (rem) {
- case 3: hash += sfh_get16(data);
- hash ^= hash << 16;
- hash ^= data[sizeof(uint16_t)] << 18;
- hash += hash >> 11;
- break;
- case 2: hash += sfh_get16(data);
- hash ^= hash << 11;
- hash += hash >> 17;
- break;
- case 1: hash += *data;
- hash ^= hash << 10;
- hash += hash >> 1;
- }
-
- /* Force "avalanching" of final 127 bits */
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 4;
- hash += hash >> 17;
- hash ^= hash << 25;
- hash += hash >> 6;
-
- return hash;
-}
-```
-
-## Reference Implementation
-
-A reference implementation can be found here:
-https://github.com/openwrt/luci/blob/master/modules/luci-lua-runtime/src/template_lmo.c
-
-The `po2lmo.c` executable implements a `*.po` to `*.lmo` conversation utility.
-Lua bindings for lmo are defined in `template_lualib.c` and associated headers.
+++ /dev/null
-# Reference: LuCI Modules
-
-See [online wiki](https://github.com/openwrt/luci/wiki/Modules) for latest version.
-
-## Categories
-
-The LuCI modules are divided into several category directories, namely:
-* applications - Single applications or plugins for other modules
-* i18n - Translation files
-* libs - libraries of Luci
-* modules - main modules of Luci itself
-* protocols - network related plugins
-* themes - Frontend themes
-
-Each module goes into a subdirectory of this category-directories.
-
-## Module directory
-The contents of a module directory are as follows:
-
-### Makefile
-This is the module's makefile. If the module just contains Lua sourcecode or resources then the following Makefile should suffice.
-```Makefile
-include $(TOPDIR)/rules.mk
-
-LUCI_TITLE:=Title of my example applications
-LUCI_DEPENDS:=+some-package +libsome-library +luci-app-anotherthing
-
-include ../../luci.mk
-
-# call BuildPackage - OpenWrt buildroot signature
-```
-
-If you have C(++) code in your module you should include a `src/` subdirectory containing another Makefile supporting a `clean`, a `compile` and an `install` target.
-The `install` target should deploy its files relative to the predefined `$(DESTDIR)` variable, e.g.
-```
-mkdir -p $(DESTDIR)/usr/bin; cp myexecutable $(DESTDIR)/usr/bin/myexecutable
-```
-
-### src
-The `src` directory is reserved for C sourcecode.
-
-### luasrc
-`luasrc` contains all Lua sourcecode files. These will automatically be stripped or compiled depending on the Make target and are installed in the LuCI installation directory.
-
-### lua
-`lua` is equivalent to `luasrc` but containing Lua files will be installed in the Lua document root.
-
-### htdocs
-All files under `htdocs` will be copied to the document root of the target webserver.
-
-### root
-All directories and files under `root` will be copied to the installation target as they are.
-
-### dist
-`dist` is reserved for the builder to create a working installation tree that will represent the filesystem on the target machine.
-**DO NOT** put any files there as they will get deleted.
-
-### ipkg
-`ipkg` contains IPKG package control files, like `preinst`, `posinst`, `prerm`, `postrm`. `conffiles`.
-See IPKG documentation for details.
-
-
-## OpenWRT feed integration
-If you want to add your module to the LuCI OpenWRT feed you have to add several sections to the `contrib/package/luci/Makefile`.
-
-For a Web UI applications this is:
-
-A package description:
-```Makefile
-define Package/luci-app-YOURMODULE
- $(call Package/luci/webtemplate)
- DEPENDS+=+some-package +some-other-package
- TITLE:=SHORT DESCRIPTION OF YOURMODULE
-endef
-```
-
-A package installation target:
-```Makefile
-define Package/luci-app-YOURMODULE/install
- $(call Package/luci/install/template,$(1),applications/YOURMODULE)
-endef
-```
-
-A module build instruction:
-```Makefile
-ifneq ($(CONFIG_PACKAGE_luci-app-YOURMODULE),)
- PKG_SELECTED_MODULES+=applications/YOURMODULE
-endif
-```
-
-A build package call:
-```Makefile
-$(eval $(call BuildPackage,luci-app-YOURMODULE))
-```
+++ /dev/null
-# LuCI Documentation
-
-See Wiki [LuCI Technical Reference](https://openwrt.org/docs/techref/luci)
-
-## API Reference
-
-- [Client side JavaScript APIs](jsapi/)
-- [How to i18n your module](i18n): internationalization via \*.po and \*.pot files
-- [How to make LuCI JS Modules](https://github.com/openwrt/luci/tree/master/applications/luci-app-example): see the luci-app-example in the repo
-- [How to use the JSON-RPC](JsonRpcHowTo)
-- [How to make themes](ThemesHowTo)
-- [LuCI Modules Reference](Modules): can be JS based or Lua (deprecated)
-
-## Deprecated API Reference (older Lua based APIs)
-
-- [CBI models reference](CBI):CBI models are Lua files describing the structure of an UCI config file and the resulting HTML form to be evaluated by the CBI parser
-- [How to make LuCI Lua Modules](ModulesHowTo): No new Lua modules for client side display are accepted, but some server side things are still done in Lua
-- [LMO - Lua Machine Objects](LMO): to pack language strings into a more efficient form for Lua
-- [Server side Lua APIs](api/index.html)
-- [Templates](Templates): template processor which parses HTML-files to Lua functions and allows to store precompiled template files
-
-## Archived
-
-- [LuCI-0.10](LuCI-0.10): No longer used, but useful reference if you encounter older LuCI versions.
\ No newline at end of file
+++ /dev/null
-# HowTo: Create Themes
-**Note:** You have already read the [Module Reference](./Modules.md) and the [Template Reference](./Templates.md).
-
-We assume you want to call your new theme `mytheme`.
-Replace `mytheme` with your module name every time this is mentioned in this Howto.
-
-## Creating the structure
-At first create a new theme directory `themes/luci-theme-mytheme`.
-
-Create a `Makefile` inside your theme directory with the following content:
-```Makefile
-include $(TOPDIR)/rules.mk
-
-LUCI_TITLE:=Title of mytheme
-
-include ../../luci.mk
-# call BuildPackage - OpenWrt buildroot signature
-```
-
-Create the following directory structure inside your theme directory.
-* ipkg
-* htdocs
- * luci-static
- * `mytheme`
-* luasrc
- * view
- * themes
- * `mytheme`
-* root
- * etc
- * uci-defaults
-
-
-## Designing
-Create two LuCI HTML-Templates named `header.htm` and `footer.htm` under `luasrc/view/themes/mytheme`.
-The `header.htm` will be included at the beginning of each rendered page and the `footer.htm` at the end.
-So your `header.htm` will probably contain a DOCTYPE description, headers,
-the menu and layout of the page and the `footer.htm` will close all remaining open tags and may add a footer bar.
-But hey that's your choice: you are the designer ;-).
-
-Just make sure your `header.htm` begins with the following lines:
-```
-<%
-require("luci.http").prepare_content("text/html")
--%>
-```
-
-This ensures your content is sent to the client with the right content type.
-Of course you can adapt `text/html` to your needs.
-
-
-Put any stylesheets, Javascripts, images, ... into `htdocs/luci-static/mytheme`.
-Refer to this directory in your header and footer templates as: `<%=media%>`.
-That means for a stylesheet `htdocs/luci-static/mytheme/cascade.css` you would write:
-```html
-<link rel="stylesheet" href="<%=media%>/cascade.css" />
-```
-
-## Making the theme selectable
-If you are done with your work there are two last steps to do.
-To make your theme OpenWrt-capable and selectable on the settings page, create a file `root/etc/uci-defaults/luci-theme-mytheme` with the following contents:
-```sh
-#!/bin/sh
-uci batch <<-EOF
- set luci.themes.MyTheme=/luci-static/mytheme
- commit luci
-EOF
-exit 0
-```
-
-and another file `ipkg/postinst` with the following content:
-```sh
-#!/bin/sh
-[ -n "${IPKG_INSTROOT}" ] || {
- ( . /etc/uci-defaults/luci-theme-mytheme ) && rm -f /etc/uci-defaults/luci-theme-mytheme
-}
-```
-
-This correctly registers the template with LuCI when it gets installed.
-
-That's all. Now send your theme to the LuCI developers to get it into the development repository - if you like.
--- /dev/null
+.navbar-item.github-home a {
+ background-image: url("data:image/svg+xml,%3Csvg width='98' height='96' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z' fill='%2324292f'/%3E%3C/svg%3E");
+ background-repeat: no-repeat;
+ background-size: 1.5em;
+ background-position: 1rem center;
+ padding-left: 3rem;
+}
+
+.signature-attributes {
+ font-style:italic;
+ font-weight:lighter;
+ font-variant:sub;
+}
+
+span.param-type {
+ color:#00918e;
+}
+
+.type-signature {
+ display: inline-block;
+ color:#00918e;
+}
+
+.type-signature::after {
+ content: ' ';
+}
+
+span.signature::after {
+ content: ' ';
+}
+
+table.props tbody td,
+table.params tbody td {
+ padding: 0.5rem;
+}
+++ /dev/null
-# LuCI client side API documentation
-
-You can browse the JavaScript apis provided by LuCI here. A good starting point
-is the central [luci.js class](https://openwrt.github.io/luci/jsapi/LuCI.html).
-
{
- "tags": {
- "allowUnknownTags": true,
- "dictionaries": ["jsdoc","closure"]
- },
- "source": {
- "include": ["modules/luci-base/htdocs/luci-static/resources"],
- "includePattern": ".+\\.js(doc|x)?$"
- },
- "plugins": [
- "plugins/markdown"
- ],
- "templates": {
- "cleverLinks": true,
- "monospaceLinks": true,
- "default": {
- "outputSourceFiles": true
- }
- },
- "opts": {
- "destination": "docs/jsapi",
- "recurse": true,
- "readme": "docs/jsapi/README.md"
- }
+ "tags": {
+ "allowUnknownTags": true,
+ "dictionaries": ["jsdoc","closure"]
+ },
+ "source": {
+ "include": ["modules/luci-base/htdocs/luci-static/resources"],
+ "includePattern": ".+\\.js(doc|x)?$"
+ },
+ "plugins": [
+ "plugins/markdown"
+ ],
+ "templates": {
+ "cleverLinks": true,
+ "monospaceLinks": true,
+ "default": {
+ "outputSourceFiles": true
+ }
+ },
+ "opts": {
+ "template": "node_modules/clean-jsdoc-theme",
+ "template_alt": "@alphanull/jsdoc-vision-theme",
+ "template_old": "jaguarjs-jsdoc",
+ "destination": "docs/",
+ "destination_comment": "output directory in the repo",
+ "recurse": true,
+ "readme": "doc_gen/README.md",
+ "readme_comment": "generates the index.html file",
+ "tutorials": "doc_gen/tutorials",
+ "tutorials_comment": "tutorials index. See 'sections' below. jaguarjs does not like the tutorials entry",
+ "theme_opts": {
+ "default_theme": "fallback-dark",
+ "favicon": "themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/logo.svg",
+ "title": "LuCI Documentation",
+ "homepageTitle": "LuCI - Reference Documentation",
+ "displayModuleHeader": false,
+ "prefixModuleToSidebarItems_experimental": false,
+ "includeFilesListInHomepage": false,
+ "include_css": [
+ "doc_gen/extra.css"
+ ],
+ "menu": [
+ {
+ "title": "GitHub Project Page",
+ "link": "https://github.com/openwrt/luci",
+ "class": "github-home"
+ }
+ ],
+ "sections": [
+ "Tutorials",
+ "Modules",
+ "Classes",
+ "Externals"
+ ]
+ }
+ },
+ "markdown": {
+ "hardwrap": false,
+ "idInHeadings": true
+ }
}
{
"scripts": {
- "doc": "LC_ALL=C jsdoc -c jsdoc.conf.json -t node_modules/jaguarjs-jsdoc"
+ "docjag": "LC_ALL=C jsdoc -c jsdoc.conf.json -t node_modules/jaguarjs-jsdoc",
+ "doc": "LC_ALL=C jsdoc -c jsdoc.conf.json"
},
"devDependencies": {
+ "@alphanull/jsdoc-vision-theme": "^1.2.2",
+ "clean-jsdoc-theme": "^4.3.0",
"jaguarjs-jsdoc": "^1.1.0",
- "jsdoc": "^3.6.7"
+ "jsdoc": "^4.0.5"
}
}