Primer commit de los tres flujos: Raspipeso, Servidor y Gestor de semaforos
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,77 @@
|
||||
# uibuilder Template: Blank (Default)
|
||||
|
||||
> NOTE: You can replace the contents of this README with text that describes your UI.
|
||||
|
||||
This is about the simplest template you can get for uibuilder. Is is also (as of uibuilder v5+), the default template.
|
||||
|
||||
It does not use any frameworks and has no other dependencies. It demonstrates that you can use uibuilder purely with HTML/JavaScript or even just HTML and still easily build a simple, dynamic, data-driven user interface with the help of Node-RED.
|
||||
|
||||
All it does is load the uibuilder client library and connect to Node-RED.
|
||||
|
||||
## UI
|
||||
|
||||
Initially only shows an H1 heading with a sub-heading. However, it contains a `<div>` with the id "`more`" which is used by many of the examples in the Node-RED import library.
|
||||
|
||||
In addition, the `more` div uses uibuilder's `uib-topic` special attribute which allows it to be used as a target for messages sent from Node-RED. This is a useful feature that allows you to easily update the content of the page without having to write any JavaScript code. Send a message containing `{ topic: 'more', payload: 'Hello World' }` to the `uibuilder` node and the content of the `more` div will be updated with "Hello World". Note that the payload can contain HTML. As an example, use an inject node with `msg.payload` set to use a JSONata expression like `"<b style='background-color:var(--error)'>Hello!</b> This is a message from Node-RED at " & $moment()`. Don't forget to set `msg.topic` to `more` so that the uibuilder client library knows where to send the message.
|
||||
|
||||
> **WARNING**: Using the "more" topic completely overwrites the contents of the `more` div.
|
||||
|
||||
## Folders
|
||||
|
||||
* `/` - The root folder contains this file. It can be used for other things **but** it will not be served up in the Node-RED web server.
|
||||
* `/src/` - the default folder that serves files as web resources. However, this can be changed to a different folder if desired.
|
||||
* `/dist/` - the default folder for serving files as web resources where a build step is used. In that case, the `/src` folder is the source used by the build tool and `/dist` is the destination for the build (the "distribution" folder).
|
||||
* `/routes/` - This folder can contain `.js` files defining routing middleware for uibuilder's ExpressJS web server.
|
||||
* `/api/` - This folder can contain `.js` files defining REST API's specific to this uibuilder instance.
|
||||
* `/types/` - Contains typescript definition files (`*.d.ts`) for the uibuilder client library. This is not used by uibuilder but can be used by your IDE to provide type checking and auto-completion for the uibuilder client library. This is useful if you are using TypeScript or JavaScript with type checking enabled. Remember to update these for new uibuilder versions.
|
||||
|
||||
The above folders will all pre-exist for the built-in uibuilder templates. The folders can safely be removed if not needed but one folder must exist to serve the web resources from (this cannot be the root folder).
|
||||
|
||||
The template only has files in the root and `src` folders. The `src` folder is the default used by uibuilder to serve up files to clients.
|
||||
|
||||
One reserved item in the root folder however will be a `package.json` file. This will be used in the future to help with build/compile steps. You can still use it yourself, just bear in mind that a future version of uibuilder will make use it as well. If you need to have any development packages installed to build your UI, don't forget to tell `npm` to save them as development dependencies not normal dependencies.
|
||||
|
||||
The `dist` folder should be used if you have a build step to convert your source code to something that browsers understand. So if you are using a build (compile) step to produce your production code, ensure that it is configured to use the `dist` folder as the output folder and that it creates at least an `index.html` file.
|
||||
|
||||
You can switch between the `src` and `dist` (or other) folders using the matching setting in the Editor. See uibuilder's advanced settings tab.
|
||||
|
||||
Also note that you can use **linked** folders and files in this folder structure. This can be handy if you want to maintain your code in a different folder somewhere or if your default build process needs to use sub-folders other than `src` and `dist`.(Though as of v6, you can specify any sub-folder to be served)
|
||||
|
||||
## Files in this template
|
||||
|
||||
* `package.json`: REQUIRED. Defines the basic structure, name, description of the project and defines any local development dependencies if any. Also works with `npm` allowing the installation of dev packages (such as build or linting tools).
|
||||
* `README.md`: This file. Change this to describe your web app and provide documentation for it.
|
||||
* `eslint.config.js`: A pre-configured configuration for the ESLINT tool. Helps when writing front-end code. Note that you need at least eslint v8+ installed for this to work.
|
||||
* `LICENSE`: A copy of the Apache 2.0 license. Replace with a different license if needed. Always license your code. Apache 2.0 matches the licensing of uibuilder.
|
||||
* `src/index.html`: REQUIRED. Contains your basic HTML and will be the file loaded and displayed in the browser when going to the uibuilder defined URL.
|
||||
* `src/index.js`: Contains all of the logic for your UI. It must be linked to in the html file. Optional.
|
||||
* `src/index.css`: Contains your custom CSS for styling. It must be linked to in the html file. Optional.
|
||||
* `tsconfig.json`: A configuration file for TypeScript. This can be used by your IDE to provide descriptions, type checking and auto-completion for the uibuilder client library. This is useful if you are using TypeScript or JavaScript with type checking enabled. Uses the typescript definition files in the `/types` folder, remember to update these for new uibuilder versions.
|
||||
|
||||
Note that only the `package.json` and `index.html` files are actually _required_. uibuilder will not function as expected without them.
|
||||
|
||||
It is possible to use the index.html file simply as a link to other files but it must be present.
|
||||
|
||||
The other files are all optional. However, you will need to change the index.html file accordingly if you rename or remove them.
|
||||
|
||||
## Multiple HTML pages
|
||||
|
||||
uibuilder will happily serve up any number of web pages from a single instance. It will also make use of sub-folders. However, each folder should have an `index.html` file so that a URL that ends with the folder name will still work without error.
|
||||
|
||||
Note that each html file is a separate page and requires its own JavaScript and uibuilder library reference. When moving between pages, remember that every page is stand-alone, a new environment. You can share one `index.js` file between multiple pages if you prefer but each page will run a separate instance.
|
||||
|
||||
If multiple pages are connected to the same uibuilder instance, they will all get the same broadcast messages from Node-RED. So if you want to handle different messages on different pages, remember to filter them in your front-end JavaScript in `uibuilder.onChange('msg', ....)` function. Turn on the advanced flag for including a `msg._uib` property in output if you need to differentiate between pages and/or clients in Node-RED.
|
||||
|
||||
## URL endpoints
|
||||
|
||||
When specifying links in your HTML, CSS and JavaScript files, you should use relative URLs. e.g. `./index.mjs` will load that file from the `src` folder or wherever else you have told uibuilder to use.
|
||||
|
||||
When using uibuilder's server-side resources, you will generally use `../uibuilder/....`, for example `../uibuilder/uib-brand.min.css` as seen in the default `index.css` file. When accessing a front-end library being served by uibuilder, you can use the form `../uibuilder/vendor/....`. Use the "Full details" button in the uibuilder node to see all of the possible endpoints you may want to use.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
This template may be used however you like. It is provided as a test template for uibuilder and is not intended to be a full template. You are free to use it as a starting point for your own template or to use it as-is if you find it useful.
|
||||
|
||||
Binary file not shown.
Vendored
@@ -0,0 +1,121 @@
|
||||
import { defineConfig } from 'eslint/config'
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import jsdoc from 'eslint-plugin-jsdoc'
|
||||
import stylistic from '@stylistic/eslint-plugin'
|
||||
import html from 'eslint-plugin-html'
|
||||
|
||||
// Shared rules
|
||||
const jsdocRules = {
|
||||
'jsdoc/check-alignment': 'off',
|
||||
// "jsdoc/check-indentation": ["warn", {"excludeTags":['example', 'description']}],
|
||||
'jsdoc/check-indentation': 'off',
|
||||
'jsdoc/check-param-names': 'warn',
|
||||
'jsdoc/check-tag-names': ['warn', {
|
||||
definedTags: ['typicalname', 'element', 'memberOf', 'slot', 'csspart'],
|
||||
}],
|
||||
'jsdoc/multiline-blocks': ['error', {
|
||||
noZeroLineText: false,
|
||||
}],
|
||||
'jsdoc/no-multi-asterisk': 'off',
|
||||
'jsdoc/no-undefined-types': ['error', {
|
||||
definedTypes: ['JQuery', 'NodeListOf', 'ProxyHandler'],
|
||||
}],
|
||||
'jsdoc/tag-lines': 'off',
|
||||
}
|
||||
const stylisticRules = {
|
||||
'@stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true, }],
|
||||
'@stylistic/comma-dangle': ['error', {
|
||||
arrays: 'only-multiline',
|
||||
objects: 'always',
|
||||
imports: 'never',
|
||||
exports: 'always-multiline',
|
||||
functions: 'never',
|
||||
importAttributes: 'never',
|
||||
dynamicImports: 'never',
|
||||
}],
|
||||
'@stylistic/eol-last': ['error', 'always'],
|
||||
'@stylistic/indent': ['error', 4, {
|
||||
SwitchCase: 1,
|
||||
}],
|
||||
'@stylistic/indent-binary-ops': ['error', 4],
|
||||
'@stylistic/linebreak-style': ['error', 'unix'],
|
||||
'@stylistic/lines-between-class-members': 'off',
|
||||
'@stylistic/newline-per-chained-call': ['error', {
|
||||
ignoreChainWithDepth: 2,
|
||||
}],
|
||||
'@stylistic/no-confusing-arrow': 'error',
|
||||
'@stylistic/no-extra-semi': 'error',
|
||||
'@stylistic/no-mixed-spaces-and-tabs': 'error',
|
||||
'@stylistic/no-trailing-spaces': 'error',
|
||||
'@stylistic/semi': ['error', 'never'],
|
||||
'@stylistic/space-before-function-paren': 'off',
|
||||
'@stylistic/spaced-comment': ['error', 'always', {
|
||||
line: {
|
||||
exceptions: ['*', '#region', '#endregion'],
|
||||
},
|
||||
block: {
|
||||
exceptions: ['*'],
|
||||
},
|
||||
}],
|
||||
'@stylistic/space-in-parens': 'off',
|
||||
'@stylistic/quotes': ['error', 'single', {
|
||||
avoidEscape: true,
|
||||
allowTemplateLiterals: 'always',
|
||||
}],
|
||||
}
|
||||
const generalRules = {
|
||||
'new-cap': 'error',
|
||||
'no-else-return': 'error',
|
||||
'no-empty': ['error', {
|
||||
allowEmptyCatch: true,
|
||||
}],
|
||||
'no-unused-vars': 'off',
|
||||
'no-useless-escape': 'off',
|
||||
'no-var': 'warn',
|
||||
'prefer-const': 'error',
|
||||
}
|
||||
|
||||
export default defineConfig([
|
||||
// Apply to all JavaScript files
|
||||
{
|
||||
files: ['**/*.js', '**/*.html'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'script', // Use script rather than ES modules
|
||||
globals: {
|
||||
...globals.browser,
|
||||
// ...globals.node,
|
||||
UibRouter: 'readonly',
|
||||
uibuilder: 'readonly',
|
||||
$: 'readonly',
|
||||
$$: 'readonly',
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'js': js,
|
||||
'jsdoc': jsdoc,
|
||||
'@stylistic': stylistic,
|
||||
'html': html,
|
||||
},
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
jsdoc.configs['flat/recommended'],
|
||||
stylistic.configs.recommended,
|
||||
],
|
||||
rules: {
|
||||
...jsdocRules,
|
||||
...stylisticRules,
|
||||
...generalRules,
|
||||
// 'no-empty': ['error', { 'allowEmptyCatch': true }],
|
||||
},
|
||||
},
|
||||
|
||||
// Specific rules for configuration files
|
||||
{
|
||||
files: ['eslint.config.mjs', '**/*.config.js', '**/*.config.mjs'],
|
||||
languageOptions: {
|
||||
sourceType: 'module', // Config files can use ES modules
|
||||
},
|
||||
},
|
||||
])
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "uib-blank",
|
||||
"version": "2025-05-27",
|
||||
"private": true,
|
||||
"description": "This is about the simplest template you can get for uibuilder.",
|
||||
"browser": "./src/index.js",
|
||||
"scripts": {
|
||||
"build": "echo \"No build process specified\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.27.0",
|
||||
"@stylistic/eslint-plugin": "^4.2.0",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-plugin-html": "^8.1.3",
|
||||
"eslint-plugin-jsdoc": "^51.3.1",
|
||||
"globals": "^16.1.0"
|
||||
},
|
||||
"keywords": ["uibuilder", "node-red", "node-red-contrib-uibuilder"],
|
||||
"author": "Julian Knight (Totally Information)",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://github.com/TotallyInformation/node-red-contrib-uibuilder",
|
||||
"bugs": "https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/TotallyInformation/node-red-contrib-uibuilder.git"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 0.5%",
|
||||
"maintained versions",
|
||||
"last 2 versions",
|
||||
"not dead",
|
||||
"not ie > 0"
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,540 @@
|
||||
/* =============================== BASE GLOBAL =============================== */
|
||||
|
||||
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Segoe UI", sans-serif;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 400px;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
#pantalla-tabla-general .container {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 10px 0 20px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* =============================== ENCABEZADO =============================== */
|
||||
|
||||
.header,
|
||||
.encabezado {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.titulo,
|
||||
h3 {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-size: 26px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* =============================== PANTALLAS SPA =============================== */
|
||||
|
||||
.pantalla {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pantalla.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* =============================== BOTONES =============================== */
|
||||
|
||||
.btn {
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn.big {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Colores */
|
||||
.btn.yellow,
|
||||
.btn.amarillo {
|
||||
background: #f1c40f;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.btn.orange,
|
||||
.btn.naranja {
|
||||
background: #e67e22;
|
||||
}
|
||||
|
||||
.btn.green,
|
||||
.btn.verde {
|
||||
background: #28a745;
|
||||
}
|
||||
|
||||
.btn.teal,
|
||||
.btn.verde-oscuro {
|
||||
background: #049a81;
|
||||
}
|
||||
|
||||
.btn.red,
|
||||
.btn.rojo {
|
||||
background: firebrick;
|
||||
}
|
||||
|
||||
.btn.blue,
|
||||
.btn.azul {
|
||||
background: #3498db;
|
||||
}
|
||||
.btn.darkblue,
|
||||
.btn.azuloscuro {
|
||||
background: #0567a9;
|
||||
}
|
||||
.btn.aqua,
|
||||
.btn.celeste {
|
||||
background: #04fbc7;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn.purple,
|
||||
.btn.morado {
|
||||
background: #9b59b6;
|
||||
}
|
||||
|
||||
.btn.gray,
|
||||
.btn.gris {
|
||||
background: #707b7c;
|
||||
}
|
||||
|
||||
.btn.gold,
|
||||
.btn.mostaza {
|
||||
background: #DAB957;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* =============================== BOTONERAS / GRID =============================== */
|
||||
|
||||
.grid-vertical {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.grid-2col {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.botonera-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
max-width: 400px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.botonera-vertical {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
max-width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
/* =============================== COMPONENTES VISUALES =============================== */
|
||||
|
||||
.circle {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 20px auto;
|
||||
border-radius: 50%;
|
||||
background: #239b56;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.imagen {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.imagen img {
|
||||
max-width: 85vw;
|
||||
max-height: 43vh;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.matricula-nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.placa {
|
||||
background: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 10px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
min-width: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.fecha {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.camara-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.desarrollo {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* =============================== TABLA EDITABLE =============================== */
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
table-layout: fixed;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #007acc;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
td {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
td[contenteditable="true"] {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.btn-actualizar,
|
||||
.btn-cancelar {
|
||||
padding: 12px 24px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-actualizar {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-actualizar:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.btn-cancelar {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-cancelar:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
/*----------------------------------------------- MODAL -------------------------------------*/
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fff;
|
||||
margin: 15% auto;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
max-width: 300px;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.modal-buttons {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/*----------------------------------------------- PANTALLA PRINCIPAL DEL TOTEM -------------------------------------*/
|
||||
.peso-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
font-weight: bold;
|
||||
margin: 5px 0 5px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.peso-display {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
font-size: 44px;
|
||||
font-weight: bold;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.peso-label {
|
||||
margin-right: 10px;
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.peso-valor {
|
||||
font-size: 90px;
|
||||
color: #2c3e50;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.peso-unidad {
|
||||
margin-left: 8px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.status-line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 16px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.status-line .label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-line.small {
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
}
|
||||
.led-semaforo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
background-color: #ccc;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
||||
margin-left: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
.semaforo-display {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.led-semaforo.led {
|
||||
box-shadow: 0 0 12px currentColor, 0 0 3px currentColor inset;
|
||||
}
|
||||
|
||||
.etiqueta {
|
||||
min-width: 90px;
|
||||
}
|
||||
.labelMat{
|
||||
font-size: 24px;
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
.labelPE {
|
||||
font-size: 18px;
|
||||
color: blue;
|
||||
font-weight: bold;
|
||||
}
|
||||
.labelValue {
|
||||
font-size: 18px;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
#pantalla-barrera .container {
|
||||
text-align: center;
|
||||
}
|
||||
/*-------------------------------------------------- PANTALLA DE LA BARRERA ---------------------------------------------------------------------*/
|
||||
.barrera-icono {
|
||||
margin: 20px auto;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.barrera-icono img {
|
||||
max-height: 100px;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------- TIPOS DE CONFIGURACION ---------------------------------------------------------------------*/
|
||||
#tipo-configuracion .parametro-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
#tipo-configuracion input {
|
||||
flex: 1;
|
||||
padding: 6px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.parametro-row button {
|
||||
font-size: 20px;
|
||||
line-height: 20px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.botonera-tipo {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
/* Estilo base para la fila */
|
||||
.parametro-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-bottom: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.parametro-row input.parametro {
|
||||
flex: 1 1 50%;
|
||||
min-width: 100px;
|
||||
max-width: 300px;
|
||||
padding: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.parametro-row input.valor {
|
||||
flex: 0 0 30%;
|
||||
min-width: 60px;
|
||||
max-width: 150px;
|
||||
padding: 4px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.parametro-row input[type="checkbox"].valor {
|
||||
flex: 0 0 30px;
|
||||
transform: scale(1.8);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.parametro-row button {
|
||||
flex: 0 0 30px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 14px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.parametro-row input.parametro {
|
||||
flex: 1 1 40%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.parametro-row input.valor {
|
||||
flex: 1 1 30%;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.parametro-row input[type="checkbox"].valor {
|
||||
flex: 0 0 30px;
|
||||
/*zoom: 1.5; */
|
||||
transform: scale(1.5) ;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.parametro-row button {
|
||||
flex: 0 0 25px;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------- IMAGEN INICIAL DEL SNAPSHOT ---------------------------------------------------------------------*/
|
||||
/*
|
||||
#foto {
|
||||
width: 65vw;
|
||||
height: 30vh;
|
||||
background-color: #eee;
|
||||
border-radius: 10px;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
margin: auto;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
*/
|
||||
@import url("../uibuilder/uib-brand.min.css");
|
||||
@@ -0,0 +1,317 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Interfaz Totem</title>
|
||||
|
||||
<script src="../uibuilder/vendor/socket.io/socket.io.js"></script>
|
||||
<script src="../uibuilder/uibuilder.iife.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./index.css">
|
||||
<script src="./index.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- ********************************************* PANTALLA INICIAL DEL TOTEM ******************************************************* -->
|
||||
<div id="pantalla-principal" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" alt="Logo" class="logo" />
|
||||
<h1 class="titulo">Sistema de Pesaje</h1>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="peso-display">
|
||||
<span id="peso" class="peso-valor">0</span>
|
||||
<span class="peso-unidad">Kg</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="semaforo-display">
|
||||
<span id="semaforo-color" class="led-semaforo led"></span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="status-line"><span class="label">Matrícula:</span> <span class="labelMat" id="matricula">----</span></div>
|
||||
<div class="status-line"><span class="label">Peso Estable:</span> <span class="labelPE" id="peso-estable">----</span></div>
|
||||
<div class="status-line"><span class="label">Vial:</span> <span class="labelValue" id="vial">--</span></div>
|
||||
<div class="status-line"><span class="label">ID:</span> <span class="labelValue" id="totem-id">--</span></div>
|
||||
<div class="status-line small"><span class="label">IP LAN:</span> <span class="labelValue" id="iplan">----</span></div>
|
||||
<div class="status-line small"><span class="label">IP Supervisor:</span> <span class="labelValue" id="ipsupervisor">----</span></div>
|
||||
|
||||
<div class="botonera-grid">
|
||||
<button class="btn verde big" data-action="menu-principal">CONFIG</button>
|
||||
<button class="btn celeste big" data-action="menu-sistema">SISTEMA</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ************************************** MENU PRINCIPAL DE CONFIGURACION ******************************************* -->
|
||||
<div id="pantalla-menu-principal" class="pantalla visible">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>Trypton Software</h2>
|
||||
</div>
|
||||
<h3 class="titulo">CONFIGURACIÓN GESTOR SEMAFOROS</h3>
|
||||
<hr>
|
||||
<div class="grid-vertical">
|
||||
<button class="btn blue" data-action="editar">EDITAR CONFIGURACION</button>
|
||||
<button class="btn green" data-action="aplicar">APLICAR CONFIGURACION</button>
|
||||
<!--
|
||||
<button class="btn orange" data-action="pruebas">PRUEBAS DEL SISTEMA</button>
|
||||
<button class="btn purple" data-action="otras">OTRAS ACCIONES</button>
|
||||
-->
|
||||
<button class="btn teal" data-action="salir">SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ******************************************* MENU EDITAR CONFIGURACION ****************************************** -->
|
||||
<div id="pantalla-editar" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" alt="Logo" class="logo" />
|
||||
<h2>Trypton Software</h2>
|
||||
</div>
|
||||
|
||||
<h3 class="titulo">EDITAR CONFIGURACION</h3>
|
||||
<hr />
|
||||
|
||||
<div class="botonera-grid">
|
||||
<button data-action="general" class="btn amarillo">GENERAL</button>
|
||||
|
||||
<button data-action="conexion" class="btn celeste">CONEXIONES</button>
|
||||
<!--
|
||||
<button data-action="sensores" class="btn morado">SENSORES</button>
|
||||
<button data-action="mensajes" class="btn gris">MENSAJES</button>
|
||||
-->
|
||||
<button data-action="tiempos" class="btn azul">TIEMPOS</button>
|
||||
</div>
|
||||
|
||||
<div class="botonera-vertical">
|
||||
|
||||
<button data-action="salvar" class="btn verde">SALVAR MODIFICACIONES</button>
|
||||
<button data-action="ayuda" class="btn mostaza">AYUDA</button>
|
||||
<button data-action="cancelar" class="btn verde-oscuro">CANCELAR Y SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ****************************************MENU PRUEBAS DEL SISTEMA ****************************************** -->
|
||||
<div id="pantalla-pruebas" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>Trypton Software</h2>
|
||||
</div>
|
||||
<h3 class="titulo">PRUEBAS DEL TOTEM</h3>
|
||||
<hr>
|
||||
<div class="grid-vertical">
|
||||
<button class="btn yellow" data-action="semaforo">ENCENDER SEMAFORO</button>
|
||||
<button class="btn aqua" data-action="barrera">ACTIVAR BARRERA</button>
|
||||
<button class="btn orange" data-action="snapshot">PEDIR SNAPSHOT</button>
|
||||
<button class="btn green" data-action="escuchar">ESCUCHAR CAMARA</button>
|
||||
<button class="btn teal" data-action="regresar">SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- -------------------------------------- MENU OTRAS ACCIONES --------------------------------------------------- -->
|
||||
<div id="pantalla-otras" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>Trypton Software</h2>
|
||||
</div>
|
||||
<h3 class="titulo">OTRAS ACCIONES</h3>
|
||||
<hr>
|
||||
<div class="desarrollo">
|
||||
<h3 style="color:#2e86c1;">EN DESARROLLO</h3>
|
||||
</div>
|
||||
<div class="grid-vertical">
|
||||
<button class="btn blue" data-action="enviar">ENVIAR SNAPSHOT</button>
|
||||
<button class="btn aqua" data-action="reboot">REBOOT RPi</button>
|
||||
<button class="btn red" data-action="apagar">APAGAR RPi</button>
|
||||
<button class="btn teal" data-action="regresar">SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- -------------------------------------- PRUEBA DEL SEMAFORO --------------------------------------------------- -->
|
||||
<div id="pantalla-semaforo" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>Trypton Software</h2>
|
||||
</div>
|
||||
<h3 class="titulo">PRUEBA DEL SEMAFORO</h3>
|
||||
<hr>
|
||||
<div class="circle" id="estado"></div>
|
||||
<div class="grid-2col">
|
||||
<button class="btn red" data-action="semaforo_on">ON</button>
|
||||
<button class="btn green" data-action="semaforo_off">OFF</button>
|
||||
</div>
|
||||
<button class="btn teal big" data-action="salir-semaforo">SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- -------------------------------------- PANTALLA DE SNAPSHOT DE LA CAMARA -------------------------------------------------- -->
|
||||
<div id="pantalla-snapshot" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>Snapshot Recibido</h2>
|
||||
</div>
|
||||
<div class="camara-row">
|
||||
<span>Camara: <strong id="camara">---</strong></span>
|
||||
</div>
|
||||
<div class="imagen"><img id="foto" src="" alt="Foto"></div>
|
||||
<div class="matricula-nav">
|
||||
|
||||
<div class="placa" id="placa">----</div>
|
||||
|
||||
</div>
|
||||
<div class="fecha" id="fecha">----</div>
|
||||
<button class="btn teal big" data-action="salir-snapshot">SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- -------------------------------------- PANTALLA DE ACTIVACION DE LA BARRERA -------------------------------------------------- -->
|
||||
<div id="pantalla-barrera" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>ACTIVACION DE BARRERA</h2>
|
||||
</div>
|
||||
<!-- ICONO BARRERA -->
|
||||
<div class="barrera-icono" id="barrera-icono">
|
||||
<img id="icono-barrera" src="/barrera_cerrada.png" alt="Barrera" />
|
||||
</div>
|
||||
|
||||
<!-- BOTONES -->
|
||||
<div class="botonera-vertical">
|
||||
<button class="btn verde big" data-action="activar-barrera">ACTIVAR BARRERA</button>
|
||||
<button class="btn teal big" data-action="salir-barrera">SALIR</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- -------------------------------------- PANTALLA PARA ESCUCHAR LA CAMARA -------------------------------------------------- -->
|
||||
<div id="pantalla-escuchar" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>Snapshot Recibido</h2>
|
||||
</div>
|
||||
<div class="camara-row">
|
||||
<span>Camara: <strong id="camara_escuchar">---</strong></span>
|
||||
<span id="contador">0 / 0</span>
|
||||
</div>
|
||||
<div class="imagen"><img id="foto_escuchar" src="" alt="Foto"></div>
|
||||
<div class="matricula-nav">
|
||||
<button class="btn green" data-action="left"><</button>
|
||||
<div class="placa" id="placa_escuchar">----</div>
|
||||
<button class="btn blue" data-action="right">></button>
|
||||
</div>
|
||||
<div class="fecha" id="fecha_escuchar">----</div>
|
||||
<button class="btn teal big" data-action="salir-escuchar">SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ------------------------------- PANTALLA DE TABLA DINAMICA PARA MOSTRAR PARAMETROS DE CONFIGURACION------------------------------------------------->
|
||||
<div id="pantalla-tabla-general" class="pantalla">
|
||||
<div class="container">
|
||||
<h2 style="text-align:center;">Parámetros del Sistema</h2>
|
||||
|
||||
<div class="button-container">
|
||||
<table id="table2">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center;">Parámetro</th>
|
||||
<th style="text-align:center;">Valor</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="config-table-body">
|
||||
<!-- Se rellena dinámicamente -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<button class="custom-btn btn-actualizar" onclick="sendRow()">ACTUALIZAR</button>
|
||||
<button class="custom-btn btn-cancelar" onclick="sendCancel()">CANCELAR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ------------------------------------- PANTALLA TIPOS DE CONFIGURACION ---------------------------------------------------- -->
|
||||
<div id="pantalla-tipos" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>Tipos de Configuración</h2>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="botonera-grid">
|
||||
<button class="btn blue" onclick="seleccionarTipo(1)">TIPO 1</button>
|
||||
<button class="btn orange" onclick="seleccionarTipo(2)">TIPO 2</button>
|
||||
<button class="btn yellow" onclick="seleccionarTipo(3)">TIPO 3</button>
|
||||
<button class="btn celeste" onclick="seleccionarTipo(4)">TIPO 4</button>
|
||||
<button class="btn purple" onclick="seleccionarTipo(5)">TIPO 5</button>
|
||||
<button class="btn gris" onclick="seleccionarTipo(6)">TIPO 6</button>
|
||||
|
||||
</div>
|
||||
<div class="botonera-vertical">
|
||||
<button class="btn green" id="btn-volver-tipos">REGRESAR</button>
|
||||
</div>
|
||||
<div id="tipo-configuracion" style="margin-top:20px; display:none;">
|
||||
<h3 id="titulo-tipo"></h3>
|
||||
<div id="parametros"></div>
|
||||
|
||||
<div class="botonera-tipo">
|
||||
<button id="btn-add-param" class="btn azul">+</button>
|
||||
<button class="btn verde" id="btn-guardar-tipo">Guardar</button>
|
||||
<button class="btn rojo" id="btn-cancelar-tipo">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ------------------------------------- PANTALLA DE AYUDA ---------------------------------------------------- -->
|
||||
<div id="pantalla-ayuda" class="pantalla">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo-trypton2.png" class="logo" alt="Logo">
|
||||
<h2>AYUDA</h2>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<iframe src="./ayuda.pdf" style="width:100%; height:600px; border:none;"></iframe>
|
||||
<div style="margin-top: 20px; text-align: center;">
|
||||
<button class="btn rojo" data-action="salir-ayuda">SALIR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ------------------------------------- MODAL PARA POPUP ---------------------------------------------------- -->
|
||||
<div id="confirm-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<p id="modal-text">¿Deseas guardar los cambios?</p>
|
||||
<div class="modal-buttons">
|
||||
<button id="btn-modal-si" class="btn verde" onclick="confirmGuardar()">Sí</button>
|
||||
<button id="btn-modal-no" class="btn rojo" onclick="cancelarGuardar()">No</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,494 @@
|
||||
/* global uibuilder */
|
||||
uibuilder.start();
|
||||
|
||||
// Navegación entre pantallas
|
||||
function mostrarPantalla(id) {
|
||||
document.querySelectorAll('.pantalla').forEach(div =>
|
||||
div.classList.toggle('visible', div.id === id)
|
||||
);
|
||||
}
|
||||
let currentTopic = "";
|
||||
let result = [];
|
||||
|
||||
//****************************************************RECEPCION DE MENSAJES DESDE NODE_RED ***************************************************************** */
|
||||
|
||||
uibuilder.onChange('msg', msg => {
|
||||
if (msg.payload && msg.payload.pantalla) {
|
||||
mostrarPantalla('pantalla-' + msg.payload.pantalla);
|
||||
}
|
||||
|
||||
if (msg.semaforo) {
|
||||
document.getElementById('estado').style.backgroundColor = msg.semaforo;
|
||||
}
|
||||
if (msg.payload && msg.payload.pantalla === 'snapshot') {
|
||||
// Limpiar datos visibles
|
||||
document.getElementById('camara').textContent = '---';
|
||||
document.getElementById('placa').textContent = '----';
|
||||
document.getElementById('fecha').textContent = '----';
|
||||
// Mostrar imagen vacía
|
||||
document.getElementById('foto').src = "";
|
||||
|
||||
}
|
||||
|
||||
if (msg.payload && msg.payload.pantalla === 'escuchar' && msg.buttons != true) {
|
||||
// Limpiar datos visibles
|
||||
document.getElementById('camara_escuchar').textContent = '---';
|
||||
document.getElementById('placa_escuchar').textContent = '----';
|
||||
document.getElementById('fecha_escuchar').textContent = '----';
|
||||
document.getElementById('contador').textContent = `0 / 0`;
|
||||
// Mostrar imagen vacía
|
||||
document.getElementById('foto_escuchar').src = "";
|
||||
}
|
||||
|
||||
if (msg.hasOwnProperty("picture")) {
|
||||
//uibuilder.send({ payload: msg.payload.Picture.Plate.PlateNumber, topic: msg.payload.Picture.SnapInfo.DeviceID });
|
||||
if (msg.snapshot_cam) {
|
||||
document.getElementById('foto').src = msg.picture;
|
||||
document.getElementById('placa').textContent = msg.plate || '----';
|
||||
document.getElementById('fecha').textContent = msg.plate_time || '';
|
||||
document.getElementById('camara').textContent = msg.camera_id || '---';
|
||||
}
|
||||
|
||||
else if (msg.escuchar_cam){
|
||||
document.getElementById('foto_escuchar').src = msg.picture;
|
||||
document.getElementById('placa_escuchar').textContent = msg.plate || '----';
|
||||
document.getElementById('fecha_escuchar').textContent = msg.plate_time || '';
|
||||
document.getElementById('camara_escuchar').textContent = msg.camera_id || '---';
|
||||
const total = msg.snapshot_indexmax || 0;
|
||||
const actual = (msg.snapshot_readindex || 0) + 1;
|
||||
document.getElementById('contador').textContent = `${actual} / ${total}`;
|
||||
}
|
||||
}
|
||||
|
||||
else if (msg.payload?.pantalla === 'tipos') {
|
||||
mostrarPantalla('pantalla-tipos');
|
||||
if (msg.payload.tiposDatos) {
|
||||
tiposDatos = msg.payload.tiposDatos;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.barrera) {
|
||||
mostrarBarreraAbierta()
|
||||
}
|
||||
else{
|
||||
mostrarBarreraCerrada()
|
||||
}
|
||||
// tabla dinamica
|
||||
if (msg.topic == "general" || msg.topic == "conexion" || msg.topic == "camara" || msg.topic == "sensores" || msg.topic == "mensajes" || msg.topic == "tiempos"){
|
||||
if (!msg.tabla || !Array.isArray(msg.tabla)) return;
|
||||
|
||||
const tbody = document.getElementById('config-table-body');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
currentTopic = msg.topic || 'general';
|
||||
|
||||
msg.tabla.forEach(item => { //generamos dinamixamente la tabla que vera el usuario en el dispositivo (PC o smartphone).
|
||||
// notese que la celda 2 de cada fila es del tipo editable.
|
||||
const row = document.createElement('tr');
|
||||
|
||||
const cell1 = document.createElement('td');
|
||||
cell1.textContent = item.parametro;
|
||||
|
||||
const cell2 = document.createElement('td');
|
||||
cell2.contentEditable = true;
|
||||
//cell2.textContent = item.valor;
|
||||
cell2.textContent = formatForCell(item.valor);
|
||||
|
||||
row.appendChild(cell1);
|
||||
row.appendChild(cell2);
|
||||
|
||||
tbody.appendChild(row); // enviamos la tabla al elemento html (config-table-body)
|
||||
});
|
||||
}
|
||||
|
||||
// configuracion del pop up de notificaciones
|
||||
if (msg.modalText) {
|
||||
document.getElementById('modal-text').textContent = msg.modalText;
|
||||
|
||||
const btnSi = document.getElementById('btn-modal-si');
|
||||
const btnNo = document.getElementById('btn-modal-no');
|
||||
|
||||
if (msg.modalType === "notificacion") {
|
||||
btnSi.textContent = 'OK';
|
||||
btnNo.style.display = 'none';
|
||||
window.modalCallback = null;
|
||||
} else {
|
||||
btnSi.textContent = 'Sí';
|
||||
btnNo.style.display = 'inline-block';
|
||||
window.modalCallback = msg.modalCallback || null;
|
||||
}
|
||||
|
||||
document.getElementById('confirm-modal').style.display = 'block';
|
||||
}
|
||||
|
||||
// ======================================== Datos para la Pantalla Principal ========================================================================
|
||||
if (msg.hasOwnProperty("peso")) document.getElementById('peso').textContent = msg.peso || 0;
|
||||
//if (msg.semaforo_color) document.getElementById('semaforo-color').style.backgroundColor = msg.semaforo_color;
|
||||
const led = document.getElementById('semaforo-color');
|
||||
if (msg.semaforo_color) {
|
||||
led.style.backgroundColor = msg.semaforo_color;
|
||||
led.classList.add('led');
|
||||
} else {
|
||||
led.style.backgroundColor = '#ccc';
|
||||
led.classList.remove('led');
|
||||
}
|
||||
if (msg.hasOwnProperty("matricula")) document.getElementById('matricula').textContent = msg.matricula;
|
||||
if (msg.hasOwnProperty("peso_estable_flag")) document.getElementById('peso-estable').textContent = msg.peso_estable_flag ? 'SI' : 'NO';
|
||||
if (msg.hasOwnProperty("vial")) document.getElementById('vial').textContent = msg.vial;
|
||||
if (msg.hasOwnProperty("totem_id")) document.getElementById('totem-id').textContent = msg.totem_id;
|
||||
if (msg.hasOwnProperty("iplan")) document.getElementById('iplan').textContent = msg.iplan;
|
||||
if (msg.hasOwnProperty("ipsupervisor")) document.getElementById('ipsupervisor').textContent = msg.ipsupervisor;
|
||||
|
||||
});
|
||||
|
||||
//****************************************************************************************************************************************************** */
|
||||
// Detectar clics en botones
|
||||
document.addEventListener('click', ev => {
|
||||
if (ev.target.matches('button[data-action]')) {
|
||||
const action = ev.target.getAttribute('data-action');
|
||||
console.log('⏺ Acción botón:', action);
|
||||
uibuilder.send({ payload: { seccion: action } });
|
||||
}
|
||||
});
|
||||
|
||||
// Mostrar pantalla tipos
|
||||
document.addEventListener('click', ev => {
|
||||
if (ev.target.matches('button[data-action="tipos"]')) {
|
||||
mostrarPantalla('pantalla-tipos');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('btn-add-param').addEventListener('click', agregarParametro);
|
||||
document.getElementById('btn-guardar-tipo').addEventListener('click', () => {
|
||||
window.modalCallback = guardarTipo;
|
||||
document.getElementById('modal-text').textContent = `¿Deseas guardar los cambios de Tipo ${tipoActual}?`;
|
||||
document.getElementById('confirm-modal').style.display = 'block';
|
||||
});
|
||||
|
||||
document.getElementById('btn-cancelar-tipo').addEventListener('click', () => {
|
||||
uibuilder.send({ payload: { accion: "cancelar_tipo", tipo: tipoActual } });
|
||||
volverATipos();
|
||||
});
|
||||
|
||||
document.getElementById('btn-volver-tipos').addEventListener('click', () => {
|
||||
volverATipos(); // esto limpia la tabla con los parametros del Tipo en el que estemos
|
||||
uibuilder.send({ payload: { seccion: "volver_tipos" } });
|
||||
});
|
||||
|
||||
let tipoActual = null;
|
||||
let tiposDatos = {}; // aquí se guarda la configuración temporal
|
||||
|
||||
//******************************************* FUNCIONES ******************************************************** */
|
||||
// Funcion para asegurar que se vea el array en la pantalla de configuracion. Si no se hace esto se ve los numeros sin los []
|
||||
// y luego al pasarlo al archivo no se puede identificar si es un array
|
||||
function formatForCell(v) {
|
||||
if (v === null || v === undefined) return '';
|
||||
if (typeof v === 'object') return JSON.stringify(v); // arrays y objetos
|
||||
return String(v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Acciones a partir de botones en html
|
||||
function sendRow() {// Aqui llega cuando se hace click en el boton Actualizar de las tablas dinamicas
|
||||
// recoge el contenido de la tabla en ese instante y saca Notificacion de guardar con opcion Si o No
|
||||
const rows = document.querySelectorAll('#config-table-body tr');
|
||||
result = []; // inicializamos result para poner exactamente la tabla actual
|
||||
|
||||
/*
|
||||
rows.forEach(row => {
|
||||
const parametro = row.cells[0].textContent.trim();
|
||||
let valor = row.cells[1].textContent.trim();
|
||||
|
||||
// normaliza a booleano si corresponde
|
||||
if (valor === "true") valor = true;
|
||||
if (valor === "false") valor = false;
|
||||
|
||||
result.push({ parametro, valor });
|
||||
});
|
||||
*/
|
||||
//Modificacion de la lectura de la tabla para asegurar que los numeros son mantenidos como numeros y no como texto
|
||||
// al igual que los valores booleanos.
|
||||
rows.forEach(row => {
|
||||
const parametro = row.cells[0].textContent.trim();
|
||||
let valor = row.cells[1].textContent.trim();
|
||||
// 1) Boolean
|
||||
if (/^(true|false)$/i.test(valor)) {
|
||||
valor = valor.toLowerCase() === "true";
|
||||
|
||||
// 2) JSON Array u Object: "[3,1,2]" o {"a":1}
|
||||
} else if (
|
||||
(valor.startsWith("[") && valor.endsWith("]")) ||
|
||||
(valor.startsWith("{") && valor.endsWith("}"))
|
||||
) {
|
||||
try {
|
||||
valor = JSON.parse(valor);
|
||||
|
||||
// Opcional: si es array, intenta convertir strings numéricas a números
|
||||
if (Array.isArray(valor)) {
|
||||
valor = valor.map(v => {
|
||||
if (typeof v === "string" && /^-?\d+$/.test(v)) return parseInt(v, 10);
|
||||
if (typeof v === "string" && /^-?\d+\.\d+$/.test(v)) return parseFloat(v);
|
||||
return v;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// Si no es JSON válido, se queda como string
|
||||
}
|
||||
|
||||
// 3) Int
|
||||
} else if (/^-?\d+$/.test(valor)) {
|
||||
valor = parseInt(valor, 10);
|
||||
|
||||
// // 4) Float
|
||||
} else if (/^-?\d+\.\d+$/.test(valor)) {
|
||||
valor = parseFloat(valor);
|
||||
}
|
||||
|
||||
result.push({ parametro, valor });
|
||||
});
|
||||
|
||||
|
||||
// Mostramos directamente la confirmación y definimos la callback. "topic" contiene el nombre de la tabla donde se guardan los valores que vienen en "result"
|
||||
mostrarConfirmacion("¿Deseas guardar los cambios?", () => {
|
||||
uibuilder.send({
|
||||
payload: { table: result, seccion: "respuesta" },
|
||||
topic: currentTopic,
|
||||
origen: "actualizar"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function sendCancel() { // boton Cancelar de las tablas dinamicas
|
||||
uibuilder.send({ payload: {seccion:'cancel-table'}, topic: currentTopic });
|
||||
}
|
||||
|
||||
function confirmGuardar() { // Respuesta Afirmativa del Modal de tabla dinamica
|
||||
document.getElementById('confirm-modal').style.display = 'none';
|
||||
|
||||
if (typeof window.modalCallback === 'function') {
|
||||
const cb = window.modalCallback;
|
||||
window.modalCallback = null; // limpia para la siguiente vez
|
||||
cb(); // ejecuta
|
||||
} else if (typeof window.modalCallback === 'string') {
|
||||
uibuilder.send({ payload: { table: result }, modalCallback: window.modalCallback, origen: "modal" });
|
||||
}
|
||||
}
|
||||
/*
|
||||
function confirmGuardar() { // Respuesta Afirmativa del Modal de tabla dinamica
|
||||
uibuilder.send({ payload: { table: result }, topic: currentTopic, origen: "modal-tabla" });
|
||||
document.getElementById('confirm-modal').style.display = 'none';
|
||||
}
|
||||
*/
|
||||
|
||||
function cancelarGuardar() { // Respuesta Negativa del Modal de tabla dinamica
|
||||
result = [];
|
||||
document.getElementById('confirm-modal').style.display = 'none';
|
||||
}
|
||||
|
||||
// Funciones para icono barrera
|
||||
function mostrarBarreraAbierta() {
|
||||
const icono = document.getElementById('icono-barrera');
|
||||
icono.src = "/barrera_abierta.png";
|
||||
/*
|
||||
setTimeout(() => {
|
||||
mostrarBarreraCerrada();
|
||||
}, 1000); // 1 segundo
|
||||
*/
|
||||
}
|
||||
|
||||
function mostrarBarreraCerrada() {
|
||||
const icono = document.getElementById('icono-barrera');
|
||||
icono.src = "/barrera_cerrada.png";
|
||||
}
|
||||
|
||||
//************************* FUNCIONES DE TIPOS DE CONFIGURACION *****************************/
|
||||
function seleccionarTipo(n) {
|
||||
tipoActual = n;
|
||||
document.getElementById('titulo-tipo').textContent = `TIPO ${n}`;
|
||||
document.getElementById('tipo-configuracion').style.display = 'block';
|
||||
|
||||
const contenedor = document.getElementById('parametros');
|
||||
contenedor.innerHTML = '';
|
||||
|
||||
const datos = tiposDatos[n] || []; // ya es un array
|
||||
|
||||
datos.forEach(d => {
|
||||
const row = crearFilaParametro(d.parametro, d.valor);
|
||||
contenedor.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
function agregarParametro() {
|
||||
const contenedor = document.getElementById('parametros');
|
||||
if (contenedor.children.length >= 8) return;
|
||||
|
||||
const row = crearFilaParametro('', '');
|
||||
contenedor.appendChild(row);
|
||||
}
|
||||
function crearFilaParametro(parametro, valor) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'parametro-row';
|
||||
|
||||
// Input para el nombre del parámetro
|
||||
const inputParam = document.createElement('input');
|
||||
inputParam.placeholder = 'Parámetro';
|
||||
inputParam.value = parametro;
|
||||
|
||||
// Input para el valor: checkbox o texto
|
||||
let inputValor;
|
||||
if (valor === true || valor === false || valor === "true" || valor === "false") {
|
||||
inputValor = document.createElement('input');
|
||||
inputValor.type = 'checkbox';
|
||||
inputValor.checked = (valor === true || valor === "true");
|
||||
} else {
|
||||
inputValor = document.createElement('input');
|
||||
inputValor.placeholder = 'Valor';
|
||||
inputValor.value = valor;
|
||||
}
|
||||
inputParam.classList.add('parametro');
|
||||
inputValor.classList.add('valor');
|
||||
// Botón para eliminar la fila
|
||||
const btnDelete = document.createElement('button');
|
||||
btnDelete.textContent = '-';
|
||||
btnDelete.className = 'btn rojo';
|
||||
btnDelete.style.flex = '0 0 40px';
|
||||
btnDelete.style.width = '40px';
|
||||
btnDelete.style.height = '40px';
|
||||
btnDelete.style.marginLeft = '4px';
|
||||
btnDelete.style.zIndex = '1';
|
||||
|
||||
btnDelete.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
window.modalCallback = () => div.remove();
|
||||
|
||||
document.getElementById('modal-text').textContent = '¿Deseas eliminar este parámetro?';
|
||||
document.getElementById('confirm-modal').style.display = 'block';
|
||||
return false;
|
||||
});
|
||||
|
||||
// Añadir los elementos a la fila
|
||||
div.appendChild(inputParam);
|
||||
div.appendChild(inputValor);
|
||||
div.appendChild(btnDelete);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
function crearFilaParametro_viejo(parametro, valor) { // Crea un nuevo elemento en la tabla del Tipo que estemos trabajando con dos campos y un boton de borrado
|
||||
const div = document.createElement('div');
|
||||
div.className = 'parametro-row';
|
||||
|
||||
const inputParam = document.createElement('input');
|
||||
inputParam.placeholder = 'Parámetro';
|
||||
inputParam.value = parametro;
|
||||
|
||||
const inputValor = document.createElement('input');
|
||||
inputValor.placeholder = 'Valor';
|
||||
inputValor.value = valor;
|
||||
|
||||
const btnDelete = document.createElement('button');
|
||||
btnDelete.textContent = '-';
|
||||
btnDelete.className = 'btn rojo';
|
||||
btnDelete.style.width = '40px';
|
||||
btnDelete.style.height = '40px';
|
||||
btnDelete.onclick = () => { // gestion de la alerta para el borrado, haciendo uso del modal que tenemos en html
|
||||
window.modalCallback = () => div.remove();
|
||||
|
||||
document.getElementById('modal-text').textContent = '¿Deseas eliminar este parámetro?';
|
||||
document.getElementById('confirm-modal').style.display = 'block';
|
||||
};
|
||||
|
||||
div.appendChild(inputParam);
|
||||
div.appendChild(inputValor);
|
||||
div.appendChild(btnDelete);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
function guardarTipo() {
|
||||
const contenedor = document.getElementById('parametros');
|
||||
const filas = contenedor.querySelectorAll('.parametro-row');
|
||||
const datos = [];
|
||||
filas.forEach(fila => {
|
||||
const [param, val] = fila.querySelectorAll('input');
|
||||
let valor;
|
||||
if (val.type === 'checkbox') {
|
||||
valor = val.checked;
|
||||
} else {
|
||||
valor = val.value.trim();
|
||||
}
|
||||
if (param.value.trim()) {
|
||||
datos.push({ parametro: param.value.trim(), valor });
|
||||
}
|
||||
});
|
||||
/*
|
||||
filas.forEach(fila => {
|
||||
const [param, val] = fila.querySelectorAll('input');
|
||||
if (param.value.trim()) {
|
||||
datos.push({ parametro: param.value.trim(), valor: val.value.trim() });
|
||||
}
|
||||
});
|
||||
*/
|
||||
tiposDatos[tipoActual] = datos;
|
||||
|
||||
uibuilder.send({ payload: { tipo: tipoActual, datos }, topic: "tipoconfig" }); // el topic nos sirve para seleccionar en el proximo nodo la funcion de guardar los datos
|
||||
|
||||
volverATipos(); // 🔷 salimos de la pantalla del tipo actual
|
||||
}
|
||||
|
||||
function volverATipos() {
|
||||
document.getElementById('tipo-configuracion').style.display = 'none';
|
||||
tipoActual = null;
|
||||
}
|
||||
|
||||
//==========================================FUNCIONES PARA MANEJAR LAS NOTIFICACIONES ======================================================
|
||||
function mostrarConfirmacion(texto, callback) {
|
||||
document.getElementById('modal-text').textContent = texto;
|
||||
|
||||
// Restablece estado normal del modal
|
||||
const btnSi = document.getElementById('btn-modal-si');
|
||||
const btnNo = document.getElementById('btn-modal-no');
|
||||
|
||||
btnSi.textContent = 'Sí';
|
||||
btnNo.style.display = 'inline-block';
|
||||
|
||||
window.modalCallback = callback;
|
||||
|
||||
document.getElementById('confirm-modal').style.display = 'block';
|
||||
}
|
||||
|
||||
function mostrarNotificacion(texto) {
|
||||
document.getElementById('modal-text').textContent = texto;
|
||||
|
||||
const btnSi = document.getElementById('btn-modal-si');
|
||||
const btnNo = document.getElementById('btn-modal-no');
|
||||
|
||||
btnSi.textContent = 'OK';
|
||||
btnNo.style.display = 'none';
|
||||
|
||||
window.modalCallback = null;
|
||||
|
||||
document.getElementById('confirm-modal').style.display = 'block';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Cuando necesitemos un modal clásico (Sí/No), por ejemplo para confirmar actualización:
|
||||
|
||||
mostrarConfirmacion("¿Deseas guardar los cambios?", () => {
|
||||
uibuilder.send({ payload: { table: result, seccion:"respuesta" }, topic: currentTopic, origen: "actualizar" });
|
||||
});
|
||||
|
||||
Cuando necesitemos simplemente notificar un error:
|
||||
|
||||
mostrarNotificacion("La IP introducida es inválida, por favor corrígela.");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"baseUrl": "./src",
|
||||
"typeRoots": ["./types"]
|
||||
},
|
||||
"include": ["types", "src/**/*.js"]
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/// <reference path="./uibuilder.module.d.ts" />
|
||||
|
||||
/**
|
||||
* Make the uibuilder instance globally available (from uibuilder.module.d.ts)
|
||||
* @version 7.3.0
|
||||
*/
|
||||
declare global {
|
||||
// Use typeof import to reference the Uib class from the module
|
||||
const uibuilder: import("./uibuilder.module").Uib;
|
||||
}
|
||||
|
||||
export {};
|
||||
+647
@@ -0,0 +1,647 @@
|
||||
/**
|
||||
* Type definitions for uibuilder.module.js
|
||||
* WCAG 2.2 AA, ESLint v9, Shift-Left security, and project conventions applied.
|
||||
* @version 7.3.0
|
||||
* @author Julian Knight (Totally Information)
|
||||
*/
|
||||
|
||||
export type HtmlString = string
|
||||
|
||||
/** Column metadata for tables */
|
||||
export interface ColumnDefinition {
|
||||
index: number,
|
||||
hasName: boolean,
|
||||
title: string,
|
||||
name?: string,
|
||||
key?: string | number,
|
||||
dataType?: 'string' | 'date' | 'number' | 'html',
|
||||
editable?: boolean,
|
||||
}
|
||||
|
||||
/** Options for building HTML tables */
|
||||
export interface TableOptions {
|
||||
cols?: ColumnDefinition[],
|
||||
parent?: HTMLElement | string,
|
||||
allowHTML?: boolean,
|
||||
}
|
||||
|
||||
/** Options for tblAddListener */
|
||||
export interface TableListenerOptions {
|
||||
eventScope?: 'row' | 'cell',
|
||||
returnType?: 'text' | 'html',
|
||||
pad?: number,
|
||||
send?: boolean,
|
||||
logLevel?: string | number,
|
||||
eventType?: string,
|
||||
}
|
||||
|
||||
/** Options for notification */
|
||||
export interface NotificationConfig {
|
||||
title?: string,
|
||||
body?: string,
|
||||
return?: boolean,
|
||||
[key: string]: any,
|
||||
}
|
||||
|
||||
/**
|
||||
* Uibuilder main class
|
||||
* @typicalname uibuilder
|
||||
* @description The client-side Front-End JavaScript for uibuilder in HTML Module form.
|
||||
* Provides a number of global objects that can be used in your own JavaScript.
|
||||
* See the docs folder `./docs/uibuilder.module.md` for details of how to use this fully.
|
||||
* @version 7.3.0
|
||||
* @author Julian Knight (Totally Information)
|
||||
*/
|
||||
export class Uib {
|
||||
/**
|
||||
* Static metadata for the Uibuilder client
|
||||
*/
|
||||
static _meta: {
|
||||
version: string,
|
||||
type: string,
|
||||
displayName: string,
|
||||
}
|
||||
|
||||
/** Client ID set by uibuilder on connect */
|
||||
clientId: string
|
||||
/** The collection of cookies provided by uibuilder */
|
||||
cookies: Record<string, string>
|
||||
/** Copy of last control msg object received from server */
|
||||
ctrlMsg: object
|
||||
/** Is Socket.IO client connected to the server? */
|
||||
ioConnected: boolean
|
||||
/** Is the library running from a minified version? */
|
||||
isMinified: boolean
|
||||
/** Is the browser tab containing this page visible or not? */
|
||||
isVisible: boolean
|
||||
/** Remember the last page (re)load/navigation type: navigate, reload, back_forward, prerender */
|
||||
lastNavType: string
|
||||
/** Max msg size that can be sent over Socket.IO - updated by "client connect" msg receipt */
|
||||
maxHttpBufferSize: number
|
||||
/** Last std msg received from Node-RED */
|
||||
msg: object
|
||||
/** Number of messages sent to server since page load */
|
||||
msgsSent: number
|
||||
/** Number of messages received from server since page load */
|
||||
msgsReceived: number
|
||||
/** Number of control messages sent to server since page load */
|
||||
msgsSentCtrl: number
|
||||
/** Number of control messages received from server since page load */
|
||||
msgsCtrlReceived: number
|
||||
/** Is the client online or offline? */
|
||||
online: boolean
|
||||
/** Last control msg object sent via uibuilder.send() */
|
||||
sentCtrlMsg: object
|
||||
/** Last std msg object sent via uibuilder.send() */
|
||||
sentMsg: object
|
||||
/** Placeholder to track time offset from server, see fn socket.on(ioChannels.server ...) */
|
||||
serverTimeOffset: number | null
|
||||
/** Placeholder for a socket error message */
|
||||
socketError: string | null
|
||||
/** Tab identifier from session storage */
|
||||
tabId: string
|
||||
/** Actual name of current page (set in constructor) */
|
||||
pageName: string | null
|
||||
/** Is the DOMPurify library loaded? Updated in start() */
|
||||
purify: boolean
|
||||
/** Is the Markdown-IT library loaded? Updated in start() */
|
||||
markdown: boolean
|
||||
/** Current URL hash. Initial set is done from start->watchHashChanges via a set to make it watched */
|
||||
urlHash: string
|
||||
/** Default originator node id - empty string by default */
|
||||
originator: string
|
||||
/** Optional default topic to be included in outgoing standard messages */
|
||||
topic?: string
|
||||
/** Either undefined or a reference to a uib router instance. Set by uibrouter, do not set manually. */
|
||||
uibrouterinstance?: any
|
||||
/** Set by uibrouter, do not set manually */
|
||||
uibrouter_CurrentRoute?: any
|
||||
/** Internal: auto-send ready flag */
|
||||
autoSendReady: boolean
|
||||
/** Node-RED setting (via cookie) */
|
||||
httpNodeRoot: string
|
||||
/** Socket.IO namespace - unique to each uibuilder node instance */
|
||||
ioNamespace: string
|
||||
/** Socket.IO path */
|
||||
ioPath: string
|
||||
/** Starting delay factor for subsequent reconnect attempts */
|
||||
retryFactor: number
|
||||
/** Starting retry ms period for manual socket reconnections workaround */
|
||||
retryMs: number
|
||||
/** Prefix for all uib-related localStorage */
|
||||
storePrefix: string
|
||||
/** Whether uibuilder client has started */
|
||||
started: boolean
|
||||
/** Socket.IO connection options */
|
||||
socketOptions: object
|
||||
|
||||
// --- Getters/Setters ---
|
||||
logLevel: number
|
||||
meta: typeof Uib._meta
|
||||
|
||||
/**
|
||||
* Set uibuilder properties to a new value - works on any property except _* or #*
|
||||
* Also triggers any event listeners.
|
||||
* @param prop Any uibuilder property who's name does not start with a _ or #
|
||||
* @param val The set value of the property or a string declaring that a protected property cannot be changed
|
||||
* @param store If true, the variable is also saved to the browser localStorage if possible
|
||||
* @param autoload If true & store is true, on load, uib will try to restore the value from the store automatically
|
||||
* @returns Input value
|
||||
*/
|
||||
set(prop: string, val: any, store?: boolean, autoload?: boolean): any
|
||||
|
||||
/**
|
||||
* Get the value of a uibuilder property
|
||||
* @param prop The name of the property to get as long as it does not start with a _ or #
|
||||
* @returns The current value of the property
|
||||
*/
|
||||
get(prop: string): any
|
||||
|
||||
/**
|
||||
* Write to localStorage if possible. Console error output if can't write
|
||||
* Also uses this.storePrefix
|
||||
* @param id localStorage var name to be used (prefixed with 'uib_')
|
||||
* @param value value to write to localstore
|
||||
* @param autoload If true, on load, uib will try to restore the value from the store
|
||||
* @returns True if succeeded else false
|
||||
*/
|
||||
setStore(id: string, value: any, autoload?: boolean): boolean
|
||||
|
||||
/**
|
||||
* Attempt to get and re-hydrate a key value from localStorage
|
||||
* @param id The key of the value to attempt to retrieve
|
||||
* @returns The re-hydrated value of the key or null if key not found, undefined on error
|
||||
*/
|
||||
getStore(id: string): any
|
||||
|
||||
/**
|
||||
* Remove a given id from the uib keys in localStorage
|
||||
* @param id The key to remove
|
||||
*/
|
||||
removeStore(id: string): void
|
||||
|
||||
/**
|
||||
* Returns a list of uibuilder properties (variables) that can be watched with onChange
|
||||
* @returns List of uibuilder managed variables
|
||||
*/
|
||||
getManagedVarList(): Record<string, string>
|
||||
|
||||
/**
|
||||
* Returns a list of currently watched variables
|
||||
* @returns List of watched variable names
|
||||
*/
|
||||
getWatchedVars(): string[]
|
||||
|
||||
/**
|
||||
* Register on-change event listeners for uibuilder tracked properties
|
||||
* @param prop The property of uibuilder that we want to monitor
|
||||
* @param callback The function that will run when the property changes, parameter is the new value of the property after change
|
||||
* @returns A reference to the callback to cancel
|
||||
*/
|
||||
onChange(prop: string, callback: (val: any) => void): number
|
||||
|
||||
/**
|
||||
* Cancel a previously registered onChange event listener
|
||||
* @param prop The property name
|
||||
* @param cbRef The callback reference number
|
||||
*/
|
||||
cancelChange(prop: string, cbRef: number): void
|
||||
|
||||
/**
|
||||
* Register a change callback for a specific msg.topic
|
||||
* @param topic The msg.topic we want to listen for
|
||||
* @param callback The function that will run when an appropriate msg is received
|
||||
* @returns A reference to the callback to cancel
|
||||
*/
|
||||
onTopic(topic: string, callback: (msg: any) => void): number
|
||||
|
||||
/**
|
||||
* Cancel a previously registered onTopic event listener
|
||||
* @param topic The topic name
|
||||
* @param cbRef The callback reference number
|
||||
*/
|
||||
cancelTopic(topic: string, cbRef: number): void
|
||||
|
||||
/**
|
||||
* Returns a new array containing the intersection of the 2 input arrays
|
||||
* @param a1 Array to check
|
||||
* @param a2 Array to intersect
|
||||
* @returns The intersection of the 2 arrays (may be an empty array)
|
||||
*/
|
||||
arrayIntersect<T>(a1: T[], a2: T[]): T[]
|
||||
|
||||
/**
|
||||
* Copies a uibuilder variable to the browser clipboard
|
||||
* @param varToCopy The name of the uibuilder variable to copy to the clipboard
|
||||
*/
|
||||
copyToClipboard(varToCopy: string): void
|
||||
|
||||
/**
|
||||
* Does the chosen CSS Selector currently exist?
|
||||
* @param cssSelector Required. CSS Selector to examine for visibility
|
||||
* @param msg Optional, default=true. If true also sends a message back to Node-RED
|
||||
* @returns True if the element exists
|
||||
*/
|
||||
elementExists(cssSelector: string, msg?: boolean): boolean
|
||||
|
||||
/**
|
||||
* Format a number using the INTL standard library
|
||||
* @param value Number to format
|
||||
* @param decimalPlaces Number of decimal places to include
|
||||
* @param intl standard locale spec, e.g. "ja-JP" or "en-GB"
|
||||
* @param opts INTL library options object
|
||||
* @returns formatted number
|
||||
*/
|
||||
formatNumber(value: number, decimalPlaces?: number, intl?: string, opts?: object): string
|
||||
|
||||
/**
|
||||
* Attempt to get rough size of an object
|
||||
* @param obj Any serialisable object
|
||||
* @returns Rough size of object in bytes or undefined
|
||||
*/
|
||||
getObjectSize(obj: any): number | undefined
|
||||
|
||||
/**
|
||||
* Returns true if a uibrouter instance is loaded, otherwise returns false
|
||||
* @returns true if uibrouter instance loaded else false
|
||||
*/
|
||||
hasUibRouter(): boolean
|
||||
|
||||
/**
|
||||
* Only keep the URL Hash & ignoring query params
|
||||
* @param url URL to extract the hash from
|
||||
* @returns Just the route id
|
||||
*/
|
||||
keepHashFromUrl(url: string): string
|
||||
|
||||
/**
|
||||
* Custom logging function
|
||||
* @param args Arguments to log
|
||||
*/
|
||||
log(...args: any[]): void
|
||||
|
||||
/**
|
||||
* Makes a null or non-object into an object. If thing is already an object.
|
||||
* If not null, moves "thing" to {payload:thing}
|
||||
* @param thing Thing to check
|
||||
* @param property property that "thing" is moved to if not null and not an object. Default='payload'
|
||||
* @returns Object
|
||||
*/
|
||||
makeMeAnObject(thing: any, property?: string): object
|
||||
|
||||
/**
|
||||
* Navigate to a new page or a new route (hash)
|
||||
* @param url URL to navigate to. Can be absolute or relative (to current page) or just a hash for a route change
|
||||
* @returns The new window.location string
|
||||
*/
|
||||
navigate(url: string): Location
|
||||
|
||||
/**
|
||||
* Convert a string attribute into a variable/constant reference
|
||||
* Used to resolve data sources in attributes
|
||||
* @param path The string path to resolve, must be relative to the `window` global scope
|
||||
* @returns The resolved data source or null
|
||||
*/
|
||||
resolveDataSource(path: string): any
|
||||
|
||||
/**
|
||||
* Fast but accurate number rounding
|
||||
* @param num The number to be rounded
|
||||
* @param decimalPlaces Number of DP's to round to
|
||||
* @returns Rounded number
|
||||
*/
|
||||
round(num: number, decimalPlaces: number): number
|
||||
|
||||
/**
|
||||
* Set the default originator. Set to '' to ignore. Used with uib-sender.
|
||||
* @param originator A Node-RED node ID to return the message to
|
||||
*/
|
||||
setOriginator(originator?: string): void
|
||||
|
||||
/**
|
||||
* HTTP Ping/Keep-alive - makes a call back to uibuilder's ExpressJS server and receives a 204 response
|
||||
* Can be used to keep sessions alive.
|
||||
* @param ms Repeat interval in ms
|
||||
*/
|
||||
setPing(ms?: number): void
|
||||
|
||||
/**
|
||||
* Convert JSON to Syntax Highlighted HTML
|
||||
* @param json A JSON/JavaScript Object
|
||||
* @returns Object reformatted as highlighted HTML
|
||||
*/
|
||||
syntaxHighlight(json: object): HtmlString
|
||||
|
||||
/**
|
||||
* Returns true/false or a default value for truthy/falsy and other values
|
||||
* @param val The value to test
|
||||
* @param deflt Default value to use if the value is not truthy/falsy
|
||||
* @returns The truth! Or the default
|
||||
*/
|
||||
truthy(val: any, deflt: any): boolean | any
|
||||
|
||||
/**
|
||||
* Joins all arguments as a URL string
|
||||
* @param paths URL fragments
|
||||
* @returns Joined URL string
|
||||
*/
|
||||
urlJoin(...paths: string[]): string
|
||||
|
||||
/**
|
||||
* Turn on/off/toggle sending URL hash changes back to Node-RED
|
||||
* @param toggle Optional on/off/etc
|
||||
* @returns True if we will send a msg to Node-RED on a hash change
|
||||
*/
|
||||
watchUrlHash(toggle?: any): boolean
|
||||
|
||||
/**
|
||||
* DEPRECATED FOR NOW - wasn't working properly.
|
||||
* Is the chosen CSS Selector currently visible to the user? NB: Only finds the FIRST element of the selection.
|
||||
* @returns False
|
||||
*/
|
||||
elementIsVisible(): false
|
||||
|
||||
// --- UI handlers ---
|
||||
/**
|
||||
* Simplistic jQuery-like document CSS query selector, returns an HTML Element.
|
||||
* If the selected element is a <template>, returns the first child element.
|
||||
* @param cssSelector A CSS Selector that identifies the element to return
|
||||
* @returns Selected HTML element or null
|
||||
*/
|
||||
$: (cssSelector: string) => HTMLElement | null
|
||||
/**
|
||||
* CSS query selector that returns ALL found selections as an array of elements.
|
||||
* @param cssSelector A CSS Selector that identifies the elements to return
|
||||
* @returns Array of DOM elements/nodes. Array is empty if selector is not found.
|
||||
*/
|
||||
$$: (cssSelector: string) => HTMLElement[]
|
||||
/**
|
||||
* Reference to the full ui library
|
||||
*/
|
||||
$ui: any
|
||||
/**
|
||||
* Add one or several class names to an element
|
||||
* @param classNames Single or array of classnames
|
||||
* @param el HTML Element to add class(es) to
|
||||
*/
|
||||
addClass(classNames: string | string[], el: HTMLElement): void
|
||||
/**
|
||||
* Apply a source template tag to a target html element
|
||||
* @param source The source element
|
||||
* @param target The target element
|
||||
* @param onceOnly If true, the source will be adopted (the source is moved)
|
||||
*/
|
||||
applyTemplate(source: HTMLElement, target: HTMLElement, onceOnly: boolean): void
|
||||
/**
|
||||
* Builds an HTML table from an array (or object) of objects
|
||||
* @param data Input data array or object
|
||||
* @param opts Table options
|
||||
* @returns Output HTML Element
|
||||
*/
|
||||
buildHtmlTable(data: object[] | object, opts?: TableOptions): HTMLTableElement | HTMLParagraphElement
|
||||
/**
|
||||
* Directly add a table to a parent element.
|
||||
* @param data Input data array or object
|
||||
* @param opts Build options
|
||||
*/
|
||||
createTable(data?: object[] | any[], opts?: TableOptions): void
|
||||
/**
|
||||
* Converts markdown text input to HTML if the Markdown-IT library is loaded
|
||||
* Otherwise simply returns the text
|
||||
* @param mdText The input markdown string
|
||||
* @returns HTML (if Markdown-IT library loaded and parse successful) or original text
|
||||
*/
|
||||
convertMarkdown(mdText: string): string
|
||||
/**
|
||||
* ASYNC: Include HTML fragment, img, video, text, json, form data, pdf or anything else from an external file or API
|
||||
* @param url The URL of the source file to include
|
||||
* @param uiOptions Object containing properties recognised by the _uiReplace function. Must at least contain an id
|
||||
*/
|
||||
include(url: string, uiOptions: object): Promise<void>
|
||||
/**
|
||||
* Attach a new remote script to the end of HEAD synchronously
|
||||
* @param url The url to be used in the script src attribute
|
||||
*/
|
||||
loadScriptSrc(url: string): void
|
||||
/**
|
||||
* Attach a new remote stylesheet link to the end of HEAD synchronously
|
||||
* @param url The url to be used in the style link href attribute
|
||||
*/
|
||||
loadStyleSrc(url: string): void
|
||||
/**
|
||||
* Attach a new text script to the end of HEAD synchronously
|
||||
* @param textFn The text to be loaded as a script
|
||||
*/
|
||||
loadScriptTxt(textFn: string): void
|
||||
/**
|
||||
* Attach a new text stylesheet to the end of HEAD synchronously
|
||||
* @param textFn The text to be loaded as a stylesheet
|
||||
*/
|
||||
loadStyleTxt(textFn: string): void
|
||||
/**
|
||||
* Load a dynamic UI from a JSON web response
|
||||
* @param url URL that will return the ui JSON
|
||||
*/
|
||||
loadui(url: string): void
|
||||
/**
|
||||
* Remove All, 1 or more class names from an element
|
||||
* @param classNames Single or array of classnames. If undefined, "" or null, remove all classes
|
||||
* @param el HTML Element to remove class(es) from
|
||||
*/
|
||||
removeClass(classNames: string | string[] | undefined | null, el: HTMLElement): void
|
||||
/**
|
||||
* Replace or add an HTML element's slot from text or an HTML string
|
||||
* WARNING: Executes <script> tags! And will process <style> tags.
|
||||
* Will use DOMPurify if that library has been loaded to window.
|
||||
* @param el Reference to the element that we want to update
|
||||
* @param slot The slot content we are trying to add/replace (defaults to empty string)
|
||||
*/
|
||||
replaceSlot(el: Element, slot: any): void
|
||||
/**
|
||||
* Replace or add an HTML element's slot from a Markdown string
|
||||
* Only does something if the markdownit library has been loaded to window.
|
||||
* Will use DOMPurify if that library has been loaded to window.
|
||||
* @param el Reference to the element that we want to update
|
||||
* @param component The component we are trying to add/replace
|
||||
*/
|
||||
replaceSlotMarkdown(el: Element, component: any): void
|
||||
/**
|
||||
* Sanitise HTML to make it safe - if the DOMPurify library is loaded
|
||||
* Otherwise just returns that HTML as-is.
|
||||
* @param html The input HTML string
|
||||
* @returns The sanitised HTML or the original if DOMPurify not loaded
|
||||
*/
|
||||
sanitiseHTML(html: string): string
|
||||
/**
|
||||
* Add table event listener that returns the text or html content of either the full row or a single cell
|
||||
* @param tblSelector The table CSS Selector
|
||||
* @param options Additional options
|
||||
* @param out A variable reference that will be updated with the output data upon a click event
|
||||
*/
|
||||
tblAddListener(tblSelector: string, options?: TableListenerOptions, out?: object): void
|
||||
/**
|
||||
* Add a row to a table element in the DOM.
|
||||
* @param tbl The table element or selector to add the row to
|
||||
* @param rowData The data for the new row (object or array)
|
||||
* @param options Optional configuration for row creation
|
||||
* @returns The created HTMLTableRowElement
|
||||
*/
|
||||
tblAddRow(tbl: string | HTMLTableElement, rowData: object | any[], options?: object): HTMLTableRowElement
|
||||
/**
|
||||
* Remove a row from a table element in the DOM.
|
||||
* @param tbl The table element or selector to remove the row from
|
||||
* @param rowIndex The index of the row to remove
|
||||
* @param options Optional configuration for row removal
|
||||
*/
|
||||
tblRemoveRow(tbl: string | HTMLTableElement, rowIndex: number, options?: object): void
|
||||
/**
|
||||
* Show a dialog (notification or alert) in the UI.
|
||||
* @param type The dialog type: 'notify' or 'alert'
|
||||
* @param ui The UI configuration object for the dialog
|
||||
* @param msg Optional message object to include
|
||||
*/
|
||||
showDialog(type: 'notify' | 'alert', ui: object, msg?: object): void
|
||||
/**
|
||||
* Apply a UI definition (JSON) to the current page.
|
||||
* @param json The UI definition object
|
||||
*/
|
||||
ui(json: object): void
|
||||
/**
|
||||
* Get properties or values from UI elements matching a selector.
|
||||
* @param cssSelector The CSS selector for the elements
|
||||
* @param propName Optional property name to retrieve
|
||||
* @returns Array of property values or elements
|
||||
*/
|
||||
uiGet(cssSelector: string, propName?: string): any[]
|
||||
/**
|
||||
* Enhance a DOM element with a UI component definition.
|
||||
* @param el The element to enhance
|
||||
* @param component The component definition or configuration
|
||||
*/
|
||||
uiEnhanceElement(el: any, component: any): void
|
||||
|
||||
// --- DOM/HTML cache ---
|
||||
/**
|
||||
* Clear the cached HTML content from memory or storage.
|
||||
*/
|
||||
clearHtmlCache(): void
|
||||
/**
|
||||
* Restore HTML content from the cache into the DOM.
|
||||
*/
|
||||
restoreHtmlFromCache(): void
|
||||
/**
|
||||
* Save the current HTML content to the cache for later restoration.
|
||||
*/
|
||||
saveHtmlCache(): void
|
||||
|
||||
// --- Message Handling ---
|
||||
/**
|
||||
* Send a standard message to Node-RED via Socket.IO.
|
||||
* @param msg The message object to send
|
||||
* @param originator Optional Node-RED node ID to return the message to
|
||||
*/
|
||||
send(msg: object, originator?: string): void
|
||||
/**
|
||||
* Send a message to a specific room via Socket.IO.
|
||||
* @param room The room name
|
||||
* @param msg The message to send
|
||||
*/
|
||||
sendRoom(room: string, msg: any): void
|
||||
/**
|
||||
* Join a Socket.IO room.
|
||||
* @param room The room name to join
|
||||
*/
|
||||
joinRoom(room: string): void
|
||||
/**
|
||||
* Leave a Socket.IO room.
|
||||
* @param room The room name to leave
|
||||
*/
|
||||
leaveRoom(room: string): void
|
||||
/**
|
||||
* Send a control message to Node-RED via Socket.IO.
|
||||
* @param msg The control message object to send
|
||||
*/
|
||||
sendCtrl(msg: object): void
|
||||
/**
|
||||
* Send a custom message on a specific channel via Socket.IO.
|
||||
* @param channel The custom channel name
|
||||
* @param msg The message object to send
|
||||
*/
|
||||
sendCustom(channel: string, msg: object): void
|
||||
/**
|
||||
* Upload a file to the server via Socket.IO.
|
||||
* @param file The file to upload
|
||||
* @param meta Optional metadata to send with the file
|
||||
*/
|
||||
uploadFile(file: File, meta?: object): void
|
||||
|
||||
// --- Socket.IO ---
|
||||
/**
|
||||
* Connect the Socket.IO client to the server.
|
||||
*/
|
||||
connect(): void
|
||||
/**
|
||||
* Disconnect the Socket.IO client from the server.
|
||||
*/
|
||||
disconnect(): void
|
||||
|
||||
// --- Startup ---
|
||||
/**
|
||||
* Start the uibuilder client, initializing all features and connections.
|
||||
* @param options Optional startup options
|
||||
*/
|
||||
start(options?: object): void
|
||||
|
||||
// --- Show/hide ---
|
||||
/**
|
||||
* Show or hide the message area in the UI.
|
||||
* @param showHide If true, show the message area; if false, hide it
|
||||
* @param parent Optional parent selector or element
|
||||
* @returns True if the message area is shown, false if hidden
|
||||
*/
|
||||
showMsg(showHide?: boolean, parent?: string): boolean
|
||||
/**
|
||||
* Show or hide the status area in the UI.
|
||||
* @param showHide If true, show the status area; if false, hide it
|
||||
* @param parent Optional parent selector or element
|
||||
* @returns True if the status area is shown, false if hidden
|
||||
*/
|
||||
showStatus(showHide?: boolean, parent?: string): boolean
|
||||
|
||||
// --- Watchers ---
|
||||
/**
|
||||
* Watch a DOM element for changes and optionally send updates to Node-RED.
|
||||
* @param cssSelector The CSS selector to watch
|
||||
* @param startStop Start, stop, or toggle the watcher
|
||||
* @param send If true, send updates to Node-RED
|
||||
* @param showLog If true, log watcher activity
|
||||
* @returns True if watching, false otherwise
|
||||
*/
|
||||
uiWatch(cssSelector: string, startStop?: boolean | 'toggle', send?: boolean, showLog?: boolean): boolean
|
||||
/**
|
||||
* Watch the DOM for changes (e.g., for dynamic UI updates).
|
||||
* @param startStop Start or stop watching
|
||||
*/
|
||||
watchDom(startStop: boolean): void
|
||||
|
||||
// --- Notifications ---
|
||||
/**
|
||||
* Show a notification or alert in the UI.
|
||||
* @param config Notification configuration or string message
|
||||
* @returns A promise resolving to the notification event, or null
|
||||
*/
|
||||
notify(config: NotificationConfig | string): Promise<Event> | null
|
||||
|
||||
// --- Clipboard ---
|
||||
/**
|
||||
* Copy a uibuilder variable's value to the clipboard.
|
||||
* @param varToCopy The name of the uibuilder variable to copy
|
||||
*/
|
||||
copyToClipboard(varToCopy: string): void
|
||||
}
|
||||
|
||||
/** The default uibuilder instance */
|
||||
declare const uibuilder: Uib
|
||||
|
||||
export { uibuilder }
|
||||
export default uibuilder
|
||||
Reference in New Issue
Block a user