diff --git a/.eslintrc.js b/.eslintrc.js index b78e965b..05ea447a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -104,7 +104,7 @@ module.exports = { // Try to keep code complexity in functions to a minimum 'sonarjs/cognitive-complexity': ['error', 60], // default is 15! Need to try and improve this :-) - 'sonarjs/no-duplicate-string': ['warn', 5], // default is 3 + 'sonarjs/no-duplicate-string': ['warn', { 'threshold': 5 }], // default is 3 // Make Standard less annoying 'brace-style': 'off', // You should only use one-true-brace style but sometimes we want to compress things a bit. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..e42e572a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,65 @@ +name: ๐Ÿชฒ Report a bug or issue +description: File an issue for UIBUILDER +labels: [needs-triage] +body: +- type: markdown + attributes: + value: | + If your issue is a general 'how-to' type question, or something that needs discussion, please + firstly ask on [the Node-RED forum using the node-red-contrib-uibuilder tag](https://totallyinformation.github.io/node-red-contrib-uibuilder). + + If you have a feature request or suggestion for a change, please use the Feature Request template. + + Before logging an issue, please make sure that you are either on the latest npm version or the latest GitHub version of UIBUILDER. + + Please ensure that as much of the following information is included as possible as it makes analysing and fixing it much easier. + + Also, please try to include a simplified Node-RED flow that illustrates the issue. +- type: textarea + attributes: + label: Current Behavior + description: A clear & concise description of what you're experiencing. + validations: + required: false +- type: textarea + attributes: + label: Expected Behavior + description: A clear & concise description of what you expected to happen. + validations: + required: false +- type: textarea + attributes: + label: Steps To Reproduce + description: Steps to reproduce the behavior. + validations: + required: false +- type: textarea + attributes: + label: Example Node-RED flow + description: If you have a minimal example flow that demonstrates the issue, share it here. + value: | + ``` + paste your flow here + ``` + validations: + required: false +- type: textarea + attributes: + label: Environment + description: Please tell us about your environment. Include any relevant information on how you are running Node-RED. + value: | + - UIBUILDER version: + - Node-RED version: + - Node.js version: + - npm version: + - Platform/OS: + - Browser: + + How is Node-RED installed? (globally/locally? admin/user?): + + How/where is UIBUILDER installed (palette-manager/globally/locally? Which folder?) + + Have you changed any of the `uibuilder` settings in your `settings.js` file? + + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..cf3f39b1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,44 @@ +blank_issues_enabled: true +contact_links: + - name: โ“ Ideas, questions & general help + url: https://discourse.nodered.org/tag/node-red-contrib-uibuilder + about: Ask your question on the Node-RED forum using the node-red-contrib-uibuilder tag + - name: ๐Ÿ“ Documentation + url: https://totallyinformation.github.io/node-red-contrib-uibuilder + about: Go to the latest documentation + - name: ๐Ÿง‘โ€๐Ÿ’ป Flows + url: https://flows.nodered.org/search?term=uibuilder + about: Example flows, nodes and collections related to UIBUILDER + - name: โ„น๏ธ WIKI + url: https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki + about: More documentation and examples + - name: ๐Ÿ“‚ Example Svelte Template + url: https://github.com/TotallyInformation/uib-template-svelte-simple + about: In case you want to build your own svelte app + - name: ๐Ÿ“‚ Example Simple Template + url: https://github.com/TotallyInformation/uib-template-test + about: In case you want to build your own external template + + + - name: ๐Ÿ“Š uPlot UIBUILDER extension + url: https://github.com/TotallyInformation/nr-uibuilder-uplot + about: Useful charts but also demonstrates how to build your own extension + - name: ๐Ÿ”จ ui library module used by UIBUILDER + url: https://github.com/TotallyInformation/ui.js + about: Can be used stand-alone for turning UI standard config JSON into HTML + - name: ๐Ÿ”จ Event Handler module used by UIBUILDER + url: https://github.com/TotallyInformation/ti-common-event-handler + about: So you can see some of the inner workings + - name: ๐Ÿงช Test Nodes for Node-RED + url: https://github.com/TotallyInformation/uib-template-test + about: Some test nodes for Node-RED that help you understand how everything works + - name: ๐Ÿšค HotNipi Gauge Web Component + url: https://github.com/TotallyInformation/gauge-hotnipi + about: A really nice looking gauge component. Works with UIBUILDER or stand-alone + - name: ๐Ÿงช Experimental Web Components + url: https://github.com/TotallyInformation/web-components + about: Have some Node-RED & UIBUILDER specific enhancements but also work well stand-alone + + - name: ๐Ÿงช Array Grouper + url: https://github.com/TotallyInformation/groupit + about: Stand-alone function to reshape an array of objects diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..3d8a0c2a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,19 @@ +name: ๐Ÿ†• Request a feature +description: File a bug/issue on the core of Node-RED +labels: [needs-triage] +body: +- type: markdown + attributes: + value: | + Before requesting a new feature or improvement, please check the docs/roadmap.md file in the latest branch to see + whether it is already on the roadmap. + + New features can be discussed in the Node-RED forum under the `node-red-contrib-uibuilder` tag and you may wish + to discuss there before raising a request. +- type: textarea + attributes: + label: Request + description: A clear & concise description of what you would like. + validations: + required: true + diff --git a/.github/issue_template.md b/.github/issue_template.md deleted file mode 100644 index 1e5539ff..00000000 --- a/.github/issue_template.md +++ /dev/null @@ -1,35 +0,0 @@ -Before logging an issue, please make sure that you are either on the latest npm version or the latest GitHub version. - -Please ensure that as much of the following information is included as possible. - -### Software and Package Versions - -> Node.JS, Node-RED and uibuilder back-end versions are listed in the Node-RED log on startup. - `npm --version` shows the installed version of npm. - From your browser's developer console (F12), the uibuilder front-end - version can be seen by issuing the command `uibuilder.get('version'). - Please include all 5. Node.JS needs to be at least 4 but realistically, anything less than 6 is unlikely to work. - -> Please also include your Operating System name and version and your browser's name and version. Any browser version less than n-2 or IE < v11 very unlikely to work without help from [polyfill.io](https://polyfill.io). - -> I know it seems like a lot but it saves time in the long run - -Software | Version --------------- | ------- -Node.JS | -npm | -Node-RED | -uibuilder node | -uibuilderFE | -OS | -Browser | - - -### How is Node-RED installed? Where is uibuilder installed? - -> Often, issues with nodes occur because of non-standard installations. - This may still indicate a bug so it is fine to report an issue. Just be sure you understand the consequences of how you have installed things. - -> A very common set of issues come from installing nodes as root instead of the user that runs Node-RED (e.g. using sudo on Mac/Linux). You will most likely be asked to undo that before we can analyse the issue. - -> Also quite common is to install the uibuilder node in the wrong folder. It is best to install using the Node-RED admin interface "Manage Palette". If installing manually, make sure you are in your `userDir` folder before installing (typically `~/.node-red`). diff --git a/.github/workflows/chk-links-v66.yml b/.github/workflows/chk-links-v66.yml new file mode 100644 index 00000000..0d2958a2 --- /dev/null +++ b/.github/workflows/chk-links-v66.yml @@ -0,0 +1,19 @@ +name: Check .md links on v6.6.0 branch + +on: + push: [v6.6.0] + +jobs: + markdown-link-check: + runs-on: ubuntu-latest + # check out the the code + steps: + - uses: actions/checkout@master + with: + ref: v6.6.0 + + # Checks the status of hyperlinks in .md files in verbose mode + - name: Check links + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-verbose-mode: 'yes' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a3b69441..50518161 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@master # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.gitignore b/.gitignore index ade30969..ec80bd0a 100644 --- a/.gitignore +++ b/.gitignore @@ -123,8 +123,7 @@ _node_modules *.code-workspace .checksums -# We shouldn't commit files with names starting with _ -_* +# Omit Obsidian db files docs/.obsidian/app.json docs/.obsidian/appearance.json docs/.obsidian/core-plugins.json @@ -133,3 +132,15 @@ docs/.obsidian/workspace.json docs/.obsidian/snippets/attention-callout.css docs/.obsidian/themes/Minimal/manifest.json docs/.obsidian/themes/Minimal/theme.css + +# Omit random test files. +tests/execa/package-lock.json +tests/execa/package.json +tests/execa/test-execa-src.js +tests/execa/test-execa-src.mjs +tests/execa/test-execa.js +tests/execa/test2.mjs +tests/execa/test3.js + +# +tmp/_* diff --git a/CHANGELOG.md b/CHANGELOG.md index 004162d3..7fac1b93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,12 +10,192 @@ Please see the documentation for archived changelogs - a new archive is produced Check the [roadmap](./docs/roadmap.md) for future developments. ----- +* Outdated examples - some of the included example flows such as the "remote-commands" example are now out of date. What is there will still work but they are no longer comprehensive. Will try to catch them up as soon as I can. +* Add URL case sensitivity flag - currently ExpressJS and Socket.IO handle URL case sensitivity differently. In rare cases, this can cause an error. Will make both case sensitive in line with W3C recommendations (will be optional until next major release). -## [Unreleased](https://github.com/TotallyInformation/node-red-contrib-uibuilder/compare/v6.4.1...main) + Add case sensitivity flag to uibuilder node and allow setting of ExpressJS flags on routers. [ref 1](https://stackoverflow.com/questions/21216523/nodejs-express-case-sensitive-urls), [Ref 2](http://expressjs.com/en/api.html). Also document in uibuilder settings. [Ref 3](https://discourse.nodered.org/t/uibuilder-and-url-case-sensitivity/81019/6). + +### TO FIX + +* Loading template - if it fails due to a missing dependency, the template isn't loaded but the Template shows the new one. Need to revert the name if loading fails. +* uibRoot package.json - add check if dependencies blank but `node_modules` is not empty, if so, repopulate? Need to decide when to check - on commit at least. +* uib-tag - Attribs Source - should be "None" as default +* Editor (all nodes) - Use jQueryUI tooltips instead of uib custom (see `uib-element`) +* Templates - add eslint dev dependencies to package.json + * .eslintrc.js: Configuration for rule "sonarjs/no-duplicate-string" is invalid: Value 6 should be object. + + + +------------ + +## [Unreleased](https://github.com/TotallyInformation/node-red-contrib-uibuilder/compare/v6.6.0...main) Nothing currently. +## [v6.6.0](https://github.com/TotallyInformation/node-red-contrib-uibuilder/compare/v6.5.0...v6.6.0) + +### Highlights + + + +### **NEW NODE** - `uib-html` - Hydrates `msg._ui` configurations into HTML + +Takes a `msg._ui` input such as those produced by the uibuilder zero-code nodes (`uib-element`, `uib-tag`, `uib-update`) and "hydrates" that config UI description into HTML. + +Uses the same code as the client library. Outputs HTML on `msg.payload`, removes the input `msg._ui`. + + +#### Current Limitations + +* Uses the widely used [`jsdom` library](https://www.npmjs.com/package/jsdom) to do all the heavy lifting. This library is used by many existing tools and implements virtually all of the DOM v4 spec. However, there will always be a few things that can't be done in a virtual DOM outside the browser. Check the JSDOM library documentation and WIKI for any current limitations. +* Some things such as the dynamic client commands (reload, toggle visible msgs, ... ) don't make sense in this context. They will either produce an error or will be ignored. Occasionally, they might produce some unexpected output. +* Testing is currently very limited. Please report any errors. + +#### Why? + +- Learn how to write your own HTML +- Output to a uibuilder node to save processing the _ui data in the front-end +- Output to a uibuilder server folder for use in your app as a static load (or occasionally changing load) +- Output to a file for use in an external (to Node-RED) static web server/service +- Output to an `http-out` node as a response to a request +- Output to a `ui_template` node for incorporation in Dashboard UI's + +### **NEW NODE** `uib-save` - Save a file to a UIBUILDER instance folder + +Makes it easy to output files to the folder structure of a uibuilder node. + +This can be used for all manner of things. + +* Use with the `uib-html` node to make a permanent copy of some zero-/low-code output. +* Use with the `htmlSend()` front-end function (`htmlSend` `_uib` cmd from Node-RED) to get a copy of the current state of the UI and save it back to the page file for future use. +* Use with HTML like `` to get one or more files from the user (e.g. images or anything else to save) and save the file. + +Obviously, this means that all input must be carefully checked for safety. + +Why might you use this node? + +- Save `msg._ui` configuration data to a static JSON which can then be used to load an entire UI on page load. +- Save/update files that are automatically available via the uibuilder web. For example a static web page that is perhaps updated periodically. This could also work with data, JavaScript, CSS, etc. In fact anything that can be serialised or that is already a string. +- Use with the `uib-html` node to save static HTML files built via `uib-element` or some other flow that outputs `msg._ui` configurations. + +### Improvements to the client library + +- **NEW Feature** A new built-in web component `uib-var`, used as ``. + + Displays the value of the given variable name in your web page and dynamically updates as long as it is changed using `uibuilder.set()`. (or from Node-RED using the appropriate uib set command). The tag inserts the variable value as inline text. Class and Style attributes can be added as for any other HTML. + + Two other attributes are available on the component tag: + + - `undefined`: If present or set to `on`, or `true`, the component will show even if the variable is undefined. If not present or set to anything else, an undefined variable will be blank. + - `report` If present or set to `on`, or `true`, the component will return a standard message back to Node-RED when the variable changes value. + + This works with Markdown as well and even works if DOMPurify is loaded as overrides to its filters are provided. + + There is no need to load the component, that is done automatically in the uibuilder client library. + + Examples: `

UIBUILDER client library version ""

` or `

Last msg received: ""

` + +* **NEW Function** `uibuilder.copyToClipboard(uibVarName)` - passed a UIBUILDER variable, will copy the contents to the clipboard (stringifying it first). Can't be used from the browser dev console due to restrictions in the browser. Use as `onclick` function on buttons. Similarly, cannot be called as a remote command. +* **NEW Function** `uibuilder.elementIsVisible(cssSelector, stop = false, threshold = 0.1)` - Sends a msg back to Node-RED when the selected element goes in and out of visibility within the browser. Sadly, browser restrictions prevent this from being called as a remote command. +* **NEW Function** `uibuilder.elementExists(cssSelector, msg = true)` - Returns `true` if the selected element exists on the page, false otherwise. Sends a msg back to Node-RED unless suppressed. Also available as a remote command. +* **NEW Function** `uibuilder.convertMarkdown(mdText)` - Returns an HTML string converted from the Markdown input text. Only if the Markdown-IT library is loaded, otherwise returns the input. +* **NEW Function** `uibuilder.sanitiseHTML(htmlText)` - Returns a safe, sanitised HTML string IF the DOMPurify library is loaded. Otherwise returns the input. +* **NEW Function** `uibuilder.getManagedVarList()` - Returns an object listing all managed variables. + + These are variables that have been set using `uibuilder.set()` or the equivalent command from Node-RED (or internally by the client library) and that can therefore be watched for changes using `uibuilder.onChange()`. + + Can be called from Node-RED as a command as well. + +* **NEW Function** `uibuilder.getWatchedVars()` - Returns an array of watched client variables. + + These are variables that have been set using `uibuilder.set()` or the equivalent command from Node-RED (or internally by the client library) and that have an active `uibuilder.onChange()`. + + Can be called from Node-RED as a command as well. + +* **NEW** "Maskable" icons added and available in the front end at the URL `./images/maskable_icon_x512.png` where `xNNN` is one of `x48`, `x72`, `x96`, `x128`, `x192`, `x384`, `x512`. (`front-end/images` folder). These are useful for PWA apps. +* **NEW** Template manifest file available at URL `./utils/manifest-template.json` (`front-end/utils` folder). Copy, amend and load this if you wish to make a PWA from your UIBUILDER instance. +* **NEW Variable** `uibuilder.get('url')` - The instance url fragment (name) for the uibuilder instance. + +* **UPDATED** `uibuilder.set('varname', value)` - Now has 2 additional optional arguments + + `store` (boolean): Tells uibuilder to attempt to save the variable/value in the browser `localStorage`. + `autoload` (boolean): Tells uibuilder to attempt to restore the last stored value from browser `localStorage` when loading the page. + +* **UPDATED** `uibuilder.setStore('varname', value)` - Now has an extra optional argument + + `autoload` (boolean): Tells uibuilder to attempt to restore the last stored value from browser `localStorage` when loading the page. + +* All UIBUILDER icons and images changed to the new, lighter blue background. +* Added close and copy (to clipboard) buttons on the Visible Messages box. They are only visible when hovering over the box. +* Stand-alone versions of the low-code ui features - the code that turns the low-code config JSON into HTML and manages DOM interactions - are now available. This code is already built in to the UIBUILDER client library but now may be used independently in your own projects. Auto-generated by `gulp watch` when the source is changed. Source is in `src/front-end-module/ui.js`, dist versions are in the `front-end/` folder. +* Added extra error handling to the syntaxHighlight function to prevent rare error. + +### Improvements to the `uib-element` node + +* **NEW Element Type** **Markdown** - Much the same as the HTML element but uses Markdown as input instead of raw HTML. Requires the Markdown-IT library to be loaded in the client. + +### Improvements to `ui.js` library + +NB: This is the library that reconstitutes uibuilder's zero- and low-code configuration JSON data into a full HTML UI. It is built into uibuilder's front-end client library but is now also available stand-alone for your own projects and is also available as a node.js class module that works with `jsdom` on the server. Eventually, it will be in a stand-alone npm package for use in other projects. + +* ESM and IIFE minimised versions of the stand-alone client are now available in the `front-end` folder. These can be used in other projects. Map files for easier debugging also available. +* Now fully self-contained, no longer has external vars. This allows it to be made available as a node.js library as well. +* `window` is now an argument you must pass in when constructing an instance of the class. This allows it to be used in node.js (in conjunction with the `jsdom` library) as well as the browser. References to `window`, `document`, `log` and `syntaxHighlight` are now fully self-contained. See `nodes/uib-html.js` for an example of using with `jsdom`. + +* **NEW Function** `convertMarkdown(mdText)` - Returns an HTML string converted from the Markdown input text. Only if the Markdown-IT library is loaded, otherwise returns the input. Allows the use of Markdown-IT independently from the `_ui` low-code processing. +* **NEW Function** `sanitiseHTML(htmlText)` - Returns a safe, sanitised HTML string IF the DOMPurify library is loaded. Otherwise returns the input. Allows the use of DOMPurify to sanitise HTML independently from the `_ui` low-code processing. + +### Improvements to the UIBUILDER node + +* On loading a template, if the "Reload connected clients on save?" flag is set on the Files tab, a reload command is issued to all connected clients. +* For the `uibindex` detailed information web page and the instance information page, replaced the old `uib-styles.css` with the newer `uib-brand.css`. +* Emoji's added to error (๐Ÿ›‘) and warn (โš ๏ธ) log outputs. ๐Ÿ“˜ emoji added to the uibuilder initialised message to make it easier to spot in a busy Node-RED log. +* Updated branding. + +### Improvements to the server libraries + +#### New `nodes/libs/fs.js` library added + +This will eventually hold ALL file system processing so that it is all together. That will allow it to be improved in a single place. Eventually will allow the deprecation of the fs-extra package. + +It is another singleton class instance. It is initialised in the main uibuilder runtime and initially just accessed in the new `uib-save` node where it does the file saving. + +#### admin-api-v3 + +* Initial code for isPackageInstalled API for the Editor + +#### package-mgt + +* isPackageInstalled function - returns true or false + +### Improvements for uib-brand.css + +* New classes to support the enhanced showMsgs command buttons features. + +### Documentation improvements + +* **NEW** The docs now have a fancy landing page! Let me know if you have ideas on how it can be improved. ๐Ÿ˜Š +* **NEW** `apis` folder - currently only contains the index readme which lists all of the REST API's provided by uibuilder. +* **NEW** `dev/client-libs` and `dev/server-libs` folders - providing a developer focused summary of all of the uibuilder library files/classes. +* **NEW** A custom "Not Found" (404) page added. Much more friendly than the previous browser default. +* **NEW** Added a `docksify-howto` page to the docs. This is not currently linked and so only available in source unless you know the name. Explains how to use Docksify with the UIBUILDER docs. +* Changed the uibuilder logo to a lighter colour to fit in with the docs. Added red highlight to `ui`, thanks to Paul-Reed for the idea. +* Added extended information links to main readme and the docs home page. +* Added available command summary to the "Control from Node-RED" client docs. + +### General Improvements + +* New branding. 'uibuilder' is now 'UIBUILDER' except when referring to code. Where feasible, UIBUILDER has the new light blue as the text colour except for the initial UI which is a slight variation of the Node-RED base colour. +* A CITATION.cff file has been added - this provides official meta-data to the repo for use in research and standardised citation references. +* Some pages of documentation reorganised. Note that this may have broken some links, if so, please do report them. The "Page Not Found" page has been updated with a reporting link. +* **NEW EXAMPLE** `quick-start` - A simple, pre-configured flow with some standard uibuilder inputs and outputs. +* Remove dependencies on `fs-extra` library - `nodes/libs/web.js` only right now - need to wait for node.js v16.7 to be baseline for the rest (allowing uibuilder to move to be a monorepo and use dependant packages). +* **NEW LIBRARY** `nodes/libs/fs.js` - Server file handling library. Using the node.js core `fs/promises` library dependency only, not `fs-extra`. Initial release only contains `writeInstanceFile`, an async function to save a file to a uibuilder node instance's folder structure (used by the new `uib-save` node). Aim is to use for all server file/folder handling eventually, helping facilitate the previous improvement. +* The `ui.js` library now added as a node.js library to `libs/ui.js` so that it can be used with the `uib-html` node. Auto-generated by `gulp watch` when the source is changed. +* Improved GitHub issue templates, workflows & funding. Added CITATION.cff. + + + ## [v6.5.0](https://github.com/TotallyInformation/node-red-contrib-uibuilder/compare/v6.5.0...v6.4.1) Apologies, the documentation has fallen a little behind with this release as things took longer and more new features were added than expected. But I needed to get this release out as it contains some important bug fixes as well. diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000..c06e5a6f --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,49 @@ +# This CITATION.cff file was generated with cffinit. +# Visit https://bit.ly/cffinit to generate yours today! + +cff-version: 1.2.0 +title: node-red-contrib-uibuilder +message: >- + If you use this software, please cite it using the + metadata from this file. +type: software +authors: + - given-names: Julian + family-names: Knight + affiliation: Totally Information + - name: Totally Information + city: Sheffield + country: GB + region: South Yorkshire + alias: TotallyInformation +identifiers: + - type: url + value: >- + https://github.com/TotallyInformation/node-red-contrib-uibuilder/releases/latest + description: Latest release of UIBUILDER for Node-RED +repository-code: >- + https://github.com/TotallyInformation/node-red-contrib-uibuilder/ +url: >- + https://totallyinformation.github.io/node-red-contrib-uibuilder +abstract: >- + UIBUILDER for Node-RED allows the easy creation of + data-driven front-end web applications. + + + It includes many helper features that can reduce or + eliminate the need to write code for building data-driven + web applications and user interfaces integrated with + Node-RED. +keywords: + - node-red + - ui + - gui + - dashboard + - SPA + - web + - website + - data-driven + - webpage + - web-app + - ui-builder +license: Apache-2.0 diff --git a/README.md b/README.md index 7e2b1d21..08b1e59b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Discussion](https://img.shields.io/static/v1.svg?label=Discussion&message=Node-RED%20Forum&color=green)](https://discourse.nodered.org/tag/node-red-contrib-uibuilder) +[![Static Badge](https://img.shields.io/badge/UIBUILDER_Homepage-0d85d7)](https://totallyinformation.github.io/node-red-contrib-uibuilder) [![NPM Version](https://img.shields.io/npm/v/node-red-contrib-uibuilder.svg)](https://www.npmjs.com/package/node-red-contrib-uibuilder) [![NPM Total Downloads](https://img.shields.io/npm/dt/node-red-contrib-uibuilder.svg)](https://www.npmjs.com/package/node-red-contrib-uibuilder) [![NPM Downloads per month](https://img.shields.io/npm/dm/node-red-contrib-uibuilder.svg)](https://www.npmjs.com/package/node-red-contrib-uibuilder) @@ -17,13 +18,13 @@ # node-red-contrib-uibuilder -uibuilder provides a stand-alone web server that allows for interfacing with Node-RED, while giving you help and complete freedom to create custom web interfaces. +UIBUILDER for Node-RED allows the easy creation of data-driven front-end web applications. -It includes many helper features that can reduce or eliminate the need to write code for building data-driven web applications and user interfaces for Node-RED. +It includes many helper features that can reduce or eliminate the need to write code for building data-driven web applications and user interfaces integrated with Node-RED. ## Installation -uibuilder is best installed using Node-RED's Palette Manager. +UIBUILDER is best installed using Node-RED's Palette Manager.
Manual installs and other versions @@ -61,9 +62,9 @@ Older changes can be found in the previous change documents: [CHANGELOG-V5](http Once installed, The following is a typical simple flow to get going. -1. Add a uibuilder node. Open its settings and give it a "URL" which is used as the identifying name. Close the settings and click on the Deploy button. +1. Add a `uibuilder` node. Open its settings and give it a "URL" which is used as the identifying name. Close the settings and click on the Deploy button. 2. Add an inject node for some simple input data and two debug nodes on the two output ports so that you can see everything that is going on. Deploy the flow. -3. Re-open the uibuilder node's settings and click the "Open" button to see the resulting web page. +3. Re-open the `uibuilder` node's settings and click the "Open" button to see the resulting web page. You are now ready to edit the front-end html/javascript/css if you wish and to add logic in Node-RED to provide inputs and handle outputs. @@ -73,23 +74,53 @@ Please see the [First-timers walkthrough](https://totallyinformation.github.io/n Within Node-RED, use the hamburger menu. Click Import. Click Examples. Select the node-red-contrib-uibuilder folder and choose an example. -The templates feature in uibuilder provides working front-end code of various configurations. +The templates feature in UIBUILDER provides working front-end code of various configurations. -Other examples can be found on the [Node-RED Flows site](https://flows.nodered.org/search?term=uibuilder) and the [uibuilder WIKI](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki). Also see the FAQ's and answered questions on the [Node-RED Forum](https://discourse.nodered.org/tag/node-red-contrib-uibuilder). +Other examples can be found on the [Node-RED Flows site](https://flows.nodered.org/search?term=uibuilder) and the [UIBUILDER WIKI](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki). Also see the FAQ's and answered questions on the [Node-RED Forum](https://discourse.nodered.org/tag/node-red-contrib-uibuilder). -## Documentation +## Documentation and other links -Please refer to the [Documentation web site](https://totallyinformation.github.io/node-red-contrib-uibuilder). This can also be accessed from within uibuilder nodes even without an Internet connection. +Please refer to the [Documentation web site](https://totallyinformation.github.io/node-red-contrib-uibuilder). This can also be accessed from within UIBUILDER nodes even without an Internet connection. -There is a library of "official" [video tutorials on YouTube](https://www.youtube.com/playlist?list=PL9IEADRqAal3mG3RcF0cJaaxIgFh3GdRQ). Other folk have also produced [uibuilder-related content](https://www.youtube.com/results?search_query=uibuilder+node-red). +There is a library of "official" [video tutorials on YouTube](https://www.youtube.com/playlist?list=PL9IEADRqAal3mG3RcF0cJaaxIgFh3GdRQ). Other folk have also produced [UIBUILDER-related content](https://www.youtube.com/results?search_query=UIBUILDER+node-red). + +### Questions, issues and suggestions + +The best place to ask questions or discuss possible enhancements is the [Node-RED Forum](https://discourse.nodered.org/). + +Alternatively, use the [GitHub issues log](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues) for raising issues or contributing suggestions and enhancements and the [GitHub Discussions page](https://github.com/TotallyInformation/node-red-contrib-uibuilder/discussions) for general questions, suggestions, etc. + +### Other links + +- ![uib](https://github.com/TotallyInformation/node-red-contrib-uibuilder/raw/main/front-end/images/node-blue.ico) [UIBUILDER for Node-RED](https://github.com/TotallyInformation/node-red-contrib-uibuilder) + - โ“ [Ideas, questions & general help](https://discourse.nodered.org/tag/node-red-contrib-uibuilder) - Ask your question on the Node-RED forum using the node-red-contrib-uibuilder tag + - ๐Ÿ“ [Documentation](https://totallyinformation.github.io/node-red-contrib-uibuilder) - Go to the latest documentation + - ๐Ÿง‘โ€๐Ÿ’ป [Flows](https://flows.nodered.org/search?term=uibuilder) - Example flows, nodes and collections related to UIBUILDER + - โ„น๏ธ [WIKI](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki) - More documentation and examples + - ๐Ÿ“‚ [Example Svelte External Template](https://github.com/TotallyInformation/uib-template-svelte-simple) - In case you want to build your own svelte app + - ๐Ÿ“‚ [Example Simple External Template](https://github.com/TotallyInformation/uib-template-test) - In case you want to build your own external template + - ๐Ÿ“Š [uPlot UIBUILDER extension](https://github.com/TotallyInformation/nr-uibuilder-uplot) - Useful charts but also demonstrates how to build your own extension + - ๐Ÿ”จ [Event Handler module used by UIBUILDER](https://github.com/TotallyInformation/ti-common-event-handler) - So you can see some of the inner workings + +- ๐Ÿ”จ [ui library module used by UIBUILDER](https://github.com/TotallyInformation/ui.js) - Can be used stand-alone for turning UI standard config JSON into HTML + +- ๐Ÿ•œ [node-red-contrib-moment](https://github.com/TotallyInformation/node-red-contrib-moment) - Nodes to make use of the MomentJS date/time handling library in Node-RED + +- ๐Ÿงช [Test Nodes for Node-RED](https://github.com/TotallyInformation/uib-template-test) - Some test nodes for Node-RED that help you understand how everything works + +- ๐Ÿšค [HotNipi Gauge Web Component](https://github.com/TotallyInformation/gauge-hotnipi) - A really nice looking gauge component. Works with Node-RED, UIBUILDER, or stand-alone + +- ๐Ÿงช [Experimental Web Components](https://github.com/TotallyInformation/web-components) - Have some Node-RED & UIBUILDER specific enhancements but also work well stand-alone + +- ๐Ÿงช [Array Grouper](https://github.com/TotallyInformation/groupit) - Stand-alone function to reshape an array of objects ## Purpose -The purpose of uibuilder is to: +The purpose of UIBUILDER is to: * Support easy methods for creating and delivering data-driven web apps and web pages (also known as web User-Interfaces). * Be a conduit between Node-RED and front-end (browser) UI web apps. -* Be UI framework agnostic. No framework is needed to use uibuilder but it will work with them where desired. uibuilder aims to reduce the requirement for a framework by making it easier to work with vanilla HTML/CSS. +* Be UI framework agnostic. No framework is needed to use UIBUILDER but it will work with them where desired. UIBUILDER aims to reduce the requirement for a framework by making it easier to work with vanilla HTML/CSS. * Provide interface/data standards for exchanging data and controls between Node-RED and the web pages. * Enable the creation and management of multiple web apps from a single Node-RED instance. * Reduce the amount of front-end code (HTML/JavaScript) needed to create and manage a web app. @@ -98,7 +129,7 @@ The purpose of uibuilder is to: ## Features -The core features of uibuilder: +The core features of UIBUILDER: * Provides nodes to enable zero-code translation of input data to usable and accessible web elements. * Provides capability for low-code, configuration-driven (data-driven) UI's. Creating a framework for describing a UI and translating to actual code without having to write code. @@ -110,8 +141,8 @@ The core features of uibuilder: * Allows editing of front-end code from the Node-RED Editor (designed for small changes, use web development tools generally). * Enables the use of external authentication and authorisation methods and services to control multi-user access to web apps. * Provides various server middleware and API options for additional custom capabilities. -* Allows as many uibuilder node instances as you like. Each instance allows the creation of many web pages and sub-folders for easy management. -* Each uibuilder node instance provides a private 2-way communications channel between the Node-RED server (back-end) and browser (front-end) UI code. +* Allows as many `uibuilder` node instances as you like. Each instance allows the creation of many web pages and sub-folders for easy management. +* Each `uibuilder` node instance provides a private 2-way communications channel between the Node-RED server (back-end) and browser (front-end) UI code. * Supports the use of standard web development workflows. * Allows the creation of a dedicated web service to facilitate independent security. * Provides a caching capability allowing newly joining clients to receive the latest data and configurations. Joining/leaving clients create notifications in Node-RED. @@ -119,9 +150,9 @@ The core features of uibuilder:
No-code UI's -uibuilder is still growing towards offering more no-code capabilities like Node-RED's Dashboard extension does. However, it is starting to offer these features via the "new" client available since v5. V6.1 introduced the new `uib-element` and `uib-update` nodes that offer the first usable no-code features. +UIBUILDER is still growing towards offering more no-code capabilities like Node-RED's Dashboard extension does. However, it is starting to offer these features via the "new" client available since v5. V6.1 introduced the new `uib-element` and `uib-update` nodes that offer the first usable no-code features. -`uib-element` takes in simple data and outputs configuration data. This can then be sent to the front-end via the uibuilder node. Alternatively, it can be saved and the result used in an initial load. Several simple options such as tables and lists are available in uibuilder v6.1, additional elements and structures will be made available in future versions. The uibuilder front-end client takes the configuration information and dynamically builds HTML elements and inserts them to the web page (or removes/updates as needed). +`uib-element` takes in simple data and outputs configuration data. This can then be sent to the front-end via the `uibuilder` node. Alternatively, it can be saved and the result used in an initial load. Several simple options such as tables and lists are available in UIBUILDER v6.1, additional elements and structures will be made available in future versions. The UIBUILDER front-end client takes the configuration information and dynamically builds HTML elements and inserts them to the web page (or removes/updates as needed). While this is not the most efficient processing approach (since updates are mostly replacing the whole element which could be quite large for things like big tables), it is very efficient from an authoring perspective. So the `uib-update` node provides a more targetted approach to updating and changing specific attributes and "slot" content for elements. @@ -138,13 +169,13 @@ The schema and the UI creator functions built into the front-end client are spec
Future direction -The general direction of uibuilder (or associated modules) is likely to include: +The general direction of UIBUILDER (or associated modules) is likely to include: * Provide more no-code and low-code UI creation and update capabilities. As of v6.1, these are now starting to be delivered, v6.2 will extend these. * The ability to save updated HTML from the front-end via Node-RED so that UI building can be done once and loaded as efficient, static HTML. * The ability to use the zero-code features to produce HTML for other tools to use. -* The ability within Node-RED to, for each uibuilder node, run npm scripts such as build processes and to manage instance-level npm packages. -* Be able to install/update/remove instance-level npm packages as can already be done for uibuilder-level packages. +* The ability within Node-RED to, for each `uibuilder` node, run npm scripts such as build processes and to manage instance-level npm packages. +* Be able to install/update/remove instance-level npm packages as can already be done for UIBUILDER-level packages. * Provide a "development server" capability that auto-reloads connected clients when code changes are made. * A UI designer allowing users without HTML/CSS/JS skills to create reasonable web apps without code.
@@ -169,27 +200,21 @@ The general direction of uibuilder (or associated modules) is likely to include: * Two detailed admin info web pages are included to help authors understand where everything is and what is available. * Uses Node-RED's own ExpressJS webservers by default. Switch to a custom ExpressJS server if desired. When using a custom server, pages can also include EJB server-side templating. * Has middleware for ExpressJS (for web services) and Socket.IO (for communications, both at initial connection and per-message) so that you can add your own custom features including security. -* Can create custom API's for each uibuilder instance. +* Can create custom API's for each UIBUILDER instance.
Current limitations * You may need to write some of your own HTML. -* You have to know the front-end library locations for installed 3rd-party packages and edit your HTML accordingly. The `uibindex` admin API (accessible from any node's admin ui) shows you all of the root folders and what the package authors report as the main entry point for all active packages. There is now also a simplified information page for the currently viewed uibuilder node instance, this is access from a button in the configuration panel. +* You have to know the front-end library locations for installed 3rd-party packages and edit your HTML accordingly. The `uibindex` admin API (accessible from any node's admin ui) shows you all of the root folders and what the package authors report as the main entry point for all active packages. There is now also a simplified information page for the currently viewed `uibuilder` node instance, this is access from a button in the configuration panel. - Note that this is a limitation of `npm` and module authors, not of uibuilder. Unless module authors correctly identify the browser entrypoint for their libraries, uibuilder can only guess. + Note that this is a limitation of `npm` and module authors, not of UIBUILDER. Unless module authors correctly identify the browser entrypoint for their libraries, UIBUILDER can only guess. * You cannot yet compile/compress your custom front-end code (HMTL, JS, SCSS, etc.) for efficiency. *This will be added soon.* - This will use a local package.json file that contains a "build" script. If it exists, uibuilder will expose a build button that will run the script. + This will use a local package.json file that contains a "build" script. If it exists, UIBUILDER will expose a build button that will run the script.
-## Questions, issues and suggestions - -The best place to ask questions or discuss possible enhancements is the [Node-RED Forum](https://discourse.nodered.org/). - -Alternatively, use the [GitHub issues log](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues) for raising issues or contributing suggestions and enhancements and the [GitHub Discussions page](https://github.com/TotallyInformation/node-red-contrib-uibuilder/discussions) for general questions, suggestions, etc. - ## Contributing If you would like to contribute to this node, you can contact [Totally Information via GitHub](https://github.com/TotallyInformation) or raise a request in the [GitHub issues log](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues). @@ -198,6 +223,13 @@ Pull Requests both for code and documentation are welcomed and the WIKI is open Please refer to the [contributing guidelines](https://github.com/TotallyInformation/node-red-contrib-uibuilder/blob/master/.github/CONTRIBUTING.md) for more information. +You can also support the development of UIBUILDER by sponsoring the development. + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/A0A3PPMRJ) + +[GitHub Sponsorship](https://github.com/sponsors/TotallyInformation), +[PayPal Sponsorship](https://paypal.me/TotallyInformation) + ## Developers/Contributors - [Julian Knight](https://github.com/TotallyInformation) - the designer and main author. diff --git a/docs/-sidebar.md b/docs/-sidebar.md index 5e5dea06..ca5a156c 100644 --- a/docs/-sidebar.md +++ b/docs/-sidebar.md @@ -1,21 +1,21 @@ * [Home](/) -* Using uibuilder +* Using uibuilder * [A first-timers walkthough](walkthrough1.md "Let's get started!") - * [Did you know?](did-you-know.md "Things you might not know about uibuilder") + * [Did you know?](did-you-know.md "Things you might not know about UIBUILDER") * [Creating data-driven web apps](web-app-workflow.md "Different styles and workflows you can use") - * [Configuring uibuilder](uib-configuration.md "Configure the uibuilder platform. Affects all uibuilder nodes") + * [Configuring uibuilder](uib-configuration.md "Configure the UIBUILDER platform. Affects all uibuilder nodes") * [Standard messages](pre-defined-msgs.md "Catalogue of messages and properties") * [Creating Templates](creating-templates "Pre-defined and reusable front-end code, dependencies, and optional build steps") * [Browser auto-refresh](browser-refresh.md "Automatically reload your page after a change") * [Zero-code UI creation](using/zero-code-ui.md "Dynamically creating web UI's") -* The nodes + * [Why uibuilder?](using/why-uibuilder.md "Why would I want to use UIBUILDER?") +* [The nodes](nodes/README.md) * [`uibuilder`](nodes/uibuilder.md) * [`uib-cache`](nodes/uib-cache.md) * [`uib-element`](nodes/uib-element.md) + * [`uib-tag`](nodes/uib-tag.md) * [`uib-update`](nodes/uib-update.md) * [`uib-sender`](nodes/uib-sender.md) - * [`uib-html`](nodes/uib-html.md) - * [`uib-save`](nodes/uib-save.md) * The front-end client * [Introduction](client-docs/readme.md) * [Features](client-docs/features.md) @@ -23,8 +23,9 @@ * [Dynamic, config-driven UI's](client-docs/config-driven-ui.md) * [Functions](client-docs/functions.md) * [Variables](client-docs/variables.md) + * [Custom Components](client-docs/custom-components.md "The built-in uib-var component, using external components") * [Custom Events](client-docs/custom-events.md) - * [uib-brand Style Sheet](client-docs/uib-brand-css.md "How to use the uibuilder standard style sheet uib-brand.css") + * [uib-brand Style Sheet](client-docs/uib-brand-css.md "How to use the UIBUILDER standard style sheet uib-brand.css") * [Troubleshooting](client-docs/troubleshooting.md) * [Old uibuilderfe client library](front-end-library.md) * Zero-code element types @@ -32,6 +33,7 @@ * [Forms](elements/forms.md) * [Lists](elements/lists.md) * [HTML](elements/html.md) + * [Markdown](elements/Markdown.md) * [Headings, text boxes, etc.](elements/other.md) * UI frameworks & builds * [VueJS complexities](vue-complexities.md) @@ -41,28 +43,20 @@ * [Optimise & transpile (build)](front-end-builds.md) * [Snowpack as build tool](front-end-build-snowpack.md) * How to - * [How & why to use the sender node](sender-node.md) - * [How & why to use the list node](list-node.md) - * [Use the cache node](cache-node.md) + * [Use Fn nodes to change msg._ui](how-to/function-node.md) + * [How & why to use the list node](how-to/list-node.md) + * [Use the cache node](how-to/cache-node.md) * [CSS Selectors](how-to/css-selectors.md) - * [Change the root folder (uibRoot)](changing-uibroot.md) - * [Create instance-specific API's](instance-apis.md) + * [Change the root folder (uibRoot)](how-to/changing-uibroot.md) + * [Create instance-specific API's](how-to/instance-apis.md) + * [How & why to use the sender node](how-to/sender-node.md) * [Other How-To's](how-to/README.md) * Security - * [Securing uib web apps](security.md "Overview of general web app security with some specifics for Node-RED and uibuilder") - * [Securing Data](securing-data.md "How to use flows and uibiulder middleware to secure your data") - * [Securing apps using NGINX](uib-security-nginx.md "How to use NGINX as a reverse proxy with TLS and identity authentication") -* [Developer documentation](/?id=developer-documentation) - * [Processes](processes/README.md) - * [`nodes/uibuilder.js`](uibuilder-js.md) - * [`nodes/uibuilder.html`](uibuilder-html.md) - * [`nodes/uiblib.js`](uiblib-js.md) - * [`nodes/tilib.js`](tilib-js.md) - * [`nodes/web.js`](web-js.md) - * [`nodes/socket.js`](socket-js.md) - * [`front-end/src/uibuilderfe.js`](uibuilderfe-js.md) -* Testing - * [Regression tests](regression-tests.md) + * [Securing uib web apps](security/security.md "Overview of general web app security with some specifics for Node-RED and UIBUILDER") + * [Securing Data](security/securing-data.md "How to use flows and uibiulder middleware to secure your data") + * [Securing apps using NGINX](security/uib-security-nginx.md "How to use NGINX as a reverse proxy with TLS and identity authentication") +* [Developer documentation](dev/README.md) +* [REST API's](apis/) * [Glossary of terms](glossary.md) * [Changelog ๐Ÿ”—](changelog) * [Roadmap](roadmap) @@ -75,7 +69,7 @@ * [v1 changelog](archived/CHANGELOG-v1) - **Links** -- [uibuilder license ๐Ÿ”—](https://github.com/TotallyInformation/node-red-contrib-uibuilder/blob/main/LICENSE) -- [uibuilder WIKI ๐Ÿ”—](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki) +- [uibuilder license ๐Ÿ”—](https://github.com/TotallyInformation/node-red-contrib-uibuilder/blob/main/LICENSE) +- [uibuilder WIKI ๐Ÿ”—](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki) - [Much Ado About IT (Blog) ๐Ÿ”—](https://it.knightnet.org.uk) - [Node-RED ๐Ÿ”—](https://nodered.org/) diff --git a/docs/README.md b/docs/README.md index 07ed38a0..1b25b39d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,21 +1,23 @@ --- -title: uibuilder Documentation +title: UIBUILDER Documentation description: > - uibuilder provides a stand-alone web server that allows for interfacing with Node-RED, while giving you help and complete freedom to create custom web interfaces. + UIBUILDER provides a stand-alone web server that allows for interfacing with Node-RED, while giving you help and complete freedom to create custom web interfaces. created: 2019-06-16 16:16:00 -lastUpdated: 2023-04-02 18:06:21 +lastUpdated: 2023-09-30 13:06:56 --- It includes many helper features that can reduce or eliminate the need to write code for building data-driven web applications and user interfaces for Node-RED. - -All you need to start making use of uibuilder is a uibuilder node added to your flows. Select a suitable URL path and deploy. Then click on the "Open url" button to open the new page in a new tab. +All you need to start making use of UIBUILDER is a `uibuilder` node added to your flows. Select a suitable URL path and deploy. Then click on the "Open url" button to open the new page in a new tab. Now you can edit the front-end html, JavaScript and CSS files. You can also send messages to your front end and send messages back to Node-RED. -uibuilder comes with some *templates* to give you some front-end code to get you started. Load a different template if you like, use the editor to customise the UI. Use the library manager if you need any front-end libraries or frameworks (this adds the appropriate folders to the web server so that you can access them from your UI). +UIBUILDER comes with some *templates* to give you some front-end code to get you started. Load a different template if you like, use the editor to customise the UI. Use the library manager if you need any front-end libraries or frameworks (this adds the appropriate folders to the web server so that you can access them from your UI). + +UIBUILDER also comes with a number of *example flows*. These are accessed from Node-RED's "hamburger" menu, import entry. They are fully working flows that demonstrate the use of UIBUILDER. -uibuilder also comes with a number of *example flows*. These are accessed from Node-RED's "hamburger" menu, import entry. They are fully working flows that demonstrate the use of uibuilder. +> [!TIP] +> These are the docs for UIBUILDER v6. If you need the v5 or earlier docs, the easiest way is to set up a test instance of Node-RED and manually install the appropriate UIBUILDER version: `npm install node-red-contrib-uibuilder@5` then use the documentation links from a `uibuilder` node. ## Getting help and contributing @@ -23,17 +25,17 @@ node-red-contrib-uibuilder is contained in a [GitHub repository](https://github. Help is available in this documentation, the help sidebar in Node-RED, and the [GitHub WIKI](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki). If you get stuck, you can also create a new topic in the [Node-RED Discourse Forum](https://discourse.nodered.org/tag/node-red-contrib-uibuilder) or in the [GitHub discussion section](https://github.com/TotallyInformation/node-red-contrib-uibuilder/discussions). -Issues occuring with uibuilder should be raised in the [GitHub issues log](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues) but please feel free to discuss in the Node-RED forum first if you like. +Issues occuring with UIBUILDER should be raised in the [GitHub issues log](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues) but please feel free to discuss in the Node-RED forum first if you like. WIKI, code (PR's), documentation, and examples are all welcome contributions and I always aim to give credit to contributors. Please see the [contribution guidelines](https://github.com/TotallyInformation/node-red-contrib-uibuilder/blob/main/.github/CONTRIBUTING.md). -## Using uibuilder +## Using UIBUILDER -* [A first-timers walkthough of using uibuilder](walkthrough1.md) - Let's get started! +* [A first-timers walkthough of using UIBUILDER](walkthrough1.md) - Let's get started! -* [Did you know?](did-you-know.md) - Things you might not know about uibuilder, hints and tips -* [Creating data-driven web apps with uibuilder and Node-RED](web-app-workflow.md) - Different styles and workflows you can use -* [Configuring uibuilder](uib-configuration.md) - Configure the uibuilder platform. Affects all uibuilder nodes +* [Did you know?](did-you-know.md) - Things you might not know about UIBUILDER, hints and tips +* [Creating data-driven web apps with UIBUILDER and Node-RED](web-app-workflow.md) - Different styles and workflows you can use +* [Configuring UIBUILDER](uib-configuration.md) - Configure the UIBUILDER platform. Affects all `uibuilder` nodes * [Standard messages](pre-defined-msgs.md) - A catalogue of messages and properties * [Creating Templates](creating-templates) - Pre-defined and reusable front-end code, dependencies, and optional build steps * [Browser auto-refresh](browser-refresh.md) - Automatically reload your page after a change @@ -41,151 +43,32 @@ WIKI, code (PR's), documentation, and examples are all welcome contributions and ## The nodes -* [`uibuilder`](nodes/uibuilder.md) - The main node. You need at least one of these in order to make full use of all of the features. - - It is this node that creates a custom web server. You can have many nodes if that best meets your needs. But each node can serve many pages. - - It also creates a set of filing system folders and files on the Node-RED server. These define the front-end UI you see in the browser as well as providing some important configuration. - - This node is also where you configure much of uibuilder's web server such as installing helper libraries that you may wish to use to support your interfaces (e.g. VueJS, jQuery, etc). You can also use it to edit your custom UI code. - -* [`uib-cache`](nodes/uib-cache.md) - Provides a capability to temporarily or permanently save data sent to uibuilder (and hence to your browser) such that it can be automatically replayed to new clients that connect later. - -* [`uib-element`](nodes/uib-element.md) - Converts raw data to UI configuration data. - - This is one of the zero-code capabilities of uibuilder. - - It allows your input data to be automatically converted to a UI description. That description data is "hydrated" by the uibuilder client library into actual HTML. The output of this node can also be further manipulated. The `uib-html` node uses the same code and can be used to hydrate the description into HTML in Node-RED flows. - - The UI configuration data is a documented and re-usable standard, other Node-RED nodes could be created to output or consume the same data. - -* [`uib-update`](nodes/uib-update.md) - -* [`uib-sender`](nodes/uib-sender.md) - -These will be available in the next release: - -* [`uib-html`](nodes/uib-html.md) - Converts (hydrates) UI configuration data into HTML. - - Optionally wraps the output with full HTML document tags so that snippets of UI input data can be converted to full pages. - - Output can be saved to files using `uib-save`, this then allows you to have highly efficient "static" HTML created from data that perhaps is only occasionally updated. - - Output can also be used with other tools such as the `http-in`/`http-out` nodes or the Node-RED Dashboard. - -* [`uib-save`](nodes/uib-save.md) - Save files to a specific uibuilder node instance. - - A convenience node that saves you needing to think about where in the servers filing system resources need to be saved. - By specifying the name of an existing uibuilder node, it will work out the correct location for you. - - Can be used to save anything that can be "[serialised](https://developer.mozilla.org/en-US/docs/Glossary/Serialization)". Including code, data, images, etc. - -## The front-end (browser) client library - - * [Introduction](client-docs/readme.md) - - * [Features](client-docs/features.md) - * [Controlling from Node-RED](client-docs/control-from-node-red.md) - * [Dynamic, config-driven UI's](client-docs/config-driven-ui.md) - * [Functions](client-docs/functions.md) - * [Variables](client-docs/variables.md) - * [Custom Events](client-docs/custom-events.md) - * [uib-brand Style Sheet](client-docs/uib-brand-css.md) - How to use the uibuilder standard style sheet uib-brand.css - * [Troubleshooting](client-docs/troubleshooting.md) - * [Old uibuilderfe client library](front-end-library.md) +[nodes](nodes/README.md ':include') -## Zero-code element types +## Content Index - * [Tables](elements/tables.md) - * [Forms](elements/forms.md) - * [Lists](elements/lists.md) - * [HTML](elements/html.md) - * [Headings, text boxes, etc.](elements/other.md) +[index](-sidebar.md ':include') -## UI frameworks and builds +## Additional Links -Working with uibuilder and specific front-end frameworks. +- ![uib](https://github.com/TotallyInformation/node-red-contrib-uibuilder/raw/main/front-end/images/node-blue.ico) [UIBUILDER for Node-RED](https://github.com/TotallyInformation/node-red-contrib-uibuilder) + - โ“ [Ideas, questions & general help](https://discourse.nodered.org/tag/node-red-contrib-uibuilder) - Ask your question on the Node-RED forum using the node-red-contrib-uibuilder tag + - ๐Ÿ“ [Documentation](https://totallyinformation.github.io/node-red-contrib-uibuilder) - Go to the latest documentation + - ๐Ÿง‘โ€๐Ÿ’ป [Flows](https://flows.nodered.org/search?term=uibuilder) - Example flows, nodes and collections related to UIBUILDER + - โ„น๏ธ [WIKI](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki) - More documentation and examples + - ๐Ÿ“‚ [Example Svelte External Template](https://github.com/TotallyInformation/uib-template-svelte-simple) - In case you want to build your own svelte app + - ๐Ÿ“‚ [Example Simple External Template](https://github.com/TotallyInformation/uib-template-test) - In case you want to build your own external template + - ๐Ÿ“Š [uPlot UIBUILDER extension](https://github.com/TotallyInformation/nr-uibuilder-uplot) - Useful charts but also demonstrates how to build your own extension + - ๐Ÿ”จ [Event Handler module used by UIBUILDER](https://github.com/TotallyInformation/ti-common-event-handler) - So you can see some of the inner workings -* [VueJS complexities](vue-complexities.md) +- ๐Ÿ”จ [ui library module used by UIBUILDER](https://github.com/TotallyInformation/ui.js) - Can be used stand-alone for turning UI standard config JSON into HTML -* [VueJS Components](vue-component-handling.md) -* [Svelte](svelte.md) -* [Avoiding a build step](front-end-no-build.md) -* [Optimise & transpile (build)](front-end-builds.md) -* [Snowpack as build tool](front-end-build-snowpack.md) -* W3C Web Components - TBC +- ๐Ÿ•œ [node-red-contrib-moment](https://github.com/TotallyInformation/node-red-contrib-moment) - Nodes to make use of the MomentJS date/time handling library in Node-RED -## How to +- ๐Ÿงช [Test Nodes for Node-RED](https://github.com/TotallyInformation/uib-template-test) - Some test nodes for Node-RED that help you understand how everything works -* [How & why to use the sender node](sender-node.md) -* [How & why to use the list node](list-node.md) -* [How to use the cache node](cache-node.md) -* [CSS Selectors](how-to/css-selectors.md) -* [Changing the root folder (uibRoot)](changing-uibroot.md) -* [Create instance-specific API's](instance-apis.md) -* [Other How-To's](how-to/README.md) +- ๐Ÿšค [HotNipi Gauge Web Component](https://github.com/TotallyInformation/gauge-hotnipi) - A really nice looking gauge component. Works with Node-RED, UIBUILDER, or stand-alone -## Security +- ๐Ÿงช [Experimental Web Components](https://github.com/TotallyInformation/web-components) - Have some Node-RED & UIBUILDER specific enhancements but also work well stand-alone -* [Securing uib web apps](security.md "Overview of general web app security with some specifics for Node-RED and uibuilder") - -* [Securing Data](securing-data.md "How to use flows and uibiulder middleware to secure your data") -* [Securing apps using NGINX](uib-security-nginx.md "How to use NGINX as a reverse proxy with TLS and identity authentication") - -## Developer Documentation - -Deep dives into the internals of uibuilder. This is where to go if you need to understand how things work. These documents may lag behind the actual code however, so it is always worth also referencing the current codebase. - -* uibuilder node - * [`nodes/uibuilder.js`](uibuilder-js.md) - Main node definition. - * [`nodes/uibuilder.html`](uibuilder-html.md) - Node-RED Editor configuration panel for the main node. - - This is not developed directly. The actual code to edit is in `src/editor/uibuilder/` and is built using `gulp` scripts. - - * [`nodes/lib/uiblib.js`](uiblib-js.md) - A uibuilder-specific utility library. - * [`nodes/lib/tilib.js`](tilib-js.md) - A generic Node.js utility library. - * [`nodes/lib/web.js`](web-js.md) - Web interface library. - * [`nodes/lib/socket.js`](socket-js.md) - Socket.IO communications library. - * `nodes/lib/package-mgt.js` - Package management (npm) library. TBC. - * `nodes/lib/admin-api-v2.js` - v2 Admin API library. TBC. - * `nodes/lib/admin-api-v3.js` - v3 Admin API library. TBC. - -* uibuilder front-end client library - * `front-end/uibuilder.iife.min.js` & `front-end/uibuilder.esm.min.js` Modern library builds - - These are generated by a `gulp` script that uses `esbuild` from `src/front-end-module/uibuilder.module.js`. - - * [`front-end/uibuilderfe.min.js`](uibuilderfe-js.md) - Old `uibuilderfe` client library - - This is generated by a `gulp` script from `src/front-end/uibuilderfe.dev.js`. - -* uib-cache node - TBC -* uib-element node - TBC -* uib-update node - TBC -* uib-sender node - TBC -* Gulp scripts - TBC - -## Testing - -Some information on testing uibuilder. Unfortunately, I have no real clue about automated testing and TLD, if you would like to contribute something, please do! - -* [Regression Tests](regression-tests.md) - -## Other - -* [Glossary of Terms](glossary.md) - -* [Changelog](changelog) - What has changed between releases. What is currently in-progress/outstanding (the "unreleased" section) -* [Roadmap](roadmap) - All about where uibuilder is going in general, what I think needs doing next and some speculation about longer-term change. -* [Main Readme](uibhome) - This is what appears in [GitHub](https://github.com/TotallyInformation/node-red-contrib-uibuilder), [npm](https://www.npmjs.com/package/node-red-contrib-uibuilder]) and the [Node-RED flows page](https://flows.nodered.org/node/node-red-contrib-uibuilder). - -## Archives - -* [v5 Changelog](archived/CHANGELOG-v5) -* [v3/4 Changelog](archived/CHANGELOG-v3-v4) -* [v2 Breaking Changes](archived/v2-breaking-changes.md) -* [v2 Changelog](archived/CHANGELOG-v2.md) -* [v1 Changelog](archived/CHANGELOG-v1.md) - -> [!TIP] -> These are the docs for uibuilder v6. If you need the v5 or earlier docs, the easiest way is to set up a test instance of Node-RED and manually install the appropriate uibuilder version: `npm install node-red-contrib-uibuilder@5` then use the documentation links from a uibuilder node. +- ๐Ÿงช [Array Grouper](https://github.com/TotallyInformation/groupit) - Stand-alone function to reshape an array of objects diff --git a/docs/_404.md b/docs/_404.md new file mode 100644 index 00000000..64c69f9f --- /dev/null +++ b/docs/_404.md @@ -0,0 +1,7 @@ +# UIBUILDER documentation + +Sadly, the page you were looking for does not seem to exist. + +Please try using the search bar. + +If you spot a broken link in the documentation, please [raise an Issue on GitHub](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues/new/choose). diff --git a/docs/_coverpage.md b/docs/_coverpage.md new file mode 100644 index 00000000..d68d9659 --- /dev/null +++ b/docs/_coverpage.md @@ -0,0 +1,25 @@ +
+ +![logo](/images/node-lblue-192x192.png) + +
+ +# UIBUILDER v6 + +for Node-RED + +
+ +
+ +> Easy data-driven web UI's. + +- No-code and Low-code options, driven from Node-RED +- Dynamic data interchange between Node-RED and the browser +- Can use any or no front-end framework +- Can integrate with existing web development workflows + +[GitHub](https://github.com/TotallyInformation/node-red-contrib-uibuilder) +[Get Started](#uibuilder-documentation) +[Quick Start](walkthrough1) + diff --git a/docs/apis/readme.md b/docs/apis/readme.md new file mode 100644 index 00000000..1a13307b --- /dev/null +++ b/docs/apis/readme.md @@ -0,0 +1,83 @@ +--- +title: UIBUILDER REST API's +description: > + UIBUILDER exposes a number of REST API's. This is an index of them. +created: 2023-09-14 19:39:52 +lastUpdated: 2023-09-16 12:36:36 +--- + +Most of UIBUILDER's standard REST API's are common across all instances of `uibuilder` nodes added to your Node-RED flows. However, see below for the instance API's features. + +In this section, "Admin API" refers to a web endpoint that is only accessible from Node-RED's admin web server, this is generally restricted therefore to the Node-RED Editor. "User API" refers to a web endppoint accessible to users of your UIBUILDER web app and therefore can be called from your front-end code as needed. + +In all examples below, `` refers to a uibuilder instance URL setting. + +## v2 Admin API's + +> [!NOTE] +> At some point, it is expected that these v2 API's will be folded into the v3 API's. + +These are the oldest API's built into uibuilder. They are provided by `nodes/libs/admin-api-v3.js` which returns an ExpressJS router function. The router is added to Node-RED's admin ExpressJS server in `libs/web.js` in the function `_adminApiSetup` which is called from `setup` which, in turn is called as `web.setup(uib)` from the main uibuilder runtime setup function. + +All of the endpoints are only accessible from the Node-RED Editor. Note that each API has a specified endpoint URL that is relative to the Editor's URL. + +* GET `uibuilder/uibgetfile` - Returns the content of a file (`fname`) in the `//` folder. Parameters: `url`, `fname`, `folder` + +* GET `uibuilder/uibindex` - return web page with full details of the uibuilder configuration (for all instances) or JSON that lists all uibuilder endpoints + +* GET `uibuilder/uibvendorpackages` - Check & update installed uibuilder front-end library packages, return list as JSON - this runs when NR Editor is loaded if a uib instance deployed + +* GET `uibuilder/uibnpmmanage` - Run `npm` commands (install, remove, update). Parameters: `url`, `cmd`. If `url` not provided, uibPath = , else uibPath = / + +* POST `uibuilder/uibputfile` - Create or update the a file (`fname`) in the `//` folder. Parameters: `url`, `fname`, `folder`, `data`. + +## v3 Admin API's + +The newer v3 API's are provided by `nodes/libs/admin-api-v3.js` which returns an ExpressJS router function. The router is added to Node-RED's admin ExpressJS server in `libs/web.js` in the function `_adminApiSetup` which is called from `setup` which, in turn is called as `web.setup(uib)` from the main uibuilder runtime setup function. + +Unlike the the v2 API's, the v3 are provided by a master set of `all`, `get`, `put`, `post`, and `delete` handlers. + +All of these API endpoints are only accessible from the Node-RED Editor. The endpoint is simply defined as `/:url` which translates in Editor code to `./uibuilder/admin/` which is relative to the Editor's URL. + +Each of the v3 API's accepts a `cmd` parameter (either via URL query parameters or via JSON in the BODY for POST/PUT/etc). Alloed `cmd`s are shown below. + +* ALL - this handles gathering of the GET/POST parameters into a common object. It is triggered first for all of the API endpoints. It passes control onto the specific handlers once finished. + +* GET + * `listall` - List all folders and files for this uibuilder instance + * `listfolders` - List all folders for this uibuilder instance + * `checkurls` - Check if URL is already in use + * `listinstances` - List all of the deployed instance urls + * `listurls` - Return a list of all user urls in use by ExpressJS + * `checkfolder` - See if a node's custom folder exists. Return true if it does, else false + * `checkpackage` - Check whether a specific package name has been installed using the library manager +* PUT + * `deleteondelete` - tells uibuilder to delete the instance folder + * `updatepackage` - *(Not currently in use)* +* POST + * `replaceTemplate` - Replace instance files from a requested template + * `newfolder` - create a new folder for the given instance + * `newfile` - create a new file for the given instance +* DELETE + * `deletefolder` - delete a folder for the given instance + * `deletefile` = delete a file for the given instance + +## Middleware User API's + +uibuilder allows additional custom API's to be defined through the use of the `/.config/uibMiddleware.js` file. This file allows any custom ExpressJS middleware to be added and can therefore be used to define additional common user API's or any other user-facing web endpoint. + +An example template file is provided but authors should expect to need to understand ExpressJS middleware concepts and programming. + +## Instance Admin API's + +These are specific to each instance of a `uibuilder` node that you add to your flows. + +uibuilder has one other admin API (accessible only from the Node-RED Editor). This should be moved into the admin v3 API's in some future release but currently exists in the uibuilder runtime at the end of the `nodeInstance` function. + +* GET `/uibuilder/instance/` - shows the instance details web page. + +## Instance User API's + +uibuilder also allows admins to create *custom* instance API's. This provides a powerful capability to define API's needed for a specific web app. See [How to use Instance API's](how-to/instance-apis?id=how-to-use-instance-api39s) for details. + +Unlike the Admin API's, these API's are accessible to any client that can reach the `http(s):////api` URL path. diff --git a/docs/browser-refresh.md b/docs/browser-refresh.md index aa3d1994..1f3fc189 100644 --- a/docs/browser-refresh.md +++ b/docs/browser-refresh.md @@ -3,12 +3,12 @@ title: Auto-refresh the browser when developing description: > Describes how to make your page refresh automatically when developing front-end code. created: 2022-02-15 20:56:20 -lastUpdated: 2022-02-15 20:56:24 +lastUpdated: 2023-09-30 13:03:51 --- ## Reload message -The uibuilder front-end library has a a reload window tab command built in. This can be triggered by sending a standard message into a node-red node with the following data: +The UIBUILDER front-end library has a a reload window tab command built in. This can be triggered by sending a standard message into a node-red node with the following data: ```json { @@ -18,13 +18,13 @@ The uibuilder front-end library has a a reload window tab command built in. This } ``` -You can use a `watch` node to trigger a reload by watching the appropriate file or folder and connecting the watch node to a change node that sets the _uib.payload property and then sends it to the uibuilder node as in this example: +You can use a `watch` node to trigger a reload by watching the appropriate file or folder and connecting the watch node to a change node that sets the _uib.payload property and then sends it to the `uibuilder` node as in this example: ![Watch autorefresh example](images/watch-example.png) ## Editing files in the Node-RED Editor -uibuilder has a file editor feature built in. If you are using that (only recommended for fairly small edits), you can tell uibuilder to automatically reload the browser tab whenever you press the save button. +UIBUILDER has a file editor feature built in. If you are using that (only recommended for fairly small edits), you can tell UIBUILDER to automatically reload the browser tab whenever you press the save button. ## Using Microsoft Edge developer tools with VScode @@ -44,7 +44,7 @@ Use the watch approach above for HTML files. Most build tools contain their own development server that includes auto-update. -To use these with uibuilder, you generally have to make some code changes in your index.html and index.js files to allow for the fact that a different, non-Node-RED web server is presenting the files. +To use these with UIBUILDER, you generally have to make some code changes in your index.html and index.js files to allow for the fact that a different, non-Node-RED web server is presenting the files. You will need to pass some parameters to the `uibuilder.start` function in index.js and will need to make the `./` and `../uibuilder/vendor/` URL's in index.html absolute to include the Node-RED URL. @@ -56,4 +56,4 @@ If you are using Svelte and its development tools, they are the exception to thi Tools such as PM2 for running Node.js applications have watch features built in. -This is really only useful for developing custom nodes as the service will restart Node-RED on changes. \ No newline at end of file +This is really only useful for developing custom nodes as the service will restart Node-RED on changes. diff --git a/docs/client-docs/config-driven-ui.md b/docs/client-docs/config-driven-ui.md index c59fc5a0..faba1d15 100644 --- a/docs/client-docs/config-driven-ui.md +++ b/docs/client-docs/config-driven-ui.md @@ -1,10 +1,10 @@ --- title: Dynamic, configuration-driven UI's (low-code) description: > - This version of the uibuilder front-end library supports the dynamic manipulation of your web pages. This is achieved either by loading a JSON file describing the layout and/or by sending messages from Node-RED via a uibuilder node where the messages contain a `msg._ui` property. + This version of the uibuilder front-end library supports the dynamic manipulation of your web pages. This is achieved either by loading a JSON file describing the layout and/or by sending messages from Node-RED via a `uibuilder` node where the messages contain a `msg._ui` property. This is known as "configuration-driven" design since you send the configuration information and not the actual HTML. It is considered a low-code approach. created: 2022-06-11 14:15:26 -lastUpdated: 2023-07-02 14:41:10 +lastUpdated: 2023-09-30 13:02:29 --- - [Restricting actions to specific pages, users, tabs](#restricting-actions-to-specific-pages-users-tabs) diff --git a/docs/client-docs/control-from-node-red.md b/docs/client-docs/control-from-node-red.md index 51ed1a34..dd357280 100644 --- a/docs/client-docs/control-from-node-red.md +++ b/docs/client-docs/control-from-node-red.md @@ -1,13 +1,13 @@ --- -title: Controlling uibuilder's client from Node-RED +title: Controlling UIBUILDER's client from Node-RED description: > How to send specially formatted messages from Node-RED to the uibuilder node that get information from the client and control how it works. created: 2023-02-23 11:59:44 -lastUpdated: 2023-07-02 15:50:23 +lastUpdated: 2023-10-14 17:00:54 --- -The uibuilder client library can be controlled in various ways from Node-RED to save you the bother of having to write front-end code. +The UIBUILDER client library can be controlled in various ways from Node-RED to save you the bother of having to write front-end code. These ways are all summarised here. They all use a pre-formatted message sent to the appropriate `uibuilder` node in Node-RED. @@ -16,13 +16,34 @@ These ways are all summarised here. They all use a pre-formatted message sent to Please load the "remote-commands" example from the library to test all of these out. +### A summary of the commands available + +Possible `msg._uib.command` values. + +* `elementExists` - does an element exist in the HTML DOM? +* `get` - gets a uibuilder client managed variable. +* `getManagedVarList` - gets the list of uibuilder client managed variables. +* `getWatchedVars` - gets the list of uibuilder client managed variables that are currently being watched for changes. +* `htmlSend` - gets the current full HTML as text. +* `include` - Include HTML fragment, img, video, text, json, form data, pdf or anything else from an external file or API. +* `set` - set a uibuilder client managed variable. +* `showMsg` - Turn on/off the display of the latest msg from Node-RED. +* `showStatus` - Turn on/off the display of the uibuilder client library settings. +* `uiGet` - get detailed information about an HTML DOM element. +* `uiWatch` - watch for changes to the HTML DOM, return messages about changes. + + +> [!NOTE] +> The _case_ of the command string matters. It must match exactly. In general, the commands match function names in the uibuilder client library. + + ## Responses When a command is issued from Node-RED to the clients via a `msg._uib` command, the client library will respond with a standard message of its own. The `msg._uib` block of the response will contain `msg._uib.command` showing what command was issued and `msg._uib.response` showing the client library's (or browsers) response to the command. `msg.payload` also contains a copy of the response. -If the uibuilder node has the "Include msg._uib in standard msg output" flag set, `msg._uib` will also contain all of the client details. +If the `uibuilder` node has the "Include msg._uib in standard msg output" flag set, `msg._uib` will also contain all of the client details. ## UI control @@ -77,17 +98,12 @@ Sending a message containing a `msg._uib` property set as follows will result in See [Client Variables](variables.md) for details of what information you can get. In addition, uibuilder allows the setting of custom variables via its `set` function (see next section). This uses the `uibuilder.get(varName)` client function. -This command results in a standard message out of the top port of the uibuilder node that will contain `msg._uib.response`. +This command results in a standard message out of the top port of the `uibuilder` node that will contain `msg._uib.response`. ## Changing settings The following client settings can be changed from Node-RED by sending a message containing a `msg._uib` property configured as shown. -> [!NOTE] -> The _case_ of the command string matters. It must match exactly the function name. The following command functions are currently allowed: -> -> 'get', 'set', 'showMsg' - ### Set variable ```json @@ -96,7 +112,24 @@ The following client settings can be changed from Node-RED by sending a message Uses the `uibuilder.set(varName, value)` client function. -This command results in a standard message out of the top port of the uibuilder node that will contain `msg._uib.response`. +The command results in a standard message out of the top port of the `uibuilder` node that will contain `msg._uib.response`. + +Optionally can set some additional options: + +```json +{ + "command": "set", "prop": "myvar", + "value": {"a": 42, "b": "hello", "c": true}, + "options": {"store": true, "autoload": true} +} +``` + +The `store` option tells the client to attempt to save the value in the browser's `localStorage`. This means that it will be saved until the page tab has been closed in the browser. + +The `autoload` option tells the client to attempt to automatically reload the variable from `localStorage` if the page is re-loaded. It is only used if `store` is also set. + +> [!WARNING] +> `localStorage` is shared per _(sub)domain_, e.g. the IP address/name and port number. All pages from the same origin share the variables. It also only survives until the browser is closed. ### Turn on/off visible last message from Node-RED @@ -123,12 +156,36 @@ Where: ## Get complete copy of the current web page -To get the current web page, complete with dynamic changes back to Node-RED as a string in `msg.payload`, send a message to the uibuilder node containing: +To get the current web page, complete with dynamic changes back to Node-RED as a string in `msg.payload`, send a message to the `uibuilder` node containing: ```json { "_uib": { "command": "sendHtml" } } ``` +## Getting other information from the client + +### Get a list of managed variables + +Send the following msg object to get a list of all variables actively managed by the client. Those which can be watched for changes using `uibuilder.onChange()`. + +```json +{ "_uib": { "command": "getManagedVarList" } } +``` + +Optionally, also send the "full" prop to get an object instead of an array: + +```json +{ "_uib": { "command": "getManagedVarList", "prop": "full" } } +``` + +### Get a list of watched variables + +Send the following msg object to get a list of all variables currently being watched by the client using `uibuilder.onChange()`. + +```json +{ "_uib": { "command": "getWatchedVars" } } +``` + ## Restricting to specific pages, users, tabs Any of the `_ui` and `_uib` messages can be limited to operate only against specific page names, client ID's and browser tab ID's. @@ -142,3 +199,4 @@ You can, of course still use `msg._socketId`. If present, the msg being sent is The client ID should remain constant while the browser stays open. The tab ID should remain until the tab or the browser is closed. For the page name, note that the default name (e.g. when the browser address bar is only showing the folder and not a specific `xxxx.html`) is `index.html`. uibuilder allows you to have any number of pages defined under a single node however. + diff --git a/docs/client-docs/custom-components.md b/docs/client-docs/custom-components.md new file mode 100644 index 00000000..26dbb462 --- /dev/null +++ b/docs/client-docs/custom-components.md @@ -0,0 +1,95 @@ +--- +title: Custom web components +description: > + Web components built into the UIBUILDER client and information about external web components. +created: 2023-10-08 13:44:56 +lastUpdated: 2023-10-08 14:59:10 +--- + +UIBUILDER can work with front-end frameworks such as REACT, VueJS, etc. However, it does not need them. But one thing that these frameworks often have are collections of components that you can add to your HTML. Each component will produce something useful in your web page such as an information card, tabbed interface, navigation menu, etc. + +For more modern browsers though, there is an alternative to a framework and that is "[web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_Components)". These are a W3C international standard and they are defined using JavaScript. + +The [`uib-var`](#uib-var-include-a-managed-variable-in-the-page) built-in component is an example of such a component. + +To make use of a web component, all that is needed is to load it. Web components are written as ES Modules (ESM). In this form, you can only use them with the ESM version of the uibuilder client library and they will need loading as an `import` statement in your module `index.js` just like the client library itself. (`uib-var` is loaded for you, you don't have to do anything). + +However, some components may also be built so that they can be loaded as a linked script. This is easily done using a build tool such as [`esbuild`](https://esbuild.github.io/). When built this way, they can be used with the standard IIFE version of the uibuilder client library. A well-crafted component will often include a version for loading this way but it is up to the author to make this available. Check the component's documentation for details. + +> [!NOTE] +> UIBUILDER's no-code `uib-element` node currently sends out low-code JSON data that describes each element. While this is reasonably efficient since no actual HTML/JavaScript code is sent, it could be even more efficient by having a corresponding web component for each element. This is something that is likely to happen in a future release. + +## Built-in components + +### uib-var - include a managed variable in the page + +A built-in web component ``, used in your HTML as ``. + +Displays the *value* of the given variable name in your web page and *dynamically updates* as long as the variable is changed using `uibuilder.set()`; or from Node-RED using the appropriate uib set command, e.g. `msg = {"command":"set","prop":"myVar","value":"42"}`. By default, the tag inserts the variable value inline with other text. Class and Style attributes can be added as for any other HTML. + +Other attributes are available on the component tag: + +- `undefined`: If present or set to `on`, or `true`, the component will show even if the variable is undefined. + + If not present or set to anything else, an undefined variable will show the _slot content_ (anything put between the open and close tag). This lets you have an initial value showing that is replaced as soon as the variable is actually set. + +- `report`: If present or set to `on`, or `true`, the component will return a standard message back to Node-RED when the variable changes value. +- `type`: Must be one of 'plain', 'html', 'markdown', or 'object'. `plain` and `html` simply insert the variable as-is. `markdown` allows the insertion of Markdown as long as the Markdown-IT library is loaded (it will also sanitise the resulting HTML if the DOMPurify library is loaded). `object` does some basic formatting to allow object or array variables to be more easily read. + +This works with Markdown via the `uib-element` node as well and even works if DOMPurify is loaded as overrides to its filters are provided. + +There is no need to load the component, that is done automatically in the uibuilder client library. + +Examples: + +```html +

+ UIBUILDER client library version + "". +

+``` + +```html +

Last msg received: "".

+``` + +```html + +

The answer is .

+``` + +```markdown +## My Heading + +The version of the uibuilder client library currently +loaded is ``. +``` + +## External components + +Web components can be challenging to build but are often fairly simple. There are plenty of web resources to get you started with development of them. However, there are also a lot of existing components that you can easily make use of with Node-RED and UIBUILDER. + +### Totally Information experimental web components + +Totally Information has a (so far experimental) set of web components that work with or without UIBUILDER though they will generally have extra features when used with. See the [TotallyInformation/web-components GitHub repo](https://github.com/TotallyInformation/web-components) for details. + +### HotNiPi Gauge component + +A nice looking gauge was gifted to the community by Node-RED forum contributor HotNiPi and this also works with or without UIBUILDER. See [HotNipi Gauge Web Component](https://github.com/TotallyInformation/gauge-hotnipi) for details. In line with UIBUILDER standards, the gauge component is available in both ESM and IIFE formats for ease of use. + +### Other components and libraries + +There are many web components and web component libraries available. All should work with UIBUILDER. + +- [Basic Material Design components](https://material-web.dev/about/intro/) - supported by Google designers and developers. +- [Elix components](https://component.kitchen/elix) - high-quality basic elements and composable mixins. +- [Webcomponents.org](https://www.webcomponents.org/) - elements, collections and how-to's. +- [Webcomponents.org libraries](https://www.webcomponents.org/libraries) +- [GitHub Components](https://github.com/orgs/github/repositories?q=component) - various components and tools written by GitHub devs. +- [Mozilla Developer Network (MDN) example components](https://github.com/mdn/web-components-examples) - example components, useful to get started on your own. +- [Open Web Components](https://open-wc.org/) - guides, tools and libraries for developing web components. +- [Open Web Components community libraries](https://open-wc.org/guides/community/component-libraries/) - list of potentially useful component libraries. +- "Awesome" lists + - [obetomuniz/awesome-webcomponents](https://github.com/obetomuniz/awesome-webcomponents/blob/master/README.md) + - [web-padawan/awesome-web-components](https://github.com/web-padawan/awesome-web-components/blob/main/README.md) + diff --git a/docs/client-docs/custom-events.md b/docs/client-docs/custom-events.md index 5b02b7f2..23ebea9a 100644 --- a/docs/client-docs/custom-events.md +++ b/docs/client-docs/custom-events.md @@ -3,7 +3,7 @@ title: Custom document events used in the modern client description: > Details about the custom `document` events used in the uibuilder modern front-end client library. created: 2023-01-28 15:56:57 -lastUpdated: 2023-04-02 18:45:49 +lastUpdated: 2023-09-30 13:02:53 --- @@ -37,14 +37,14 @@ No data included. ## `uibuilder:socket:connected` -When Socket.IO successfully connects to the matching uibuilder node in Node-RED +When Socket.IO successfully connects to the matching `uibuilder` node in Node-RED The connection count is provided on the events `detail` object. This is likely to be the first event that is usable in your own front-end code, you can use it as an indicator that the uibuilder library is started and running correctly with a link back to Node-RED active. However, if using in your own code, note that it will fire again if the socket gets disconnected and then reconnects. So put in a flag if you only want to do something on initial startup. ## `uibuilder:socket:disconnected` -When Socket.IO disconnects from the matching uibuilder node in Node-RED +When Socket.IO disconnects from the matching `uibuilder` node in Node-RED The disconnect reason is provided on the events `detail` object if available. May be a string or an error object. diff --git a/docs/client-docs/features.md b/docs/client-docs/features.md index 59795c5e..74396844 100644 --- a/docs/client-docs/features.md +++ b/docs/client-docs/features.md @@ -3,31 +3,32 @@ title: Features of the modern, modular front-end client `uibuilder.esm.js` and ` description: > Description of the main features. created: 2022-06-11 14:15:26 -lastUpdated: 2023-07-05 21:56:42 +lastUpdated: 2023-10-08 13:39:09 --- - [Dynamic, data-driven HTML content](#dynamic-data-driven-html-content) -- [Exposes global uibuilder and $](#exposes-global-uibuilder-and-) -- [Includes the Socket.IO client library](#includes-the-socketio-client-library) -- [start function (now rarely needed)](#start-function-now-rarely-needed) -- [$ function](#-function) +- [Exposes global uibuilder, uib, $, and $$](#exposes-global-uibuilder-uib--and-) +- [$ and $$ functions](#-and--functions) - [onChange/cancelChange functions](#onchangecancelchange-functions) - [onTopic/cancelTopic functions](#ontopiccanceltopic-functions) +- [send function](#send-function) +- [eventSend function](#eventsend-function) +- [uib-var custom HTML tag (include managed variables in the UI)](#uib-var-custom-html-tag-include-managed-variables-in-the-ui) +- [set function (Managed variables)](#set-function-managed-variables) +- [Auto-loading of the uibuilder default stylesheet](#auto-loading-of-the-uibuilder-default-stylesheet) - [Conditional logging](#conditional-logging) - [document-level events](#document-level-events) - [setPing function](#setping-function) -- [set function](#set-function) - [Page auto-reload](#page-auto-reload) - [setStore, getStore, removeStore functions](#setstore-getstore-removestore-functions) -- [send function](#send-function) -- [eventSend function](#eventsend-function) -- [Auto-loading of the uibuilder default stylesheet](#auto-loading-of-the-uibuilder-default-stylesheet) - [Initial connection message now shows whether the page is newly loaded or not](#initial-connection-message-now-shows-whether-the-page-is-newly-loaded-or-not) - [Stable client identifier](#stable-client-identifier) - [Number of connections is tracked and sent to server on (re)connect](#number-of-connections-is-tracked-and-sent-to-server-on-reconnect) - [Client connection/disconnection control messages](#client-connectiondisconnection-control-messages) - [ui function](#ui-function) - [Controlling from Node-RED](#controlling-from-node-red) +- [Includes the Socket.IO client library](#includes-the-socketio-client-library) +- [start function (now rarely needed)](#start-function-now-rarely-needed) ## Dynamic, data-driven HTML content @@ -35,51 +36,23 @@ This feature allows you to dynamically create a UI or part of a UI using just co See the [Dynamic, data-driven HTML content](client-docs/config-driven-ui.md) page for details. -## Exposes global uibuilder and $ - -For ease of use, both `uibuilder` and `$` objects are added to the global `window` context unless they already exist there. - -## Includes the Socket.IO client library - -There is no longer a need to load this library, which sometimes caused confusion in the past. The correct version of the library is included. - -## start function (now rarely needed) - -!> You should hardly ever need to manually run this now. Try without first. See the details below. - -The start function is what kick-starts the uibuilder front-end library into action. It attempts to make a connection to Node-RED and exchanges the initial control messages. - -It: - -* Attempts to use some cookie values passed from Node-RED by uibuilder in order to work out how to connect the websocket (actually uses Socket.IO). -* Starts the communications with Node-RED/uibuilder node using Socket.IO. This also issues 1 or more document custom events (see [Event Handling](#event-handling) below). -* An event handler is created for incoming messages from Node-RED. It checks for reload and UI requests and deals with them automatically. -* Automatically loads the default stylesheet if you haven't loaded your own. +## Exposes global uibuilder, uib, $, and $$ -Normally, you will not have to pass any options to this function (unlike the equivalent function in the older `uibuilderfe.js` library before uibuilder v5). However, see the troubleshooting section if you are having problems connecting correctly. - -If you do need the options, there is now only a single object argument with only two possible properties: - -```javascript -uibuilder.start({ - ioNamespace: '/components-html', // Will be the uibuilder instance URL prefixed with a leading / - ioPath: '/uibuilder/vendor/socket.io', // Actual path may be altered if httpNodeRoot is set in Node-RED settings -}) -``` +For ease of use, both `uibuilder`, `$`, and `$$` objects are added to the global `window` context unless they already exist there. `uib` is a global alias for `uibuilder` for brevity. -Note that if the Node-RED/uibuilder server is different to the one serving up your html and/or js files (as when using a framework dev server for example), you will need to pass the remote server and uibuilder URL as the ioNamespace: `uibuilder.start({ioNamespace: 'https://remote.server/uib-instance-url'})` +## $ and $$ functions -## $ function +uibuilder adds the global `$` and `$$` functions when loaded if it can (it won't do it if there is a name clash, such as if jQuery has been loaded before uibuilder). This is for convenience. -uibuilder adds the global `$` function when loaded if it can (it won't do it if `$` is already present, such as if jQuery has been loaded before uibuilder). This is for convenience. +The `$` function acts in a similar way to the version provided by jQuery and the same as in your browser dev console. It is actually bound to [`document.querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) which lets you get a reference to an HTML element using a CSS selector. If multiple elements match the selection, the element returned will be the first one found. -The `$` function acts in a similar way to the version provided by jQuery. It is actually bound to [`document.querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) which lets you get a reference to an HTML element using a CSS selector. +!> Note that this function will only ever return a **single** element which is different to jQuery but the same as the dev console. -!> Note that this function will only ever return a **single** element which is differnt to jQuery. You can always redefine it to `querySelectorAll` using `window.$ = document.querySelectorAll.bind(document)` should you need to. +Example. With the HTML `` and the JavaScript `$('#button1').innerHTML = 'boo!'`. The label on the button will change from "Press me" to "Boo!". -If multiple elements match the selection, the element returned will be the first one found. +The `$$` function is the same as in the browser dev console, it is a reference to `querySelectorAll`. So it returns an array containing all found DOM elements. -Example. With the HTML `` and the JavaScript `$('#button1').innerHTML = 'boo!'`. The label on the button will change from "Press me" to "Boo!". +Should either of these globals already be defined, you can still access them as `uibuilder.$` and `uibuilder.$$` (noting that `uib` is also a global alias for `uibuilder` for us lazy folk). See the [MDN documentation on CSS query selectors](https://developer.mozilla.org/en-US/docs/Web/API/Document_object_model/Locating_DOM_elements_using_selectors) for details on selecting elements. @@ -142,144 +115,6 @@ let otRef = uibuilder.onTopic('mytopic', (msg) => { Because `this` now points to the parent and not to the callback function. You could use a bound function if you really wanted the correct `this` when using an arrow function but at present, there is no real value in doing that as the content of `this` is identical to the `msg` argument. That may change in future releases. -## Conditional logging - -Internal logging is much improved over previous versions of this library. There is now a dedicated internal `log` function which adds colour highlighting to browsers that support it in the dev tools console. That includes all Chromium-based browsers and Firefox. - -You can alter the amount of information that the uibuilder library outputs to the console by changing the `logLevel` with `uibuilder.logLevel = 4` where the number should be between 0 and 5. you can set that at any time in your code, however it will generally be most useful set _before_ calling `uibuilder.start()`. - -The default level is set to 1 (warn). The levels are: 0 'error', 1 'warn', 2 'info', 3 'log', 4 'debug', 5 'trace'. - -Changing the log level outputs an info note to the console telling you what the level is. - -The log function is also available to your own code as `uibuilder.log(level, prefix, ...outputs)`. - -## document-level events - -In previous versions of the library, a custom event feature was used. In this version, we make use of custom DOM events on the `document` global object. DOM events are especially useful when working with ESM modules since module code isolation can prohibit some other forms of cross-module sharing. - -Each event name starts with `uibuilder:` to avoid name clashes. - -See the [Custom Events](#custom-events) below for details. - -The main current events are (other events may be added later): - -* `uibuilder:stdMsgReceived` - triggered when a non-control msg arrives from Node-RED -* `uibuilder:propertyChanged` - triggered when any uibuilder managed property is changed -* `uibuilder:msg:topic:${msg.topic}` - triggered when an incoming msg contains a `msg.topic` property allowing specific topics to be monitored -* `uibuilder:msg:_ui` - triggered when an incoming msg contains a `msg._ui` property (used for UI automation using web components) -* `uibuilder:msg:_ui:${action.method}${action.id ? `:${action.id}` : ''}` - triggered when the incoming msg contains `msg._ui.add`, `msg._ui.update`, or `msg._ui.remove` for UI automation. For the update action, the `msg._ui.id` property links the msg to a specific on-page element by its HTML id attribute. -* `uibuilder:socket:connected` - when Socket.IO successfully connects to the matching uibuilder node in Node-RED -* `uibuilder:socket:disconnected` - when Socket.IO disconnects from the matching uibuilder node in Node-RED - -You can watch for these events in your own code using something like: - -```javascript -document.addEventListener('uibuilder:propertyChanged', function (evt) { - console.log('>> EVENT uibuilder:propertyChanged >>', evt.detail) -}) -``` - -In each case, `evt.detail` contains the relevant custom data. - -In general, you should not need to use these events. There are more focused features that are easier to use such as `onChange` and `onTopic`. - -Of particular note are the `_ui` events. These are used by uibuilder-aware web components for UI automation. - -## setPing function - -`setPing` accesses a special endpoint (URL) provided by uibuilder. That endpoint returns a single value which really isn't of any use to your code. However, it _does_ do several useful things: - -1. It tells the server that your browser tab is alive. - - This may be useful when working either with a reverse Proxy server or with uibuilder's ExpressJS middleware for authentication and/or authorisation. - - Because most communication with uibuilder happens over websockets, telling the server whether a client is still active or whether the client's session has expired is challenging. A ping such as this may be sufficient for the proxy or your custom middleware code to continue to refresh any required security tokens, etc. - -2. It returns the timespan (in milliseconds) of the round-trip time. - - This can help with understanding networking and client device or Node-RED issues. - -3. It returns the uibuilder/Node-RED HTTP headers. - - Normally, the web server headers cannot be accessed by your custom JavaScript code. However, the ping function uses the `Fetch` feature available to modern browsers which does return the headers. - - You can watch for ping responses as follows: - - ```javascript - uibuilder.setPing(2000) // repeat every 2 sec. Re-issue with ping(0) to turn off repeat. - uibuilder.onChange('ping', function(data) { - console.log('>> PING RESPONSE >>', data) - }) - // Output: - // pinger {success: true, status: 201, headers: Array(6)} - - // Turn off the repeating ping with - uibuilder.setPing(0) - ``` - - The headers are included in the data object. - -4. It returns the full originating URL. - - While not normally needed, it can be useful in order to work out whether Node-RED's httpNode URL path has been changed. - -## set function - -the `uibuilder.set()` function is now more flexible than in `uibuilderfe.js`. You can now set anything that doesn't start with `_` or `#`. - -!> Please note that there may be some rough edges still in regard to what should and shouldn't be `set`. Please try to avoid setting an internal variable or function or bad things may happen ๐Ÿ˜ฒ - -This means that you can simulate an incoming message from Node-RED with something like `uibuilder.set('msg', {topic:'uibuilder', payload:42})` in your front-end JavaScript. - -One interesting possibility is getting your page to auto-reload using `uibuilder.set('msg', {_uib:{reload:true}})`. Perhaps even more useful is the ability to very easily alter your UI on the page by using the dynamic UI feature (detailed below) `uibuilder.set('msg', {_ui:[{method:'add', ...}, {method:'remove', ....}]})`. - -Using the `set` function triggers an event `uibuilder:propertyChanged` which is attached to the `document` object. This means that you have two different ways to watch for variables changing. - -This will listen for a specific variable changing: - -```javascript -uibuilder.onChange('myvar', (myvar) => { - console.log('>> MYVAR HAS CHANGED >>', myvar) -}) -// ... -uibuilder.set('myvar', 42) -// Outputs: -// >> MYVAR HAS CHANGED >> 42 -``` - -Whereas this will listen for anything changing: - -```javascript -document.addEventListener('uibuilder:propertyChanged', function (evt) { - // evt.detail contains the information on what has changed and what the new value is - console.log('>> EVENT uibuilder:propertyChanged >>', evt.detail) -}) -// ... -uibuilder.set('myvar', 42) -// Outputs: -// >> EVENT uibuilder:propertyChanged >> {prop: 'myvar', value: 42} -``` - -## Page auto-reload - -By sending a message such as `{_uib:{reload:true}}` from Node-RED, you can make your page reload itself. This is already used by the uibuilder file editor. But you can add a flow in Node-RED that consists of a watch node followed by a set node that will create this message and send it into your uibuilder node. This will get your page to auto-reload when you make changes to the front-end code using an editor such as VSCode. This is what a dev server does in one of the many front-end frameworks that have build steps. You don't need a build step though and you don't need a dev server! ๐Ÿ˜Ž - -## setStore, getStore, removeStore functions - -Stores & retrieves information in the browser's localStorage if allowed. localStorage will survive page reloads as well as tab, window, browser, and machine restarts. However, whether storage is allowed and how much is decided by the browser (the user) and so it may not be available or may be full. - -Applies an internal prefix of 'uib_'. Returns `true` if it succeded, otherwise returns `false`. If the data to store is an object or array, it will stringify the data. - -Example - -```javascript -uibuilder.setStore('fred', 42) -console.log(uibuilder.getStore('fred')) -``` - -To remove an item from local storage, use `removeStore('fred')`. - ## send function The send function sends a message from the browser to the Node-RED server via uibuilder. @@ -391,6 +226,51 @@ Alternatively, you can use the simpler form (noting the use of the `event` argum ``` +## uib-var custom HTML tag (include managed variables in the UI) + +The `` custom component lets you include a uibuilder managed variable in your web page. + +See [Custom Components](client-docs/custom-components) for details. + +## set function (Managed variables) + +the `uibuilder.set()` function is now more flexible than in `uibuilderfe.js`. You can now set anything that doesn't start with `_` or `#`. + +!> Please note that there may be some rough edges still in regard to what should and shouldn't be `set`. Please try to avoid setting an internal variable or function or bad things may happen ๐Ÿ˜ฒ + +This means that you can simulate an incoming message from Node-RED with something like `uibuilder.set('msg', {topic:'uibuilder', payload:42})` in your front-end JavaScript. + +One interesting possibility is getting your page to auto-reload using `uibuilder.set('msg', {_uib:{reload:true}})`. Perhaps even more useful is the ability to very easily alter your UI on the page by using the dynamic UI feature (detailed below) `uibuilder.set('msg', {_ui:[{method:'add', ...}, {method:'remove', ....}]})`. + +Using the `set` function triggers an event `uibuilder:propertyChanged` which is attached to the `document` object. This means that you have two different ways to watch for variables changing. + +This will listen for a specific variable changing: + +```javascript +uibuilder.onChange('myvar', (myvar) => { + console.log('>> MYVAR HAS CHANGED >>', myvar) +}) +// ... +uibuilder.set('myvar', 42) +// Outputs: +// >> MYVAR HAS CHANGED >> 42 +``` + +Whereas this will listen for anything changing: + +```javascript +document.addEventListener('uibuilder:propertyChanged', function (evt) { + // evt.detail contains the information on what has changed and what the new value is + console.log('>> EVENT uibuilder:propertyChanged >>', evt.detail) +}) +// ... +uibuilder.set('myvar', 42) +// Outputs: +// >> EVENT uibuilder:propertyChanged >> {prop: 'myvar', value: 42} +``` + +Note that `uibuilder.get()` will do a one-off get of a managed variable including the client libraries own internal variables and constants. + ## Auto-loading of the uibuilder default stylesheet In previous versions of the front-end library, you had to provide your own CSS code and had to make sure that you imported (or loaded) the uibuilder default stylesheet (`uib-styles.css`). @@ -401,6 +281,107 @@ In this version, if you haven't loaded any other stylesheets, the library will a If you are trying to load the default CSS and can't find the correct URL, try removing the style link from your HTML and check what the client loads in the browsers dev tools network tab. +## Conditional logging + +Internal logging is much improved over previous versions of this library. There is now a dedicated internal `log` function which adds colour highlighting to browsers that support it in the dev tools console. That includes all Chromium-based browsers and Firefox. + +You can alter the amount of information that the uibuilder library outputs to the console by changing the `logLevel` with `uibuilder.logLevel = 4` where the number should be between 0 and 5. you can set that at any time in your code, however it will generally be most useful set _before_ calling `uibuilder.start()`. + +The default level is set to 1 (warn). The levels are: 0 'error', 1 'warn', 2 'info', 3 'log', 4 'debug', 5 'trace'. + +Changing the log level outputs an info note to the console telling you what the level is. + +The log function is also available to your own code as `uibuilder.log(level, prefix, ...outputs)`. + +## document-level events + +In previous versions of the library, a custom event feature was used. In this version, we make use of custom DOM events on the `document` global object. DOM events are especially useful when working with ESM modules since module code isolation can prohibit some other forms of cross-module sharing. + +Each event name starts with `uibuilder:` to avoid name clashes. + +See the [Custom Events](#custom-events) below for details. + +The main current events are (other events may be added later): + +* `uibuilder:stdMsgReceived` - triggered when a non-control msg arrives from Node-RED +* `uibuilder:propertyChanged` - triggered when any uibuilder managed property is changed +* `uibuilder:msg:topic:${msg.topic}` - triggered when an incoming msg contains a `msg.topic` property allowing specific topics to be monitored +* `uibuilder:msg:_ui` - triggered when an incoming msg contains a `msg._ui` property (used for UI automation using web components) +* `uibuilder:msg:_ui:${action.method}${action.id ? `:${action.id}` : ''}` - triggered when the incoming msg contains `msg._ui.add`, `msg._ui.update`, or `msg._ui.remove` for UI automation. For the update action, the `msg._ui.id` property links the msg to a specific on-page element by its HTML id attribute. +* `uibuilder:socket:connected` - when Socket.IO successfully connects to the matching uibuilder node in Node-RED +* `uibuilder:socket:disconnected` - when Socket.IO disconnects from the matching uibuilder node in Node-RED + +You can watch for these events in your own code using something like: + +```javascript +document.addEventListener('uibuilder:propertyChanged', function (evt) { + console.log('>> EVENT uibuilder:propertyChanged >>', evt.detail) +}) +``` + +In each case, `evt.detail` contains the relevant custom data. + +In general, you should not need to use these events. There are more focused features that are easier to use such as `onChange` and `onTopic`. + +Of particular note are the `_ui` events. These are used by uibuilder-aware web components for UI automation. + +## setPing function + +`setPing` accesses a special endpoint (URL) provided by uibuilder. That endpoint returns a single value which really isn't of any use to your code. However, it _does_ do several useful things: + +1. It tells the server that your browser tab is alive. + + This may be useful when working either with a reverse Proxy server or with uibuilder's ExpressJS middleware for authentication and/or authorisation. + + Because most communication with uibuilder happens over websockets, telling the server whether a client is still active or whether the client's session has expired is challenging. A ping such as this may be sufficient for the proxy or your custom middleware code to continue to refresh any required security tokens, etc. + +2. It returns the timespan (in milliseconds) of the round-trip time. + + This can help with understanding networking and client device or Node-RED issues. + +3. It returns the uibuilder/Node-RED HTTP headers. + + Normally, the web server headers cannot be accessed by your custom JavaScript code. However, the ping function uses the `Fetch` feature available to modern browsers which does return the headers. + + You can watch for ping responses as follows: + + ```javascript + uibuilder.setPing(2000) // repeat every 2 sec. Re-issue with ping(0) to turn off repeat. + uibuilder.onChange('ping', function(data) { + console.log('>> PING RESPONSE >>', data) + }) + // Output: + // pinger {success: true, status: 201, headers: Array(6)} + + // Turn off the repeating ping with + uibuilder.setPing(0) + ``` + + The headers are included in the data object. + +4. It returns the full originating URL. + + While not normally needed, it can be useful in order to work out whether Node-RED's httpNode URL path has been changed. + +## Page auto-reload + +By sending a message such as `{_uib:{reload:true}}` from Node-RED, you can make your page reload itself. This is already used by the uibuilder file editor. But you can add a flow in Node-RED that consists of a watch node followed by a set node that will create this message and send it into your uibuilder node. This will get your page to auto-reload when you make changes to the front-end code using an editor such as VSCode. This is what a dev server does in one of the many front-end frameworks that have build steps. You don't need a build step though and you don't need a dev server! ๐Ÿ˜Ž + +## setStore, getStore, removeStore functions + +Stores & retrieves information in the browser's localStorage if allowed. localStorage will survive page reloads as well as tab, window, browser, and machine restarts. However, whether storage is allowed and how much is decided by the browser (the user) and so it may not be available or may be full. + +Applies an internal prefix of 'uib_'. Returns `true` if it succeded, otherwise returns `false`. If the data to store is an object or array, it will stringify the data. + +Example + +```javascript +uibuilder.setStore('fred', 42) +console.log(uibuilder.getStore('fred')) +``` + +To remove an item from local storage, use `removeStore('fred')`. + ## Initial connection message now shows whether the page is newly loaded or not In previous versions, it was not possible for Node-RED to know whether the client was a freshly loaded page (or a page reload) or whether it was simply reconnecting after a Node-RED restart or lost websocket connection. @@ -476,7 +457,9 @@ When a client (a browser tab) connects or disconnects, the uibuilder node output These messages can be used for cache control and for user session management. -The client also receives an initial message from the server +The client also receives an initial message from the server. + +See [Pre-defined UIBUILDER messages](pre-defined-msgs) for details. ### Client Connect message @@ -555,8 +538,39 @@ Once the client receives this message, it replies with a "ready for content" con This new function allows passing the same data as `msg._ui` from within your front-end code. It allows front-end scripts to be able to dynamically generate and update UI's using simple configuration JSON. -See the next section for details. +See [Dynamic, configuration-driven UI's (low-code)](client-docs/config-driven-ui) for details. ## Controlling from Node-RED -A number of the uibuilder client's functions can be controlled from Node-RED via specially formatted messages. See []() for details. +A number of the uibuilder client's functions can be controlled from Node-RED via specially formatted messages. See [Controlling from Node-RED](client-docs/control-from-node-red) for details. + +## Includes the Socket.IO client library + +There is no longer a need to load this library, which sometimes caused confusion in the past. The correct version of the library is included. + +## start function (now rarely needed) + +!> You should hardly ever need to manually run this now. Try without first. See the details below. + +The start function is what kick-starts the uibuilder front-end library into action. It attempts to make a connection to Node-RED and exchanges the initial control messages. + +It: + +* Attempts to use some cookie values passed from Node-RED by uibuilder in order to work out how to connect the websocket (actually uses Socket.IO). +* Starts the communications with Node-RED/uibuilder node using Socket.IO. This also issues 1 or more document custom events (see [Event Handling](#event-handling) below). +* An event handler is created for incoming messages from Node-RED. It checks for reload and UI requests and deals with them automatically. +* Automatically loads the default stylesheet if you haven't loaded your own. + +Normally, you will not have to pass any options to this function (unlike the equivalent function in the older `uibuilderfe.js` library before uibuilder v5). However, see the troubleshooting section if you are having problems connecting correctly. + +If you do need the options, there is now only a single object argument with only two possible properties: + +```javascript +uibuilder.start({ + ioNamespace: '/components-html', // Will be the uibuilder instance URL prefixed with a leading / + ioPath: '/uibuilder/vendor/socket.io', // Actual path may be altered if httpNodeRoot is set in Node-RED settings +}) +``` + +Note that if the Node-RED/uibuilder server is different to the one serving up your html and/or js files (as when using a framework dev server for example), you will need to pass the remote server and uibuilder URL as the ioNamespace: `uibuilder.start({ioNamespace: 'https://remote.server/uib-instance-url'})` + diff --git a/docs/client-docs/functions.md b/docs/client-docs/functions.md index d3ea042f..cd29524f 100644 --- a/docs/client-docs/functions.md +++ b/docs/client-docs/functions.md @@ -1,10 +1,10 @@ --- title: Functions available in the modern client description: > - Details about the functions/methods used in the uibuilder front-end client library. + Details about the functions/methods used in the UIBUILDER front-end client library. Some functions are available to your own custom code and some are hidden inside the `uibuilder` client object. created: 2023-01-28 15:56:57 -lastUpdated: 2023-07-02 14:23:47 +lastUpdated: 2023-10-14 17:23:41 --- Functions accessible in client-side user code. @@ -18,32 +18,23 @@ Functions accessible in client-side user code. - [Utility](#utility) - [Startup](#startup) +> [!NOTE] +> Where functions are marked as being accessible as Node-RED command messages, details can be found in [Controling From Node-RED](client-docs/control-from-node-red). + ## Receiving Messages from Node-RED -uibuilder automatically creates a live websocket channel from the Node-RED server to your browser when you open a uibuilder page. By sending a msg to a uibuilder node, it will be transferred to ALL connected clients unless you specify otherwise. +UIBUILDER automatically creates a live websocket channel from the Node-RED server to your browser when you open a UIBUILDER page. By sending a msg to a UIBUILDER node, it will be transferred to ALL connected clients unless you specify otherwise. -To process a message in your browser, you can use one of the event handling uibuilder library functions such as [`onChange`](#event-handling) or [`onTopic`](#event-handling). Alternatively, you can use the standard `document.addEventListener` function to listen for one of the uibuilder library's custom events. +To process a message in your browser, you can use one of the event handling UIBUILDER library functions such as [`onChange`](#event-handling) or [`onTopic`](#event-handling). Alternatively, you can use the standard `document.addEventListener` function to listen for one of the UIBUILDER library's custom events. You can also do `uibuilder.set('msg', {/*your object details*/})` in your front-end code which instructs the client to treat the object as though it had come from Node-RED. You can use one or more of the `msg._uib.pageName`, `msg._uib.clientId`, or `msg._uib.tabId` properties to control whether a specific page, client or browser tab will process an inbound message. Use this where you have multiple pages or clients and need to target a message to a specific one. -## Sending Messages to Node-RED - -### `htmlSend()` - Sends the whole DOM/HTML back to Node-RED - -Results in a standard message sent to Node-RED where the `msg.payload` contains the whole current HTML page as a string. +UIBUILDER also allows you to issue control commands from Node-RED to your front-end app by sending messages to the `uibuilder` node containing `msg._uib.command` which must be set to [one of the recognised commands](/client-docs/control-from-node-red). -Use with the `uib-save` node to fix the latest page complete with any dynamic updates as the html page to load for new client connections for example. - -The returned message inludes `msg.length` to allow checking that the returned html payload wasn't truncated by a Socket.IO message length restriction. - -### `send(msg, originator = '')` - Send a custom message back to Node-RED - -The `msg` format is the same as used in Node-RED. - -The `originator` is optional and if used, should match the id from a `uib-sender` node. That allows you to specifically return a message into a flow that uses one of those nodes. However, ensure that the `uib-sender` node has turned on the flag to allow returned messages. +## Sending Messages to Node-RED ### `eventSend(domevent, originator = '')` - Send a standard message back to Node-RED in response to a DOM event @@ -67,33 +58,77 @@ If the source event type is `change` (e.g. a user changed an input field and the > The input element validity property can contain any of the following: badInput, customError, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing. See [ValidityState](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState) for details of the meanings. -### `setOriginator(originator = '')` - Set/clear the default originator +### `beaconLog(txtToSend, logLevel)` - Send a short log message to Node-RED -Will automatically be used by `send` and `eventSend`. +This has the advantage of working even if Socket.IO is not connected. It uses a logging API provided by UIBUILDER. -Set to an empty string to remove. +However, only text strings can be sent and messages need to be kept short. It only works with modern browsers that support the web beacon API. + +The `logLevel` matches both Node-RED and UIBUILDER defined log levels (e.g. error, warn, info, debug, trace ). + +### `htmlSend()` - Sends the whole DOM/HTML back to Node-RED + +Results in a standard message sent to Node-RED where the `msg.payload` contains the whole current HTML page as a string. + +Use with the `uib-save` node to fix the latest page complete with any dynamic updates as the html page to load for new client connections for example. + +The returned message includes `msg.length` to allow checking that the returned html payload wasn't truncated by a Socket.IO message length restriction. + +This can also be triggered from Node-RED. Send a message to the `uibuilder` node containing `msg._uib.command` set to "htmlSend". [Reference](client-docs/control-from-node-red?id=get-complete-copy-of-the-current-web-page) + +### ~~logToServer()~~ - Not yet reliable. Will cause the input to appear in Node-RED logs + +### `send(msg, originator = '')` - Send a custom message back to Node-RED + +The `msg` format is the same as used in Node-RED. + +The `originator` is optional and if used, should match the id from a `uib-sender` node. That allows you to specifically return a message into a flow that uses one of those nodes. However, ensure that the `uib-sender` node has turned on the flag to allow returned messages. ### `sendCtrl(msg)` - Send a custom control message back to Node-RED -The message will be assessed by uibuilder and passed to its #2 (bottom) output port if considered acceptible. +The message will be assessed by UIBUILDER and passed to its #2 (bottom) output port if considered acceptible. This lets you create your own control custom messages should you wish to. Use with caution. -### `beaconLog(txtToSend, logLevel)` - Send a short log message to Node-RED +### `setOriginator(originator = '')` - Set/clear the default originator -This has the advantage of working even if Socket.IO is not connected. It uses a logging API provided by uibuilder. +Will automatically be used by `send` and `eventSend`. -However, only text strings can be sent and messages need to be kept short. It only works with modern browsers that support the web beacon API. +Set to an empty string to remove. -The `logLevel` matches both Node-RED and uibuilder defined log levels (e.g. error, warn, info, debug, trace ). +### `setPing(ms)` - Set a repeating ping/keep-alive HTTP call to Node-RED -### ~~logToServer()~~ - Not yet reliable. Will cause the input to appear in Node-RED logs +This uses an HTTP API call to a custom UIBUILDER API endpoint in Node-RED. So it works even if the Socket.IO connection is not working. It is used to check that the Node-RED server and the UIBUILDER instance are both still working. + +##### Example + +```javascript +uibuilder.setPing(2000) // repeat every 2 sec. Re-issue with ping(0) to turn off repeat. + +// Optionally monitor responses +uibuilder.onChange('ping', function(data) { + console.log('pinger', data) +}) +``` ## Variable Handling -### `get(prop)` - Get a uibuilder property +> [!NOTE] +> See [client variables](client-docs/variables) for details of what uibuilder variables are available. + +### `copyToClipboard(varToCopy)` - Copy the specified UIBUILDER variable to the browser clipboard -This is the preferred method to get an exposed uibuilder variable or property. Do not try to access variables and properties directly unless explicitly shared in this documentation. This function can also be called from Node-RED via `msg._uib.command` - `get` with `msg._uib.prop` set to the variable name to get. +Can only be used as an event handler because browsers do not allow unrestricted JavaScript access to the browser clipboard. + +`varToCopy` has to be a variable specified in UIBUILDER. One that could be retrieved by `uibuilder.get('varToCopy')`. + +```html + +``` + +### `get(prop)` - Get a UIBUILDER property + +This is the preferred method to get an exposed UIBUILDER variable or property. Do not try to access variables and properties directly unless explicitly shared in this documentation. This function can also be called from Node-RED via `msg._uib.command` - `get` with `msg._uib.prop` set to the variable name to get. ##### Example @@ -101,21 +136,20 @@ This is the preferred method to get an exposed uibuilder variable or property. D console.log( uibuilder.get('version') ) ``` -### `set(prop, val)` - Set a uibuilder property and dispatch a change event +### `getManagedVarList()` - Get a list of all UIBUILDER managed variables -This is the preferred method to set an exposed uibuilder variable or property. Do not try to set variables and properties directly. +A UIBUILDER managed variable is one that has been created with `uibuilder.set()` (or changed from Node-RED with the equivalent command msg). As such, it can be watched for changes with `uibuilder.onChange()`. -When using set, the variable that is set becomes responsive. That is to say, that issuing a set triggers both the internal event handler (as used in `uibuilder.onChange('prop', ...)`) but also the DOM custom event `uibuilder:propertyChanged`. Normally, you will want to use the `onChange` handler. +This function can also be called from Node-RED via `msg._uib.command` - `getManagedVarList`. The returned `msg.payload` contains the list. Optionally, you can also add `msg._uib.prop` set to `full` which will return an object where each key/value is the variable name. This can be usefull for some types of processing. -Note that you can add additional custom data to the uibuilder object but care must be taken not to overwrite existing internal variables. This is useful if you want to be able to automatically process changes to your own variables using the `onChange` handler. +### `getWatchedVars()` - Get a list of all UIBUILDER watched variables -This function can also be called from Node-RED via `msg._uib.command` - `set` with `msg._uib.prop` set to the variable name to set. and `msg._uib.value` set to the new value. +Shows all variables that are being watched using `uibuilder.onChange()`. -##### Example +This function can also be called from Node-RED via `msg._uib.command` - `getWatchedVars`. The returned `msg.payload` contains the list. -```javascript -uibuilder.set('logLevel', 3) -``` +> [!WARNING] +> `localStorage` is shared per _(sub)domain_, e.g. the IP address/name and port number. All pages from the same origin share the variables. ### `getStore(id)` - Attempt to get and re-hydrate a key value from browser localStorage @@ -123,41 +157,51 @@ Note that browser localStorage is persisted even after a browser closes. It can If the `id` is not found in the store, `null` is returned. If the store is not available or some other error occurs, `undefined` is returned. -All `id`s have a pre-defined uibuilder prefix added to the key name to help ensure that the key being saved will be unique. This prefix is defined in the library and cannot be changed, it is set to `uib_`. +All `id`s have a pre-defined UIBUILDER prefix added to the key name to help ensure that the key being saved will be unique. This prefix is defined in the library and cannot be changed, it is set to `uib_`. Because the browser storage API only allows strings as values, the data has to be serialised. This function attempts to unserialise (re-hydrate). It should be noted that sometimes, this process results in values that may differ from the original. For example, `uibuilder.setStore('mydate',new Date()); console.log( uibuilder.getStore('mydate') )` will return the saved date as an ISO8602 date string, not a JavaScript Date object. -### `setStore(id, val)` - Attempt to save to the browsers localStorage +### `removeStore(id)` - Attempt to remove a UIBUILDER key from browser localStorage -Write a value to the given id to localStorage. Will fail if localStorage has been turned off or is full. - -The value to save has to be serialisable. Some JavaScript objects cannot be serialised (using `JSON.stringify`). If this happens `false` is returned and an error output to the browser console. However, you can store any basic value (number, string, boolean) as well as array's and objects. +Does not return anything. Does not generate an error if the key does not exist. -Browsers set a limit on the size of the store for a particular source. Typically this is 10MB but may be altered by the user. The user can turn off localStorage as well. +> [!WARNING] +> `localStorage` is shared per _(sub)domain_, e.g. the IP address/name and port number. All pages from the same origin share the variables. It also only survives until the browser is closed. -Returns `true` if the save was successful, otherwise returns false. +### `set(prop, val, store, autoload)` - Set a UIBUILDER property and dispatch a change event -Errors are output to the browser console if saving fails but processing will continue. +This is the preferred method to set an exposed UIBUILDER variable or property. Do not try to set variables and properties directly. -### `removeStore(id)` - Attempt to remove a uibuilder key from browser localStorage +When using set, the variable that is set becomes responsive. That is to say, that issuing a set triggers both the internal event handler (as used in `uibuilder.onChange('prop', ...)`) but also the DOM custom event `uibuilder:propertyChanged`. Normally, you will want to use the `onChange` handler. -Does not return anything. Does not generate an error if the key does not exist. +Note that you can add additional custom data to the UIBUILDER object but care must be taken not to overwrite existing internal variables. This is useful if you want to be able to automatically process changes to your own variables using the `onChange` handler. -### `setPing(ms)` - Set a repeating ping/keep-alive HTTP call to Node-RED +This function can also be called from Node-RED via `msg._uib.command` - `set` with `msg._uib.prop` set to the variable name to set. and `msg._uib.value` set to the new value. `msg._uib.options` is used as `{store: true, autoload: true}` to optionally pass the additional arguments. -This uses an HTTP API call to a custom uibuilder API endpoint in Node-RED. So it works even if the Socket.IO connection is not working. It is used to check that the Node-RED server and the uibuilder instance are both still working. +> [!WARNING] +> `localStorage` is shared per _(sub)domain_, e.g. the IP address/name and port number. All pages from the same origin share the variables. It also only survives until the browser is closed. ##### Example ```javascript -uibuilder.setPing(2000) // repeat every 2 sec. Re-issue with ping(0) to turn off repeat. - -// Optionally monitor responses -uibuilder.onChange('ping', function(data) { - console.log('pinger', data) -}) +uibuilder.set('logLevel', 3) ``` +### `setStore(id, val, autoload)` - Attempt to save to the browsers localStorage + +Write a value to the given id to localStorage. Will fail if localStorage has been turned off or is full. + +The value to save has to be serialisable. Some JavaScript objects cannot be serialised (using `JSON.stringify`). If this happens `false` is returned and an error output to the browser console. However, you can store any basic value (number, string, boolean) as well as array's and objects. + +Browsers set a limit on the size of the store for a particular source. Typically this is 10MB but may be altered by the user. The user can turn off localStorage as well. + +Returns `true` if the save was successful, otherwise returns false. + +Errors are output to the browser console if saving fails but processing will continue. + +> [!WARNING] +> `localStorage` is shared per _(sub)domain_, e.g. the IP address/name and port number. All pages from the same origin share the variables. It also only survives until the browser is closed. + ## UI Handling These are the new dynamic, configuration-driven UI features. They let you create your UI dynamically from simple data sent to the client. @@ -166,21 +210,84 @@ In addition, internal message handling will recognise standard messages from nod For functions with no descriptions, please refer to the code. In general, these will not need to be used in your own code. -### `ui(json)` - Directly manage UI via JSON +### `convertMarkdown(mdText)` - Convert's Markdown text input to HTML -Takes either an object containing `{_ui: {}}` or simply simple `{}` containing ui instructions. See [Config Driven UI](client-docs/config-driven-ui.md) for details of the required data. +Returns an HTML string converted from the Markdown input text. Only if the Markdown-IT library is loaded, otherwise just returns the input text. -Directly calls `_ui.ui` from the `ui.js` library. +### `elementExists(cssSelector, msg = true)` - Does the element exist on the page? + +Returns a payload of true or false depending on whether the selected element exists on the page. + +Available as a command. Can be called from Node-RED with a message like: `{"command":"elementExists","prop":"#more"}`. + +### `elementIsVisible(cssSelector, stop = false, threshold = 0.1)` - Can an HTML element currently be seen by the user? + +When the selected element is showing at least 10% in the users browser view, sends a message to Node-RED with `msg.isVisible` set to `true`. Will send another message if the elements shows less than 10%. Will continue to send messages when the element moves in and out of visibility. + +To turn it off, call it again with the same cssSelector but with the `stop` argument set to `true`. + +The `threshold` argument defaults to 0.1 (10%). It must be between 0 and 1 and represents, as a percentage, how much of the element must be in the browser viewport to trigger an output. + +Notes: + +* Unlike the visibility control message, this function sends a standard message AND is not effected by the browser tab visibility. So even if the tab containing the page is not visible but the element would be if the tab were showing, the result of this function is still TRUE. +* Requires the browser to support the IntersectionObserver API (available to all mainstream browsers from early 2019). +* The element has to exist on the page before it can be observed. +* Turn on the optional `msg._uib` feature in the UIBUILDER node to see which client is sending the messages. +* Due to the nature of the IntersectionObserver API, this fn is not available as a command for now. ### `htmlSend()` - Sends the whole DOM/HTML back to Node-RED See under [Message Handling](#message-handling) above for details. -### `loadui(url)` - Load a dynamic UI from a JSON web reponse +### `include(url, uiOptions)` - insert an external file into the web page -Requires a valid URL that returns correct _ui data. For example, a JSON file delivered via static web server or a dynamic API that returns JSON as the body response. +Requires a browser supporting the [`fetch` API](https://caniuse.com/fetch). This function is asynchronous, that should be allowed for when using in custom front-end code. -Directly calls `_ui.loadui` from the `ui.js` library. +> [!NOTE] +> This function uses the standard [`replaceSlot`](#replaceslotel-component-replace-or-add-an-html-element39s-slot-from-text-or-an-html-string) internal function. As such, it will use [DOMPurify](client-docs/readme#_1-dompurify-sanitises-html-to-ensure-safety-and-security) if loaded. DOMPurify will block the loading of most file types. + +The `uiOptions` parameter is **required** and must contain at least an `id` property. Options are: + +```json +{ + // REQUIRED: Must be unique on the web page and is applied to the wrapping `div` tag. + "id": "unique99", + // A CSS Selector that identifies the parent element to which the included + // file will be attached. If not provided, 'body' will be used + "parent": "#more", + // Optional. If the parent has multiple children, identifies where the new element + // will be inserted. Defaults to "last". May be "first", "last" or a number. + "position": "last", + // Optional. Attributes that will be applied to the wrapping DIV tag + "attributes": { + // NB: The "included" class is applied by default, if adding further + // classes it is generally best to include that. + "class": "myclass included" + } + // Other properties from the UI `replace` mode may also be included but + // caution is required not to clash with properties from the included file. +} +``` + +Each of the includes are wrapped in a `div` tag to which the supplied `id` attribute is applied along with a class of `included`. This makes styling of the included elements very easy. For example, to style an included image, add something like this to your `index.css` file: `.included img { width: 100%, border:5px solid silver;}`. + +The following file types are handled: + +* *HTML document/fragment* (*.html) - Will be wrapped in a div given the specified `id` attribute. + + If the `DOMPurify` library is loaded before the UIBUILDER client library, it will be used to sanitise the HTML. + +* *Image* - Any image file type recognised by the browser will be shown using an `img` tag (wrapped in the div as usual). +* *Video* - Any video file type recognised by the browser will be shown using a `video` tag (wrapped in the div as usual). The video controls will be shown and it will auto-play if the browser allows it. +* *JSON* - A `*.json` file will be syntax highlighted and shown in a panel. The syntax highlight CSS is contained in the `uib-brand.css` file and can be copied to your own CSS definitions if needed. The panel is defined as a `pre` tag with the `syntax-highlight` class added. +* *PDF* - A `*.pdf` file will be shown in a resizable iFrame. +* *Text* - The contents of the text file will be shown in a resizable iFrame. +* *Other* - Any other file type will be shown in a resizable iFrame. + +Any file type that the browser cannot handle will trigger the browser to automatically download it. This is a browser limitation. + +Can be called from Node-RED with a message like: `{"command":"include","prop":"./test.html","value":{"id":"incHtm","parent":"#more","attributes":{"style":"width:50%;"}}}`. ### `loadScriptSrc(url)`, `loadStyleSrc(url)`, `loadScriptTxt(string)`, `loadStyleTxt(string)` - Attach a new script or CSS stylesheet to the end of HEAD synchronously @@ -188,6 +295,12 @@ Either from a remote URL or from a text string. Directly call the functions of the same name from the `ui.js` library. +### `loadui(url)` - Load a dynamic UI from a JSON web response + +Requires a valid URL that returns correct _ui data. For example, a JSON file delivered via static web server or a dynamic API that returns JSON as the body response. + +Directly calls `_ui.loadui` from the `ui.js` library. + ### `notify(config)` - Use the browser and OS notification API to show a message to the user Requires a browser that supports the [Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notification/Notification). @@ -259,6 +372,10 @@ Will use [DOMPurify](client-docs/readme#_1-dompurify-sanitises-html-to-ensure-sa Directly calls `_ui.replaceSlotMarkdown` from the `ui.js` library. +### `sanitiseHTML(htmlText)` - Ensures that input HTML text is safe + +Returns a safe, sanitised HTML string IF the DOMPurify library is loaded. Otherwise returns the input. + ### `showDialog(type, ui, msg)` - Show a toast or alert style message on the UI Directly calls `_ui.showDialog` from the `ui.js` library. @@ -295,19 +412,19 @@ Simply add `uibuilder.showMsg(true)` early in your index.js custom code and a bo `uibuilder.showMsg(false)` or `uibuilder.showMsg()` will remove the box and stop the updates. -You can also position the box in a different location by specifying a "parent". This is a CSS selector that, if found on the page, uibuilder will add the box to the end of. For example, `uibuilder.showMsg(true, 'h1')` would attach the box to the end of a heading level 1 element on the page. Don't forget that the box will inherit at least some of the CSS style from the parent, so attaching to an H1 element will make the text much bigger. +You can also position the box in a different location by specifying a "parent". This is a CSS selector that, if found on the page, UIBUILDER will add the box to the end of. For example, `uibuilder.showMsg(true, 'h1')` would attach the box to the end of a heading level 1 element on the page. Don't forget that the box will inherit at least some of the CSS style from the parent, so attaching to an H1 element will make the text much bigger. This function can also be called from Node-RED via `msg._uib.command` - `showMsg` with `msg._uib.value` set to `true`. Leave the value property off to toggle the display. Adds/removes `
` to/from the page. -### `showStatus(boolean, parent=body)` - Show/hide a card shows the current status of the uibuilder client library +### `showStatus(boolean, parent=body)` - Show/hide a card shows the current status of the UIBUILDER client library -Simply add `uibuilder.showStatus(true)` early in your index.js custom code and a box will be added to the end of your page that will show all of the important settings in the uibuilder client. Use `uibuilder.showStatus()` to toggle the display. +Simply add `uibuilder.showStatus(true)` early in your index.js custom code and a box will be added to the end of your page that will show all of the important settings in the UIBUILDER client. Use `uibuilder.showStatus()` to toggle the display. `uibuilder.showStatus(false)` or `uibuilder.showStatus()` will remove the box and stop the updates. -You can also position the box in a different location by specifying a "parent". This is a CSS selector that, if found on the page, uibuilder will add the box to the end of. For example, `uibuilder.showStatus(true, 'h1')` would attach the box to the end of a heading level 1 element on the page. Don't forget that the box will inherit at least some of the CSS style from the parent, so attaching to an H1 element will make the text much bigger. +You can also position the box in a different location by specifying a "parent". This is a CSS selector that, if found on the page, UIBUILDER will add the box to the end of. For example, `uibuilder.showStatus(true, 'h1')` would attach the box to the end of a heading level 1 element on the page. Don't forget that the box will inherit at least some of the CSS style from the parent, so attaching to an H1 element will make the text much bigger. This function can also be called from Node-RED via `msg._uib.command` - `showStatus` optionally with `msg._uib.value` set to `true`. Leave the value property off to toggle the display. @@ -326,6 +443,12 @@ const eMsg = $('#msg') // or document.getElementById('msg') if you prefer if (eMsg) eMsg.innerHTML = uibuilder.syntaxHighlight(msg) ``` +### `ui(json)` - Directly manage UI via JSON + +Takes either an object containing `{_ui: {}}` or simply simple `{}` containing ui instructions. See [Config Driven UI](client-docs/config-driven-ui.md) for details of the required data. + +Directly calls `_ui.ui` from the `ui.js` library. + ### `uiGet(cssSelector, propName=null)` - Get most useful information, or specific property from a DOM element Will return an array of found elements with properties. @@ -354,56 +477,17 @@ If `startStop` is undefined, null or 'toggle', the watch will be toggled. Can be called from Node-RED with a message like: `{"_uib: {"command": "uiWatch", "prop": "#more"} }`. -### `include(url, uiOptions)` - insert an external file into the web page - -Requires a browser supporting the [`fetch` API](https://caniuse.com/fetch). This function is asynchronous, that should be allowed for when using in custom front-end code. - -> [!NOTE] -> This function uses the standard [`replaceSlot`](#replaceslotel-component-replace-or-add-an-html-element39s-slot-from-text-or-an-html-string) internal function. As such, it will use [DOMPurify](client-docs/readme#_1-dompurify-sanitises-html-to-ensure-safety-and-security) if loaded. DOMPurify will block the loading of most file types. - -The `uiOptions` parameter is **required** and must contain at least an `id` property. Options are: - -```json -{ - // REQUIRED: Must be unique on the web page and is applied to the wrapping `div` tag. - "id": "unique99", - // A CSS Selector that identifies the parent element to which the included - // file will be attached. If not provided, 'body' will be used - "parent": "#more", - // Optional. If the parent has multiple children, identifies where the new element - // will be inserted. Defaults to "last". May be "first", "last" or a number. - "position": "last", - // Optional. Attributes that will be applied to the wrapping DIV tag - "attributes": { - // NB: The "included" class is applied by default, if adding further - // classes it is generally best to include that. - "class": "myclass included" - } - // Other properties from the UI `replace` mode may also be included but - // caution is required not to clash with properties from the included file. -} -``` - -Each of the includes are wrapped in a `div` tag to which the supplied `id` attribute is applied along with a class of `included`. This makes styling of the included elements very easy. For example, to style an included image, add something like this to your `index.css` file: `.included img { width: 100%, border:5px solid silver;}`. -The following file types are handled: - -* *HTML document/fragment* (*.html) - Will be wrapped in a div given the specified `id` attribute. - - If the `DOMPurify` library is loaded before the uibuilder client library, it will be used to sanitise the HTML. - -* *Image* - Any image file type recognised by the browser will be shown using an `img` tag (wrapped in the div as usual). -* *Video* - Any video file type recognised by the browser will be shown using a `video` tag (wrapped in the div as usual). The video controls will be shown and it will auto-play if the browser allows it. -* *JSON* - A `*.json` file will be syntax highlighted and shown in a panel. The syntax highlight CSS is contained in the `uib-brand.css` file and can be copied to your own CSS definitions if needed. The panel is defined as a `pre` tag with the `syntax-highlight` class added. -* *PDF* - A `*.pdf` file will be shown in a resizable iFrame. -* *Text* - The contents of the text file will be shown in a resizable iFrame. -* *Other* - Any other file type will be shown in a resizable iFrame. +## HTML/DOM Cacheing -Any file type that the browser cannot handle will trigger the browser to automatically download it. This is a browser limitation. +### `clearHtmlCache()` - Clears the HTML previously saved to the browser localStorage +### `restoreHtmlFromCache()` - Swaps the currently displayed HTML to the version last saved in the browser localStorage -Can be called from Node-RED with a message like: `{"command":"include","prop":"./test.html","value":{"id":"incHtm","parent":"#more","attributes":{"style":"width:50%;"}}}`. +### `saveHtmlCache()` - Manually saves the currently displayed HTML to the browser localStorage -## HTML/DOM Cacheing +> [!NOTE] +> Browser local cache is generally limited to 10MB for the whole source domain. +> Therefore, it is quite easy to exceed this - use with caution. ### `watchDom(startStop)` - Start/stop watching for DOM changes. Changes automatically saved to browser localStorage @@ -412,18 +496,10 @@ Can be called from Node-RED with a message like: `{"command":"include","prop":". You can ensure that the page display looks exactly like the last update upon page load simply by adding `uibuilder.restoreHtmlFromCache()` at the start of your index.js custom code. > [!note] -> Browser `localStorage` capacity is set by the browser, not uibuilder. Very large pages might concevably fill the storage as might other things saved to it. +> Browser `localStorage` capacity is set by the browser, not UIBUILDER. Very large pages might concevably fill the storage as might other things saved to it. > > You should be able to change the capacity in the browser settings but of course, this would have to be done on every client device. -### `clearHtmlCache()` - Clears the HTML previously saved to the browser localStorage -### `restoreHtmlFromCache()` - Swaps the currently displayed HTML to the version last saved in the browser localStorage - -### `saveHtmlCache()` - Manually saves the currently displayed HTML to the browser localStorage - -> [!NOTE] -> Browser local cache is generally limited to 10MB for the whole source domain. -> Therefore, it is quite easy to exceed this - use with caution. ## Event Handling @@ -432,7 +508,7 @@ You can ensure that the page display looks exactly like the last update upon pag > to control whether a specific page, client or browser tab will process an inbound message. > Use this where you have multiple pages or clients and need to target a message to a specific one. -### `onChange(prop, callbackFn)` - Register on-change event listeners for uibuilder tracked properties +### `onChange(prop, callbackFn)` - Register on-change event listeners for UIBUILDER tracked properties Returns a reference to the callback so that it can be cancelled if needed. @@ -475,7 +551,7 @@ uibuilder.cancelTopic('my topic', topicChgEvt) ### Custom Events -The uibuilder library also issues a number of custom events. These can be handled using the standard `document.addEventListener` JavaScript function. +The UIBUILDER library also issues a number of custom events. These can be handled using the standard `document.addEventListener` JavaScript function. * `uibuilder:stdMsgReceived` - triggered whenever a normal msg is received from Node-RED. Passes the msg in the data parameter. Happens before any processing of `msg._uib`, `msg._ui` or page/client/tab filtering. * `uibuilder:msg:topic:${msg.topic}` - triggered immediately after the above event if the `msg.topic` property is set. Passes the msg in the data parameter. @@ -501,14 +577,14 @@ This is a convenience method to help you select HTML DOM elements in your own cu As per the native function, it returns a single [HTML element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). If the CSS Selector provided is not unique (e.g. >1 element would be returned), only the first element found in the DOM is returned. Use `document.querySelectorAll(cssSelector)` if you want to get back an array of selected elements. -If the uibuilder client finds an existing definition of `$` on startup, it will not make this global. However, it would still be usable as `uibuilder.$(...)`. This avoids clashes with libraries such as jQuery. +If the UIBUILDER client finds an existing definition of `$` on startup, it will not make this global. However, it would still be usable as `uibuilder.$(...)`. This avoids clashes with libraries such as jQuery. If the selector finds a `