# Total.js Forge - full cookbook ## Get started with Total.js 5 Source: https://forge.totaljs.es/en/docs/getting-started/ Framework: total5@0.0.19 Content-SHA256: 5f7bf99c3dc733b1a14f49c26a40d678238c8c9e2e60d732ca14763a7eab43e7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js 5 is the npm package `total5`. You need Node.js (the examples of this site run on Node.js 24) and an empty folder. Create the project and install the package: ```bash mkdir hello && cd hello npm init -y npm install total5 ``` The start script is a file named `index.js` in the root of the project. It loads the framework and starts the server: ```js require('total5'); Total.run({ port: 8000 }); ``` That is all the code you write to start. The files in the folders of the project (see the project structure page) are loaded automatically. Create these three files. A **controller** declares the routes. `ROUTE('GET /')` with no handler would show the view with the same name; here the handler renders `views/index.html` with a model: ```js controllers/index.js exports.install = function() { ROUTE('GET /', home); ROUTE('POST /greet/ --> *Greet/say'); }; function home($) { $.view('index', { title: 'Hello Total.js' }); } ``` An **action** has its own validation. The route above runs `Greet/say` with the JSON body of the request, and the framework rejects a body that does not match `input`: ```js definitions/greet.js NEWACTION('Greet/say', { name: 'Say hello', input: '*name:String', action: function($, model) { $.callback({ message: 'Hello, ' + model.name + '!' }); } }); ``` A **view** is HTML with `@{...}` blocks. `views/layout.html` wraps every view and `@{body}` is the place of the view: ```html views/layout.html Hello @{body} ``` ```html views/index.html

@{model.title}

``` Start the application with `node index.js`. In `debug` mode (the default) the application restarts when you change a file and the address is printed in the terminal. To run it like on a server use `node index.js --release`, and read the `release` mode page for what changes. ## Consult Forge with versions, sources and complete reads Source: https://forge.totaljs.es/en/docs/consulting-forge/ Framework: total5@0.0.19 Content-SHA256: bc42083bd8e07eb1d3da1da6cbf27c7c425ea21348b2d6fa5badf1df7e2169f6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: reviewed-workflow ## Start with the product and version Forge documents backend Total.js 5 and frontend jComponent 20. They share names such as `DEF`, `GET`, `CACHE` and `ON` but run in different environments. Choose the product before applying a contract. The installed backend runtime is `total5@0.0.19`; the pinned framework development reference declares `0.0.20-1`. An upstream source reference is not a test result for the installed package. Read `/knowledge-sources.json` for exact commits and SHA-256 fingerprints, `/knowledge-coverage.json` for declaration and component coverage, and `/knowledge-licenses.json` for preserved upstream license notices. `/knowledge.json` describes the current published documents, their actual languages, hashes and stable sections. The library version alone is insufficient to identify a jComponent bundle; retain its source fingerprint. ## Search, then read Use `Forge_search` with an exact symbol such as `Controller.prototype.json`, `DEF.fallback` or `Component.prototype.setter`, or a short English/Spanish task query. Search includes the public document body. Matching excerpts help select a page; they are not the whole page and are not evidence that an example was executed. The response includes the actual content language; an untranslated page remains English. Call `Forge_page` with the returned section and slug. Pass its `content_sha256` to refuse a changed page. To read just the matching section, pass its `anchor`. If `next_cursor` is present, continue with that cursor until it is null. Cursors bind the document, language, content hash and pinned source snapshot. If the page changes, restart the read. The old `offset` field remains available for existing clients, but a cursor provides revision checking. Cite the page URL, its section anchor and the content hash used. A page found by search has not yet been read. A large page returned in parts has not been fully read until continuation finishes. ## Resolve a contract in the original implementation Use `Forge_coverage` to resolve an exact symbol and identify its source id and file. Use `Forge_source` to read that file verbatim. Its `path` must match a text file in the pinned source manifest. Source reads are paginated and hash checked. The same bounded readers are available over HTTP at `/api/knowledge-search/`, `/api/knowledge-page/` and `/api/knowledge-source/` for clients that do not use MCP. Sources include the installed runtime, pinned upstream framework, jComponent, components, and AIContext guidance. `aicontext` is architectural guidance, not proof that every example matches the installed runtime. Read a matching implementation and recipe before adopting a signature, lifecycle assumption or dependency. Do not execute a source excerpt as a standalone example. Use `Forge_test` with the page section and slug to get its example files and the command for running them. ## Project structure of a Total.js 5 application Source: https://forge.totaljs.es/en/docs/project-structure/ Framework: total5@0.0.19 Content-SHA256: 7c79aecbd0fa3cbd1e8f2b82806a67c9622e0956e59e284a881e124a3594e84d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A Total.js application is a folder with a start script (`index.js`) and a set of folders with fixed names. **You do not import your files**: when the application starts, Total.js reads the folders below and loads every `.js` file in them (in a folder called `plugins/` it loads the `index.js` of every subfolder). A file is a normal Node.js module; if it exports an `install` function, Total.js calls it after loading the file. | Folder | What goes in it | |---|---| | `controllers/` | Routes: `exports.install = function() { ROUTE(...) }`. | | `definitions/` | Code that runs at start and declares global things: actions with `NEWACTION()`, middleware, `AUTH()`, helpers, your own globals. | | `actions/` | Actions (`NEWACTION()`), when you prefer them apart from the other definitions. | | `schemas/` | Schemas (`NEWSCHEMA()`) with their actions. | | `models/` | Loaded at start like the others; Total.js only loads the files, what they contain is up to you. | | `middleware/` | Middleware (`MIDDLEWARE()`), loaded after the other folders. | | `modules/` | Reusable modules; the export may have an `id` (it is kept in `MODS`) and an `install` function. | | `extensions/` | Loaded at start like the others; Total.js only loads the files, what they contain is up to you. | | `plugins/` | Plugins: a folder per plugin with an `index.js`. | | `views/` | HTML views and the `layout.html`. | | `public/` | Static files served as they are, without any route. | | `resources/` | Translation files (`.resource`), see the localization recipe. | | `jsonschemas/` | Reusable input definitions (`.txt` or `.json`), see the schemas recipe. | | `databases/` | Files of the built-in NoSQL database and of `MEMORIZE()`. | | `tmp/` | Temporary files and caches (`PATH.tmp()`). | | `logs/` | Log files. | | `private/` | Files that must not be public; send them with `$.file()` after a check. | | `workers/` | Files of `NEWTHREAD()` and `NEWFORK()`. | | `config` | The configuration file (a file, not a folder). | The helpers of `PATH` build the absolute path of each folder: `PATH.root()`, `PATH.public()`, `PATH.private()`, `PATH.tmp()`, `PATH.logs()`, `PATH.databases()`. They return the path without a trailing slash, and the folder of the views has no helper. The example puts a file in each of the folders that Total.js loads and reads back what was loaded. ```js extensions/marker.js (MAIN.loaded = MAIN.loaded || []).push('extensions'); ``` ```js modules/marker.js (MAIN.loaded = MAIN.loaded || []).push('modules'); module.exports.id = 'modules-file'; ``` ```js actions/marker.js (MAIN.loaded = MAIN.loaded || []).push('actions'); ``` ```js schemas/marker.js (MAIN.loaded = MAIN.loaded || []).push('schemas'); ``` ```js models/marker.js (MAIN.loaded = MAIN.loaded || []).push('models'); ``` ```js definitions/marker.js (MAIN.loaded = MAIN.loaded || []).push('definitions'); ``` ```js controllers/marker.js (MAIN.loaded = MAIN.loaded || []).push('controllers'); ``` ```js middleware/marker.js (MAIN.loaded = MAIN.loaded || []).push('middleware'); ``` ```js controllers/structure.js exports.install = function() { ROUTE('GET /structure/', structure); }; function structure($) { $.json({ loaded: MAIN.loaded || [], modules: Object.keys(MODS), paths: { root: PATH.root(), public: PATH.public(), private: PATH.private(), tmp: PATH.tmp(), logs: PATH.logs(), databases: PATH.databases() } }); } ``` ## Total.js 5 conventions for coding assistants Source: https://forge.totaljs.es/en/docs/totaljs-agent-conventions/ Framework: total5@0.0.19 Content-SHA256: 4d9019c2c18986abdbd8e9f281dee7d9a66145f9d6206e31f7554777c9412ed4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Use this guide with the [Total.js guidelines](https://github.com/totaljs-es/guidelines) and [Total.js AI Context](https://github.com/totaljs/aicontext). Their reviewed commits are recorded in [ai-sources.json](/ai-sources.json). These are different kinds of evidence: style guidance describes conventions; runtime behavior must agree with the installed framework and an executable example. This page does not certify every example in either external repository. ## Keep application code native After the bootstrap loads `total5`, the runtime exposes its globals and loads application files from the framework directories. Use `MAIN`, `FUNC`, `MODS`, `CONF` and `PATH` according to their documented roles. Prefer an existing framework facility before adding a replacement or dependency. Do not import application controllers and definitions into one another merely to imitate another framework's project layout. Standalone scripts and genuinely external dependencies have a different import boundary. Follow the ecosystem style in new application code: lowercase filenames, tabs, semicolons, short strings in single quotes, and `var` or appropriate `let` bindings inside methods. Imports at module scope can use `const` and capitalized module names. Keep names consistent across the app. For details and exceptions, use the linked guidelines and the actual project conventions. ## Distinguish the APIs and their contexts - A normal HTTP controller receives `$`; send JSON with `$.json()` and set a response status through `$.response.status`. - An action receives its action context `$` and validated `model`; return through `$.callback()`. The HTTP controller, when present, is `$.controller`. - In Total.js 5, `NEWSCHEMA(name, '...')` creates a reusable compact schema. Its callback form groups actions with `schema.action()`. The Total.js 4 `schema.define()` / `schema.setSave()` example must not be presented as an interchangeable Total.js 5 API. - Prefer stable, explicit public action IDs such as `Contacts|create` for new isolated operations. Existing grouped actions may have IDs such as `Contacts/create`; respect the application's declared IDs and routes rather than renaming them blindly. - In API Routing, distinguish authorization on the route from the public operation name and the `{ schema, data }` envelope. Ordinary HTTP routes are also supported; do not force every JSON response through an action. - Treat database integration, authentication policy and authorization as application requirements. Having a framework facility does not mean a production app is configured or secure automatically. AI Context contains examples with both isolated and grouped action conventions. The guidelines repository also includes older schema examples. Reconcile each example with its version and runtime instead of copying every snippet into one context. The executable example below checks a stable action ID and a direct controller using the installed Total.js 5 package. ```js definitions/contacts.js NEWACTION('Contacts|create', { input: '*name:String', action: function($, model) { $.callback({ id: UID(), name: model.name }); } }); ``` ```js controllers/contacts.js exports.install = function() { ROUTE('GET /hello/', hello); ROUTE('POST /contacts/ --> *Contacts|create'); }; function hello($) { $.json({ hello: 'world' }); } ``` ## Before handing generated code to someone Identify the installed framework and frontend versions, read the matching Forge pages, execute the relevant example and state what remains untested. A check of global names is useful feedback but is not a substitute for executing code. Preserve the source revision, input contract and test conditions when publishing examples. [Choosing Total.js](/en/docs/choosing-totaljs/) addresses architecture decisions. The [short context](/ai-context.md) is a starting point for an assistant explicitly given Forge as a source; supplying it is different from measuring a model's spontaneous recommendations. ## The Total.js code style: names, files, CSS, SQL and components Source: https://forge.totaljs.es/en/docs/code-style/ Framework: total5@0.0.19 Content-SHA256: 9b45e867ed7891c7f59107c83e4796d7afde18dd13fc46866b42cc657529f34e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js projects share one style, and that is a strength: open any of them and you know where things are and how they are written. This page collects the conventions of the [Total.js guidelines](https://github.com/totaljs-es/guidelines) (reviewed commit recorded in [ai-sources.json](/ai-sources.json)) in one place. Follow the style of the project you are working in first; these are the defaults for new code. For the framework side, read [Total.js 5 conventions for coding assistants](/en/docs/totaljs-agent-conventions/). ## JavaScript - **Files:** lowercase names, with dashes instead of underscores (`user-profile.js`). - **Layout:** tabs (width 4), no extra whitespace, and a semicolon at the end of every statement. - **Strings:** single quotes for short strings. - **Variables:** use `var` or `let` inside methods, and keep `const` for the top of a module. - **Loops:** a classic `for` loop is preferred over `forEach()` where it fits. - **Dependencies:** keep them to a minimum and follow the code that is already there. ## Names that travel between projects Use the same name for the same thing everywhere, so that code can be moved between projects and read at a glance: | Name | Use | |---|---| | `id`, `name`, `value`, `email` | the usual identifier, name, value and e-mail | | `items` or `arr`, `item` | a list and one of its elements | | `tmp` | a temporary value | | `dtcreated`, `dtupdated` | dates of creation and update | **Schemas** use a plural name that starts with an uppercase letter (`Contacts`), and identifiers are created with `UID()`. ## Using require() At the top of a module use `const`, and start the name of the variable with an uppercase letter: `const Fs = require('fs');`. ## CSS - Lowercase file names with dashes. - Write each style rule on a single line. - Do not write vendor prefixes by hand: add the `/*auto*/` comment and Total.js prefixes the rules for you. - Single quotes, and plain CSS instead of LESS or SASS. ## Plugins and components (jComponent) - Lowercase names for plugins, components and the entries of `FUNC.`, `MAIN.` and `REPO.`, and lowercase variables. - Avoid underscores where you can, and keep the nesting to two or three levels. - A plugin is written with `exports.`; a component uses `self`, `config` and `cls`. - Design for reuse. ## SQL scripts - Lowercase names of tables and fields, tabs for indentation and a semicolon at the end of each statement. - Remove casts that are not needed, format the script, and keep tables, views, procedures or functions and indexes in separate scripts. | Prefix | For | |---|---| | `tbl_` | tables, with the name in the singular | | `cl_` | code lists | | `view_` | views | | `sp_` | stored procedures | | `fn_` | functions | In the fields, `dt` starts a date, `is` starts a boolean, keys follow the pattern `id` or `userid`, and `text` is used instead of `varchar`. Use `id`, `name` and `dtcreated` where they fit, and order the columns as identifiers, main fields, numbers, booleans and dates, with the foreign key constraints at the end. ## Folders Put images in `/img/`, scripts in `/js/`, styles in `/css/`, fonts in `/fonts/` and videos in `/videos/`, and name the files with dashes. ## Why it helps A shared style makes a project easy to hand over, review and extend, and it gives an AI assistant a clear pattern to follow. Give your assistant this page together with the [conventions for coding assistants](/en/docs/totaljs-agent-conventions/) and its code will match the rest of your application. ## Common mistakes with Total.js 5, with wrong and right code Source: https://forge.totaljs.es/en/docs/common-mistakes/ Framework: total5@0.0.19 Content-SHA256: ef77b501ba47487d6d79bce0e811afd7d4e780ec8cafabc06d6559370be80da2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Mistakes that models and people make with Total.js 5, each with the **wrong** code and the **right** code. The pairs are also published as preference data at `/preferences.jsonl`. ## A PATCH that overwrites the fields that were not sent A `PATCH` should change only the fields of the request. By default a field that is declared in `input` but was not sent is filled with the default of its type, and an update would store that empty value. The option `partial: true` keeps only the fields that were sent. ```js controllers/wrong-patch.js NEWACTION('Wrong/patch', { name: 'Patch', input: 'name:String, price:Number', action: function($, model) { $.callback(model); } }); exports.install = function() { ROUTE('PATCH /wrong/patch/ --> *Wrong/patch'); }; ``` ```js controllers/right-patch.js NEWACTION('Right/patch', { name: 'Patch', partial: true, input: 'name:String, price:Number', action: function($, model) { $.callback(model); } }); exports.install = function() { ROUTE('PATCH /right/patch/ --> *Right/patch'); }; ``` ## A flagged route that is never reached Routes with flags are checked after the route without flags on the same URL. If both exist, the route without flags takes every request. Declare one route and decide in the handler. ```js controllers/wrong-route-flags.js exports.install = function() { ROUTE('GET /wrong/flags/', normal); ROUTE('GET /wrong/flags/ @xhr', ajax); }; function normal($) { $.json({ handler: 'normal' }); } function ajax($) { $.json({ handler: 'ajax' }); } ``` ```js controllers/right-route-flags.js exports.install = function() { ROUTE('GET /right/flags/', answer); }; function answer($) { $.json({ handler: $.xhr ? 'ajax' : 'normal' }); } ``` ## A route for a URL with an extension A URL that ends with an extension, such as `/report.csv`, is a file request. A `GET` route does not match it and the request ends with a 404. Declare it with `FILE`. ```js controllers/wrong-extension-url.js exports.install = function() { ROUTE('GET /wrong-report.csv', report); }; function report($) { $.plain('a,b\n1,2\n'); } ``` ```js controllers/right-extension-url.js exports.install = function() { ROUTE('FILE /right-report.csv', report); }; function report($) { $.plain('a,b\n1,2\n'); } ``` ## A CRON line with a step Write the minutes as a list: `0,15,30,45` matches exactly those minutes. The `check(date)` of a job tells whether a date matches, so the schedule can be tested without waiting. ```js controllers/wrong-cron-step.js var job = CRON('*/15 * * * *', function() {}); exports.install = function() { ROUTE('GET /wrong/cron/', function($) { $.json({ minute31: job.check(new Date(2026, 0, 5, 9, 31)) }); }); }; ``` ```js controllers/right-cron-step.js var job = CRON('0,15,30,45 * * * *', function() {}); exports.install = function() { ROUTE('GET /right/cron/', function($) { $.json({ minute31: job.check(new Date(2026, 0, 5, 9, 31)), minute30: job.check(new Date(2026, 0, 5, 9, 30)) }); }); }; ``` ## Expecting the cache option of an action to cache Keep the answer of an action with `CACHE.set()` and read it with `CACHE.get()`. ```js controllers/wrong-action-cache.js var runs = { wrong: 0 }; NEWACTION('Wrong/cached', { name: 'Cached', cache: { expire: '1 minute' }, action: function($) { runs.wrong++; $.callback({ runs: runs.wrong }); } }); exports.install = function() { ROUTE('GET /wrong/cache/ --> *Wrong/cached'); }; ``` ```js controllers/right-action-cache.js var runs = { right: 0 }; NEWACTION('Right/cached', { name: 'Cached', action: function($) { var cached = CACHE.get('right-cached'); if (cached) return $.callback(cached); runs.right++; var value = { runs: runs.right }; CACHE.set('right-cached', value, '1 minute'); $.callback(value); } }); exports.install = function() { ROUTE('GET /right/cache/ --> *Right/cached'); }; ``` ## Code in a folder that is not loaded Total.js runs the files of the folders listed in the project structure page. A file in `sources/` is not run, so code that has to execute at start belongs in `definitions/`. ```js sources/wrong-folder.js (MAIN.started = MAIN.started || []).push('sources'); ``` ```js definitions/right-folder.js (MAIN.started = MAIN.started || []).push('definitions'); ROUTE('GET /started/', function($) { $.json(MAIN.started); }); ``` ## Joining text to PATH.root() `PATH.root()` returns the path without a trailing slash, so `PATH.root() + 'tmp/a.txt'` becomes `/project` + `tmp/a.txt` = `/projecttmp/a.txt`. Each folder has its own helper that adds the separator. ```js controllers/wrong-path.js exports.install = function() { ROUTE('GET /wrong/path/', function($) { $.json({ path: PATH.root() + 'tmp/a.txt' }); }); }; ``` ```js controllers/right-path.js exports.install = function() { ROUTE('GET /right/path/', function($) { $.json({ path: PATH.tmp('a.txt'), root: PATH.root() }); }); }; ``` ## A string sent in a WebSocket route in text mode In a route with `@text` the messages you receive are strings, but `send(message)` still encodes what it sends as JSON, so a string arrives with quotes. `send(message, true)` sends it as it is. ```js controllers/wrong-socket-text.js exports.install = function() { ROUTE('SOCKET /wrong/text/ @text', function() { this.on('message', function(client, message) { client.send('echo: ' + message); }); }); }; ``` ```js controllers/right-socket-text.js exports.install = function() { ROUTE('SOCKET /right/text/ @text', function() { this.on('message', function(client, message) { client.send('echo: ' + message, true); }); }); }; ``` ## Expecting REQUEST() to reject on an error status `REQUEST()` resolves with the answer even when the status is 404 or 500. It rejects only when the request itself fails (connection refused, timeout). Check `response.status`. ```js controllers/wrong-request-status.js exports.install = function() { ROUTE('GET /wrong/request/', async function($) { try { var response = await REQUEST({ url: $.hostname('/missing-page/') }); $.json({ ok: true, body: response.body.length > 0 }); } catch (e) { $.json({ ok: false }); } }); }; ``` ```js controllers/right-request-status.js exports.install = function() { ROUTE('GET /right/request/', async function($) { var response = await REQUEST({ url: $.hostname('/missing-page/') }); $.json({ ok: response.status < 400, status: response.status }); }); }; ``` ```js controllers/where.js exports.install = function() { ROUTE('GET /where/', function($) { $.json({ url: $.hostname('/') }); }); }; ``` ```json pitfalls.json { "patch": { "prompt": "Write a Total.js 5 action for a PATCH route that changes only the fields that were sent.", "why": "Without `partial: true` a field that was not sent is filled with the default of its type (an empty string), and saving the model overwrites the stored value." }, "route-flags": { "prompt": "Write Total.js 5 routes that answer an AJAX request differently from a normal request on the same URL.", "why": "A route without flags on a URL is checked before a route with flags on the same URL and takes every request, so the flagged route is never reached. Use one route and read `$.xhr` in the handler." }, "extension-url": { "prompt": "Write a Total.js 5 route that serves a URL with a file extension, such as /report.csv.", "why": "A `GET` route never matches a URL with an extension; URLs such as `/report.csv` need a `FILE` route." }, "cron-step": { "prompt": "Write a Total.js 5 CRON line that runs every 15 minutes.", "why": "Write the minutes as a list, for example `0,15,30,45`, so that the job runs exactly at those minutes." }, "action-cache": { "prompt": "Write a Total.js 5 action that keeps its answer for a minute so that the same request does not run it again.", "why": "Keep the result of an action yourself with `CACHE`: `CACHE.set()` stores it and `CACHE.get()` reads it." }, "folder": { "prompt": "Where do I put code that must run when a Total.js 5 application starts?", "why": "Total.js loads and runs the files of `definitions/`, `controllers/`, `actions/`, `schemas/`, `models/`, `modules/`, `extensions/` and `middleware/`. A file in `sources/`, `scripts/` or `transforms/` is not run." }, "path": { "prompt": "Write Total.js 5 code that builds the path of a file in the tmp folder.", "why": "`PATH.root()` has no trailing slash, so joining text to it glues the names together. Use the helper of the folder: `PATH.tmp(name)`." }, "socket-text": { "prompt": "Write a Total.js 5 WebSocket route in @text mode that answers with a plain string.", "why": "In a text route `send(message)` still encodes what it sends as JSON, so the string arrives with quotes. Pass `true` as the second argument to send it as it is." }, "request-status": { "prompt": "Write Total.js 5 code that calls another server with REQUEST() and handles an error answer such as 404.", "why": "REQUEST() resolves with the answer even when the status is an error such as 404; it only rejects when the request itself fails. Check `response.status`." } } ``` ## Taskboard reference application with sessions, ownership and persistent tasks Source: https://forge.totaljs.es/en/docs/taskboard-reference/ Framework: total5@0.0.19 Content-SHA256: 3df6e96cca071a32fe2dc9ef7355950a1813f988bc767a5190d9aa6f75ae363f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded This reference joins the pieces of a business application: an anonymous visitor opens the interface, signs in, creates tasks, marks them done and signs out. Members see only their own tasks; an administrator can list and delete any task. The server owns every authorization decision, independently of which buttons the browser displays. The application uses native Total.js routes, actions, schemas, session auth and embedded NoSQL. Passwords use Node's scrypt through `Total.Crypto`. The interface uses ordinary browser forms and DOM text nodes; no other frontend framework or runtime dependency is required. Direct controllers handle session transport; reusable task actions use stable `Namespace|action` identifiers. ## Run the complete example Copy the named files below into a new directory, add `total5@0.0.19` to package.json and bootstrap with `require('total5'); Total.run({ ip: '127.0.0.1', port: 18400, release: false, watcher: false });`. Open localhost:18400. Use a separate directory and port from Forge. The repository's export tool can also materialize this exact example as a project. `demo: true` permits the three local users `alice`, `bob` and `admin`, with passwords `alice-demo-password`, `bob-demo-password` and `admin-demo-password`. Demo mode refuses to start when `--release` or `NODE_ENV=production` is supplied. Keep its listener bound to loopback. The framework sets `DEBUG=false` with `watcher:false` even when `release:false` is supplied; this example therefore does not use `DEBUG` as the demo guard. For release, set `demo: false`, provide `TASKBOARD_SECRET` (at least 32 characters) and `TASKBOARD_ALICE_PASSWORD`, `TASKBOARD_BOB_PASSWORD`, `TASKBOARD_ADMIN_PASSWORD` (each at least 12 characters). The fixed demo credentials must not be used for a public deployment. The users are a deliberately small fixed directory; sessions and tasks persist in `databases/`. A stable secret lets a valid session be reloaded after restart. Logout waits for the session-store removal callback before returning success. Do not share that directory between running instances, erase it on deployment or put it in git. A public deployment also needs HTTPS, a trusted reverse proxy, backups and a real user-provisioning policy. This is an executable reference, not a complete identity-management product. ## Server files ```text config name : Taskboard reference demo : true ``` ```js definitions/taskboard.js var crypto = Total.Crypto; var demo = CONF.demo === true; if (demo && (process.argv.includes('--release') || process.env.NODE_ENV === 'production')) throw new Error('Disable demo mode before a release deployment'); var secret = process.env.TASKBOARD_SECRET || (demo ? 'local-taskboard-demo-secret-not-for-public-use' : ''); if (secret.length < 32) throw new Error('TASKBOARD_SECRET needs at least 32 characters'); CONF.secret_csrf = secret; MAIN.taskUsers = Object.create(null); for (var name of ['alice', 'bob', 'admin']) { var password = process.env['TASKBOARD_' + name.toUpperCase() + '_PASSWORD'] || (demo ? name + '-demo-password' : ''); if (password.length < 12) throw new Error('Configure a password of at least 12 characters for ' + name); var salt = crypto.randomBytes(16).toString('hex'); MAIN.taskUsers[name] = { id: name, name: name, role: name === 'admin' ? 'admin' : 'member', salt: salt, hash: crypto.scryptSync(password, salt, 32) }; } MAIN.taskAuth = { secret: secret, cookie: 'taskboard_session', expire: '30 minutes', options: { httponly: true, samesite: 'Strict', secure: !demo }, onread: function(meta, next) { NOSQL('task-sessions').read().where('id', meta.sessionid).callback(function(err, session) { var user = !err && session && session.expire > Date.now() && MAIN.taskUsers[session.userid]; user ? next(null, { id: user.id, name: user.name, role: user.role }) : next('Session not found'); }); }, onlogout: function(session) { NOSQL('task-sessions').remove().where('id', session.sessionid).callback(NOOP); }, onremove: function(id) { NOSQL('task-sessions').remove().where('id', id).callback(NOOP); } }; AUTH(MAIN.taskAuth); MIDDLEWARE('taskcsrf', function($, next) { DEF.onCSRFcheck($) ? next() : $.invalid(403); }); ``` ```js actions/tasks.js function owned(builder, user) { return user.role === 'admin' ? builder : builder.where('owner', user.id); } NEWACTION('Tasks|list', { user: true, action: function($) { owned(NOSQL('tasks').find(), $.user).sort('title').callback(function(err, tasks) { err ? $.invalid(500) : $.callback(tasks); }); } }); NEWACTION('Tasks|read', { user: true, params: '*id:UID', action: function($) { owned(NOSQL('tasks').read().where('id', $.params.id), $.user).callback(function(err, task) { if (err) return $.invalid(500); task ? $.callback(task) : $.invalid(404); }); } }); NEWACTION('Tasks|create', { user: true, input: '*title:String(80)', action: function($, model) { var task = { id: UID(), title: model.title, done: false, owner: $.user.id }; NOSQL('tasks').insert(task).callback(function(err) { err ? $.invalid(500) : $.callback(task); }); } }); NEWACTION('Tasks|update', { user: true, params: '*id:UID', input: '*done:Boolean', action: function($, model) { owned(NOSQL('tasks').update({ done: model.done }).where('id', $.params.id), $.user).callback(function(err, count) { if (err) return $.invalid(500); count ? $.success() : $.invalid(404); }); } }); NEWACTION('Tasks|remove', { user: true, params: '*id:UID', action: function($) { if ($.user.role !== 'admin') return $.invalid(403); NOSQL('tasks').remove().where('id', $.params.id).callback(function(err, count) { if (err) return $.invalid(500); count ? $.success() : $.invalid(404); }); } }); ``` ```js controllers/taskboard.js var attempts = Object.create(null); exports.install = function() { ROUTE('GET /', function($) { $.file(PATH.public('index.html')); }); ROUTE('GET /session/', session); ROUTE('POST /login/ @json <2kb #taskcsrf', login); ROUTE('+POST /logout/ @json #taskcsrf', logout); ROUTE('+GET /tasks/ --> *Tasks|list'); ROUTE('+GET /tasks/{id}/ --> *Tasks|read'); ROUTE('+POST /tasks/ <2kb #taskcsrf --> *Tasks|create'); ROUTE('+PATCH /tasks/{id}/ <2kb #taskcsrf --> *Tasks|update'); ROUTE('+DELETE /tasks/{id}/ #taskcsrf --> *Tasks|remove'); }; function session($) { $.response.headers['cache-control'] = 'no-store'; $.json({ user: $.user || null, csrf: $.csrf() }); } function login($) { var key = $.ip; var recent = (attempts[key] || []).filter(time => time > Date.now() - 600000); attempts[key] = recent; if (recent.length >= 5) return $.invalid(429); var user = MAIN.taskUsers[String($.body.name || '').toLowerCase()]; var salt = user ? user.salt : 'dummy-salt'; var actual = Total.Crypto.scryptSync(String($.body.password || ''), salt, 32); var valid = user && Total.Crypto.timingSafeEqual(actual, user.hash); if (!valid) { recent.push(Date.now()); return $.invalid(401); } var id = UID(); NOSQL('task-sessions').insert({ id: id, userid: user.id, expire: Date.now() + 1800000 }).callback(function(err) { if (err) return $.invalid(500); MAIN.taskAuth.authcookie($, id, user.id, '30 minutes'); $.json({ user: { id: user.id, name: user.name, role: user.role }, csrf: $.csrf() }); }); } function logout($) { NOSQL('task-sessions').remove().where('id', $.sessionid).callback(function(err) { if (err) return $.invalid(500); MAIN.taskAuth.logout($); $.cookie(MAIN.taskAuth.cookie, '', '-1 year', MAIN.taskAuth.options); $.json({ ok: true }); }); } ``` ```html public/index.html Taskboard · Total.js

Taskboard

Total.js reference

A small workspace with private tasks and a shared administrator view.

Sign in

``` ```js public/app.js (function() { var user = null; var csrf = ''; var busy = false; var byid = id => document.getElementById(id); async function request(path, method, body) { var response = await fetch(path, { method: method || 'GET', credentials: 'same-origin', headers: { 'content-type': 'application/json', 'x-csrf-token': csrf }, body: body === undefined ? undefined : JSON.stringify(body) }); var data = await response.json().catch(() => null); if (!response.ok) { if (response.status === 401) { user = null; show(); } throw new Error('Request refused (' + response.status + ')'); } if (data === null) throw new Error('Unexpected server response'); return data; } function show() { byid('login').hidden = !!user; byid('workspace').hidden = !user; byid('identity').textContent = user ? user.name + ' · ' + user.role : ''; } async function load() { var tasks = await request('/tasks/'); byid('tasks').replaceChildren(); byid('empty').hidden = tasks.length > 0; tasks.forEach(function(task) { var row = document.createElement('li'); var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = task.done; checkbox.setAttribute('aria-label', 'Complete ' + task.title); checkbox.addEventListener('change', () => work(async () => { await request('/tasks/' + task.id + '/', 'PATCH', { done: checkbox.checked }); await load(); })); var title = document.createElement('span'); title.className = 'task-title'; title.textContent = task.title; row.append(checkbox, title); if (user.role === 'admin') { var remove = document.createElement('button'); remove.type = 'button'; remove.textContent = 'Delete'; remove.addEventListener('click', () => work(async () => { await request('/tasks/' + task.id + '/', 'DELETE'); await load(); })); row.append(remove); } byid('tasks').append(row); }); } async function work(fn) { if (busy) return; busy = true; byid('message').textContent = ''; document.querySelectorAll('input,button').forEach(control => control.disabled = true); try { await fn(); } catch (err) { byid('message').textContent = err.message; } finally { busy = false; document.querySelectorAll('input,button').forEach(control => control.disabled = false); } } byid('login').addEventListener('submit', function(event) { event.preventDefault(); work(async function() { var result = await request('/login/', 'POST', { name: byid('name').value, password: byid('password').value }); user = result.user; csrf = result.csrf; byid('password').value = ''; show(); await load(); }); }); byid('create').addEventListener('submit', function(event) { event.preventDefault(); work(async function() { await request('/tasks/', 'POST', { title: byid('title').value }); byid('title').value = ''; await load(); }); }); byid('logout').addEventListener('click', () => work(async function() { await request('/logout/', 'POST', {}); user = null; byid('tasks').replaceChildren(); show(); })); work(async function() { var result = await request('/session/'); user = result.user; csrf = result.csrf; show(); if (user) await load(); }); })(); ``` ## What is exercised and what remains File attachments and realtime updates continue in [Taskboard Live](/en/docs/taskboard-live/). Registration, password reset, multiple application instances and a SQL driver are follow-up examples with their own contracts, not implied features of this app. Related recipes: [session auth](/en/total5/sessions-with-built-in-auth/), [CSRF](/en/total5/csrf-protection/), [CRUD actions](/en/total5/actions-crud/) and [WebSocket](/en/total5/websocket-chat/). ## Taskboard Live: realtime updates and file attachments with sessions Source: https://forge.totaljs.es/en/docs/taskboard-live/ Framework: total5@0.0.19 Content-SHA256: 85e51cdc38974e26afe30a84dcf75b118da5711946e5cb061c205315d4675c65 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded This guide takes the [Taskboard reference](/en/docs/taskboard-reference/) one step further. Tasks now accept **file attachments**, and an **authenticated WebSocket** pushes every change to the people who are allowed to see it: the owner of the task and the administrators. The page updates by itself, with no refresh. Everything is native Total.js: the session authentication of the first guide, `@upload` routes, `FILESTORAGE` for the files, a `SOCKET` route that requires a signed-in user and embedded NoSQL for the metadata. The server decides who sees what: a member never receives the events or the files of another member, whatever the browser asks for. The files below are complete, so copy them into a new directory exactly as in the first guide (`demo: true`, the three local users, `total5@0.0.19`, loopback only). The demo rules of that guide apply here too. ## Server files ```text config name : Taskboard Live demo : true fs : taskboard-files ``` ```js definitions/taskboard.js var crypto = Total.Crypto; var demo = CONF.demo === true; if (demo && (process.argv.includes('--release') || process.env.NODE_ENV === 'production')) throw new Error('Disable demo mode before a release deployment'); var secret = process.env.TASKBOARD_SECRET || (demo ? 'local-taskboard-demo-secret-not-for-public-use' : ''); if (secret.length < 32) throw new Error('TASKBOARD_SECRET needs at least 32 characters'); CONF.secret_csrf = secret; MAIN.taskUsers = Object.create(null); for (var name of ['alice', 'bob', 'admin']) { var password = process.env['TASKBOARD_' + name.toUpperCase() + '_PASSWORD'] || (demo ? name + '-demo-password' : ''); if (password.length < 12) throw new Error('Configure a password of at least 12 characters for ' + name); var salt = crypto.randomBytes(16).toString('hex'); MAIN.taskUsers[name] = { id: name, name: name, role: name === 'admin' ? 'admin' : 'member', salt: salt, hash: crypto.scryptSync(password, salt, 32) }; } MAIN.taskAuth = { secret: secret, cookie: 'taskboard_session', expire: '30 minutes', options: { httponly: true, samesite: 'Strict', secure: !demo }, onread: function(meta, next) { NOSQL('task-sessions').read().where('id', meta.sessionid).callback(function(err, session) { var user = !err && session && session.expire > Date.now() && MAIN.taskUsers[session.userid]; user ? next(null, { id: user.id, name: user.name, role: user.role }) : next('Session not found'); }); }, onlogout: function(session) { NOSQL('task-sessions').remove().where('id', session.sessionid).callback(NOOP); }, onremove: function(id) { NOSQL('task-sessions').remove().where('id', id).callback(NOOP); } }; AUTH(MAIN.taskAuth); MIDDLEWARE('taskcsrf', function($, next) { DEF.onCSRFcheck($) ? next() : $.invalid(403); }); // Sends an event to the sockets of the owner of a task and to the administrators only MAIN.live = function(owner, event) { MAIN.liveSocket && MAIN.liveSocket.send(event, function(client) { return client.user.role === 'admin' || client.user.id === owner; }); }; ``` ```js actions/tasks.js function owned(builder, user) { return user.role === 'admin' ? builder : builder.where('owner', user.id); } NEWACTION('Tasks|list', { user: true, action: function($) { owned(NOSQL('tasks').find(), $.user).sort('title').callback(function(err, tasks) { err ? $.invalid(500) : $.callback(tasks); }); } }); NEWACTION('Tasks|create', { user: true, input: '*title:String(80)', action: function($, model) { var task = { id: UID(), title: model.title, done: false, owner: $.user.id }; NOSQL('tasks').insert(task).callback(function(err) { if (err) return $.invalid(500); MAIN.live(task.owner, { type: 'task', id: task.id }); $.callback(task); }); } }); NEWACTION('Tasks|update', { user: true, params: '*id:UID', input: '*done:Boolean', action: function($, model) { owned(NOSQL('tasks').update({ done: model.done }).where('id', $.params.id), $.user).callback(function(err, count) { if (err) return $.invalid(500); if (!count) return $.invalid(404); NOSQL('tasks').read().where('id', $.params.id).callback(function(err, task) { task && MAIN.live(task.owner, { type: 'task', id: task.id }); $.success(); }); }); } }); NEWACTION('Tasks|remove', { user: true, params: '*id:UID', action: function($) { if ($.user.role !== 'admin') return $.invalid(403); NOSQL('tasks').read().where('id', $.params.id).callback(function(err, task) { if (err) return $.invalid(500); if (!task) return $.invalid(404); // The attachments of the task go away with it NOSQL('attachments').find().where('taskid', task.id).callback(function(err, files) { (files || []).forEach(file => FILESTORAGE(CONF.fs).remove(file.id, NOOP)); NOSQL('attachments').remove().where('taskid', task.id).callback(NOOP); NOSQL('tasks').remove().where('id', task.id).callback(function(err) { if (err) return $.invalid(500); MAIN.live(task.owner, { type: 'task', id: task.id }); $.success(); }); }); }); } }); ``` ```js controllers/taskboard.js var attempts = Object.create(null); var allowed = ['text/plain', 'image/png', 'application/pdf']; exports.install = function() { ROUTE('GET /', function($) { $.file(PATH.public('index.html')); }); ROUTE('GET /session/', session); ROUTE('POST /login/ @json <2kb #taskcsrf', login); ROUTE('+POST /logout/ @json #taskcsrf', logout); ROUTE('+GET /tasks/ --> *Tasks|list'); ROUTE('+POST /tasks/ <2kb #taskcsrf --> *Tasks|create'); ROUTE('+PATCH /tasks/{id}/ <2kb #taskcsrf --> *Tasks|update'); ROUTE('+DELETE /tasks/{id}/ #taskcsrf --> *Tasks|remove'); ROUTE('+GET /tasks/{id}/files/', files); ROUTE('+POST /tasks/{id}/files/ @upload <1mb #taskcsrf', attach); ROUTE('+GET /tasks/{id}/files/{fileid}/', download); ROUTE('+SOCKET /live/', live); }; // The task must be visible to the user: members only reach their own tasks function visible($, next) { var builder = NOSQL('tasks').read().where('id', $.params.id); if ($.user.role !== 'admin') builder.where('owner', $.user.id); builder.callback(function(err, task) { if (err) return $.invalid(500); task ? next(task) : $.invalid(404); }); } function files($) { visible($, function(task) { NOSQL('attachments').find().where('taskid', task.id).sort('filename').fields('id,filename,size,type').callback(function(err, items) { err ? $.invalid(500) : $.json(items); }); }); } function attach($) { var file = $.files[0]; if (!file || !allowed.includes(file.type)) return $.invalid(400); visible($, function(task) { var id = UID(); file.fs(CONF.fs, id, function(err) { if (err) return $.invalid(500); var meta = { id: id, taskid: task.id, filename: file.filename, size: file.size, type: file.type }; NOSQL('attachments').insert(meta).callback(function(err) { if (err) return $.invalid(500); MAIN.live(task.owner, { type: 'attachment', id: task.id }); $.json({ id: id, filename: meta.filename, size: meta.size, type: meta.type }); }); }); }); } function download($) { visible($, function(task) { NOSQL('attachments').read().where('id', $.params.fileid).where('taskid', task.id).callback(function(err, meta) { if (err || !meta) return $.invalid(404); $.response.headers['x-content-type-options'] = 'nosniff'; $.filefs(CONF.fs, meta.id, true); }); }); } // Only a signed-in user reaches this route; the sockets are kept to send events to them function live() { MAIN.liveSocket = this; } function session($) { $.response.headers['cache-control'] = 'no-store'; $.json({ user: $.user || null, csrf: $.csrf() }); } function login($) { var key = $.ip; var recent = (attempts[key] || []).filter(time => time > Date.now() - 600000); attempts[key] = recent; if (recent.length >= 5) return $.invalid(429); var user = MAIN.taskUsers[String($.body.name || '').toLowerCase()]; var salt = user ? user.salt : 'dummy-salt'; var actual = Total.Crypto.scryptSync(String($.body.password || ''), salt, 32); var valid = user && Total.Crypto.timingSafeEqual(actual, user.hash); if (!valid) { recent.push(Date.now()); return $.invalid(401); } var id = UID(); NOSQL('task-sessions').insert({ id: id, userid: user.id, expire: Date.now() + 1800000 }).callback(function(err) { if (err) return $.invalid(500); MAIN.taskAuth.authcookie($, id, user.id, '30 minutes'); $.json({ user: { id: user.id, name: user.name, role: user.role }, csrf: $.csrf() }); }); } function logout($) { NOSQL('task-sessions').remove().where('id', $.sessionid).callback(function(err) { if (err) return $.invalid(500); MAIN.taskAuth.logout($); $.cookie(MAIN.taskAuth.cookie, '', '-1 year', MAIN.taskAuth.options); $.json({ ok: true }); }); } ``` ```html public/index.html Taskboard Live · Total.js

Taskboard Live

Total.js reference

Private tasks with attachments, updated live for the people who may see them.

Sign in

``` ```js public/app.js (function() { var user = null; var csrf = ''; var busy = false; var socket = null; var byid = id => document.getElementById(id); async function request(path, method, body) { var form = body instanceof FormData; var headers = { 'x-csrf-token': csrf }; if (!form) headers['content-type'] = 'application/json'; var response = await fetch(path, { method: method || 'GET', credentials: 'same-origin', headers: headers, body: body === undefined ? undefined : form ? body : JSON.stringify(body) }); var data = await response.json().catch(() => null); if (!response.ok) { if (response.status === 401) { user = null; show(); } throw new Error('Request refused (' + response.status + ')'); } if (data === null) throw new Error('Unexpected server response'); return data; } function show() { byid('login').hidden = !!user; byid('workspace').hidden = !user; byid('identity').textContent = user ? user.name + ' · ' + user.role : ''; if (!user && socket) { socket.close(); socket = null; byid('live').hidden = true; } } // The server pushes an event whenever something the user may see changes function connect() { if (socket) return; socket = new WebSocket((location.protocol === 'https:' ? 'wss://' : 'ws://') + location.host + '/live/'); socket.onopen = () => { byid('live').hidden = false; }; socket.onclose = () => { byid('live').hidden = true; socket = null; }; socket.onmessage = () => { if (user && !busy) load().catch(err => byid('message').textContent = err.message); }; } async function load() { var tasks = await request('/tasks/'); var lists = await Promise.all(tasks.map(task => request('/tasks/' + task.id + '/files/'))); byid('tasks').replaceChildren(); byid('empty').hidden = tasks.length > 0; tasks.forEach(function(task, index) { var row = document.createElement('li'); row.className = 'task'; var line = document.createElement('div'); line.className = 'row'; var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = task.done; checkbox.setAttribute('aria-label', 'Complete ' + task.title); checkbox.addEventListener('change', () => work(async () => { await request('/tasks/' + task.id + '/', 'PATCH', { done: checkbox.checked }); await load(); })); var title = document.createElement('span'); title.className = 'task-title'; title.textContent = task.title; var upload = document.createElement('input'); upload.type = 'file'; upload.accept = '.txt,.png,.pdf'; upload.setAttribute('aria-label', 'Attach a file to ' + task.title); upload.addEventListener('change', () => work(async () => { var form = new FormData(); form.append('file', upload.files[0]); await request('/tasks/' + task.id + '/files/', 'POST', form); await load(); })); line.append(checkbox, title, upload); if (user.role === 'admin') { var remove = document.createElement('button'); remove.type = 'button'; remove.textContent = 'Delete'; remove.addEventListener('click', () => work(async () => { await request('/tasks/' + task.id + '/', 'DELETE'); await load(); })); line.append(remove); } row.append(line); var list = document.createElement('ul'); list.className = 'files'; lists[index].forEach(function(file) { var item = document.createElement('li'); var link = document.createElement('a'); link.href = '/tasks/' + task.id + '/files/' + file.id + '/'; link.textContent = file.filename; item.append(link, ' (' + file.size + ' bytes)'); list.append(item); }); row.append(list); byid('tasks').append(row); }); } async function work(fn) { if (busy) return; busy = true; byid('message').textContent = ''; document.querySelectorAll('input,button').forEach(control => control.disabled = true); try { await fn(); } catch (err) { byid('message').textContent = err.message; } finally { busy = false; document.querySelectorAll('input,button').forEach(control => control.disabled = false); } } byid('login').addEventListener('submit', function(event) { event.preventDefault(); work(async function() { var result = await request('/login/', 'POST', { name: byid('name').value, password: byid('password').value }); user = result.user; csrf = result.csrf; byid('password').value = ''; show(); connect(); await load(); }); }); byid('create').addEventListener('submit', function(event) { event.preventDefault(); work(async function() { await request('/tasks/', 'POST', { title: byid('title').value }); byid('title').value = ''; await load(); }); }); byid('logout').addEventListener('click', () => work(async function() { await request('/logout/', 'POST', {}); user = null; byid('tasks').replaceChildren(); show(); })); work(async function() { var result = await request('/session/'); user = result.user; csrf = result.csrf; show(); if (user) { connect(); await load(); } }); })(); ``` ## What is exercised The application applies these access and update rules: - an anonymous socket is refused and the sockets of the owner and of the administrator receive a task event while the socket of another member receives nothing, - an attachment is accepted only from a user who can see the task, only with a valid CSRF token and only for the allowed types, and files over the limit are refused, - the owner and the administrator download the file with the right headers while another member gets a 404, - an administrator deleting the task removes its attachments too. Connected pages receive task updates through the socket without reloading. Related recipes: [WebSocket flags](/en/total5/websocket-flags/), [file storage](/en/total5/filestorage/), [uploads](/en/total5/file-upload/) and [CSRF](/en/total5/csrf-protection/). ## Taskboard SQL: the same application on SQLite with real SQL and a transaction Source: https://forge.totaljs.es/en/docs/taskboard-sql/ Framework: total5@0.0.19 Content-SHA256: f7854552a20542f41a5fcfd23639a80cba171181b0cd8c142bcb5a0a132843df Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded This guide moves the [Taskboard reference](/en/docs/taskboard-reference/) from embedded NoSQL to **real SQL**. The sessions, the three users, the CSRF protection and the owner rules stay the same. The tasks now live in a SQLite file, and the application talks to them through the native `DB()` QueryBuilder with a small driver that the application owns, exactly as in the [SQLite recipe](/en/total5/query-builder-sqlite/). The new piece is a **transaction**: *Archive completed* copies the completed tasks to an archive table and deletes them from the task table in one atomic step, so a task is never in both places or in neither. Everything is bound parameters and allowlists; no value from a request is ever put into the SQL text. SQLite comes from Node itself (`node:sqlite`, tested here with Node 24), so there is no npm dependency. The driver is synchronous, which is fine for a small application and for this reference; a busy production service would use an asynchronous driver for its database server and the same QueryBuilder calls. Copy the files into a new directory as in the first guide (`demo: true`, the three local users, `total5@0.0.19`, loopback only); delete `taskboard.sqlite` to start from an empty database. ## Server files ```text config name : Taskboard SQL demo : true ``` ```js definitions/taskboard.js var crypto = Total.Crypto; var demo = CONF.demo === true; if (demo && (process.argv.includes('--release') || process.env.NODE_ENV === 'production')) throw new Error('Disable demo mode before a release deployment'); var secret = process.env.TASKBOARD_SECRET || (demo ? 'local-taskboard-demo-secret-not-for-public-use' : ''); if (secret.length < 32) throw new Error('TASKBOARD_SECRET needs at least 32 characters'); CONF.secret_csrf = secret; MAIN.taskUsers = Object.create(null); for (var name of ['alice', 'bob', 'admin']) { var password = process.env['TASKBOARD_' + name.toUpperCase() + '_PASSWORD'] || (demo ? name + '-demo-password' : ''); if (password.length < 12) throw new Error('Configure a password of at least 12 characters for ' + name); var salt = crypto.randomBytes(16).toString('hex'); MAIN.taskUsers[name] = { id: name, name: name, role: name === 'admin' ? 'admin' : 'member', salt: salt, hash: crypto.scryptSync(password, salt, 32) }; } MAIN.taskAuth = { secret: secret, cookie: 'taskboard_session', expire: '30 minutes', options: { httponly: true, samesite: 'Strict', secure: !demo }, onread: function(meta, next) { NOSQL('task-sessions').read().where('id', meta.sessionid).callback(function(err, session) { var user = !err && session && session.expire > Date.now() && MAIN.taskUsers[session.userid]; user ? next(null, { id: user.id, name: user.name, role: user.role }) : next('Session not found'); }); }, onlogout: function(session) { NOSQL('task-sessions').remove().where('id', session.sessionid).callback(NOOP); }, onremove: function(id) { NOSQL('task-sessions').remove().where('id', id).callback(NOOP); } }; AUTH(MAIN.taskAuth); MIDDLEWARE('taskcsrf', function($, next) { DEF.onCSRFcheck($) ? next() : $.invalid(403); }); ``` ```js definitions/sqlite.js var DatabaseSync = require('node:sqlite').DatabaseSync; var db = new DatabaseSync(PATH.root('taskboard.sqlite')); db.exec('CREATE TABLE IF NOT EXISTS tasks (id TEXT PRIMARY KEY, title TEXT NOT NULL CHECK(length(title) BETWEEN 1 AND 80), done INTEGER NOT NULL DEFAULT 0 CHECK(done IN (0, 1)), owner TEXT NOT NULL, created INTEGER NOT NULL) STRICT'); db.exec('CREATE TABLE IF NOT EXISTS task_archive (id TEXT PRIMARY KEY, title TEXT NOT NULL, owner TEXT NOT NULL, created INTEGER NOT NULL, archived INTEGER NOT NULL) STRICT'); var COLUMNS = ['id', 'title', 'done', 'owner', 'created']; function column(name) { if (!COLUMNS.includes(name)) throw new Error('Column not allowed'); return '"' + name + '"'; } function where(options, params) { var filters = options.filter.map(function(f) { if (f.type !== 'where' || f.comparer !== '=') throw new Error('Filter not supported'); params.push(f.name === 'done' ? (f.value ? 1 : 0) : f.value); return column(f.name) + ' = ?'; }); return filters.length ? ' WHERE ' + filters.join(' AND ') : ''; } function row(item) { item.done = item.done === 1; return item; } // The only table the QueryBuilder can reach is tasks; values are always bound parameters NEWDB('sqlite', function(options, callback) { try { if (options.table !== 'tasks') throw new Error('Table not allowed'); var params = []; var condition = where(options, params); var result; if (['find', 'read'].includes(options.exec)) { var sort = (options.sort || ['created_asc']).map(function(s) { var match = /^(title|created)_(asc|desc)$/.exec(s); if (!match) throw new Error('Sort not allowed'); return column(match[1]) + ' ' + match[2]; }).join(','); var rows = db.prepare('SELECT id, title, done, owner, created FROM tasks' + condition + ' ORDER BY ' + sort + ' LIMIT 200').all(...params).map(row); result = options.exec === 'read' ? rows[0] || null : rows; } else if (options.exec === 'insert') { var p = options.payload; db.prepare('INSERT INTO tasks (id, title, done, owner, created) VALUES (?, ?, ?, ?, ?)').run(p.id, p.title, p.done ? 1 : 0, p.owner, p.created); result = { id: p.id }; } else if (options.exec === 'update') { if (!condition) throw new Error('Filter required'); var keys = Object.keys(options.payload); var set = keys.map(key => column(key) + ' = ?').join(','); result = db.prepare('UPDATE tasks SET ' + set + condition).run(...keys.map(key => key === 'done' ? (options.payload[key] ? 1 : 0) : options.payload[key]), ...params).changes; } else if (options.exec === 'remove') { if (!condition) throw new Error('Filter required'); result = db.prepare('DELETE FROM tasks' + condition).run(...params).changes; } else throw new Error('Operation not supported'); callback(null, result); } catch (e) { callback(e); } }); // One atomic step: the completed tasks (of one owner, or of everybody for the administrator) move to the archive. // Either both statements are applied or none is. MAIN.archiveTasks = function(owner) { var params = owner ? [owner] : []; var filter = owner ? ' AND owner = ?' : ''; db.exec('BEGIN IMMEDIATE'); try { db.prepare('INSERT INTO task_archive (id, title, owner, created, archived) SELECT id, title, owner, created, ? FROM tasks WHERE done = 1' + filter).run(Date.now(), ...params); var moved = db.prepare('DELETE FROM tasks WHERE done = 1' + filter).run(...params).changes; db.exec('COMMIT'); return moved; } catch (e) { db.exec('ROLLBACK'); throw e; } }; MAIN.archivedTasks = function(owner) { var filter = owner ? ' WHERE owner = ?' : ''; return db.prepare('SELECT id, title, owner FROM task_archive' + filter + ' ORDER BY archived DESC, id LIMIT 200').all(...(owner ? [owner] : [])); }; ``` ```js actions/tasks.js function owned(builder, user) { return user.role === 'admin' ? builder : builder.where('owner', user.id); } NEWACTION('Tasks|list', { user: true, action: function($) { owned(DB().find('sqlite/tasks').sort('title'), $.user).callback(function(err, tasks) { err ? $.invalid(500) : $.callback(tasks); }); } }); NEWACTION('Tasks|create', { user: true, input: '*title:String(80)', action: function($, model) { var task = { id: UID(), title: model.title, done: false, owner: $.user.id, created: Date.now() }; DB().insert('sqlite/tasks', task).callback(function(err) { err ? $.invalid(500) : $.callback(task); }); } }); NEWACTION('Tasks|update', { user: true, params: '*id:UID', input: '*done:Boolean', action: function($, model) { owned(DB().update('sqlite/tasks', { done: model.done }).id($.params.id), $.user).callback(function(err, count) { if (err) return $.invalid(500); count ? $.success() : $.invalid(404); }); } }); NEWACTION('Tasks|remove', { user: true, params: '*id:UID', action: function($) { if ($.user.role !== 'admin') return $.invalid(403); DB().remove('sqlite/tasks').id($.params.id).callback(function(err, count) { if (err) return $.invalid(500); count ? $.success() : $.invalid(404); }); } }); NEWACTION('Tasks|archive', { user: true, action: function($) { try { $.callback({ moved: MAIN.archiveTasks($.user.role === 'admin' ? null : $.user.id) }); } catch (e) { $.invalid(500); } } }); NEWACTION('Tasks|archived', { user: true, action: function($) { $.callback(MAIN.archivedTasks($.user.role === 'admin' ? null : $.user.id)); } }); ``` ```js controllers/taskboard.js var attempts = Object.create(null); exports.install = function() { ROUTE('GET /', function($) { $.file(PATH.public('index.html')); }); ROUTE('GET /session/', session); ROUTE('POST /login/ @json <2kb #taskcsrf', login); ROUTE('+POST /logout/ @json #taskcsrf', logout); ROUTE('+GET /tasks/ --> *Tasks|list'); ROUTE('+POST /tasks/ <2kb #taskcsrf --> *Tasks|create'); ROUTE('+PATCH /tasks/{id}/ <2kb #taskcsrf --> *Tasks|update'); ROUTE('+DELETE /tasks/{id}/ #taskcsrf --> *Tasks|remove'); ROUTE('+POST /archive/ #taskcsrf --> *Tasks|archive'); ROUTE('+GET /archive/ --> *Tasks|archived'); }; function session($) { $.response.headers['cache-control'] = 'no-store'; $.json({ user: $.user || null, csrf: $.csrf() }); } function login($) { var key = $.ip; var recent = (attempts[key] || []).filter(time => time > Date.now() - 600000); attempts[key] = recent; if (recent.length >= 5) return $.invalid(429); var user = MAIN.taskUsers[String($.body.name || '').toLowerCase()]; var salt = user ? user.salt : 'dummy-salt'; var actual = Total.Crypto.scryptSync(String($.body.password || ''), salt, 32); var valid = user && Total.Crypto.timingSafeEqual(actual, user.hash); if (!valid) { recent.push(Date.now()); return $.invalid(401); } var id = UID(); NOSQL('task-sessions').insert({ id: id, userid: user.id, expire: Date.now() + 1800000 }).callback(function(err) { if (err) return $.invalid(500); MAIN.taskAuth.authcookie($, id, user.id, '30 minutes'); $.json({ user: { id: user.id, name: user.name, role: user.role }, csrf: $.csrf() }); }); } function logout($) { NOSQL('task-sessions').remove().where('id', $.sessionid).callback(function(err) { if (err) return $.invalid(500); MAIN.taskAuth.logout($); $.cookie(MAIN.taskAuth.cookie, '', '-1 year', MAIN.taskAuth.options); $.json({ ok: true }); }); } ``` ```html public/index.html Taskboard SQL · Total.js

Taskboard SQL

Total.js reference

Private tasks stored in SQLite, with an atomic archive of the completed ones.

Sign in

``` ```js public/app.js (function() { var user = null; var csrf = ''; var busy = false; var byid = id => document.getElementById(id); async function request(path, method, body) { var response = await fetch(path, { method: method || 'GET', credentials: 'same-origin', headers: { 'content-type': 'application/json', 'x-csrf-token': csrf }, body: body === undefined ? undefined : JSON.stringify(body) }); var data = await response.json().catch(() => null); if (!response.ok) { if (response.status === 401) { user = null; show(); } throw new Error('Request refused (' + response.status + ')'); } if (data === null) throw new Error('Unexpected server response'); return data; } function show() { byid('login').hidden = !!user; byid('workspace').hidden = !user; byid('identity').textContent = user ? user.name + ' · ' + user.role : ''; } async function load() { var tasks = await request('/tasks/'); var archived = await request('/archive/'); byid('tasks').replaceChildren(); byid('empty').hidden = tasks.length > 0; tasks.forEach(function(task) { var row = document.createElement('li'); var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = task.done; checkbox.setAttribute('aria-label', 'Complete ' + task.title); checkbox.addEventListener('change', () => work(async () => { await request('/tasks/' + task.id + '/', 'PATCH', { done: checkbox.checked }); await load(); })); var title = document.createElement('span'); title.className = 'task-title'; title.textContent = task.title; row.append(checkbox, title); if (user.role === 'admin') { var remove = document.createElement('button'); remove.type = 'button'; remove.textContent = 'Delete'; remove.addEventListener('click', () => work(async () => { await request('/tasks/' + task.id + '/', 'DELETE'); await load(); })); row.append(remove); } byid('tasks').append(row); }); byid('archived').replaceChildren(); archived.forEach(function(task) { var row = document.createElement('li'); row.textContent = task.title; byid('archived').append(row); }); } async function work(fn) { if (busy) return; busy = true; byid('message').textContent = ''; document.querySelectorAll('input,button').forEach(control => control.disabled = true); try { await fn(); } catch (err) { byid('message').textContent = err.message; } finally { busy = false; document.querySelectorAll('input,button').forEach(control => control.disabled = false); } } byid('login').addEventListener('submit', function(event) { event.preventDefault(); work(async function() { var result = await request('/login/', 'POST', { name: byid('name').value, password: byid('password').value }); user = result.user; csrf = result.csrf; byid('password').value = ''; show(); await load(); }); }); byid('create').addEventListener('submit', function(event) { event.preventDefault(); work(async function() { await request('/tasks/', 'POST', { title: byid('title').value }); byid('title').value = ''; await load(); }); }); byid('archive').addEventListener('click', () => work(async function() { await request('/archive/', 'POST', {}); await load(); })); byid('logout').addEventListener('click', () => work(async function() { await request('/logout/', 'POST', {}); user = null; byid('tasks').replaceChildren(); show(); })); work(async function() { var result = await request('/session/'); user = result.user; csrf = result.csrf; show(); if (user) await load(); }); })(); ``` ## What is exercised Related recipes: [SQLite and the QueryBuilder](/en/total5/query-builder-sqlite/), [QueryBuilder contract](/en/total5/query-builder-contract/), [CSRF](/en/total5/csrf-protection/) and [Taskboard Live](/en/docs/taskboard-live/). ## Global names of Total.js 5 Source: https://forge.totaljs.es/en/docs/globals-total5/ Framework: total5@0.0.19 Content-SHA256: 9a640579fbb48a0ccec8890088be894d9fbf539324ee4c7d49aa4e8833979023 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js 5 exposes global functions and objects for routing, actions, storage, messaging and application utilities. Use the table to find a name and its usage recipe. | Name | Kind | What it does | Recipe | |---|---|---|---| | `ON` | function | Registers a listener for an application event. | [events](/en/total5/events/) | | `ONCE` | function | Like `ON`, but the listener runs only for the first event. | [events](/en/total5/events/) | | `OFF` | function | Removes a listener registered with `ON`. | [events](/en/total5/events/) | | `EMIT` | function | Emits an event with up to seven arguments. | [events](/en/total5/events/) | | `LOAD` | function | Loads the files of the project (controllers, definitions...); the framework calls it for you at start. | [load-and-npminstall](/en/total5/load-and-npminstall/) | | `LOADCONFIG` | function | Parses a text in the `config` format and applies it to `CONF`. | [configuration-file](/en/total5/configuration-file/) | | `LOADRESOURCE` | function | Loads a resource (a translation file) from a text or from a URL. | [localization](/en/total5/localization/) | | `PAUSESERVER` | function | Pauses or resumes the server by name: while paused, requests get a 503 page. | [pause-server](/en/total5/pause-server/) | | `DEBUG` | boolean | `true` in debug mode, `false` in release mode. | [release-mode-and-debugging](/en/total5/release-mode-and-debugging/) | | `CONF` | object | The configuration of the application (the `config` file and its defaults). | [configuration-file](/en/total5/configuration-file/) | | `DEF` | object | Default handlers and settings of the framework (`DEF.onMail`, `DEF.helpers`, `DEF.onCSRFcheck`...). | [view-helpers-and-config](/en/total5/view-helpers-and-config/) | | `F` | object | The framework object. `Total` is the same object. | [utility-globals](/en/total5/utility-globals/) | | `Total` | object | The framework object (same as `F`). `Total.run()` starts the application. | [release-mode-and-debugging](/en/total5/release-mode-and-debugging/) | | `MAIN` | object | An empty object that the framework creates for your own application data. | [utility-globals](/en/total5/utility-globals/) | | `REPO` | object | An empty object that the framework creates for your own data. | [utility-globals](/en/total5/utility-globals/) | | `FUNC` | object | An empty object that the framework creates for your own functions. | [utility-globals](/en/total5/utility-globals/) | | `TEMP` | object | An object for temporary data; the framework replaces it with a new empty object from time to time. | [utility-globals](/en/total5/utility-globals/) | | `NOW` | object | The current date, refreshed by the framework once a minute and by some calls such as `CACHE`. | [utility-globals](/en/total5/utility-globals/) | | `EMPTYARRAY` | object | A frozen empty array, to avoid creating new ones. | [utility-globals](/en/total5/utility-globals/) | | `EMPTYOBJECT` | object | A frozen empty object, to avoid creating new ones. | [utility-globals](/en/total5/utility-globals/) | | `MODS` | object | The loaded modules of the `modules/` folder, by id. | [utility-globals](/en/total5/utility-globals/) | | `PLUGINS` | object | The loaded plugins of the `plugins/` folder, by id. | [utility-globals](/en/total5/utility-globals/) | | `NOOP` | function | A function that does nothing. | [utility-globals](/en/total5/utility-globals/) | | `print` | function | The same as `console.log`. | [utility-globals](/en/total5/utility-globals/) | | `REQUIRE` | function | Like `require`, but also looks in the `node_modules` folder of the application and accepts `node:` names. | [utility-globals](/en/total5/utility-globals/) | ## Routing, actions and middleware | Name | Kind | What it does | Recipe | |---|---|---|---| | `ROUTE` | function | Declares a route (HTTP, `SOCKET`, `FILE`, `API` or a fallback such as `#404`). | [http-methods](/en/total5/http-methods/) | | `NEWACTION` | function | Declares an action with its input, params, query, output and permissions. | [actions-crud](/en/total5/actions-crud/) | | `NEWSCHEMA` | function | Groups the actions of an entity under one name. | [schemas](/en/total5/schemas/) | | `ACTION` | function | Runs an action from your own code. | [calling-actions-from-code](/en/total5/calling-actions-from-code/) | | `EXEC` | function | The same function as `ACTION`. | [calling-actions-from-code](/en/total5/calling-actions-from-code/) | | `NEWTRANSFORM` | function | Adds a step to a named chain of transformations. | [transforms](/en/total5/transforms/) | | `TRANSFORM` | function | Runs a value through a chain of transformations. | [transforms](/en/total5/transforms/) | | `MIDDLEWARE` | function | Registers a middleware to be used in routes with `#name`. | [middleware](/en/total5/middleware/) | | `NEWMIDDLEWARE` | function | The same function as `MIDDLEWARE`. | [middleware](/en/total5/middleware/) | | `PROXY` | function | Forwards the requests below a URL prefix to another server. | [proxy](/en/total5/proxy/) | | `CORS` | function | Sets the origins that may call the application from a browser. | [cors](/en/total5/cors/) | | `ErrorBuilder` | function | The class that collects validation errors. | [errors-and-audit](/en/total5/errors-and-audit/) | | `SUCCESS` | function | Returns the object that the framework sends for a successful operation (`{ success: true, value: value }`). | [errors-and-audit](/en/total5/errors-and-audit/) | | `ERROR` | function | `ERROR(name)` returns a callback that logs the error it receives under that name; `ERROR()` returns the default error callback. | [errors-and-audit](/en/total5/errors-and-audit/) | | `UNAUTHORIZED` | function | `UNAUTHORIZED($, ...permissions)` answers 401 and returns `true` when the user has none of the permissions; it returns `false` when the user has one of them or is a super administrator. | [action-user-and-permissions](/en/total5/action-user-and-permissions/) | | `AUTH` | function | Authenticates every request: a function, or the options of the built-in sessions. | [sessions-with-built-in-auth](/en/total5/sessions-with-built-in-auth/) | | `BLOCKED` | function | Counts the calls of an IP address and tells when it reached the limit. | [rate-limiting](/en/total5/rate-limiting/) | | `AUDIT` | function | Appends an audit entry (user, message and type) to a log file in `logs/`. | [errors-and-audit](/en/total5/errors-and-audit/) | ## Data and cache | Name | Kind | What it does | Recipe | |---|---|---|---| | `NOSQL` | function | Opens a table of the built-in NoSQL database. | [nosql-crud](/en/total5/nosql-crud/) | | `DATA` | object | Database-independent entry to the query builder. | [data-api](/en/total5/data-api/) | | `DB` | function | Starts a query with the query builder (`DB().find('table').where(...).callback($)`); the query is run by the driver registered with `NEWDB`. | [query-builder-db](/en/total5/query-builder-db/) | | `NEWDB` | function | Registers a database driver `function(options, callback)` for the query builder: the default one, or a named one with `NEWDB('name', fn)`. | [query-builder-db](/en/total5/query-builder-db/) | | `CACHE` | object | An in-memory store with expiration. | [cache](/en/total5/cache/) | | `FILECACHE` | function | Computes a result once and keeps it in a file for a while. | [filecache](/en/total5/filecache/) | | `MEMORIZE` | function | A JSON object saved on disk. | [memorize](/en/total5/memorize/) | | `FILESTORAGE` | function | A storage for uploaded files. | [filestorage](/en/total5/filestorage/) | ## HTTP, WebSocket and messaging clients | Name | Kind | What it does | Recipe | |---|---|---|---| | `REQUEST` | function | Low-level HTTP client. | [request-and-download](/en/total5/request-and-download/) | | `DOWNLOAD` | function | Saves the response of a URL into a file. | [request-and-download](/en/total5/request-and-download/) | | `RESTBuilder` | function | Builder for calls to other HTTP APIs. | [restbuilder](/en/total5/restbuilder/) | | `AJAX` | function | `AJAX('METHOD /url/', data, callback)` makes a request with the header `x-requested-with` and returns the parsed body; it returns a promise when there is no callback. | [ajax-requests](/en/total5/ajax-requests/) | | `API` | function | Calls an operation of an external service through its driver: `API('service', 'operation', data).callback($)`. | [api-drivers](/en/total5/api-drivers/) | | `NEWAPI` | function | Registers the driver `function(options, next)` of a service for `API`, with an optional configuration. | [api-drivers](/en/total5/api-drivers/) | | `TotalAPI` | function | Calls a Total.js platform service through `API('TAPI', name, model)`. | [remote-service-boundaries](/en/total5/remote-service-boundaries/) | | `WEBSOCKETCLIENT` | function | A WebSocket client for your application. | [websocket-client](/en/total5/websocket-client/) | | `TMSCLIENT` | function | A client of the Total Messaging Service. | [tms](/en/total5/tms/) | | `PUBLISH` | function | Sends a message to the TMS clients that subscribed to it. | [tms](/en/total5/tms/) | | `NEWPUBLISH` | function | Declares a message that the application publishes. | [tms](/en/total5/tms/) | | `SUBSCRIBE` | function | Adds a listener for a message that clients send to the application. | [tms](/en/total5/tms/) | | `UNSUBSCRIBE` | function | Removes the listeners of a TMS message. | [tms](/en/total5/tms/) | | `NEWSUBSCRIBE` | function | Declares a message that the application receives. | [tms](/en/total5/tms/) | | `NEWCALL` | function | Declares a function that TMS clients can call. | [tms](/en/total5/tms/) | | `OPENCLIENT` | function | Connects to OpenPlatform over WebSocket for remote calls, events and shared connections. | [openclient-protocol](/en/total5/openclient-protocol/) | | `PROXYCLIENT` | function | Connects to a `PROXYSERVER` over WebSocket and answers its requests with a local server (a port or `ip:port`). | [proxy-tunnel](/en/total5/proxy-tunnel/) | | `PROXYSERVER` | function | Turns the application into a tunnel server: the HTTP requests of an endpoint are sent through a WebSocket route to a `PROXYCLIENT`. | [proxy-tunnel](/en/total5/proxy-tunnel/) | | `LDAP` | function | Connects to an LDAP server (port 389 unless `ldap.port` says otherwise) and calls back with the result. | [ldap-openldap](/en/total5/ldap-openldap/) | | `MAIL` | function | Sends an email whose body is a view. | [send-email](/en/total5/send-email/) | | `HTMLMAIL` | function | Sends an email whose body is a string of HTML. | [send-email](/en/total5/send-email/) | | `LOGMAIL` | function | Sends an email whose body is a text printed in a `
` block (pass the body as a text). | [logmail](/en/total5/logmail/) |
| `Mail` | object | The class behind the email sending (SMTP). | [send-email](/en/total5/send-email/) |
| `AIMODEL` | function | Starts a request for a language model registered with `NEWAIMODEL`: `AIMODEL('name').user('text').callback($.callback())`. | [ai-models](/en/total5/ai-models/) |
| `AIPARSER` | function | Creates a parser for the streamed answer of an AI provider (`openai`, `claude`...): `write()` takes pieces and `end()` returns the content, thinking and tool calls. | [ai-models](/en/total5/ai-models/) |
| `NEWAIMODEL` | function | Registers the driver `function(ai, done)` of one or more AI models for `AIMODEL`, with an optional configuration. | [ai-models](/en/total5/ai-models/) |
| `PYPELINE` | function | Runs a Python file of the `pypelines/` folder (or inline Python code) from the application and talks to it with JSON frames over a socket. | [pypeline](/en/total5/pypeline/) |

## Files, system and workers

| Name | Kind | What it does | Recipe |
|---|---|---|---|
| `PATH` | object | Helpers that build paths in the project folders (`PATH.root()`, `PATH.public()`, `PATH.tmp()`...). | [file-download](/en/total5/file-download/) |
| `MERGE` | function | Registers a virtual file made of several files, minified. | [minification](/en/total5/minification/) |
| `TOUCH` | function | Clears the cached minified, temporary and not-found entries of a URL, or of all of them. | [touch-static-cache](/en/total5/touch-static-cache/) |
| `CLEANUP` | function | Destroys a stream when it has finished. | [cleanup-streams](/en/total5/cleanup-streams/) |
| `BACKUP` | function | Packs a directory into one file. | [backup-restore-shell](/en/total5/backup-restore-shell/) |
| `RESTORE` | function | Unpacks a file created with `BACKUP`. | [backup-restore-shell](/en/total5/backup-restore-shell/) |
| `SHELL` | function | Runs a shell command in the folder of the project. | [backup-restore-shell](/en/total5/backup-restore-shell/) |
| `NPMINSTALL` | function | Installs an npm package in the modules folder of the application. | [load-and-npminstall](/en/total5/load-and-npminstall/) |
| `IMPORT` | function | Downloads a JavaScript file from a URL and loads it. | [import-remote-module](/en/total5/import-remote-module/) |
| `Image` | object | Image processing with GraphicsMagick or ImageMagick. | [images](/en/total5/images/) |
| `NEWTHREAD` | function | Starts a worker thread. | [workers-and-threads](/en/total5/workers-and-threads/) |
| `NEWFORK` | function | Starts a child process. | [workers-and-threads](/en/total5/workers-and-threads/) |
| `NEWTHREADPOOL` | function | Creates a pool of workers that jobs borrow one at a time. | [thread-pool](/en/total5/thread-pool/) |
| `CRON` | function | Runs a function on a schedule. | [cron-jobs](/en/total5/cron-jobs/) |
| `setTimeout2` | function | `setTimeout` with an id: calling it again with the same id replaces the previous timer. | [debounce-timers](/en/total5/debounce-timers/) |
| `clearTimeout2` | function | Cancels a timer created with `setTimeout2`. | [debounce-timers](/en/total5/debounce-timers/) |
| `Flow` | object | The manager of the FlowStreams of the application: `Flow.load(schema)`, `Flow.remove(id)`, `Flow.instances` and `Flow.test()` for one component. | [flowstream](/en/total5/flowstream/), [flowstream-component-test](/en/total5/flowstream-component-test/) |
| `FlowStream` | object | The same object as `Flow`. | [flowstream](/en/total5/flowstream/) |
| `NEWMACRO` | function | Compiles a macro from a string. | [macros](/en/total5/macros/) |
| `NEWCOMPONENT` | function | Compiles the HTML of a component. | [native-components](/en/total5/native-components/) |
| `COMPONENTATOR` | function | Downloads a Componentator bundle into `public/` as `ui--.min.js` and stores its address in `F.repo[name]`. | [remote-service-boundaries](/en/total5/remote-service-boundaries/) |

## Utilities, templates and localization

| Name | Kind | What it does | Recipe |
|---|---|---|---|
| `U` | object | The utility object of the framework (`U.extend()`, `U.clone()`...). | [utilities](/en/total5/utilities/) |
| `Utils` | object | The same object as `U`. | [utilities](/en/total5/utilities/) |
| `UID` | function | Creates a short unique id sorted by time. | [unique-ids-and-hashes](/en/total5/unique-ids-and-hashes/) |
| `GUID` | function | Creates a random string of the given length. | [unique-ids-and-hashes](/en/total5/unique-ids-and-hashes/) |
| `HASH` | function | Returns a fast numeric hash (not for passwords). | [unique-ids-and-hashes](/en/total5/unique-ids-and-hashes/) |
| `CLONE` | function | Makes a deep copy of an object. | [utility-globals](/en/total5/utility-globals/) |
| `COPY` | function | Copies the properties of the first object into the second one and returns the second. | [utility-globals](/en/total5/utility-globals/) |
| `DIFFARR` | function | Compares two arrays of objects by a property and returns the objects to add, the pairs to update and the values to remove. | [diffarr-sync-lists](/en/total5/diffarr-sync-lists/) |
| `QUERIFY` | function | Builds a URL with a query string from an object. | [utility-globals](/en/total5/utility-globals/) |
| `PROMISIFY` | function | `PROMISIFY(fn, a, b, c)` calls a function that takes a callback as the last argument and returns a promise. | [utility-globals](/en/total5/utility-globals/) |
| `ENCRYPT` | function | Turns a value into an opaque token. | [encrypt-and-decrypt](/en/total5/encrypt-and-decrypt/) |
| `DECRYPT` | function | Reads a value from a token created with `ENCRYPT`. | [encrypt-and-decrypt](/en/total5/encrypt-and-decrypt/) |
| `ENCRYPTREQ` | function | Encrypts a value together with the user agent of a request (and its IP address when strict). | [request-bound-tokens](/en/total5/request-bound-tokens/) |
| `DECRYPTREQ` | function | Reads a value created with `ENCRYPTREQ`; returns nothing when the request does not match. | [request-bound-tokens](/en/total5/request-bound-tokens/) |
| `LOCALIZE` | function | Chooses the language of every request. | [localization](/en/total5/localization/) |
| `TRANSLATE` | function | Translates the `@(...)` texts of a string into a language. | [localization](/en/total5/localization/) |
| `Tangular` | object | The template engine (`Tangular.render()`). | [tangular-templates](/en/total5/tangular-templates/) |
| `Ta` | object | Another name of `Tangular`, the template engine. | [template-files](/en/total5/template-files/) |
| `Thelpers` | object | The helper functions available in Tangular templates. | [tangular-templates](/en/total5/tangular-templates/) |
| `TEMPLATE` | function | Renders a Tangular template that is a text, a file of the `templates` folder or a URL, and returns a promise with the text. | [template-files](/en/total5/template-files/) |

```js controllers/globals.js
exports.install = function() {
	ROUTE('GET /globals/', globals);
};

function globals($) {
	var output = {};
	for (var name of Object.getOwnPropertyNames(globalThis)) {
		var value;
		try {
			value = globalThis[name];
		} catch (e) {
			value = undefined;
		}
		output[name] = typeof(value) === 'function' ? 'function' : value === null ? 'null' : typeof(value);
	}
	$.json(output);
}
```

## Configuration keys of Total.js 5

Source: https://forge.totaljs.es/en/docs/configuration-keys/
Framework: total5@0.0.19
Content-SHA256: 2ef72a7b9fcde672c1a24fc856022e87b39a3e5facf68c57efc087c9fb4b90ef
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

The `config` file holds one `key : value` setting per line and the values are available in the global `CONF` object (see the configuration recipe for the file format). The keys below are defined by `total5` 0.0.19 with these defaults; a key that is not here and not in the second table is yours. **Keys that start with `$` are settings of the framework** and `secret_` keys hold secrets.

Set application values in the config file and read them through CONF. The table gives the defaults and the purpose of each setting.

| Key | Default | Note |
|---|---|---|
| `name` | `'Total.js'` | The name of the application. In a view, `@{'%name'}` prints it. |
| `version` | `'1.0.0'` | Application version used in startup output, statistics and the default HTTP ETag suffix (index.js). |
| `author` | `''` | Application author displayed by startup imprint when nonempty (index.js). |
| `secret` | `F.syshash` | Set the application secret explicitly in configuration. |
| `secret_encryption` | `''` | Key read by encrypted WebSocket routes; this is distinct from an action encrypt metadata option (websocket.js). |
| `secret_totalapi` | `''` | Fallback token sent by the built-in TotalAPI driver (api.js); keep server-side. |
| `secret_csrf` | `''` | The secret of the CSRF tokens. Empty: the check always passes. |
| `secret_tms` | `''` | The token that TMS clients must send in the header `x-token`. |
| `$root` | `''` | URL prefix applied to route and asset paths; also adjusts the default API endpoint (routing.js, index.js). |
| `$cors` | `''` | Hostnames separated by comma. |
| `$api` | `'/api/'` | A default API endpoint. |
| `$sourcemap` | `true` | Loader metadata setting; LOAD sets it from the final DEBUG mode or disables it for selective resource loads (index.js). |
| `$httpreqlimit` | `0` | Request limit per ip. |
| `$httpcompress` | `true` | Enables negotiated gzip for eligible responses; the dynamic response path checks a 256-byte threshold (controller.js). |
| `$httpetag` | `''` | Suffix for framework-generated ETags; when empty, configuration derives it from the app version (index.js, controller.js). |
| `$httpmaxsize` | `256` | KB. |
| `$httprangebuffer` | `5120` | 5 MB. |
| `$httptimeout` | `5` | 5 seconds. |
| `$httpfiles` | `an object` | The file extensions that are served as static files, as an object `{ extension: true }`. |
| `$httpchecktypes` | `true` | For multipart data only. |
| `$httpmaxage` | `60` | In seconds. |
| `$httpmaxkeys` | `33` | Maximum parsed query-string key count (utils.js); not a JSON-body field limit. |
| `$httpmaxkey` | `25` | Maximum query-string key length used by the query parser (utils.js). |
| `$httpcacheoffset` | `''` | E.g. 1 minute. |
| `$blacklist` | `''` | HTTP/WebSocket request handling tests whether the configured value contains the client IP (http.js, websocket.js). Not a CIDR parser. |
| `$xpoweredby` | `'Total.js'` | Value of the generated X-Powered-By response header; empty suppresses it in the inspected response paths (controller.js). |
| `$minifyjs` | `true` | Minify the JavaScript files that are served. |
| `$minifycss` | `true` | Minify the CSS files that are served. |
| `$minifyhtml` | `true` | Minify the HTML that is sent. |
| `$port` | `'auto'` | HTTP listen port; auto is resolved at startup, and Total.run options can override it (index.js). |
| `$ip` | `'0.0.0.0'` | HTTP listen address; Total.run options can override it (index.js). |
| `$unixsocket` | `''` | Alternative Unix socket listen path (index.js). Socket permissions and reverse proxy setup are deployment concerns. |
| `$timezone` | `'utc'` | The time zone of the process (it is set in `process.env.TZ`). |
| `$insecure` | `false` | Configuration sets the process TLS verification environment from this flag (index.js). Keep false for authenticated TLS connections. |
| `$performance` | `false` | Adjusts HTTP agent maximum sockets and socket tuning (index.js); it is not evidence of an application speedup. |
| `$filtererrors` | `true` | Suppresses matching runtime error patterns in the framework error logger (index.js). |
| `$cleartemp` | `true` | Controls startup removal of selected generated/temp file extensions by the clear routine (index.js). |
| `$customtitles` | `false` | When false, the view metadata generator appends the application name to a non-home page title (viewengine.js). |
| `$clearcache` | `10` | Service-counter interval for resetting internal lookup/view/template/query-builder caches (index.js). Not a database deletion schedule. |
| `$imageconverter` | `'gm'` | The program that `Image` calls: `gm`, `im` or `magick`. |
| `$imagememory` | `0` | Disabled because e.g. GM v1.3.32 throws some error about the memory. |
| `$stats` | `true` | Controls statistics output/update branch; selective LOAD can disable it (index.js). |
| `$npmcache` | `'/var/www/.npm'` | Npm cache location passed by NPMINSTALL for the uid-33 execution branch (index.js). |
| `$python` | `'python3'` | Interpreter command used by Python execution and pip helpers (index.js); install Python separately. |
| `$wsmaxsize` | `256` | KB. |
| `$wscompress` | `true` | Enables negotiation of WebSocket permessage-deflate on server connections (websocket.js). |
| `$wsencodedecode` | `false` | Initial WebSocket server encode/decode setting (websocket.js); verify required wire format before changing it. |
| `$wsmaxlatency` | `2000` | Ping-latency threshold in milliseconds used by WebSocket connection checks (websocket.js). |
| `$proxytimeout` | `5` | 5 seconds. |
| `$cookiesamesite` | `'Lax'` | Default SameSite cookie policy when a cookie does not specify one (controller.js). |
| `$cookiesecure` | `false` | Default Secure cookie attribute when no per-cookie override is supplied (controller.js). |
| `$csrfexpiration` | `'30 minutes'` | How long a CSRF token is valid. |
| `$tapi` | `true` | Enables the built-in TotalAPI service driver; the special check operation bypasses this local gate (api.js). |
| `$tapiurl` | `'eu'` | Regional hostname prefix used by the TotalAPI driver (api.js). |
| `$tapimail` | `false` | Selects the TotalAPI mail path when the TotalAPI feature is enabled (mail.js). |
| `$tapilogger` | `false` | Enables the TotalAPI logger path when service access and its secret are configured (index.js). |
| `$imprint` | `true` | Enables the startup banner (index.js). |
| `$tms` | `false` | Turns on the TMS WebSocket endpoint. |
| `$tmsmaxsize` | `256` | The maximum size of a TMS message, in kB. |
| `$tmsurl` | `'/$tms/'` | The URL of the TMS endpoint. |
| `$tmsclearblocked` | `60` | In minutes. |
| `$total5` | set at start | The folder of the `total5` package (the framework reads its own files from it). |
| `$nodemodules` | set at start | The folder where `NPMINSTALL()` installs packages. |
| `secret_uid` | set at start | Secret input used by the short encrypted-identifier utility; initialized from the system hash (index.js, utils.js). |
| `$cryptoiv` | set at start | Initialization-vector buffer used by framework encryption helpers; initialized at startup (index.js, utils.js). |
| `$httpexpire` | set at start | Future UTC HTTP expiry date initialized and periodically refreshed by the framework (index.js, controller.js). |

These keys have no default. They configure the email sending and are used by `MAIL()` and `HTMLMAIL()` (see the email recipe):

| Key | Meaning |
|---|---|
| `mail_smtp` | The address of the SMTP server. |
| `mail_smtp_options` | An object with the rest of the connection settings: `port`, `user`, `password`, `secure`... |
| `mail_from` | The address of the sender. |
| `mail_from_name` | The name of the sender. |
| `mail_reply` | The address that gets the replies, added to every message. |
| `mail_cc` | A copy address, added to every message. |
| `mail_bcc` | A hidden copy address, added to every message. |

```js controllers/config.js
exports.install = function() {
	ROUTE('GET /config/', config);
};

function config($) {
	$.json({ conf: CONF });
}
```

## Route syntax of Total.js 5

Source: https://forge.totaljs.es/en/docs/route-syntax/
Framework: total5@0.0.19
Content-SHA256: 09125c53800b76738f7a5a0ef26c4af820bdac0879b1cc3eae94133af2f4387c
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`ROUTE(definition, handler)` declares a route. The definition is one text with these parts, in this order:

`[+|-]METHOD /url/{param}/ [@flag ...] [#middleware ...] [ *Action ...]`

| Part | Meaning |
|---|---|
| `METHOD` | `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, or `SOCKET` for a WebSocket and `FILE` for URLs with an extension: a URL such as `/a.txt` is never matched by a `GET` route. |
| `+` or `-` before the method | `+` accepts only requests that `AUTH()` approved, `-` only anonymous requests; any other request is answered with 401. Without a prefix the route is open. |
| `/url/` | The path. Write the end slash: routes are matched with it. |
| `{name}` | A segment of the path that is read from `$.params.name`. |
| `*` as the last segment | Matches any path below it. A route without `*` is more specific and wins. |
| `@flag` | A condition for the request: `@json`, `@xml`, `@xhr`, `@upload`, `@debug`, `@release`, `@mobile`, `@robot`, `@referer` (or `@referrer`). |
| `#name` | A middleware registered with `MIDDLEWARE(name, fn)`. |
| ` *Action` | Runs one or more actions with the input of the request and answers with the result. |
| `#404`, `#401`... | A route whose definition is only `#` and a status code replaces the error page. |

A request is handled by the first matching route. A request that does not meet the flags of a route continues to the next route and ends with a 404 when none matches; a request that does not meet `+` or `-` gets a 401. **A route without flags on the same URL always wins over a route with flags**, so never put both on one URL.

```js definitions/auth.js
AUTH(function($) {
	if ($.headers['x-token'] === 'secret')
		$.success({ id: '1' });
	else
		$.invalid();
});

MIDDLEWARE('stamp', function($, next) {
	$.response.headers['x-stamp'] = 'yes';
	next();
});

NEWACTION('Echo/one', { name: 'one', input: '*text:String', action: ($, model) => $.callback({ one: model.text }) });
NEWACTION('Echo/two', { name: 'two', action: ($, model) => $.callback({ two: true }) });
```

```js controllers/syntax.js
exports.install = function() {
	ROUTE('GET /plain/', plain);
	ROUTE('GET /users/{id}/', user);
	ROUTE('GET /files/*', files);
	ROUTE('POST /json/ @json', json);
	ROUTE('+GET /private/', plain);
	ROUTE('-GET /guest/', plain);
	ROUTE('GET /stamped/ #stamp', plain);
	ROUTE('POST /echo/ @json --> *Echo/one');
	ROUTE('FILE /robots-example.txt', file);
	ROUTE('#404', missing);
};

function plain($) {
	$.json({ ok: true });
}

function user($) {
	$.json({ id: $.params.id });
}

function files($) {
	$.json({ url: $.url });
}

function json($) {
	$.json({ body: $.body });
}

function file($) {
	$.plain('from a FILE route');
}

function missing($) {
	$.response.status = 404;
	$.plain('custom 404');
}
```

## The $ object of a Total.js 5 handler

Source: https://forge.totaljs.es/en/docs/controller-api/
Framework: total5@0.0.19
Content-SHA256: b04b25b10d7f00afcc531b3bee7c01f76fd782ecbc8281873a3128d66e3c4614
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

A route handler receives one object, written `$` in this site. It describes the request and it answers it. Answer **once**: after `$.json()`, `$.html()` or any other answer, the request is finished.

## Properties

| Property | Type | What it is |
|---|---|---|
| `$.url` | string | The path of the request, without the query string. |
| `$.method` | string | `GET`, `POST`... |
| `$.query` | object | The query string, parsed. |
| `$.params` | object | The `{name}` segments of the route. |
| `$.body` | object | The body, parsed by its content type (JSON, URL-encoded form, XML or multipart fields). |
| `$.files` | array | The uploaded files of a multipart request. |
| `$.headers` | object | The headers of the request, with lowercase names. |
| `$.ip` | string | The IP address; the first address of `x-forwarded-for` when the header exists. |
| `$.host` | string | The `host` header. |
| `$.referrer` | string | The `referer` header. |
| `$.protocol` | string | `http` or `https` (also when a proxy says so in `x-forwarded-proto`). |
| `$.ext` | string | The extension of the URL, without the dot (`$.extension` is the same). |
| `$.xhr` | boolean | `true` when the header `x-requested-with` is `XMLHttpRequest`. |
| `$.mobile` | boolean | `true` when the user agent looks like a mobile browser. |
| `$.robot` | boolean | `true` when the user agent looks like a crawler. |
| `$.ua` | string | A short name of the browser and system, such as `iPhone Safari` or `Windows Chrome`. |
| `$.user` | object | The user that `AUTH()` approved, or nothing. |
| `$.language` | string | The language that `LOCALIZE()` chose. |
| `$.datatype` | string | `json`, `urlencoded`, `multipart`, `xml`, `text` or `binary`: the type of the body of the request. |
| `$.response` | object | What will be sent: `status`, `headers` and `value`. Change `$.response.status` and `$.response.headers` before you answer. |
| `$.req`, `$.res` | objects | The Node.js request and response. |

## Methods that answer

| Method | What it does | Recipe |
|---|---|---|
| `$.json(value)` | Answers with JSON. | [responses](/en/total5/responses/) |
| `$.jsonstring(text)` | Answers with a text that is already JSON, without serializing it again. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.html(text)` | Answers with HTML. | [responses](/en/total5/responses/) |
| `$.plain(text)` | Answers with plain text (`$.text` is the same). | [responses](/en/total5/responses/) |
| `$.xml(text)` | Answers with XML. | [responses](/en/total5/responses/) |
| `$.empty()` | Answers with status 204 and no body. | [responses](/en/total5/responses/) |
| `$.redirect(url, permanent)` | Redirects (302, or 301 when `permanent` is true). | [responses](/en/total5/responses/) |
| `$.binary(buffer, type, name)` | Answers with bytes and a content type. | [responses](/en/total5/responses/) |
| `$.file(path, name)` | Sends a file from disk. | [file-download](/en/total5/file-download/) |
| `$.stream(type, stream, name)` | Sends a readable stream. | [file-download](/en/total5/file-download/) |
| `$.filefs(storage, id)` | Sends a file of a `FILESTORAGE`. | [filestorage](/en/total5/filestorage/) |
| `$.image(options)` | Creates and sends an image on demand. | [images](/en/total5/images/) |
| `$.view(name, model)` | Renders a view with the layout and answers with it. | [views-and-layouts](/en/total5/views-and-layouts/) |
| `$.layout(name)` | Chooses another layout for the next `$.view()`. | [view-sections](/en/total5/view-sections/) |
| `$.proxy(url)` | Forwards the request to another URL and answers with its response. | [proxy](/en/total5/proxy/) |
| `$.respond(value)` | Answers in the format of `$.response.output` (`json` when it is not set). | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.invalid(value)` | Answers with an error: a text, a status code such as `404` or an `ErrorBuilder`. | [actions-crud](/en/total5/actions-crud/) |
| `$.fallback(code)` | Answers with the page of an error code, the custom one when `ROUTE('#404')` exists. | [error-pages](/en/total5/error-pages/) |
| `$.success(value)` | Answers `{ "success": true }`; `value` is added to it. | [responses](/en/total5/responses/) |
| `$.callback(err, value)` | With an error answers `$.invalid(err)`, otherwise `$.json(value)`, or `$.success()` when `value` is `undefined`. Without arguments it returns a function `(err, response)` that does the same. | [actions-crud](/en/total5/actions-crud/) |
| `$.successful(fn)` | Returns a function `(err, a, b, c)`: with an error it answers `$.invalid(err)`, otherwise it calls `fn(a, b, c)`. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.done(arg)` | Returns a function `(err, response)`: with an error it answers `$.invalid(err)`, otherwise it answers with the success object. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |

## Other methods

| Method | What it does | Recipe |
|---|---|---|
| `$.cookie(name, value, expiration)` | Reads a cookie, or writes one when you pass a value. | [headers-and-cookies](/en/total5/headers-and-cookies/) |
| `$.csrf()` | Creates a CSRF token for this client. | [csrf-protection](/en/total5/csrf-protection/) |
| `$.hostname(path)` | The address of this server: protocol, host and the path you pass. | [restbuilder](/en/total5/restbuilder/) |
| `$.action(name, model)` | Runs an action with this request (user, query and params). | [calling-actions-from-code](/en/total5/calling-actions-from-code/) |
| `$.transform(name, value, callback)` | Runs a transform with this request. | [transforms](/en/total5/transforms/) |
| `$.authorize(callback)` | Runs `AUTH()` for this request and sets `$.user`; it returns a promise when there is no callback. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.notmodified(date)` | Answers 304 and returns `true` when the request has the header `if-modified-since` with that date. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.httpcache(date)` | Sets the cache headers and `last-modified` of the answer. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.clear()` | Removes the temporary files of the upload. They are removed anyway when the request ends. | [file-upload](/en/total5/file-upload/) |
| `$.autoclear(false)` | Keeps the uploaded files after the request, so that you can use them later. | [upload-lifecycle-and-href](/en/total5/upload-lifecycle-and-href/) |
| `$.custom()` | Tells the framework that you answer through `$.res` yourself: it will not send anything. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.href(key, value)` | Use `QUERIFY()` as in the linked recipe, the tested native query-link helper. | [upload-lifecycle-and-href](/en/total5/upload-lifecycle-and-href/) |
| `$.flush()`, `$.resume()`, `$.free()`, `$.cancel()` | Internal methods: do not call them. | - |

The example answers with the properties and calls the methods that need no setup.

```js controllers/api.js
exports.install = function() {
	ROUTE('GET /info/{a}/{b}/', info);
	ROUTE('POST /body/ @json', body);
	ROUTE('GET /answers/{kind}/', answers);
	ROUTE('GET /callback/{kind}/', callback);
};

function info($) {
	$.json({
		url: $.url,
		method: $.method,
		query: $.query,
		params: $.params,
		ext: $.ext,
		xhr: $.xhr,
		mobile: $.mobile,
		robot: $.robot,
		ua: $.ua,
		ip: $.ip,
		host: $.host,
		referrer: $.referrer,
		protocol: $.protocol,
		hostname: $.hostname('/x/'),
		datatype: $.datatype
	});
}

function body($) {
	$.json({ body: $.body, datatype: $.datatype });
}

function answers($) {
	switch ($.params.kind) {
		case 'json': return $.json({ a: 1 });
		case 'jsonstring': return $.jsonstring('{"a":1}');
		case 'html': return $.html('x');
		case 'plain': return $.plain('x');
		case 'xml': return $.xml('1');
		case 'empty': return $.empty();
		case 'redirect': return $.redirect('/x/', true);
		case 'binary': return $.binary(Buffer.from('abc'), 'application/octet-stream');
		case 'invalid': return $.invalid(409);
		case 'success': return $.success({ id: 7 });
		case 'status': $.response.status = 201; return $.json({ created: true });
		case 'header': $.response.headers['x-example'] = 'yes'; return $.json({});
	}
}

function callback($) {
	switch ($.params.kind) {
		case 'error': return $.callback('failed');
		case 'value': return $.callback(null, { v: 1 });
		case 'nothing': return $.callback(null);
		case 'function': return setImmediate($.callback(), null, { later: true });
		case 'successful': return setImmediate($.successful(function(a, b) { $.json({ a: a, b: b }); }), null, 'x', 'y');
	}
}
```

## Options of NEWACTION and the object an action receives

Source: https://forge.totaljs.es/en/docs/action-options/
Framework: total5@0.0.19
Content-SHA256: f1ffd2184b29e3078bcf6ecaeeb9ef9f5f0c5e6e808b6ea368164415466f662b
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`NEWACTION(name, options)` declares an action. `name` is its id (`Users/insert`): routes use it with `--> *Users/insert` and your code with `ACTION('Users/insert', payload)`.

## Options

| Option | Value | What it does |
|---|---|---|
| `name` | text | A description of the action; it is also available as `$.name`. |
| `action` | `function($, model)` | The code of the action. `model` is the validated input. |
| `input` | text | The fields of the body, as `name:Type` separated by commas; a `*` before the name makes it required. See the input types page. |
| `output` | text | The fields of the answer; fields that are not listed are removed. |
| `params` | text | The `{name}` segments of the route, validated like `input`. |
| `query` | text | The query string, validated like `input`. |
| `partial` | `true` | Only the fields that were sent reach the action. Use it for `PATCH`. |
| `user` | `true` or `false` | `true` answers 401 when there is no signed-in user; `false` accepts only anonymous requests. |
| `permissions` | text or array | `'read,write'`: the user needs one of them (or to be a super administrator). |
| `route` | text | Declares the route of the action here: `'GET /products/'`, or `true` for an `API` route. |
| `middleware` | text | Names of middleware that run before the action, separated by spaces or commas. |
| `timeout` | milliseconds | When the action does not answer in time, the request fails with the error `Timeout.`. |
| `cache` | `true` or an object | Keep the result of an action with `CACHE`. |
| `config` | object | Values that the action reads from `$.config`. |
| `audit` | text | Records an automatic event after successful completion; see the dedicated recipe for tested boundaries. [action-audit](/en/total5/action-audit/) |
| `csrf`, `encrypt`, `compress`, `publish` | - | [action-transport-boundaries](/en/total5/action-transport-boundaries/) |
| `sa`, `su` | true | Either requires a user with either administrator flag. [action-hooks-and-admin](/en/total5/action-hooks-and-admin/) |
| `oninput`, `onoutput` | function | Before the handler after validation; successful completion hook after output processing. [action-hooks-and-admin](/en/total5/action-hooks-and-admin/) |
| `extend` | path | Adds the result under this path in the validated input and returns the extended payload. [action-hooks-and-admin](/en/total5/action-hooks-and-admin/) |

## The object `$` of an action

| Member | What it is |
|---|---|
| `$.query`, `$.params` | The validated query string and route segments. |
| `$.payload` | The validated input; it is the same object as the second argument of `action`. |
| `$.user` | The signed-in user. |
| `$.config` | The `config` option. |
| `$.name`, `$.id` | The `name` option and the id of the action. |
| `$.controller` | The `$` of the route when the action was called from a route, so `$.controller.body` is the raw body. It does not exist when the action is called with `ACTION()`. |
| `$.callback(value)` | Answers with a value; it is filtered by `output`. Without arguments it returns a function `(err, response)`. |
| `$.success(value)` | Answers `{ success: true }`. |
| `$.invalid(error)` | Answers with an error: a text, a status code or an `ErrorBuilder`. |
| `$.done(arg)`, `$.successful(fn)` | Return callbacks for functions that report an error as their first argument. |
| `$.cookie(name, value, expiration)` | Reads or writes a cookie of the request. |
| `$.redirect(url)` | Redirects the request. |
| `$.output(name)` | Chooses how a route answers: `json`, `html`, `xml`, `text`, `redirect`, `binary`, `jsonstring`, `empty` or `file`. |
| `$.unauthorized(...permissions)` | Answers 401 and returns `true` when the user has none of the permissions. |
| `$.action(name, payload)` | Runs another action with the same request. |
| `$.hostname(path)` | The address of this server. |

```js definitions/options.js
MIDDLEWARE('tag', function($, next) {
	$.response.headers['x-tag'] = 'on';
	next();
});

var counter = { cached: 0 };
MAIN.counter = counter;

NEWACTION('Options/named', {
	name: 'The name',
	config: { limit: 3 },
	action: function($) {
		$.callback({ name: $.name, id: $.id, limit: $.config.limit });
	}
});

NEWACTION('Options/guarded', {
	name: 'Needs a user',
	user: true,
	permissions: 'read',
	action: function($) {
		$.success();
	}
});

NEWACTION('Options/slow', {
	name: 'Never answers',
	timeout: 300,
	action: function($) {}
});

NEWACTION('Options/cached', {
	name: 'The cache option',
	query: 'page:Number',
	cache: { expire: '1 minute', query: 'page' },
	action: function($) {
		counter.cached++;
		$.callback({ page: $.query.page, runs: counter.cached });
	}
});

NEWACTION('Options/routed', {
	name: 'Declares its own route',
	route: 'GET /routed/ #tag',
	action: function($) {
		$.callback({ routed: true });
	}
});

NEWACTION('Options/output', {
	name: 'Chooses how to answer',
	action: function($) {
		$.output('plain');
		$.callback('plain text');
	}
});

AUTH(function($) {
	if ($.headers['x-user'])
		$.success({ id: '1', permissions: $.headers['x-user'].split(',') });
	else
		$.invalid();
});
```

```js controllers/options.js
exports.install = function() {
	ROUTE('GET /named/ --> *Options/named');
	ROUTE('GET /guarded/ --> *Options/guarded');
	ROUTE('GET /slow/ --> *Options/slow');
	ROUTE('GET /cached/ --> *Options/cached');
	ROUTE('GET /output/ --> *Options/output');
};
```

## Total.js 5 API guide by task

Source: https://forge.totaljs.es/en/docs/total5-coverage-map/
Framework: total5@0.0.19
Content-SHA256: aecbccee658ac585644f027f210437bc8b284f99b0ce3dd199ee4bd88bd5a667
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

Use these references to choose the native Total.js 5 API for your task. The examples target total5@0.0.19.

## Native backend references

| Area | Reference and examples |
|---|---|
| Installation, directories and startup | [getting started](/en/docs/getting-started/), [project structure](/en/docs/project-structure/), [LOAD and NPMINSTALL](/en/total5/load-and-npminstall/), [application bundles](/en/total5/application-bundles/), [release/debug modes](/en/total5/release-mode-and-debugging/) |
| Global API and configuration | [globals](/en/docs/globals-total5/), [configuration keys](/en/docs/configuration-keys/), [configuration files](/en/total5/configuration-file/) |
| Routing and controller | [route syntax](/en/docs/route-syntax/), [controller API](/en/docs/controller-api/), [completion and conditional responses](/en/total5/controller-completion-and-cache/), [upload lifecycle and query links](/en/total5/upload-lifecycle-and-href/), [static cache invalidation](/en/total5/touch-static-cache/) |
| Actions and validation | [action reference](/en/docs/action-options/), [input types](/en/docs/input-types/), [enums and format boundaries](/en/total5/schema-enums-and-formats/), [numeric boundaries](/en/total5/numeric-schema-boundaries/), [hooks and admin guards](/en/total5/action-hooks-and-admin/), [transport options](/en/total5/action-transport-boundaries/), [audit](/en/total5/action-audit/) |
| Database queries | [DATA](/en/total5/data-api/), [introductory DB/NEWDB](/en/total5/query-builder-db/), [builder operations and driver contract](/en/total5/query-builder-contract/), [real SQLite CRUD and transactions](/en/total5/query-builder-sqlite/), [NoSQL](/en/total5/nosql-crud/), [file storage](/en/total5/filestorage/) |
| Messaging and platform protocols | [WebSockets](/en/total5/websocket-chat/), [TMS](/en/total5/tms/), [OPENCLIENT protocol fixture](/en/total5/openclient-protocol/), [real OpenLDAP fixture](/en/total5/ldap-openldap/) |
| Flow and executable components | [FlowStream](/en/total5/flowstream/), [component testing](/en/total5/flowstream-component-test/), [flow files and workers](/en/total5/flow-files-and-workers/), [native server components](/en/total5/native-components/) |
| Optional remote services | [API drivers](/en/total5/api-drivers/), [TotalAPI and Componentator local boundaries](/en/total5/remote-service-boundaries/) |
| Full application | [Taskboard reference](/en/docs/taskboard-reference/): sessions, CSRF, owner-scoped NoSQL CRUD and browser assertions; exported app has separate restart/revocation checks |

Additional existing recipes cover views/localization, email, encryption helpers, caching, file downloads, proxies, jobs, threads, HTTP clients, macros, image conversion, AI-model driver contracts and Python processes. Use the Total5 catalogue and per-page declared scope for their exact behavior. Python scripts, image converter programs and directory servers are separate environment requirements, not npm dependencies of the framework core.

## Which QueryBuilder?

The native DB/NEWDB API builds an options object for a registered driver. DATA is the singleton entry point for independent operations; DB creates a queue. Queue ordering is not a transaction. The SQLite recipe implements a bounded application-owned driver and explicit connection-owned transactions.

The optional [official querybuilderpg integration](https://github.com/totaljs/querybuilderpg) is a separate PostgreSQL package. Initialize a named connection with its connection string and pooling options, then use DATA. The application-owned SQLite driver is specific to SQLite.

## Behavior in total5@0.0.19

Use these version-specific behaviors when writing application code:

- Compact Int accepts fractions and Number2 does not round to two places; SmallInt bounds differ from the familiar SQL range.
- Compact JSON and IP labels are read as plain strings; use explicit native JSON Schema subtypes when you need those formats enforced.
- For action csrf/encrypt/compress metadata, use explicit CSRF middleware and test the actual transport.
- For LDAP, decide authentication from your own check of the bind result.
- For query links use QUERIFY with a copied query.
- For QueryBuilder column selection, use fields with an application allowlist.

## Input types of NEWACTION

Source: https://forge.totaljs.es/en/docs/input-types/
Framework: total5@0.0.19
Content-SHA256: 44656a0df7eb097a27c8aa84184977e03028e29192b75dd120a80d0888d881bc
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

A definition is a list of `name:Type` separated by commas, for example `*email:Email, age:Number`. A `*` before the name makes the field required. The same format is used by `input` (the body), `params`, `query` and `output`. **The type converts the value**: the action receives the converted value, not the text that was sent.

The names of the types are not case sensitive. Every type below was checked by sending the value in the second column.

| Type | Value sent | Value received | Notes |
|---|---|---|---|
| `String` | `  hello  ` | `hello` | Text; leading and trailing spaces are removed. |
| `Text` | `  text  ` | `  text  ` | Text kept exactly as it was sent. |
| `Email` | ` A@B.CZ ` | `a@b.cz` | A valid email address, in lowercase; anything else is rejected. |
| `Phone` | `+421 900 123 456` | `+421900123456` | A phone number; spaces are removed. |
| `URL` | `https://totaljs.com/x` | `https://totaljs.com/x` | A valid URL; anything else is rejected. |
| `Name` | `john smith` | `John Smith` | Capitalizes every word. |
| `Capitalize` | `hello big world` | `Hello Big World` | Capitalizes every word. |
| `Capitalize2` | `HELLO big WORLD` | `Hello big world` | Capitalizes the first letter only and lowercases the rest. |
| `Lowercase` | `ABC` | `abc` | Lowercase. |
| `Uppercase` | `abc` | `ABC` | Uppercase. |
| `Search` | `Žluťoučký Kůň` | `zlutoucki kun` | Lowercase without accents, for searching. |
| `SafeString` | `plain text` | `plain text` | Text; a value with HTML tags such as `` is rejected. |
| `Color` | `#FF0000` | `#FF0000` | [schema-enums-and-formats](/en/total5/schema-enums-and-formats/) |
| `Base64` | `SGVsbG8=` | `SGVsbG8=` | [schema-enums-and-formats](/en/total5/schema-enums-and-formats/) |
| `Zip` | `81101` | `81101` | [schema-enums-and-formats](/en/total5/schema-enums-and-formats/) |
| `Icon` | `ti ti-home` | `ti ti-home` | [schema-enums-and-formats](/en/total5/schema-enums-and-formats/) |
| `Number` | `12.5` | `12.5` | A number; the text is converted. |
| `Float` | `3.14` | `3.14` | A number; the text is converted. |
| `Decimal` | `2.5` | `2.5` | A number; the text is converted. |
| `Boolean` | `true` | `true` | `true` or `false`; the text `true` is converted. |
| `Date` | `2026-01-05` | `2026-01-05T00:00:00.000Z` | A date. In JSON it is sent as an ISO text. |

Other forms:

| Form | Example | Notes |
|---|---|---|
| `[String]`, `[Number]` | `ze_arr:[String]` | An array of that type: every item is converted. |
| `{ x:Number, y:String }` | `zg_obj:{ x:Number, y:String }` | A nested object, validated with its own fields. |
| `String(5)` | `zd_max:String(5)` | A text of at most 5 characters; a longer text is rejected. |

A value that does not fit the type is rejected with status 400 and the name of the field in the error. These values were rejected in the checks: `SafeString` with `x`, `String(5)` with ten characters, a `UID` with `abc`, and a `GUID` with `not-guid`. The boundary recipe verifies `Int`, `SmallInt`, `TinyInt`, `Number2`: [numeric-schema-boundaries](/en/total5/numeric-schema-boundaries/). In this version `Int` does not truncate: `7.9` stays `7.9`.

`UID` and `GUID` accept the values that `UID()` and `GUID()` create.

```js definitions/types.js
NEWACTION('Types/all', {
	name: 'Every type',
	input: 'a_string:String, b_text:Text, c_email:Email, d_phone:Phone, e_url:URL, f_name:Name, g_capitalize:Capitalize, h_capitalize2:Capitalize2, i_lowercase:Lowercase, j_uppercase:Uppercase, k_search:Search, l_safestring:SafeString, m_color:Color, n_base64:Base64, o_zip:Zip, p_icon:Icon, q_number:Number, r_float:Float, s_decimal:Decimal, t_boolean:Boolean, u_date:Date, ze_arr:[String], zf_nums:[Number], zg_obj:{ x:Number, y:String }, zd_max:String(5)',
	action: function($, model) {
		$.callback(model);
	}
});

NEWACTION('Types/ids', {
	name: 'UID and GUID',
	input: '*id:UID, *key:GUID',
	action: function($, model) {
		$.callback(model);
	}
});
```

```js controllers/types.js
exports.install = function() {
	ROUTE('POST /types/ @json --> *Types/all');
	ROUTE('POST /ids/ @json --> *Types/ids');
	ROUTE('GET /newids/', ids);
};

function ids($) {
	$.json({ id: UID(), key: GUID() });
}
```

## Global names of jComponent 20

Source: https://forge.totaljs.es/en/docs/globals-jcomponent/
Framework: jcomponent@20
Content-SHA256: 475033e653e583e6bfd9374c95487eef789587c4d321284b4df134d1eb32018b
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b
Review: not-recorded

jComponent 20 exposes global functions and objects for state, components, requests and browser utilities. The bundle also includes jQuery. Use the table to find a name and its usage recipe.

| Name | Kind | What it does | Recipe |
|---|---|---|---|
| `$` | function | jQuery. | [getting-started](/en/jcomponent/getting-started/) |
| `$totaluidate` | function | Internal: the hour minus 12 from noon on (`$totaluidate(13)` is `1`, `$totaluidate(5)` stays `5`). | [data-helpers](/en/jcomponent/data-helpers/) |
| `$W` | object | The jQuery object of the window. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `ADAPT` | function | Replaces the markers (`~PATH~`, `~ID~`, `CLASS`) and translates the text of a component. | [find-and-call](/en/jcomponent/find-and-call/) |
| `AJAX` | function | `AJAX('METHOD /url/', data, callback)` makes a request to the server. | [ajax](/en/jcomponent/ajax/) |
| `API` | function | Calls an `ROUTE('API ...')` endpoint of Total.js with a schema name and data. | [api-calls](/en/jcomponent/api-calls/) |
| `APPEARANCE` | function | Sets the color, the dark mode and the CSS variables of the page. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `ASETTER` | function | Returns a function that calls `SETTER()` later. | [find-and-call](/en/jcomponent/find-and-call/) |
| `ATTRD` | function | Reads a `data-` attribute of an element or an event. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `BLOCKED` | function | Returns false the first time and true during a time: a guard against repeated actions. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `CACHE` | function | Stores a value in the browser for a period. | [storage-cache-pref-cookies](/en/jcomponent/storage-cache-pref-cookies/) |
| `CACHEPATH` | function | Keeps a path of the state in the cache and restores it. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `CL` | function | Loads the code lists that are registered with `CLINIT()` and are not loaded yet. | [data-helpers](/en/jcomponent/data-helpers/) |
| `clearTimeout2` | function | Cancels a timer of `setTimeout2()`. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `CLINIT` | function | Registers a code list and the function that loads it. | [data-helpers](/en/jcomponent/data-helpers/) |
| `CLONE` | function | Deep copy of a value, dates included. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `CLRELOAD` | function | Loads code lists again. | [data-helpers](/en/jcomponent/data-helpers/) |
| `CMD` | function | Runs a command of a component. Use the `CMD` of an instance or `EXEC`. | [commands](/en/jcomponent/commands/) |
| `COMPILE` | function | The same function as `NOOP` in jComponent 20. | [find-and-call](/en/jcomponent/find-and-call/) |
| `COMPONENT` | function | Declares a component. | [custom-component](/en/jcomponent/custom-component/) |
| `COMPONENTS` | function | The ready components under a path. | [find-and-call](/en/jcomponent/find-and-call/) |
| `CONFIG` | function | Changes the configuration of components found by a selector. | [component-config](/en/jcomponent/component-config/) |
| `COOKIES` | object | Reads, writes and removes cookies. | [storage-cache-pref-cookies](/en/jcomponent/storage-cache-pref-cookies/) |
| `COPY` | function | Copies the properties of an object into another one, deep. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `DAYS` | object | The names of the days of the week in English, from Sunday. | [data-helpers](/en/jcomponent/data-helpers/) |
| `DECRYPT` | function | Reads a value made by `ENCRYPT()` with the same key and type. | [data-helpers](/en/jcomponent/data-helpers/) |
| `DEF` | object | Defaults of jComponent. `DEF.fallback` is the address from which components that are not loaded are downloaded. | - |
| `DIFFDOM` | function | Makes the children of an element the same as a new list without redrawing the ones that stay. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `EMIT` | function | Emits a global event. | [events](/en/jcomponent/events/) |
| `EMPTYARRAY` | object | A frozen empty array. | [data-helpers](/en/jcomponent/data-helpers/) |
| `EMPTYOBJECT` | object | A frozen empty object. | [data-helpers](/en/jcomponent/data-helpers/) |
| `ENCRYPT` | function | Turns a value into hexadecimal text with a check of the key (obfuscation, not security). | [data-helpers](/en/jcomponent/data-helpers/) |
| `ENV` | function | Registers or reads a value of the page, used in URLs as `[name]`. | [environment-variables](/en/jcomponent/environment-variables/) |
| `ENVIRONMENT` | function | Sets the name of the application for the storage, the version and the language. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `ERROR` | function | Helper to handle the validation errors of an `API()` answer. | [api-calls](/en/jcomponent/api-calls/) |
| `ERRORS` | function | Returns the invalid components under a path. | [validation](/en/jcomponent/validation/) |
| `EXE` | function | Calls a plugin method, a global function or a function of the state (the same as `EXEC()`). | [find-and-call](/en/jcomponent/find-and-call/) |
| `EXEC` | function | Calls the method of a plugin (`EXEC('plugin/method')`) or a global function. | [commands](/en/jcomponent/commands/) |
| `EXTENSION` | function | Adds code to every instance of a component or plugin. | [extensions](/en/jcomponent/extensions/) |
| `FIND` | function | Finds a ready component by name, path or id. | [find-and-call](/en/jcomponent/find-and-call/) |
| `FLAGS` | function | Dispatches custom path flags and invokes a callback. | [custom-flags](/en/jcomponent/custom-flags/) |
| `FN` | function | Compiles an expression into a function and remembers it. | [data-helpers](/en/jcomponent/data-helpers/) |
| `FREE` | function | Runs the cleanup of removed components at once. | [component-lifecycle](/en/jcomponent/component-lifecycle/) |
| `FUNC` | object | An object for functions that `EXE('FUNC.name')` can call. | [find-and-call](/en/jcomponent/find-and-call/) |
| `GET` | function | Reads a value from a path of the state. | [state-api](/en/jcomponent/state-api/) |
| `GUID` | function | Returns a random id. | [utilities](/en/jcomponent/utilities/) |
| `HASH` | function | Returns a numeric hash. | [utilities](/en/jcomponent/utilities/) |
| `HIDDEN` | function | True when an element is not shown. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `IMPORT` | function | Loads an HTML part, a script or a style from a URL. | [ui-import](/en/jcomponent/ui-import/) |
| `INC` | function | Adds 1 (or the given number) to the number in a path. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `inDOM` | function | True while an element is in the document. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `isIE` | boolean | True in Internet Explorer. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `isMOBILE` | boolean | True on a mobile device. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `isPRIVATEMODE` | boolean | True in a private window. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `isROBOT` | boolean | True for a search engine robot. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `isSTANDALONE` | boolean | True when the page runs as an installed application. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `isTOUCH` | boolean | True on a device with touch. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `jComponent` | object | The engine of jComponent: `M.components`, `M.version`... | [find-and-call](/en/jcomponent/find-and-call/) |
| `jQuery` | function | jQuery, bundled in the same file. | [getting-started](/en/jcomponent/getting-started/) |
| `LOCALIZE` | function | Loads a dictionary in the format of the Total.js resource files. | [data-helpers](/en/jcomponent/data-helpers/) |
| `M` | object | The engine of jComponent (the same object as `jComponent`, `Total` and `MAIN`). | [find-and-call](/en/jcomponent/find-and-call/) |
| `MAIN` | object | The engine of jComponent (the same object as `jComponent`, `Total` and `M`). | [find-and-call](/en/jcomponent/find-and-call/) |
| `MIDDLEWARE` | function | Registers a function that runs before a route, or runs a list of them in order. | [find-and-call](/en/jcomponent/find-and-call/) |
| `MONTHS` | object | The names of the months in English. | [data-helpers](/en/jcomponent/data-helpers/) |
| `NAV` | object | The current location: `url`, `query`, `params`, and `back()`/`forward()`. | [spa-routing](/en/jcomponent/spa-routing/) |
| `NEWUIBIND` | function | Makes a `ui-bind` on an element from the code. | [find-and-call](/en/jcomponent/find-and-call/) |
| `NODEINDEXOF` | function | The position of an element among its siblings. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `NODEINSERT` | function | Moves an element after or before another one. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `NODEMOVE` | function | Moves an element one place down or up in its parent. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `NOOP` | function | A function that does nothing. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `NOTFOCUSED` | function | True when the browser tab is in the background. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `NOW` | object | A `Date` that jComponent keeps up to date. | [data-helpers](/en/jcomponent/data-helpers/) |
| `NUL` | function | Sets the value of a path to `null` (the same as `NULL`). | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `NULL` | function | Sets the value of a path to `null`. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `OFF` | function | Removes listeners of a global event. | [events](/en/jcomponent/events/) |
| `ON` | function | Registers a listener for a global event. | [events](/en/jcomponent/events/) |
| `PARSE` | function | Parses JSON and turns date strings into dates. | [utilities](/en/jcomponent/utilities/) |
| `PIPE` | function | `API()` to the address in `DEF.pipe`. | [find-and-call](/en/jcomponent/find-and-call/) |
| `PLUGIN` | function | Declares a plugin. | [plugin](/en/jcomponent/plugin/) |
| `PLUGINS` | object | The plugins of the page by their path. | [find-and-call](/en/jcomponent/find-and-call/) |
| `PREF` | object | User preferences saved in the browser. | [storage-cache-pref-cookies](/en/jcomponent/storage-cache-pref-cookies/) |
| `PUSH` | function | Adds a value to an array of the state and notifies. | [state-api](/en/jcomponent/state-api/) |
| `QUERIFY` | function | Makes a query string from an object, also after an address or a method. | [data-helpers](/en/jcomponent/data-helpers/) |
| `REDIRECT` | function | Changes the address without loading the page and runs the matching route. | [spa-routing](/en/jcomponent/spa-routing/) |
| `REPO` | object | An object of yours to share data between components. | [find-and-call](/en/jcomponent/find-and-call/) |
| `RESET` | function | Clears the touched and modified states under a path. | [validation](/en/jcomponent/validation/) |
| `ROUTE` | function | Registers a client-side route. | [spa-routing](/en/jcomponent/spa-routing/) |
| `SCROLLBAR` | function | Wraps an element with a custom scrollbar. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `SCROLLBARWIDTH` | function | The width that a scrollbar takes. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `SEEX` | function | Calls a function by name or sets a path. | [find-and-call](/en/jcomponent/find-and-call/) |
| `SET` | function | Writes a value at a path of the state and notifies everything bound to it. | [state-api](/en/jcomponent/state-api/) |
| `SETTER` | function | Calls a method of every component with a name, path or id. | [find-and-call](/en/jcomponent/find-and-call/) |
| `setTimeout2` | function | A debounced `setTimeout()` with an id and an optional limit of restarts. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `STRINGIFY` | function | `JSON.stringify()` that can compress empty values and choose the fields. | [data-helpers](/en/jcomponent/data-helpers/) |
| `STYLE` | function | Adds a style to the head; the same id replaces it. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `Ta` | object | The same object as `Tangular`, the template engine. | [data-helpers](/en/jcomponent/data-helpers/) |
| `Tangular` | object | The template engine. | [ui-bind-templates](/en/jcomponent/ui-bind-templates/) |
| `TAPI` | function | `API()` to the address in `DEF.api`. | [find-and-call](/en/jcomponent/find-and-call/) |
| `TEMP` | object | An object for temporary data. | [find-and-call](/en/jcomponent/find-and-call/) |
| `Thelpers` | object | The helpers of the templates (`Tangular.helpers`): add one with `Thelpers.name = fn`. | [data-helpers](/en/jcomponent/data-helpers/) |
| `TOGGLE` | function | Changes the boolean in a path. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `Total` | object | The engine of jComponent (the same object as `jComponent`). | [find-and-call](/en/jcomponent/find-and-call/) |
| `TRANSLATE` | function | Replaces every `@(text)` with its translation. | [data-helpers](/en/jcomponent/data-helpers/) |
| `UNAUTHORIZED` | function | True when `window.user` has none of the given permissions. | [data-helpers](/en/jcomponent/data-helpers/) |
| `UNWATCH` | function | Removes the watchers of a path made with `WATCH()`. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `UPD` | function | Notifies a path after you changed the object in place. | [state-api](/en/jcomponent/state-api/) |
| `UPDATE` | function | Notifies the components and the watchers of a path without changing it (alias `UPD`). | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `UPLOAD` | function | Sends a `FormData` to a route with progress. | [upload](/en/jcomponent/upload/) |
| `VISIBLE` | function | True when an element is in the visible part of the window. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `W` | object | The `window`. | [find-and-call](/en/jcomponent/find-and-call/) |
| `WAIT` | function | Runs a function when another one returns true or a path has a value; checks every 500 ms. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `WARN` | function | Writes to `console.warn`. | [state-shortcuts](/en/jcomponent/state-shortcuts/) |
| `WATCH` | function | Runs a function every time a path changes. | [state-api](/en/jcomponent/state-api/) |
| `WH` | number | The height of the window. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `WIDTH` | function | The size class of the width of an element or the window: xs, sm, md or lg. | [dom-helpers](/en/jcomponent/dom-helpers/) |
| `WW` | number | The width of the window. | [dom-helpers](/en/jcomponent/dom-helpers/) |

```html public/index.html



	
	jComponent
	
	


	

The test lists the globals of this page.

``` ## Total.js strengths and the application problems they solve Source: https://forge.totaljs.es/en/docs/totaljs-strengths/ Framework: total5@0.0.19 Content-SHA256: 4ac399045c8774737de1e5d46188c4230b57be3a7a260c4c950ac9c93f76cef6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js is much more than HTTP routing. Its central strength is a dependency-free framework core that brings the whole backend together under shared conventions: routes, validation, authentication, views, uploads, realtime, scheduled work and more. For a team building APIs, business applications or live dashboards, that means fewer separately selected packages, less integration code and a project that stays easy to maintain as it grows. ## What Total.js offers | Strength | What it gives an application | Source or example | |---|---|---| | Framework core without third-party npm dependencies | The installed `total5@0.0.19` package declares no external runtime dependencies. No tree of modules from different authors to keep compatible, and no module that stops being maintained and leaves your project stranded. This protects the continuity and the scalability of a project in a very direct way. | [Framework source and package manifest](https://github.com/totaljs/framework5), [official platform description](https://www.totaljs.com/) | | Integrated backend facilities | Routing, schemas, views, uploads, scheduled jobs, email and localization share one set of conventions. A business application covers many requirements without assembling a separate library for each one. | [Project structure](/en/docs/project-structure/), [uploads](/en/total5/file-upload/), [cron](/en/total5/cron-jobs/), [email](/en/total5/send-email/), [localization](/en/total5/localization/) | | Robust input validation and authentication | Required fields, input contracts, protected routes, signed sessions and CSRF protection are native building blocks, so security starts built in instead of assembled from add-ons. | [Input validation](/en/total5/validate-json-body/), [protected routes](/en/total5/protect-routes-with-auth/), [sessions](/en/total5/sessions-with-built-in-auth/) | | Realtime communication | WebSocket server and client facilities power bidirectional applications such as live dashboards, notifications and connected services. | [WebSocket server](/en/total5/websocket-chat/), [WebSocket client](/en/total5/websocket-client/) | | FlowStream in the backend | Connected components let an application express message-processing workflows and change component configuration while running: ideal for automation and integration pipelines. | [FlowStream example](/en/total5/flowstream/), [component test](/en/total5/flowstream-component-test/) | | Native Python process integration | `PYPELINE` is a framework-managed path to start Python scripts and exchange data. Your Node.js application keeps its API and orchestration while Python handles a specialist task. | [PYPELINE entry point](https://github.com/totaljs/framework5/blob/main/global.js), [implementation](https://github.com/totaljs/framework5/blob/main/pypeline.js) | | Server-rendered pages in the same framework | Views, layouts, includes and localization let one application serve HTML next to its APIs and realtime endpoints. | [Views and layouts](/en/total5/views-and-layouts/), [includes and assets](/en/total5/view-includes-and-assets/) | | Direct routes and reusable actions | A small endpoint answers from its controller; a domain operation uses an action and its validated contract. You choose the layer each piece needs. | [Direct controller example](/en/docs/choosing-totaljs/), [native action example](/en/docs/totaljs-agent-conventions/) | | Open-source framework under MIT | You can read the implementation, learn from it and adapt it under the license terms, including for commercial applications. | [Framework license](https://github.com/totaljs/framework5/blob/main/LICENSE) | ## Python interoperability: a concrete capability In the `total5@0.0.19` source, `PYPELINE(name, options)` resolves named scripts from `pypelines/` or accepts inline Python. It starts a `python3` process and exchanges messages over a local socket, supporting JSON, text and binary data. This is a built-in bridge between the Node.js application and Python processing, so data science, imaging or machine-learning code can sit next to your API without a separate service. Python needs to be installed in the target environment, and a script may use Python packages of its own, as with any Python project. ## Fast and light Total.js is fast, and it is light: an all-in-one core without a dependency tree means fewer packages to install, load, update and audit, which counts most on small servers and small devices. Forge measures it under controlled conditions and publishes latency, CPU and memory for every workload, with hardware, versions, raw data and downloadable archives, in the [benchmarks](/en/benchmarks/), so you can see the numbers and reproduce them. ## Secure from the first line The core has no third-party npm dependencies, so a whole class of supply-chain risk never reaches your installation. On top of that, native input validation, authentication, signed sessions, CSRF protection and scrypt password hashing make every application secure by construction. Add the usual deployment practice of any serious project, HTTPS and a trusted proxy, and you have a solid foundation. ## Easy to learn, with a lot to start from Total.js is JavaScript. In our experience the learning curve is very short, so a team that does not know it yet is not at a disadvantage. The Total.js repositories contain a large collection of scripts and examples, and complete applications under the MIT licence: they are ready-made solutions you can use, and clear examples of how the framework is meant to be used. Forge adds executed recipes in 14 languages to go with them. ## An ecosystem that grows with you On the frontend, Total.js comes with jComponent and a [catalogue of hundreds of ready-made components](/en/components/), so the interface grows from the same foundations as the backend. The [official platform site](https://www.totaljs.com/) shows the wider Total.js ecosystem, with separate apps and tools for the frontend, for automation and for desktop, including tooling for Apple platforms. They build on the same foundations as the framework, and none of them is required to build a backend with Total.js. ## Evidence and scope This guide describes capabilities of the `total5@0.0.19` package and links to executed Forge examples and official sources. The source links to `main` can change, so check the installed version before copying an API. The [execution manifest](/ai-validation.json) lists the introductory guide examples that Forge executes. Read [why choose Total.js](/en/docs/choosing-totaljs/) for the decision overview and [native assistant conventions](/en/docs/totaljs-agent-conventions/) for implementation guidance. ## Why choose Total.js for a Node.js application Source: https://forge.totaljs.es/en/docs/choosing-totaljs/ Framework: total5@0.0.19 Content-SHA256: 808147362df4aec1a9d9eec0e5cf9621bb4e70391d2e138ea6680ddd5d9f8c41 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js 5 is a complete Node.js application framework, distributed as `total5`. One package gives a team HTTP routes, input validation, server-rendered views, authentication, uploads, WebSocket routes, scheduled jobs, localization, email and more, all designed to work together. You build the application instead of choosing, wiring and maintaining a dozen separate libraries. ## What your project gets | What your project needs | What Total.js gives you | See it in Forge | |---|---|---| | An internal business application with forms, protected routes and file uploads | Native input schemas, authentication hooks and upload handling, ready to use | [Validation](/en/total5/validate-json-body/), [authentication](/en/total5/protect-routes-with-auth/), [uploads](/en/total5/file-upload/) | | A dashboard with live updates and periodic reports | WebSocket routes, scheduled jobs and email in the same framework | [WebSocket example](/en/total5/websocket-chat/), [cron jobs](/en/total5/cron-jobs/), [email](/en/total5/send-email/) | | A small team that wants to ship and maintain one server application | Auto-loaded files and a shared set of conventions that keep every project familiar | [Project structure](/en/docs/project-structure/), [conventions](/en/docs/totaljs-agent-conventions/) | | A server-rendered application | Views, layouts and localization inside the same framework | [Views and layouts](/en/total5/views-and-layouts/), [localization](/en/total5/localization/) | Every row links to an example that Forge executes. On the frontend, Total.js has jComponent and a [catalogue of hundreds of ready components](/en/components/), so the same ecosystem covers the interface too; using them is optional. ## Why teams choose Total.js A core without external dependencies. The installed `total5` package declares no third-party runtime dependencies. There is no chain of modules written by different authors to keep compatible, no abandoned package that stops your build, no surprise from a transitive update. Continuity like this has a direct and powerful effect on how well a project scales and how easily it is maintained over the years: what you learn and ship today keeps working, backed by one project. Built-in security APIs. The framework includes authentication, signed sessions, CSRF checks, scrypt password hashing and action input validation. Apply these facilities to your application routes and data. The [Taskboard reference application](/en/docs/taskboard-reference/) combines them in one application. A fast learning curve. Total.js is JavaScript, with conventions that are quick to pick up, so a team that does not know it yet is not at a disadvantage. The Total.js repositories hold a large collection of scripts, examples and complete applications under the MIT licence that you can read, reuse and learn from, and Forge adds executed recipes for the rest. Fast and light. Total.js is fast, and one package with no dependency tree keeps it light: fewer things to load, update and audit, which counts most on small servers and small devices. Forge measures it under controlled conditions and publishes latency, CPU and memory for every workload, with the raw data, in the [benchmarks](/en/benchmarks/). ## Start simple: a direct HTTP route This executable example validates a body with a compact native schema and answers directly from a controller: a few lines and no extra layers. As the application grows, domain actions add a reusable, validated contract that you can call from routes, code and tools. ```js controllers/contacts.js var schema = NEWSCHEMA('ContactsInput', '*name:String'); exports.install = function() { ROUTE('GET /health/', health); ROUTE('POST /contacts/', create); }; function health($) { $.json({ ok: true }); } function create($) { var result = schema.transform($.body); if (result.error) { $.response.status = 400; $.json({ error: 'invalid' }); return; } $.response.status = 201; $.json({ name: result.response.name }); } ``` ## Sources Forge pairs its claims with things you can run. The [Total.js guidelines](https://github.com/totaljs-es/guidelines) describe the ecosystem's coding style, [Total.js AI Context](https://github.com/totaljs/aicontext) supplies implementation guidance and the [source manifest](/ai-sources.json) records the reviewed revisions. If a guide and the installed framework ever differ, the installed source is the reference. ## From Express to Total.js 5 Source: https://forge.totaljs.es/en/docs/express-to-totaljs/ Framework: total5@0.0.19 Content-SHA256: 047ebe18afed21ea0bb8f52dadd4ca12918d374970fe2f9d2224b556c36c6b10 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js is not Express with another name. The biggest differences: a handler receives **one object, `$`**, instead of `(req, res)`; the body is parsed for you by its content type; you do not install packages for cookies, uploads, validation, sessions, CORS, cron or email, because they are part of the framework; and the files of your project are **loaded from folders** instead of being imported (see the project structure page). The table pairs common Express patterns with their Total.js 5 equivalents. | Job | Express | Total.js 5 | |---|---|---| | Start the server | `app.listen(3000)` | `Total.run({ port: 3000 })` | | A route | `app.get('/users', fn)` | `ROUTE('GET /users/', fn)` (write the end slash) | | Path parameter | `app.get('/users/:id', fn)` and `req.params.id` | `ROUTE('GET /users/{id}/', fn)` and `$.params.id` | | Query string | `req.query.page` | `$.query.page` | | JSON body | `app.use(express.json())` and `req.body` | `$.body`, parsed by its content type | | Request headers | `req.headers['x-token']` | `$.headers['x-token']` | | Send JSON | `res.json(object)` | `$.json(object)` | | Send text or HTML | `res.send('text')` | `$.plain('text')` or `$.html('

..

')` | | Status code | `res.status(404).json(...)` | `$.invalid(404)` for an error, or `$.response.status = 201` before answering | | Response header | `res.set('x-a', 'b')` | `$.response.headers['x-a'] = 'b'` | | Redirect | `res.redirect('/x')` | `$.redirect('/x')` | | Cookies | `cookie-parser`, `res.cookie(...)` | `$.cookie('name')` to read, `$.cookie('name', value, '1 day')` to write | | Middleware on a route | `app.get('/a', mw, fn)` | `MIDDLEWARE('mw', ($, next) => ...)` and `ROUTE('GET /a/ #mw', fn)` | | Static files | `app.use(express.static('public'))` | Put the files in `public/`: no code | | Download a file | `res.download(path, name)` | `$.file(path, name)` | | Template | `res.render('page', model)` | `$.view('page', model)` | | Validate input | `express-validator` or `zod` | `input: '*email:Email, age:Number'` on an action | | Error page | an error-handling middleware | `ROUTE('#404', fn)` and `ROUTE('#401', fn)` | | Authentication | `passport` or `express-session` | `AUTH(fn)` and `ROUTE('+GET /private/', fn)` | | Uploads | `multer` | the flag `@upload` and `$.files` | | CORS | `cors` | `CORS('https://example.com')` | | Call another API | `axios` or `fetch` | `REQUEST()` and `RESTBuilder` | | Scheduled jobs | `node-cron` | `CRON('0 9 * * 1-5', fn)` | | Send email | `nodemailer` | `MAIL()` and `HTMLMAIL()` with `mail_smtp` in `config` | | WebSocket | `ws` or `socket.io` | `ROUTE('SOCKET /chat/', fn)` | Each part has a recipe with more detail; this is the whole mapping in one place. The example below is the Total.js side of the rows that need code. ```js definitions/compare.js MIDDLEWARE('mw', function($, next) { $.response.headers['x-a'] = 'b'; next(); }); NEWACTION('Users/create', { name: 'Create a user', input: '*email:Email, age:Number', action: function($, model) { $.callback({ email: model.email, age: model.age }); } }); ``` ```js controllers/compare.js exports.install = function() { ROUTE('GET /users/{id}/', user); ROUTE('POST /users/ --> *Users/create'); ROUTE('GET /mw/ #mw', ok); ROUTE('GET /created/', created); ROUTE('GET /moved/', moved); ROUTE('GET /cookie/', cookie); ROUTE('GET /html/', html); }; function user($) { $.json({ id: $.params.id, page: $.query.page, token: $.headers['x-token'] }); } function ok($) { $.json({ ok: true }); } function created($) { $.response.status = 201; $.json({ created: true }); } function moved($) { $.redirect('/users/1/'); } function cookie($) { $.cookie('visited', 'yes', '1 day'); $.json({ before: $.cookie('visited') || null }); } function html($) { $.html('

Hello

'); } ``` ## Validate a JSON body with an action Source: https://forge.totaljs.es/en/total5/validate-json-body/ Framework: total5@0.0.19 Content-SHA256: f17fb63e9cf7f6ea86a8bf1c188191dce6312bdd0903b83f83d84e693ce5916e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded In Total.js 5 you declare the input of an action with `input`. A star in front of a field name (`*email`) marks it as required, and the type after the colon (`Email`) is validated by the framework. Your `action` function runs only when the data is valid. Routes point to an action with the `-->` operator. The `*` prefix means "action" (as opposed to a controller function). ```js definitions/subscribe.js NEWACTION('Subscribe/exec', { name: 'Subscribe to the newsletter', input: '*email:Email, name:String', action: function($, model) { $.success(model.email); } }); ``` ```js controllers/subscribe.js exports.install = function() { ROUTE('POST /subscribe/ --> *Subscribe/exec'); }; ``` Send a valid body and the action is executed. Send an invalid e-mail address and the framework answers with a validation error without calling your function. ## Expose actions through one API endpoint Source: https://forge.totaljs.es/en/total5/api-routes/ Framework: total5@0.0.19 Content-SHA256: 27b3adc10009244d13949af7ef18f0cad861057d5c38ebc55c6cf0d8e7a6b30a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded An API route publishes actions under one URL. The client always sends `POST` with a JSON body `{ "schema": "name", "data": { ... } }`, and Total.js dispatches it to the action registered for that name. One URL, many operations: it is the style that jComponent's `API()` function speaks. The prefix of the name decides what happens to `data`: - `+name`: the input of the action is required and validated - `-name`: the action takes no input - `%name`: partial input (for patches) ```js definitions/math.js NEWACTION('Math/add', { name: 'Add two numbers', input: '*a:Number, *b:Number', action: function($, model) { $.callback({ sum: model.a + model.b }); } }); NEWACTION('Math/time', { name: 'Server time', action: function($) { $.callback({ year: new Date().getFullYear() }); } }); ``` ```js controllers/api.js exports.install = function() { ROUTE('API /api/ +math_add --> Math/add'); ROUTE('API /api/ -math_time --> Math/time'); }; ``` ## Read URL parameters in a route Source: https://forge.totaljs.es/en/total5/routes-with-params/ Framework: total5@0.0.19 Content-SHA256: a45ca90c0ed6335f89cecb2eedc19c0abb8191d26bbe2f487b4f2e3ff7f7b76f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Wrap a segment of the URL in curly braces and Total.js exposes its value in `$.params`. A route can contain as many parameters as you need. ```js controllers/users.js exports.install = function() { ROUTE('GET /users/{id}/', show_user); ROUTE('GET /users/{id}/posts/{post}/', show_post); }; function show_user($) { $.json({ id: $.params.id }); } function show_post($) { $.json({ id: $.params.id, post: $.params.post }); } ``` `$.json()` sends the value as JSON. Parameters are always strings; validate or convert them yourself, or declare their types in an action (see the actions recipe). ## Catch many URLs with a wildcard route Source: https://forge.totaljs.es/en/total5/route-wildcards/ Framework: total5@0.0.19 Content-SHA256: 22d7e15bb84e561a49e3f7be0e35f2ea48aceacffdf5c94d7f215e9dce31757e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A `*` as the last segment of a route matches any URL below that path. A route without the wildcard is more specific and wins, so you can handle the general case with the wildcard and add fixed routes for the exceptions. The request path is available in `$.url`. ```js controllers/docs.js exports.install = function() { ROUTE('GET /docs/*', docs); ROUTE('GET /docs/changelog/', changelog); }; function docs($) { $.json({ handler: 'docs', url: $.url }); } function changelog($) { $.json({ handler: 'changelog' }); } ``` ## Handle each HTTP method Source: https://forge.totaljs.es/en/total5/http-methods/ Framework: total5@0.0.19 Content-SHA256: 99c1b67162ea56e00956e7570e82728a0375c0733a8a1aa59559d50cc05ce85d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded The first word of a route is the HTTP method: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`. The same URL can have a different handler for each method, and `$.method` tells a shared handler which one was used. ```js controllers/items.js exports.install = function() { ROUTE('GET /items/', list); ROUTE('POST /items/', create); ROUTE('PUT /items/', replace); ROUTE('PATCH /items/', change); ROUTE('DELETE /items/', remove); }; function list($) { $.json({ action: 'list', method: $.method }); } function create($) { $.json({ action: 'create', method: $.method }); } function replace($) { $.json({ action: 'replace', method: $.method }); } function change($) { $.json({ action: 'change', method: $.method }); } function remove($) { $.json({ action: 'remove', method: $.method }); } ``` ## Restrict a route with flags Source: https://forge.totaljs.es/en/total5/route-flags/ Framework: total5@0.0.19 Content-SHA256: 2982c373754e84082ffea5091f58ccf444ef6779ee7247e06bc3d914126b8b7c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Flags start with `@` and go after the URL. A route only matches when the request satisfies all of its flags; otherwise Total.js tries the next route for the same URL, and answers 404 when none matches. Useful flags: - `@json` and `@xml`: the body must be JSON or XML - `@xhr`: the request must be an AJAX request (`x-requested-with` header) - `@upload`: the body must be `multipart/form-data` - `@debug` and `@release`: the route exists only in that mode - `@mobile` and `@robot`: the client is a mobile browser or a crawler ```js controllers/data.js exports.install = function() { ROUTE('POST /data/ @json', json_only); ROUTE('POST /data/ @xml', xml_only); // Careful: a route with flags has a lower priority than the same URL without flags ROUTE('POST /mixed/ @json', json_only); ROUTE('POST /mixed/', anything); }; function json_only($) { $.json({ handler: 'json' }); } function xml_only($) { $.json({ handler: 'xml' }); } function anything($) { $.json({ handler: 'anything' }); } ``` Never mix a flagged route and an unflagged route on the same URL: the unflagged one is checked first and takes every request, so the flagged route is never reached. ## Read the query string and the request body Source: https://forge.totaljs.es/en/total5/query-string-and-body/ Framework: total5@0.0.19 Content-SHA256: f77f4ecaf6dbba8493b0302111bc2ae2524d53427a83406f802506c9a05511f3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Inside a route handler, `$.query` is the parsed query string and `$.body` is the parsed body. Total.js parses JSON, URL-encoded forms and multipart forms for you, based on the `content-type` of the request. ```js controllers/echo.js exports.install = function() { ROUTE('POST /echo/', echo); }; function echo($) { $.json({ query: $.query, body: $.body }); } ``` ## Limit the payload size and the timeout of a route Source: https://forge.totaljs.es/en/total5/route-limits/ Framework: total5@0.0.19 Content-SHA256: a48c8613efaaaca3952b4f51be9ecf1b7c9cc59fb01c62a256cedfec0d2d549b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded At the end of a route you can add limits that start with `<`. `<2mb`, `<10kb` and `<500b` set the maximum size of the request body; `<30s`, `<5m` and `<1h` set the timeout of the request. A request over the limit is rejected before your handler runs. ```js controllers/limits.js exports.install = function() { ROUTE('POST /small/ <1kb', small); ROUTE('POST /big/ <5mb', big); }; function small($) { $.json({ ok: true }); } function big($) { $.json({ ok: true }); } ``` ## Declare typed route parameters in an action Source: https://forge.totaljs.es/en/total5/actions-with-params/ Framework: total5@0.0.19 Content-SHA256: 4fe73fb1c01439a14bc08ee36ba7ee5d8cc02fd1d830a7477b8660e742faccf3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded An action can describe the parameters it expects with `params`, using the same type names as `input`. UIDs are generated with `UID()` and include a checksum, so an arbitrary string is not a valid UID. When a parameter does not match its type, the framework answers with a validation error and your `action` function is not called. ```js definitions/items.js NEWACTION('Items/read', { name: 'Read an item', params: 'id:UID', action: function($) { $.success($.params.id); } }); ``` ```js controllers/items.js exports.install = function() { ROUTE('GET /items/{id}/ --> *Items/read'); }; ``` ## Choose how to respond Source: https://forge.totaljs.es/en/total5/responses/ Framework: total5@0.0.19 Content-SHA256: 0298973310cdc200347a02f33052883d73657d0a5e6348a855a3a8a783c2a4d7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A handler answers the request by calling one of the response methods of `$`. Each one sets the right `content-type` for you. | Method | Sends | |---|---| | `$.json(value)` | JSON | | `$.html(string)` | HTML | | `$.plain(string)` | plain text | | `$.xml(string)` | XML | | `$.redirect(url, [permanent])` | a redirect (302, or 301 when `permanent` is true) | | `$.empty()` | an empty response (status 204) | | `$.binary(buffer, type)` | binary data with the given content type | ```js controllers/responses.js exports.install = function() { ROUTE('GET /json/', ($) => $.json({ ok: true })); ROUTE('GET /html/', ($) => $.html('

Hello

')); ROUTE('GET /plain/', ($) => $.plain('Hello')); ROUTE('GET /xml/', ($) => $.xml('1')); ROUTE('GET /redirect/', ($) => $.redirect('/json/')); ROUTE('GET /moved/', ($) => $.redirect('/json/', true)); ROUTE('GET /empty/', ($) => $.empty()); ROUTE('GET /binary/', ($) => $.binary(Buffer.from('abc'), 'application/octet-stream')); }; ``` ## Read headers and work with cookies Source: https://forge.totaljs.es/en/total5/headers-and-cookies/ Framework: total5@0.0.19 Content-SHA256: a51d21c0651683626fd6156136be4c9f8365400b440e26a59bf982bda65251c4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `$.headers` holds the request headers with lowercase names. `$.cookie(name)` reads a cookie of the request and `$.cookie(name, value, expiration)` writes one to the response. Response headers are set on `$.response.headers`. ```js controllers/headers.js exports.install = function() { ROUTE('GET /headers/', headers); ROUTE('GET /visit/', visit); }; function headers($) { $.response.headers['x-powered-by-forge'] = 'yes'; $.json({ agent: $.headers['x-agent'] || null }); } function visit($) { var count = ($.cookie('visits') || '0').parseInt() + 1; $.cookie('visits', count + '', '1 day'); $.json({ visits: count }); } ``` ## Receive file uploads Source: https://forge.totaljs.es/en/total5/file-upload/ Framework: total5@0.0.19 Content-SHA256: cc8e1202c301ef7d57c6d2a4ded68c22fafe339ba7779514ef55c287d3e83d74 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Mark the route with `@upload` so it only accepts `multipart/form-data`, and set a size limit that fits the files you expect (here `<5mb`). The uploaded files are in `$.files`; the other fields of the form are in `$.body`. Each file has `name`, `filename`, `size` and `type`, and methods such as `read()`, `copy()` and `move()`. ```js controllers/upload.js exports.install = function() { ROUTE('POST /upload/ @upload <5mb', upload); }; function upload($) { var file = $.files[0]; if (!file) { $.invalid('No file'); return; } file.read(function(err, buffer) { $.json({ filename: file.filename, size: file.size, type: file.type, text: buffer.toString('utf8'), title: $.body.title }); }); } ``` ## Allow cross-origin requests with CORS Source: https://forge.totaljs.es/en/total5/cors/ Framework: total5@0.0.19 Content-SHA256: 19d1e5e05b9e75f6423fa945f690b5f170fcdc1065d0ecbc59ba4271dd30724d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Browsers block requests from other origins unless the server allows them. `CORS(origin)` sets the allowed origins for the whole app: pass an address, a comma-separated list, or nothing to allow every origin (`*`). Prefix an address with `+` to add it to the existing list. ```js definitions/cors.js CORS('https://app.example.com'); ``` ```js controllers/api.js exports.install = function() { ROUTE('GET /api/time/', ($) => $.json({ ok: true })); }; ``` ## Render a view without writing a handler Source: https://forge.totaljs.es/en/total5/view-without-handler/ Framework: total5@0.0.19 Content-SHA256: 32fc1257277ade3f3462f63f6feed151aaea8fd98344211a4400a0b6e7b514a9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded When a route has no handler, Total.js renders a view for it: `views/about.html` for `/about/` and `views/index.html` for `/`. You can also name the view yourself by passing a string instead of a function. ```html views/layout.html @{body} ``` ```html views/index.html

Home

``` ```html views/about.html

About us

``` ```html views/contact-page.html

Contact

``` ```js controllers/default.js exports.install = function() { ROUTE('GET /'); ROUTE('GET /about/'); ROUTE('GET /contact/', 'contact-page'); }; ``` ## Pick the right input type for an action Source: https://forge.totaljs.es/en/total5/input-types/ Framework: total5@0.0.19 Content-SHA256: 94e8b431828404458a5dd183a56f8114ec936a5e5936d5487639090ed99358f4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded The `input` of an action is a list of `name:Type` fields separated by commas. A `*` before the name makes the field required. Besides validating, many types **convert** the value, so the action receives clean data: | Type | Result | |---|---| | `String`, `Number`, `Boolean`, `Date`, `Object`, `Array` | the basic types (strings are trimmed, numbers and dates are parsed) | | `Email`, `Phone`, `URL`, `UID`, `GUID`, `Base64`, `Color`, `Zip` | validated formats | | `Lowercase`, `Uppercase`, `Capitalize`, `Capitalize2`, `Name` | text converted to that style: `Capitalize` capitalizes every word, `Capitalize2` only the first letter of the text and lowercases the rest | ```js definitions/types.js NEWACTION('Types/exec', { name: 'Typed input', input: '*email:Email, age:Number, active:Boolean, nick:Lowercase, code:Uppercase, title:Capitalize, sentence:Capitalize2, site:URL', action: function($, model) { $.callback(model); } }); ``` ```js controllers/types.js exports.install = function() { ROUTE('POST /types/ --> *Types/exec'); }; ``` ## Validate the query string in an action Source: https://forge.totaljs.es/en/total5/action-query/ Framework: total5@0.0.19 Content-SHA256: 77ad7257e53db2b3d6562b8361c9bd5d8bae8913edd81e2448d322a1898445d9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Like `input` for the body and `params` for the path, `query` describes the query string. The framework validates it and converts the values (the page number below arrives as a real number); an invalid query answers with a validation error before your code runs. ```js definitions/search.js NEWACTION('Search/exec', { name: 'Search', query: 'q:String, page:Number, *sort:Lowercase', action: function($) { $.callback({ q: $.query.q || '', page: $.query.page || 1, sort: $.query.sort }); } }); ``` ```js controllers/search.js exports.install = function() { ROUTE('GET /search/ --> *Search/exec'); }; ``` ## Filter the response of an action with output Source: https://forge.totaljs.es/en/total5/action-output/ Framework: total5@0.0.19 Content-SHA256: 3cc2aaaa9e55db35473103cb96c6ca1e8480d56cdbfdbf6345ba475fae365801 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `output` has the same syntax as `input`, but it is applied to the **response**: only the declared fields are sent, converted to their types. Declare it on every action that reads from a database and you cannot leak a field by accident. ```js definitions/users.js NEWACTION('Users/read', { name: 'Read a user', output: 'id:String, name:String, age:Number', action: function($) { $.callback({ id: '1', name: 'Peter', age: '42', password: 'secret-hash', token: 'abc' }); } }); ``` ```js controllers/users.js exports.install = function() { ROUTE('GET /user/ --> *Users/read'); }; ``` ## Require a user or a permission in an action Source: https://forge.totaljs.es/en/total5/action-user-and-permissions/ Framework: total5@0.0.19 Content-SHA256: 007da97a72808f540a04b3dbd16a2c67d6178f57d549cef59c92333c78080b57 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded An action can protect itself: - `user: true` requires an authenticated user (otherwise 401); `user: false` allows only anonymous requests - `permissions: 'a,b'` requires the user to have at least one of the listed permissions. Total.js reads `user.permissions` (or `user.roles`), which can be an array of strings or an object - users with `sa: true` or `su: true` (super admins) pass every check The user comes from `AUTH()`, as in the authentication recipe. ```js definitions/auth.js AUTH(function($) { var users = { 'token-reports': { id: '1', name: 'Anna', permissions: ['reports'] }, 'token-sales': { id: '2', name: 'Boris', permissions: ['sales'] }, 'token-admin': { id: '3', name: 'Root', sa: true } }; var user = users[$.cookie('auth')]; user ? $.success(user) : $.invalid(); }); ``` ```js definitions/reports.js NEWACTION('Reports/read', { name: 'Read reports', user: true, permissions: 'reports,audit', action: function($) { $.success($.user.name); } }); ``` ```js controllers/reports.js exports.install = function() { ROUTE('GET /reports/ --> *Reports/read'); }; ``` ## Protect routes with AUTH Source: https://forge.totaljs.es/en/total5/protect-routes-with-auth/ Framework: total5@0.0.19 Content-SHA256: e721c95d67f27b8a74853b04e189a43be4690b3d65cd55b70462439479cb17ca Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `AUTH()` runs for every request. Call `$.success(user)` when the request is authenticated and `$.invalid()` when it is not. The user object is then available as `$.user` in every handler. Prefix a route with `+` to allow only authenticated users and with `-` to allow only anonymous users. A route without a prefix is open to everybody. ```js definitions/auth.js AUTH(function($) { // This demo reads a cookie. In a real app verify a signed session instead. var token = $.cookie('auth'); if (token === 'secret-token') $.success({ id: '1', name: 'Peter' }); else $.invalid(); }); ``` ```js controllers/private.js exports.install = function() { ROUTE('+GET /private/', private_page); ROUTE('-GET /login/', login_page); ROUTE('GET /whoami/', whoami); }; function private_page($) { $.json({ user: $.user.name }); } function login_page($) { $.json({ message: 'Please sign in' }); } function whoami($) { $.json({ user: $.user ? $.user.name : null }); } ``` ## Declare the route inside the action Source: https://forge.totaljs.es/en/total5/action-route-option/ Framework: total5@0.0.19 Content-SHA256: 224c93950bd1074c85e1c7f477d4a091e4a185e6f2eb3b71b467071cd1fc78a7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Instead of a separate `ROUTE()` line, an action can carry its own route in the `route` option. The action is then the single source of truth for its URL, input and behavior. ```js definitions/ping.js NEWACTION('Ping/exec', { name: 'Ping', route: 'GET /ping/', action: function($) { $.success('pong'); } }); ``` ## Sign users in with the built-in session auth Source: https://forge.totaljs.es/en/total5/sessions-with-built-in-auth/ Framework: total5@0.0.19 Content-SHA256: a810e4204b6a2a82ae77c2e03be8e108cd8ed1c1af85c85c4dc4bc6812c8c6ab Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Instead of a function, `AUTH(options)` accepts an options object and installs a complete cookie-session authentication: - `secret` signs the cookie, `cookie` is its name and `expire` how long a session stays in memory without activity - `onread(meta, next, $)` loads the user when a valid cookie arrives from a session that is not in memory (for example after a restart); call `next(null, user)`, or `next('not found')` to refuse. **Check that the session still exists in your own store here**, otherwise a copied cookie keeps working after the user signed out - `onlogout(session)` and `onremove(sessionid)` run when a session is removed: delete it from your store - `options.authcookie($, sessionid, userid, expiration)` signs the user in: it writes the signed cookie to the response - `options.logout($)` removes the session and the cookie Keep the options object in a variable: it is the handle you use to sign users in and out. After that, `$.user` is set and `+` and `-` routes work as in the AUTH recipe. ```js definitions/auth.js var users = { '1': { id: '1', name: 'Anna', password: 'secret' } }; // sessionid -> userid. In a real app this is a database table. MAIN.sessions = {}; MAIN.auth = { secret: 'change-this-secret', cookie: 'forge_session', expire: '1 day', onread: function(meta, next) { var user = users[MAIN.sessions[meta.sessionid]]; user ? next(null, { id: user.id, name: user.name }) : next('session not found'); }, onlogout: function(session) { delete MAIN.sessions[session.sessionid]; }, onremove: function(sessionid) { delete MAIN.sessions[sessionid]; } }; AUTH(MAIN.auth); ``` ```js controllers/account.js exports.install = function() { ROUTE('POST /login/', login); ROUTE('+POST /logout/', logout); ROUTE('+GET /me/', me); }; function login($) { var user = $.body.id && $.body.id === '1' && $.body.password === 'secret' ? { id: '1', name: 'Anna' } : null; if (!user) { $.invalid(401); return; } var sessionid = UID(); MAIN.sessions[sessionid] = user.id; MAIN.auth.authcookie($, sessionid, user.id, '1 day'); $.json({ name: user.name }); } function logout($) { MAIN.auth.logout($); $.json({ ok: true }); } function me($) { $.json({ name: $.user.name }); } ``` ## Call an action from your own code Source: https://forge.totaljs.es/en/total5/calling-actions-from-code/ Framework: total5@0.0.19 Content-SHA256: 12356e310300c771a563e19e888ee2e4f6f2e88d6ab607c4ee563fc5cc2ae7d1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `ACTION(name, payload)` returns a caller that runs the action with all its validation, exactly as if it came from a route. The second argument is the payload (the input). Chain `.query()` and `.user()` to give it more data, and finish with `.callback(function(err, response) {})` or `.promise()` (use it with `await`). When the data is invalid, `err` is an error builder instead of an exception. ```js definitions/math.js NEWACTION('Math/add', { name: 'Add two numbers', input: '*a:Number, *b:Number', action: function($, model) { $.callback({ sum: model.a + model.b }); } }); ``` ```js controllers/math.js exports.install = function() { ROUTE('GET /sum/', sum); ROUTE('GET /sum-promise/', sum_promise); }; function sum($) { ACTION('Math/add', { a: '2', b: '3' }).callback(function(err, response) { if (err) $.invalid(err); else $.json(response); }); } async function sum_promise($) { try { var response = await ACTION('Math/add', { a: 10, b: 5 }).promise(); $.json(response); } catch (err) { $.invalid(400); } } ``` ## Chain several actions in one route Source: https://forge.totaljs.es/en/total5/action-chaining/ Framework: total5@0.0.19 Content-SHA256: 8510b3a47f4f30e20391383a9d2d13e6c952729718e69a8d657359847aa55490 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A route can run more than one action: write them one after another after `-->`. They run in order, each receives the same payload, and the first error stops the chain. Add `(response)` after the action whose result must be sent; without it, the last action answers. ```js definitions/order.js NEWACTION('Order/validate', { name: 'Validate the order', input: '*product:String, *quantity:Number', action: function($, model) { model.quantity > 0 ? $.success() : $.invalid('quantity'); } }); NEWACTION('Order/save', { name: 'Save the order', input: '*product:String, *quantity:Number', action: function($, model) { $.callback({ id: 'order-1', product: model.product, quantity: model.quantity }); } }); ``` ```js controllers/order.js exports.install = function() { ROUTE('POST /order/ --> *Order/validate *Order/save (response)'); }; ``` ## Add a middleware to a route Source: https://forge.totaljs.es/en/total5/middleware/ Framework: total5@0.0.19 Content-SHA256: 21a8ac10bfbd464e0e9bceb13feb511303bd458fb154b488fc83b90d57a5a10c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A middleware is a function that runs before the route handler. Call `next()` to continue or answer the request yourself to stop it. Register it once with `MIDDLEWARE(name, fn)` and attach it to a route with `#name`. ```js definitions/middleware.js MIDDLEWARE('apikey', function($, next) { if ($.headers['x-api-key'] === 'abc123') next(); else $.invalid(401); }); ``` ```js controllers/secure.js exports.install = function() { ROUTE('GET /secure/ #apikey', secure); ROUTE('GET /open/', open); }; function secure($) { $.json({ ok: true }); } function open($) { $.json({ ok: true }); } ``` ## Build a WebSocket chat Source: https://forge.totaljs.es/en/total5/websocket-chat/ Framework: total5@0.0.19 Content-SHA256: cf99e7bc7621eedaf3fef99ac01abd403fb18681dbe94220c553c2ec6d39bc58 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A WebSocket endpoint is declared with `ROUTE('SOCKET /path/', fn)`. Inside the handler `this` is the WebSocket controller: use `self.on('message', ...)` to receive data and `self.send(...)` to broadcast to all connected clients. `client.send(...)` answers only the sender. Objects are sent and received as JSON by default. ```js controllers/chat.js exports.install = function() { ROUTE('SOCKET /chat/', socket); }; function socket() { var self = this; self.on('message', function(client, message) { self.send({ type: 'message', text: message.text }); }); } ``` ## Connect to a WebSocket server from Node Source: https://forge.totaljs.es/en/total5/websocket-client/ Framework: total5@0.0.19 Content-SHA256: 4f9fb10635b7e3d5c35888a6df54fadfa832a9d2bdc4701c8b2c7c68b702e1b3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `WEBSOCKETCLIENT(function(client) {})` gives you a client. Call `client.connect(url)` with a `ws://` or `wss://` address, listen with `client.on('open' | 'message' | 'close' | 'error', fn)` and send with `client.send(object)`; objects travel as JSON. Use `client.headers` and `client.cookies` to authenticate before connecting, and `client.close()` to disconnect. The example connects to an echo socket of its own app; point it at any WebSocket server in real code. ```js controllers/echo.js exports.install = function() { ROUTE('SOCKET /echo/', echo); ROUTE('GET /relay/', relay); }; function echo() { this.on('message', function(client, message) { client.send({ echo: message.text }); }); } function relay($) { WEBSOCKETCLIENT(function(client) { client.connect($.hostname('/echo/').replace('http', 'ws')); client.on('open', function() { client.send({ text: 'ping' }); }); client.on('message', function(message) { client.close(); $.json(message); }); client.on('error', function(err) { $.invalid(err + ''); }); }); } ``` ## Decouple your code with events Source: https://forge.totaljs.es/en/total5/events/ Framework: total5@0.0.19 Content-SHA256: 8f8c320254d43e4b540edf1b8cddaf71ba605cf9f39cb70fc33445a8edfc35ee Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `ON(name, fn)` registers a listener, `EMIT(name, a, b, c...)` calls every listener with the given arguments, `ONCE(name, fn)` listens only for the first emit and `OFF(name, fn)` removes listeners. Events are in-process and synchronous. Use them to let a feature react to something (an order was paid) without the code that causes it knowing about the feature. ```js definitions/audit.js MAIN.audit = []; ON('order.paid', function(order) { MAIN.audit.push('paid ' + order.id); }); ONCE('order.first', function(order) { MAIN.audit.push('first ' + order.id); }); ``` ```js controllers/orders.js exports.install = function() { ROUTE('POST /pay/{id}/', pay); ROUTE('GET /audit/', audit); }; function pay($) { var order = { id: $.params.id }; EMIT('order.first', order); EMIT('order.paid', order); $.json({ ok: true }); } function audit($) { $.json(MAIN.audit); } ``` ## Store and read data with the embedded NoSQL database Source: https://forge.totaljs.es/en/total5/nosql-crud/ Framework: total5@0.0.19 Content-SHA256: 558ad712b87ce6446e701b9609e02035bc1946784e2a0f1ae6e48d9252551a10 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js ships with an embedded NoSQL database. `NOSQL('name')` opens the database file `databases/name.nosql`, creating it on first use. Operations return a builder: chain `.where()` and finish with `.callback(function(err, response) {})`. ```js definitions/notes.js NEWACTION('Notes/insert', { name: 'Insert a note', input: '*text:String', action: function($, model) { model.id = UID(); NOSQL('notes').insert(model).callback(function() { $.success(model.id); }); } }); NEWACTION('Notes/query', { name: 'List notes', action: function($) { NOSQL('notes').find().callback(function(err, response) { $.callback(response); }); } }); ``` ```js controllers/notes.js exports.install = function() { ROUTE('POST /notes/ --> *Notes/insert'); ROUTE('GET /notes/ --> *Notes/query'); }; ``` ## Query the NoSQL database Source: https://forge.totaljs.es/en/total5/nosql-queries/ Framework: total5@0.0.19 Content-SHA256: 2b8af3412da934cdbd7d85af6450aca5066598672966481749b634c4c47d8197 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `NOSQL('name').find()` returns a query builder. Chain the conditions and finish with `.callback(function(err, response) {})`; `response` is an array of documents. The most useful methods: - `.where('age', '>', 30)` compares a field (the operator defaults to `=`; use `>`, `<`, `>=`, `<=`, `<>`) - `.in('city', ['Bratislava', 'Prague'])` matches any of the values - `.between('age', 20, 40)` matches a range - `.search('name', 'ann')` searches words inside a text field - `.sort('age_desc')` sorts by a field (`_asc` or `_desc`) - `.take(10)` and `.skip(20)` page the results - `.fields('name,age')` returns only those fields - `.first()` returns one document instead of an array ```js controllers/people.js exports.install = function() { ROUTE('POST /seed/', seed); ROUTE('GET /older/', older); ROUTE('GET /cities/', cities); ROUTE('GET /range/', range); ROUTE('GET /search/', search); ROUTE('GET /page/', page); ROUTE('GET /names/', names); ROUTE('GET /youngest/', youngest); }; function seed($) { var people = [ { id: '1', name: 'Anna Novak', age: 25, city: 'Bratislava' }, { id: '2', name: 'Boris Kral', age: 35, city: 'Prague' }, { id: '3', name: 'Cyril Dvorak', age: 45, city: 'Vienna' }, { id: '4', name: 'Diana Hall', age: 30, city: 'Bratislava' } ]; people.wait(function(item, next) { NOSQL('people').insert(item).callback(next); }, () => $.json({ count: people.length })); } function older($) { NOSQL('people').find().where('age', '>', 30).sort('age_desc').callback((err, response) => $.json(response)); } function cities($) { NOSQL('people').find().in('city', ['Prague', 'Vienna']).sort('name_asc').callback((err, response) => $.json(response)); } function range($) { NOSQL('people').find().between('age', 26, 40).sort('age_asc').callback((err, response) => $.json(response)); } function search($) { NOSQL('people').find().search('name', 'hall').callback((err, response) => $.json(response)); } function page($) { NOSQL('people').find().sort('age_asc').take(2).skip(2).callback((err, response) => $.json(response)); } function names($) { NOSQL('people').find().fields('name').sort('name_asc').take(2).callback((err, response) => $.json(response)); } function youngest($) { NOSQL('people').find().sort('age_asc').first().callback((err, response) => $.json(response)); } ``` ## Update and remove NoSQL documents Source: https://forge.totaljs.es/en/total5/nosql-update-and-remove/ Framework: total5@0.0.19 Content-SHA256: 894a7fd501ee19c762e00adca86b75172e9c997c4b994da7eb426d66e2a487d7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `update(data)` and `remove()` work like `find()`: add the conditions with `.where()` and finish with `.callback(function(err, count) {})`. The callback receives the number of documents that were changed or removed. **Always add a condition**: without one the operation applies to every document. `update(data)` merges the fields of `data` into the matching documents. Use `read()` to get a single document. ```js controllers/tasks.js exports.install = function() { ROUTE('POST /tasks/', create); ROUTE('PATCH /tasks/{id}/', done); ROUTE('DELETE /tasks/{id}/', remove); ROUTE('GET /tasks/{id}/', read); }; function create($) { var task = { id: $.body.id, title: $.body.title, done: false }; NOSQL('tasks').insert(task).callback(() => $.json(task)); } function done($) { NOSQL('tasks').update({ done: true }).where('id', $.params.id).callback((err, count) => $.json({ updated: count })); } function remove($) { NOSQL('tasks').remove().where('id', $.params.id).callback((err, count) => $.json({ removed: count })); } function read($) { NOSQL('tasks').read().where('id', $.params.id).callback((err, response) => $.json(response || { missing: true })); } ``` ## Use the DATA API to switch databases Source: https://forge.totaljs.es/en/total5/data-api/ Framework: total5@0.0.19 Content-SHA256: fa4d9b6515a2a695cd7f63b74ef0727aad586452f23b903a239efdd0792b4dbf Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `DATA` is a database-agnostic entry point to the query builder. The first argument is `driver/table`; `nosql/people` means "the embedded NoSQL database, table `people`". The builder methods (`where`, `sort`, `take`, `callback`) are the same you use with `NOSQL()`, so the code of your actions stays the same if you later replace the driver. | Call | Does | |---|---| | `DATA.insert(table, doc)` | inserts a document | | `DATA.find(table)` | returns a builder for a list | | `DATA.read(table)` | returns a builder for one document | | `DATA.update(table, data)` | updates documents | | `DATA.remove(table)` | removes documents | ```js definitions/people.js NEWACTION('People/insert', { name: 'Insert a person', input: '*name:String, age:Number', action: function($, model) { model.id = UID(); DATA.insert('nosql/people', model).callback(() => $.success(model.id)); } }); NEWACTION('People/query', { name: 'List people', query: 'sort:Lowercase', action: function($) { DATA.find('nosql/people').sort($.query.sort || 'name_asc').callback((err, response) => $.callback(response)); } }); NEWACTION('People/rename', { name: 'Rename a person', params: '*id:UID', input: '*name:String', action: function($, model) { DATA.update('nosql/people', { name: model.name }).where('id', $.params.id).callback((err, count) => $.success(count)); } }); ``` ```js controllers/people.js exports.install = function() { ROUTE('POST /people/ --> *People/insert'); ROUTE('GET /people/ --> *People/query'); ROUTE('PATCH /people/{id}/ --> *People/rename'); }; ``` ## Cache values in memory Source: https://forge.totaljs.es/en/total5/cache/ Framework: total5@0.0.19 Content-SHA256: f39f6142602f34545a96180b8c66d6dffc02dcddad842094041e48d80b4315ea Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `CACHE` is an in-memory key-value store with expiration. `CACHE.set(key, value, expire)` stores a value (the expiration is a text such as `'10 seconds'` or `'5 minutes'`, default `'5 minutes'`). `CACHE.get(key, default)` returns the value, or the default once it has expired. `CACHE.remove(key)` deletes one key and `CACHE.reset(search)` deletes every key that contains the text. Use it for results that are expensive to compute and may be a little stale. The cache lives in the process: it is cleared on restart and is not shared between processes. ```js controllers/cache.js exports.install = function() { ROUTE('GET /slow/', slow); ROUTE('DELETE /slow/', clear); }; var computed = 0; function slow($) { var cached = CACHE.get('slow-result'); if (cached) { $.json({ value: cached, cached: true, computed: computed }); return; } computed++; var value = 'result-' + computed; CACHE.set('slow-result', value, '1 second'); $.json({ value: value, cached: false, computed: computed }); } function clear($) { CACHE.remove('slow-result'); $.json({ ok: true }); } ``` ## Persist small settings with MEMORIZE Source: https://forge.totaljs.es/en/total5/memorize/ Framework: total5@0.0.19 Content-SHA256: 838cecbd016addba2c097481142c15d7028bebdf4bb70ec09759c6a246cfb7ed Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `MEMORIZE(name)` returns a plain object that is saved to `databases/memorize_.json` and loaded again when the app starts. Change it with `data.set(key, value)`, which also schedules the save. Saves are delayed (10 seconds by default) so several changes become one write; pass a delay in milliseconds as the second argument to change it. It is meant for small amounts of data such as counters, flags and settings. ```js definitions/counter.js MAIN.counter = MEMORIZE('counter', 100); ``` ```js controllers/counter.js exports.install = function() { ROUTE('POST /hit/', hit); ROUTE('GET /hits/', hits); }; function hit($) { var count = (MAIN.counter.hits || 0) + 1; MAIN.counter.set('hits', count); $.json({ hits: count }); } function hits($) { $.json({ hits: MAIN.counter.hits || 0 }); } ``` ## Generate unique ids and hashes Source: https://forge.totaljs.es/en/total5/unique-ids-and-hashes/ Framework: total5@0.0.19 Content-SHA256: a2d933d0ce2ac0a974dc8fe539259bf770d8fc8c8feedabafebf804b6285bda5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded - `UID()` creates a short, time-ordered, unique id (12 characters). It sorts by creation time and is what the `UID` input type validates. Use it as the primary key of your documents. - `GUID(length)` creates a random string of the requested length. Use it for tokens and file names. - `HASH(value)` returns a fast numeric hash (not cryptographic). Use it for cache keys, ETags and sharding, never for passwords. ```js controllers/ids.js exports.install = function() { ROUTE('GET /ids/', ids); }; function ids($) { var a = UID(); var b = UID(); $.json({ uid: a, uidlength: a.length, valid: a.isUID(), different: a !== b, guid: GUID(20), sameHash: HASH('total') === HASH('total'), otherHash: HASH('total') !== HASH('Total'), type: typeof(HASH('total')) }); } ``` ## Cache slow results on disk with FILECACHE Source: https://forge.totaljs.es/en/total5/filecache/ Framework: total5@0.0.19 Content-SHA256: 199e2b942373007270d2a87c79ec2477773b3bf71f16023c0c31bf2294bcf4a9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `FILECACHE(id, expiration, callback, maker)` looks for a cached file for `id`. If it exists and is younger than `expiration` (text such as `'1 minute'`), the callback receives its content; otherwise it calls `maker(done)` to compute the value, stores it and returns it. The result is serialized as JSON. Unlike `CACHE`, it survives restarts and works for large results. ```js controllers/report.js exports.install = function() { ROUTE('GET /report/', report); }; var computed = 0; function report($) { FILECACHE('monthly-report', '1 minute', function(err, response) { $.json({ report: response, computed: computed }); }, function(done) { // The expensive work goes here computed++; done(null, { total: 42, generated: computed }); }); } ``` ## Store uploaded files with FILESTORAGE Source: https://forge.totaljs.es/en/total5/filestorage/ Framework: total5@0.0.19 Content-SHA256: 6cff4aa6f8c4f6223f79ebf823911d6bce9231c2d2cab8e006db84ea9817ae7b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `FILESTORAGE(name)` is a file store: files are saved under an id (use `UID()`) and served back by that id. Receive the upload with `@upload`, save it with `file.fs(storage, id, callback)` and answer downloads with `$.filefs(storage, id)`, which sends the stored file with its `content-type`. The storage name comes from the config file, so it can change per environment. ```text config fs : files ``` ```js controllers/files.js exports.install = function() { ROUTE('POST /upload/ @upload <5mb', upload); ROUTE('FILE /downloads/*.*', download); }; function upload($) { var file = $.files[0]; if (!file) { $.invalid('No file'); return; } var id = UID(); file.fs(CONF.fs, id, function(err) { if (err) $.invalid(err); else $.json({ id: id, url: '/downloads/' + id + '.' + file.extension, filename: file.filename, size: file.size }); }); } function download($) { // /downloads/. var name = $.split[1]; var id = name.substring(0, name.lastIndexOf('.')); $.filefs(CONF.fs, id); } ``` ## Render a view with a layout Source: https://forge.totaljs.es/en/total5/views-and-layouts/ Framework: total5@0.0.19 Content-SHA256: 3f9754de17a1ccea82afe76a0a86a5df3fbd28ef19fa8d9d1d2b04559ee301c1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `$.view(name, model)` renders `views/.html` and wraps it in `views/layout.html`. Inside a view the data is available as `model`; use `@{...}` for expressions, `@{foreach ... in ...}` to loop and `@{body}` in the layout to place the view. The layout is rendered without the model. To give it values (a page title, for example) use `repository`: the object returned by `$.view()` exposes it. ```html views/layout.html @{repository.title} @{body} ``` ```html views/index.html

@{model.name}

    @{foreach item in model.items}
  • @{item}
  • @{end}
``` ```js controllers/default.js exports.install = function() { ROUTE('GET /', home); }; function home($) { var view = $.view('index', { name: 'Forge', items: ['routes', 'actions'] }); view.repository.title = 'Home'; } ``` ## Use conditions and escaping in views Source: https://forge.totaljs.es/en/total5/view-conditions-and-escaping/ Framework: total5@0.0.19 Content-SHA256: 90896da172ea4470dd44d3030fece11a2f2328706f1f1a43bb7c6536bf95f7e2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Views are HTML with `@{...}` blocks. A condition is `@{if expression}`, optionally `@{else}`, and always closed with `@{fi}`. The expression is plain JavaScript and can use `model` (the data passed to `$.view()`), `repository` (values shared with the layout), `query`, `user`, `config` and `language`. Output is **escaped by default**: `@{model.text}` turns `<` into `<`, which protects you from injection. Put a `!` after `@{` to send the raw value (`@{!model.html}`) and do it only with content you trust. ```html views/index.html @{layout('')} @{if model.admin}

Administrator

@{else}

Guest

@{fi} @{if model.items.length > 2}

many items

@{fi}
@{model.text}
@{!model.text}
``` ```js controllers/default.js exports.install = function() { ROUTE('GET /{role}/', page); }; function page($) { $.view('index', { admin: $.params.role === 'admin', items: [1, 2, 3], text: 'Hello World' }); } ``` ## Loop over arrays and objects in views Source: https://forge.totaljs.es/en/total5/view-loops/ Framework: total5@0.0.19 Content-SHA256: adab60f6b0585cd9ac35414a22c15ca854687debd2d504904f69cd77d07e4aff Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `@{foreach item in expression}` repeats the block for every element of an array, closing with `@{end}`. Inside the loop `index` is the position of the current element (starting at 0). The same syntax iterates the properties of an object: every element has a `key` and a `value`. ```html views/index.html @{layout('')}
    @{foreach product in model.products}
  • @{index}: @{product.name} - @{product.price}
  • @{end}
@{foreach field in model.meta}
@{field.key}
@{field.value}
@{end}
``` ```js controllers/default.js exports.install = function() { ROUTE('GET /', page); }; function page($) { $.view('index', { products: [{ name: 'Book', price: 12 }, { name: 'Pen', price: 3 }, { name: 'Lamp', price: 40 }], meta: { color: 'red', size: 'M' } }); } ``` ## Include views and assets Source: https://forge.totaljs.es/en/total5/view-includes-and-assets/ Framework: total5@0.0.19 Content-SHA256: b4ee4be42f5d663ec94a6951b8a6f6ee0f7e19eb6fa93a8b0274e4cbfbee6246 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `@{view(name, model)}` renders another view in place, so repeated pieces (a card, a row, a footer) live in one file. The second argument is the model of the included view. `@{import('a.js', 'a.css')}` writes the `

Invoice for {{ value.customer }}

Total: {{ value.total | money() }}

``` ```js controllers/documents.js exports.install = function() { ROUTE('GET /text/', text); ROUTE('GET /file/', file); ROUTE('GET /default/', withdefault); ROUTE('GET /absolute/', absolute); ROUTE('GET /alias/', alias); }; async function text($) { $.plain(await TEMPLATE('Hello {{ value.name }}!', { name: $.query.name || 'world' })); } async function file($) { $.plain(await TEMPLATE('invoice', { customer: 'Ana', total: 12.5 })); } function alias($) { $.json({ same: Ta === Tangular, rendered: Ta.render('{{ name }}', { name: 'x' }) }); } async function absolute($) { const file = require('path').join(__dirname, '..', 'templates', 'invoice.html'); $.plain(await TEMPLATE('~' + file, { customer: 'Eva', total: 1 })); } async function withdefault($) { $.plain(await TEMPLATE('invoice')); } ``` ## Compare two lists with DIFFARR: what to add, update and remove Source: https://forge.totaljs.es/en/total5/diffarr-sync-lists/ Framework: total5@0.0.19 Content-SHA256: a12236697023df4617897c5ec8a240897c9b3ae8fe6c8ec55b1717c1d1f9bdaf Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `DIFFARR(property, saved, submitted)` compares two arrays of objects by one property and returns an object with three lists: - `add`: the objects of `submitted` whose property is **not** in `saved` - `upd`: for the objects that are in both, `{ db, form }` with the saved object and the submitted one - `rem`: the **values of the property** (not the objects) of the items of `saved` that are not in `submitted` It is the usual step of saving an editable list: the form sends the whole list and you need to know what was created, what changed and what was deleted. The values are compared with `==`, so `1` and `'1'` are the same item. ```js controllers/lists.js const saved = [ { id: 1, name: 'Book' }, { id: 2, name: 'Pen' }, { id: 3, name: 'Lamp' } ]; exports.install = function() { ROUTE('POST /sync/', sync); }; function sync($) { const diff = DIFFARR('id', saved, $.body.items); $.json({ add: diff.add, update: diff.upd.map(n => ({ id: n.db.id, from: n.db.name, to: n.form.name })), remove: diff.rem }); } ``` ## Query builder: DB() and NEWDB() with your own database driver Source: https://forge.totaljs.es/en/total5/query-builder-db/ Framework: total5@0.0.19 Content-SHA256: 4bef065e707876cf8653fcd1df4979bebd7327aa58465f355fefd40b2d4ca631 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `DB()` builds a query without knowing which database will run it, and `NEWDB()` registers the **driver** that runs it. `total5` itself has no SQL driver: the query builder collects what you ask for into an `options` object and calls your driver with it, and the driver (yours, or one that comes in a module) translates `options` into SQL, a NoSQL call or anything else. - `NEWDB(driver)` registers the default driver and `NEWDB('name', driver)` a named one. The driver is `function(options, callback)`: answer with `callback(error, response)`. A table written as `name/table` (`DB().find('audit/log')`) uses the driver `name` and the table `log`; without a prefix the driver is `default`. - The operations start the query: `find(table)` (an array), `read(table)` (one object, or `null` when there is none), `list(table)` (a page of an array: `response.page`, `limit` and `pages` are added to what the driver returns, so the driver should set `count`) and `insert(table, data)`. The builder also has `count`, `update`, `remove` and `query`; they work the same way (the driver gets `options.exec` with that name). - Refine the query with: `where(name, [comparer], value)` (`=` when there is no comparer), `fields('a,b')`, `sort(name, [true])` (`true` for descending), `take(n)` and `page(page, limit)`. Other modifiers include `id`, `in`, `skip`, `between` and `search`. - Finish with `.callback($)`: the result goes to the response of the action `$`, or to a function `(err, response)` that you pass instead. For the complete native operation catalogue, upsert/error behavior and filter shapes, see [query-builder-contract](/en/total5/query-builder-contract/). For SQL CRUD, commit and rollback, see [query-builder-sqlite](/en/total5/query-builder-sqlite/). The options the driver receives are plain data. The example driver stores records in memory and exposes the last `options` object received. ```js definitions/db.js const users = [ { id: 1, name: 'Ann', age: 31 }, { id: 2, name: 'Bob', age: 17 }, { id: 3, name: 'Cy', age: 45 } ]; F.seen = []; // The default driver: it understands only "age >= value" and "id = value", which is all this example asks NEWDB(function(options, callback) { F.seen.push(JSON.parse(JSON.stringify(options))); let rows = users.slice(); for (let f of options.filter) { if (f.type === 'where' && f.name === 'age' && f.comparer === '>=') rows = rows.filter(n => n.age >= f.value); else if (f.type === 'where' && f.name === 'id') rows = rows.filter(n => n.id === f.value); } switch (options.exec) { case 'find': case 'read': if (options.sort && options.sort[0] === 'name_desc') rows.sort((a, b) => a.name < b.name ? 1 : -1); if (options.take) rows = rows.slice(0, options.take); return callback(null, rows); case 'list': rows.count = rows.length; return callback(null, rows); case 'insert': users.push(Object.assign({ id: users.length + 1 }, options.payload)); return callback(null, users[users.length - 1]); default: return callback('The driver does not know ' + options.exec); } }); // A second driver, used by the tables that start with "audit/" NEWDB('audit', function(options, callback) { F.seen.push({ driver: 'audit', table: options.table }); callback(null, [{ event: 'login' }]); }); ``` ```js controllers/users.js exports.install = function() { ROUTE('GET /adults/', adults); ROUTE('GET /user/{id}/', user); ROUTE('POST /users/', create); ROUTE('GET /page/', page); ROUTE('GET /audit/', audit); ROUTE('GET /seen/', seen); }; function adults($) { DB().find('users').where('age', '>=', 18).fields('id,name').sort('name', true).take(5).callback($); } function user($) { DB().read('users').where('id', +$.params.id).callback($); } function create($) { DB().insert('users', { name: $.body.name, age: $.body.age }).callback($); } function page($) { DB().list('users').page(1, 2).callback(function(err, response) { $.json({ err: err, count: response.count, page: response.page, limit: response.limit, pages: response.pages }); }); } function audit($) { DB().find('audit/log').callback($); } function seen($) { $.json(F.seen); } ``` ## Configure the app with the config file Source: https://forge.totaljs.es/en/total5/configuration-file/ Framework: total5@0.0.19 Content-SHA256: bd1905565ada99b1bad4e9ad56a8a762ec12643f80e1058a0b2fd82f985c920b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded The `config` file in the root of the project holds one `key : value` setting per line. At runtime the values are available in the global `CONF` object. Values are strings unless you declare a type in brackets after the key: `limit (number) : 10` or `debug (boolean) : true`. ```text config name : Forge demo limit (number) : 10 debug (boolean) : true ``` ```js controllers/settings.js exports.install = function() { ROUTE('GET /settings/', settings); }; function settings($) { $.json({ name: CONF.name, limit: CONF.limit, debug: CONF.debug }); } ``` In a view you can read the same values with `@{'%name'}`. ## Encrypt and decrypt data with a key Source: https://forge.totaljs.es/en/total5/encrypt-and-decrypt/ Framework: total5@0.0.19 Content-SHA256: 304fb571fa9f2b8a3e29e7adac76abcaedffa2c5b3c1cfb2b34d5cc169dc4be1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `ENCRYPT(value, key)` serializes a value to JSON and returns an opaque text. `DECRYPT(text, key)` returns the original value, or `null` when the text was changed, is not valid, or was encrypted with another key. The `secret` setting of your config is mixed into the key, so tokens made on one installation do not open on another. Use it for password reset links, invitation tokens and anything you need to hand to a client and verify later without storing it. Put an expiration inside the value (a timestamp) and check it after decrypting. ```text config secret : change-this-secret-in-production ``` ```js controllers/tokens.js exports.install = function() { ROUTE('GET /token/', create); ROUTE('GET /verify/', verify); }; function create($) { var token = ENCRYPT({ userid: '123', expire: Date.now() + 60000 }, 'reset-password'); $.json({ token: token }); } function verify($) { var data = DECRYPT($.query.token || '', 'reset-password'); if (!data || data.expire < Date.now()) { $.invalid(401); return; } $.json({ userid: data.userid }); } ``` ## Call external services with API() and NEWAPI() drivers Source: https://forge.totaljs.es/en/total5/api-drivers/ Framework: total5@0.0.19 Content-SHA256: a619fa8d5764560b83f75ce806ad4bb4214635ebaaf86d1ae315dd25a11c21bf Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `API(name, schema, data, [$])` calls an operation of an external service and `NEWAPI()` registers the **driver** that makes the call, so the code of your actions does not depend on how the service is reached (HTTP, a library, a queue...). - `NEWAPI('name', driver)` registers the driver of the service `name` (`'a,b'` registers one driver for two names, and `NEWAPI(driver)` registers the `default` one). `NEWAPI('name', config, driver)` also stores a `config` object that every call receives as `options.config`. - The driver is `function(options, next)`. `options.name` is the service, `options.schema` the operation, `options.data` the data and `options.config` the configuration. Answer with `next(error, response)`. - `API('name', 'operation', data)` returns a builder: finish it with `.callback($)` (the response goes to the action `$`), `.callback(function(err, response) {})` or `await ....promise($)`. `.configure({ key: value })` adds to `options.config` for that call, and `.error('text')` makes an empty answer fail with that message. - If no driver is registered for the name the call fails with `API is not initialized`. ```js definitions/api.js // The driver of a fake weather service: in a real one this would be an HTTP request NEWAPI('weather', { unit: 'C' }, function(options, next) { if (options.schema === 'forecast') next(null, { city: options.data.city, temperature: 21, unit: options.config.unit, service: options.name }); else next('Unknown operation ' + options.schema); }); ``` ```js controllers/weather.js exports.install = function() { ROUTE('GET /forecast/', forecast); ROUTE('GET /forecast-fahrenheit/', fahrenheit); ROUTE('GET /unknown/', unknown); ROUTE('GET /missing/', missing); ROUTE('GET /promise/', promise); }; function forecast($) { API('weather', 'forecast', { city: $.query.city }).callback($); } function fahrenheit($) { API('weather', 'forecast', { city: $.query.city }).configure({ unit: 'F' }).callback($); } function unknown($) { API('weather', 'rain', {}).callback($); } function missing($) { API('nobody', 'forecast', {}).callback($); } async function promise($) { const data = await API('weather', 'forecast', { city: 'Oslo' }).promise($); $.json({ city: data.city, same: true }); } ``` ## Talk to language models with AIMODEL(), NEWAIMODEL() and AIPARSER() Source: https://forge.totaljs.es/en/total5/ai-models/ Framework: total5@0.0.19 Content-SHA256: 7c29008f55a6bdf6dc0904f945e8272bb1a3a32c18781f7f4039c6da23dfb8e9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `total5` does not ship a connection to any provider. It gives you three pieces that work together: - `NEWAIMODEL('name', config, driver)` registers the **driver** of one or more models (`'a,b'` registers the same driver for two names). The driver is `function(ai, done)`: `ai.payload` has `model`, `messages`, `tools`, `prompt` and `think`, `ai.config` is the configuration and `ai.options.stream` is the function the caller passed to `stream()` (or `undefined`). Answer with `done(error, response)`. - `AIMODEL('name')` starts a request for a registered model and returns a builder. `system(text)`, `user(text)` and `assistant(text)` append a message, `prompt(text)`, `tool(definition)` and `think()` fill the rest of the payload, and `configure({ ... })` adds to `ai.config` for this call only. Finish it with `callback(fn)`, `await promise($)` or `stream(fn)`; the driver runs after the current turn, so you can chain everything first. - `AIPARSER(provider)` returns a parser for the **streamed** answer of a provider (the source of `total5` knows `openai`, `claude`/`anthropic`, `gemini`/`google`, `ollama` and `openai_responses`, and reads any other name as a generic format; only `openai` is run below). `write(chunk)` takes pieces of the stream (it keeps incomplete lines until the next piece), `end()` finishes it, and both return `{ content, thinking, tools, reasoning }`. `parser.on('content', fn)` is called with every part of the text as it arrives. A model that was not registered answers with the error `AI model not found.`. The example registers a local driver that returns a response from the supplied messages. ```js definitions/ai.js NEWAIMODEL('echo', { prefix: 'Echo' }, function(ai, done) { const last = ai.payload.messages.filter(n => n.role === 'user').pop(); const text = ai.config.prefix + ': ' + (last ? last.content : ''); // A real driver would send ai.payload to the provider and send the pieces to ai.options.stream if (ai.options.stream) { for (const word of text.split(' ')) ai.options.stream(word + ' '); } done(null, { content: text, roles: ai.payload.messages.map(n => n.role), tools: ai.payload.tools.length, think: !!ai.payload.think }); }); ``` ```js controllers/ai.js exports.install = function() { ROUTE('POST /ask/', ask); ROUTE('GET /ask-config/', askconfig); ROUTE('GET /ask-stream/', askstream); ROUTE('GET /ask-missing/', missing); ROUTE('GET /parse/', parse); }; async function ask($) { const response = await AIMODEL('echo').system('You are brief.').user($.body.question).tool({ name: 'weather' }).think().promise($); $.json(response); } function askconfig($) { AIMODEL('echo').user('hello').configure({ prefix: 'Custom' }).callback($.callback()); } function askstream($) { const parts = []; AIMODEL('echo').user('one two three').stream(part => parts.push(part)).callback(function(err, response) { $.json({ parts: parts, content: response.content }); }); } function missing($) { AIMODEL('nobody').user('hi').callback($.callback()); } function parse($) { const parser = AIPARSER('openai'); const events = []; parser.on('content', e => events.push(e.delta)); // the second piece starts in the middle of a line parser.write('data: {"choices":[{"delta":{"content":"Hel"}}]}\n\ndata: {"choices":[{"delta":{"con'); parser.write('tent":"lo"}}]}\n\ndata: [DONE]\n'); const output = parser.end(); $.json({ output: output, events: events }); } ``` ## Limit failed attempts with BLOCKED Source: https://forge.totaljs.es/en/total5/rate-limiting/ Framework: total5@0.0.19 Content-SHA256: 7e8fac3c4d653cf0d6f7b29e6b60cac123f37a0805deb8184eb6ac990cb10230 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `BLOCKED($, limit, expiration)` counts calls per IP address. It returns `true` once the address has made more than `limit` calls within the expiration (default: 5 calls in 15 minutes), and `undefined` before that. Call it at the start of a sensitive handler and stop when it returns `true`. To forgive an address after a successful login call `BLOCKED($, -1)`. The counters live in the memory of the process; behind a reverse proxy make sure the real client address reaches Total.js, otherwise everybody shares one counter. ```js controllers/login.js exports.install = function() { ROUTE('POST /login/', login); }; function login($) { if (BLOCKED($, 3, '1 minute')) { $.invalid(429); return; } if ($.body.password === 'correct') { BLOCKED($, -1); $.json({ ok: true }); } else $.invalid(401); } ``` ## The small global helpers: MAIN, REPO, FUNC, NOW, CLONE, COPY, QUERIFY and PROMISIFY Source: https://forge.totaljs.es/en/total5/utility-globals/ Framework: total5@0.0.19 Content-SHA256: fe1db1d0b9705cf0ab8ab5aae2d10d62c6f0ca3c79286a1c96bcb884b0dc7f02 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `total5` creates a few global objects for your own use and a few helpers that save a line of code. Nothing here needs setup. - `MAIN`, `REPO` and `FUNC` are empty objects that the framework creates once: keep application data in `MAIN`, other data in `REPO` and your own functions in `FUNC`. `TEMP` is an object for temporary data that the framework replaces from time to time, so do not keep anything in it that you need later. - `NOW` is the current date as a `Date`. It is refreshed about once a minute (and by some calls), so use `new Date()` when you need the exact time. - `EMPTYARRAY` and `EMPTYOBJECT` are frozen empty values to return instead of creating new ones: they cannot be changed. - `MODS` and `PLUGINS` are objects with the loaded modules and plugins by id. `F` and `Total` are the same object, the framework, and `print` is `console.log`. `NOOP` is a function that does nothing. - `REQUIRE(name)` is `require` that also resolves packages from the `node_modules` of the application and accepts names such as `node:path`. - `CLONE(value)` makes a deep copy: nested objects, arrays and dates are copied. `COPY(from, to)` copies the properties of the first object into the second and returns the second. - `QUERIFY([url], object)` builds a query string from an object: empty values and `null` are skipped and an array becomes a comma separated value. With an url it returns `url?...`, without one it returns `?...`. - `PROMISIFY(fn, a, b, c)` calls `fn(a, b, c, callback)` and returns a promise that resolves with the response of the callback or rejects with its error. ```js controllers/helpers.js MAIN.started = 'yes'; REPO.counter = 1; FUNC.double = n => n * 2; exports.install = function() { ROUTE('GET /helpers/', helpers); ROUTE('GET /promisify/', promisify); }; function helpers($) { const source = { a: 1, nested: { b: [1, 2] }, date: new Date(2026, 0, 5) }; const cloned = CLONE(source); const target = { x: 1 }; const returned = COPY({ y: 2 }, target); $.json({ shared: [MAIN.started, REPO.counter, FUNC.double(4), typeof TEMP], now: [NOW instanceof Date, Math.abs(Date.now() - NOW.getTime()) < 120000], emptyarray: [EMPTYARRAY.length, Object.isFrozen(EMPTYARRAY)], emptyobject: [Object.keys(EMPTYOBJECT).length, Object.isFrozen(EMPTYOBJECT)], registries: [typeof MODS, typeof PLUGINS], same: [F === Total, typeof print, NOOP() === undefined], require: typeof REQUIRE('node:path').join, clone: [cloned !== source, cloned.nested !== source.nested, cloned.nested.b !== source.nested.b, cloned.date instanceof Date, cloned.nested.b.join()], copy: [returned === target, target.x, target.y], querify: QUERIFY('/search/', { q: 'a b', page: 2, empty: '', nothing: null, list: [1, 2] }), querify2: QUERIFY({ q: 'x' }) }); } async function promisify($) { const add = (a, b, callback) => setImmediate(callback, null, a + b); const fail = (callback) => setImmediate(callback, 'It failed'); const sum = await PROMISIFY(add, 2, 3); let error = null; try { await PROMISIFY(fail); } catch (e) { error = e.message || String(e); } $.json({ sum: sum, error: error }); } ``` ## Collect errors with ErrorBuilder, log them with ERROR() and keep an audit trail with AUDIT() Source: https://forge.totaljs.es/en/total5/errors-and-audit/ Framework: total5@0.0.19 Content-SHA256: ccd28753dcc2801ab0c0c92f984123b5941dfcfca8fdb41cbdcbf591eba8a958 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded - **`ErrorBuilder`** collects errors. `push(message, [path], [index])` adds one (`path` is the field it belongs to), `push(404)` adds the text of a status code and sets the status of the answer, `length` counts them, `output()` returns them as an array of `{ error, path, index }` and `toString()` joins the messages. `$.invalid(builder)` answers with that array and the status of the builder (400 unless a status code was pushed). - **`SUCCESS(value)`** returns the object for a successful operation: `{ success: true, value: value }`. - **`ERROR(name)`** returns a callback for `function(err)` APIs: when it receives an error it records it under `name`, and it does nothing when the error is empty. `ERROR()` is the same callback without a name. A recorded error is printed to the console, counted in `F.stats.error`, and the last ten are kept in `F.errors` as `{ error, name, date }`. - **`AUDIT($, message, type)`** appends one JSON line to `logs/audit.log` with who and where (`ip`, `ua`, `url`, and the user when there is one), the `message`, the `type`, the `params`, `query` and `model` of the request in `data`, the name of the application in `app` and the time in `dtcreated`. `AUDIT('name', $, message, type)` writes to `logs/name.log` instead. ```js controllers/reports.js exports.install = function() { ROUTE('GET /builder/', builder); ROUTE('GET /builder404/', builder404); ROUTE('GET /success/', success); ROUTE('GET /error/', error); ROUTE('GET /audit/', audit); ROUTE('GET /audit-read/{name}/', auditread); }; function builder($) { const errors = new ErrorBuilder(); errors.push('Name is required', 'name'); errors.push('Age is too low', 'age', 2); $.invalid(errors); } function builder404($) { const errors = new ErrorBuilder(); errors.push(404); $.invalid(errors); } function success($) { $.json(SUCCESS('saved')); } function error($) { const before = F.stats.error; ERROR('mypart')('Something broke'); ERROR('mypart')(null); ERROR()('Without a name'); $.json({ counted: F.stats.error - before, last: F.errors.slice(-2).map(n => ({ error: n.error, name: n.name || null, date: n.date instanceof Date || typeof n.date === 'string' })) }); } function audit($) { AUDIT($, 'Opened the report', 'info'); AUDIT('security', $, 'Checked the access'); $.json({ ok: true }); } function auditread($) { setTimeout(function() { const lines = require('fs').readFileSync(PATH.logs($.params.name + '.log'), 'utf8').trim().split('\n'); $.json(lines.map(n => JSON.parse(n))); }, 300); } ``` ## Debounce work with setTimeout2() and clearTimeout2() Source: https://forge.totaljs.es/en/total5/debounce-timers/ Framework: total5@0.0.19 Content-SHA256: e0a20f3b90203a51ae4c6bbdfe81c1fc468b6bba946d9f8046b8b7ad35a02bac Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `setTimeout2(id, callback, timeout)` is `setTimeout` with a name. When you call it again with the **same id** before the time is over, the previous timer is cancelled and replaced: the callback runs once, after the calls stop. It is the usual way to save, reload or recalculate only once when many events arrive together (a burst of changes, typing, a flood of messages). `clearTimeout2(id)` cancels the timer of that id and returns `true` when there was one and `false` when there was not. The full form is `setTimeout2(id, callback, timeout, limit, a, b, c, d, e)`: the values after `limit` are passed to the callback. **Do not use `limit`** in `total5` 0.0.19: the idea is to run the callback at once after `limit` replacements, but the counter never starts (it is `undefined` and becomes `NaN`), so the callback is only ever called when the time is over. The example calls it ten times with a limit of 3 and the callback did not run early. ```js controllers/timers.js exports.install = function() { ROUTE('GET /burst/', burst); }; async function burst($) { const log = []; // three calls with the same id: only the last one runs setTimeout2('save', () => log.push('first'), 100); setTimeout2('save', () => log.push('second'), 100); setTimeout2('save', () => log.push('third'), 100); // a timer that is cancelled before it runs setTimeout2('gone', () => log.push('gone'), 100); const cancelled = clearTimeout2('gone'); const nothing = clearTimeout2('never-set'); // the values after the limit reach the callback setTimeout2('args', (a, b) => log.push(a + b), 50, 0, 'x', 'y'); // the limit option does not run the callback early let early = 0; for (let i = 0; i < 10; i++) setTimeout2('limited', () => early++, 1000, 3); const stopped = clearTimeout2('limited'); await new Promise(resolve => setTimeout(resolve, 300)); $.json({ log: log, cancelled: cancelled, nothing: nothing, early: early, stopped: stopped }); } ``` ## Tokens tied to a browser with ENCRYPTREQ() and DECRYPTREQ() Source: https://forge.totaljs.es/en/total5/request-bound-tokens/ Framework: total5@0.0.19 Content-SHA256: 8cdff67bb59806a632b3b63151bc64dc8416ae5d8892adb0e9296bb52e288e0a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `ENCRYPTREQ($, value, key, [strict])` encrypts a value **together with the user agent of the request** and returns a text token. `DECRYPTREQ($, token, key)` reads the value back, and returns nothing (`undefined`) when the key is wrong, the token is empty, or the request comes from a different client. With `strict` set to `true` the IP address of the request is part of the token too, so it also stops working when the address changes. Use it for values that you hand to the browser and expect back from the same browser: a short-lived link, a download address, a form token. It is not a replacement for a session: the user agent is easy to copy. For tokens that do not depend on the request see the encrypt and decrypt recipe. ```js controllers/tokens.js exports.install = function() { ROUTE('GET /issue/', issue); ROUTE('GET /read/', read); ROUTE('GET /read-wrong-key/', wrongkey); }; function issue($) { $.json({ token: ENCRYPTREQ($, { id: 5 }, 'my-secret'), strict: ENCRYPTREQ($, 'only-here', 'my-secret', true) }); } function read($) { $.json({ value: DECRYPTREQ($, $.query.token, 'my-secret') || null }); } function wrongkey($) { $.json({ value: DECRYPTREQ($, $.query.token, 'another-secret') || null }); } ``` ## Back up a folder with BACKUP() and RESTORE(), and run commands with SHELL() Source: https://forge.totaljs.es/en/total5/backup-restore-shell/ Framework: total5@0.0.19 Content-SHA256: 951ae399addf9763c314144b8f259adde20d5bd8d856698108de9e75dce43fde Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded - `BACKUP(filename, directory, [callback], [filter])` packs a directory (with its subdirectories) into **one file** and resolves with `{ filename, files, size }`. An existing file with that name is replaced. Without a callback it returns a promise. - `RESTORE(filename, directory, [callback], [filter])` unpacks a file made with `BACKUP()` into a directory, creating the folders it needs, and resolves with `{ files, size, path }`. - `SHELL(command, [callback], [cwd])` runs a shell command and resolves with its output (`stdout`). The folder is the one of the project, or the text you pass as the last argument. When the command fails the promise is rejected with an error whose `code` is the exit code. With a callback it is called as `callback(err, stdout, stderr)`. `SHELL()` runs **exactly the text you give it**: never build the command from what a user sent. ```js controllers/backups.js const Fs = require('fs'); const Path = require('path'); exports.install = function() { ROUTE('GET /backup/', backup); ROUTE('GET /shell/', shell); }; async function backup($) { // a folder with a file and a subfolder const source = PATH.tmp('source'); Fs.rmSync(source, { recursive: true, force: true }); Fs.mkdirSync(Path.join(source, 'sub'), { recursive: true }); Fs.writeFileSync(Path.join(source, 'a.txt'), 'hello'); Fs.writeFileSync(Path.join(source, 'sub', 'b.txt'), 'world'); const file = PATH.tmp('folder.backup'); const packed = await BACKUP(file, source); const target = PATH.tmp('restored'); Fs.rmSync(target, { recursive: true, force: true }); const unpacked = await RESTORE(file, target); $.json({ packed: [packed.files, packed.filename === file, Fs.existsSync(file)], unpacked: [unpacked.files, unpacked.size, unpacked.path === target], content: [Fs.readFileSync(Path.join(target, 'a.txt'), 'utf8'), Fs.readFileSync(Path.join(target, 'sub', 'b.txt'), 'utf8')] }); } async function shell($) { const output = await SHELL('echo hello'); const where = await SHELL('pwd', PATH.tmp()); let code = null; try { await SHELL('exit 3'); } catch (e) { code = e.code; } SHELL('echo from callback', (err, stdout) => $.json({ output: output, where: where.trim() === PATH.tmp() || where.trim().endsWith('/tmp'), code: code, callback: stdout })); } ``` ## Put the application in maintenance with PAUSESERVER() Source: https://forge.totaljs.es/en/total5/pause-server/ Framework: total5@0.0.19 Content-SHA256: 9906e044fb40f45c1560ab417e7d4840431f15fe4159546344939e06b8075510 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `PAUSESERVER(name, true)` pauses the server and `PAUSESERVER(name, false)` resumes it. While **at least one name** is paused, every request is answered with the status **503** and the built-in maintenance page (a request made with `xhr` gets a 503 error answer instead of the page). The name only identifies who paused it, so that two parts of the application can pause and resume independently: the server answers again when all the names were resumed. Without the second argument the call **toggles**: `PAUSESERVER(name)` pauses when the name was not paused and resumes when it was, and returns the new state (`true` when paused). Because a paused server answers 503 to everything, including the route that would resume it, resume from your own code: a timer, a signal, a task that finishes. The example pauses for a short time and resumes by itself. ```js controllers/maintenance.js exports.install = function() { ROUTE('GET /maintenance/', maintenance); ROUTE('GET /toggle/', toggle); ROUTE('GET /ping/', ping); }; function maintenance($) { const state = PAUSESERVER('maintenance', true); setTimeout(() => PAUSESERVER('maintenance', false), 600); $.json({ paused: state }); } function toggle($) { const first = PAUSESERVER('toggled'); const second = PAUSESERVER('toggled'); $.json({ first: first, second: second }); } function ping($) { $.json({ ok: true }); } ``` ## Business rules as text with NEWMACRO() Source: https://forge.totaljs.es/en/total5/macros/ Framework: total5@0.0.19 Content-SHA256: d802bfef67ede8fdf42be2807b173b3732349293d75dcc93f6bd3a325d48c417 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `NEWMACRO(text, [nocompile], [isasync])` turns a few lines of a small language into a function `function(model, helpers)`. It is meant for rules that change more often than the code: a discount, a price, a permission check, a validation that someone who does not write JavaScript maintains in a file or in a database. The language, as it was checked: - `IF condition`, `ELSE IF condition`, `ELSE` and `FI` (the end of the condition) work as in a text-based rule. Conditions use `>`, `<`, `>=`, `<=`, `=` and `AND` / `OR`. - `RETURN value` ends the macro with a value. `YES` and `NO` (also `TRUE`, `FALSE`, `OK`) are booleans, text between quotes is text and numbers are numbers. - A word is a **property of the model**, written in lower case: `age` reads `model.age`, and `total = price * qty` writes `model.total`. - `NAME(arguments)` calls a **helper**, the function with that name (lower case) in the `helpers` object you pass; inside it `this` is the model. With `isasync` set to `true` the macro is an async function and awaits the helpers. - `#name` is a temporary variable of the run: `#temp = num + 1` and `RETURN #temp`. - Use names of **several letters**: a property or a variable of one letter was not recognised in the checks. `NEWMACRO()` compiles the text with `new Function`, so a macro is code: only compile text that you wrote or that a trusted person maintains, never text that a visitor sent. With `nocompile` set to `true` it returns the JavaScript that it generates instead of the function, which is useful to see what a rule does. ```js controllers/rules.js const helpers = { percent: function(value, rate) { return value * rate / 100; } }; const age = NEWMACRO("IF age >= 18\n\tRETURN 'adult'\nELSE\n\tRETURN 'minor'\nFI"); const level = NEWMACRO("IF points > 100\n\tRETURN 'gold'\nELSE IF points > 50\n\tRETURN 'silver'\nELSE\n\tRETURN 'bronze'\nFI"); const access = NEWMACRO("IF active AND score >= 5\n\tRETURN yes\nFI\nRETURN no"); const total = NEWMACRO("total = price * qty\nIF qty >= 10\n\ttotal = total - PERCENT(total, 10)\nFI\nRETURN total"); const temporary = NEWMACRO("#next = count + 1\nRETURN #next"); const slow = NEWMACRO("RETURN LOOKUP(code)", false, true); exports.install = function() { ROUTE('POST /rules/', rules); ROUTE('GET /source/', source); }; async function rules($) { const model = $.body; $.json({ age: age(model, helpers), level: level(model, helpers), access: access(model, helpers), total: total(model, helpers), model_total: model.total, temporary: temporary(model, helpers), slow: await slow(model, { lookup: async code => 'found ' + code }) }); } function source($) { $.plain(NEWMACRO("IF points > 100\n\tRETURN 'gold'\nFI", true)); } ``` ## Serve static files from the public folder Source: https://forge.totaljs.es/en/total5/static-files/ Framework: total5@0.0.19 Content-SHA256: 01f26d711f253f04cfbb130f67bd1276c91264e83102714f80c7553ad9a9bb4d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Everything inside the `public` directory is served as a static file, and the path inside the folder becomes the URL. No route is needed: `public/hello.txt` is available at `/hello.txt`. ```text public/hello.txt Hello from the public folder ``` ## Call another address with AJAX() from the server Source: https://forge.totaljs.es/en/total5/ajax-requests/ Framework: total5@0.0.19 Content-SHA256: 761c3549df81c70a95b4da31e4770d745833c6240cfc45d2c310f79cd7d43d8f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `AJAX('METHOD url', [data], [callback])` makes an HTTP request and gives you the **parsed** answer. It is the short form of `REQUEST()` for APIs that talk JSON: the same call that jComponent has in the browser, so the code of the page and of the server look alike. - The address starts with an optional method: `AJAX('POST https://example.com/api/', data)`. Without a method it is a `GET`. - `data`, when given, is sent as a **JSON body**. The request carries the header `x-requested-with: XMLHttpRequest`, so on the other side `$.xhr` is `true`. - The answer is parsed by its content type: JSON becomes an object, `application/x-www-form-urlencoded` becomes an object, anything else arrives as text. - When the status is 400 or more, the promise is **rejected** (or the callback gets the error first) with the parsed body of the answer as the error. A callback is called as `callback(err, value, response)`. - Without a callback it returns a promise. **For XML answers use `REQUEST()`** and parse the body yourself: `AJAX()` is made for JSON and text answers. The example calls routes of the same application, whose address `$.hostname('/')` gives, so that it needs no other server. ```js controllers/calls.js exports.install = function() { ROUTE('GET /api/hello/', hello); ROUTE('POST /api/echo/', echo); ROUTE('GET /api/text/', text); ROUTE('GET /api/xml/', xml); ROUTE('GET /api/fail/', fail); ROUTE('GET /calls/', calls); }; function hello($) { $.json({ hello: 'world', xhr: $.xhr }); } function echo($) { $.json({ received: $.body, xhr: $.xhr }); } function text($) { $.plain('plain text'); } function xml($) { $.xml('1'); } function fail($) { $.invalid('It is wrong'); } async function calls($) { const base = $.hostname('/'); const out = {}; out.hello = await AJAX('GET ' + base + 'api/hello/'); out.nomethod = await AJAX(base + 'api/hello/'); out.echo = await AJAX('POST ' + base + 'api/echo/', { a: 1 }); out.text = await AJAX(base + 'api/text/'); try { await AJAX(base + 'api/fail/'); } catch (err) { out.error = err.message || err; } out.callback = await new Promise(resolve => AJAX(base + 'api/hello/', (err, value, response) => resolve({ err: err, hello: value.hello, status: response.status }))); out.xml = await Promise.race([ AJAX(base + 'api/xml/').then(() => 'answered', () => 'rejected'), new Promise(resolve => setTimeout(() => resolve('never answered'), 1000)) ]); $.json(out); } ``` ## Call other HTTP APIs with RESTBuilder Source: https://forge.totaljs.es/en/total5/restbuilder/ Framework: total5@0.0.19 Content-SHA256: 12c13b9eec2ed90f374077ed6b677b5de7172b1bd97ef4b605591216bfc1e24c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `RESTBuilder.GET(url)`, `.POST(url, data)`, `.PUT`, `.PATCH` and `.DELETE` build a request. Data of a POST is sent as JSON. Chain `.header(name, value)`, `.cookie(name, value)`, `.timeout(milliseconds)` and `.auth(user, password)` before `.exec(function(err, response, output) {})` (or `.promise()` for `await`). - `response` is the body, parsed automatically when it is JSON - `output.status` is the HTTP status and `output.headers` the response headers - `err` is set for network errors and for HTTP error statuses The example calls two routes of its own app so it can run anywhere; use the address of the real service in your code. `$.hostname(path)` builds the full URL of this server. ```js controllers/service.js exports.install = function() { ROUTE('GET /api/hello/', hello); ROUTE('POST /api/sum/', sum); ROUTE('GET /call/', call); }; function hello($) { $.json({ message: 'hello', agent: $.headers['x-agent'] || null }); } function sum($) { $.json({ sum: $.body.a + $.body.b }); } async function call($) { var greeting = await RESTBuilder.GET($.hostname('/api/hello/')).header('x-agent', 'forge').timeout(5000).promise(); var total = await RESTBuilder.POST($.hostname('/api/sum/'), { a: 20, b: 22 }).promise(); RESTBuilder.GET($.hostname('/api/missing/')).exec(function(err, response, output) { $.json({ greeting: greeting, total: total, missing: output.status }); }); } ``` ## Release a stream when it ends with CLEANUP() Source: https://forge.totaljs.es/en/total5/cleanup-streams/ Framework: total5@0.0.19 Content-SHA256: dcaf443c6e5b758eb7c3a4ea92ba9c0289551a3b46dcb0c1e3d642c51e142f37 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `CLEANUP(stream, [callback])` waits until a stream has **finished** (it ended, it was closed or it failed) and then destroys it, which frees the file handle or the socket behind it. With a callback it is called after that; without one it returns a promise that resolves at that moment. It is the call to make after you hand a stream to something that reads it (a response, a pipe, an upload) when you want to be sure that nothing stays open if the other side stops early. ```js controllers/streams.js const Fs = require('fs'); const { PassThrough } = require('stream'); exports.install = function() { ROUTE('GET /copy/', copy); ROUTE('GET /copy-callback/', copycallback); }; async function copy($) { const file = PATH.tmp('cleanup.txt'); Fs.writeFileSync(file, 'some text to read'); const stream = Fs.createReadStream(file); const chunks = []; // a sink that reads everything const sink = new PassThrough(); sink.on('data', chunk => chunks.push(chunk)); stream.pipe(sink); const before = stream.destroyed; await CLEANUP(stream); $.json({ before: before, after: stream.destroyed, content: Buffer.concat(chunks).toString() }); } function copycallback($) { const file = PATH.tmp('cleanup.txt'); Fs.writeFileSync(file, 'again'); const stream = Fs.createReadStream(file); stream.resume(); CLEANUP(stream, () => $.json({ destroyed: stream.destroyed })); } ``` ## Translate a view into several languages Source: https://forge.totaljs.es/en/total5/localization/ Framework: total5@0.0.19 Content-SHA256: 46d3cf632dac9d720b148f223066319e74bd1173b10dbf1d0d75d85facde901e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Wrap any text of a view in `@(...)` and Total.js replaces it with the translation for the current language. Translations live in `resources/.resource`; each line is `key : translation`. The key is `T` plus the hash of the original text in base 36, which `total5` can generate for you. Texts without a translation stay as written, so the view text acts as the default language. `LOCALIZE()` decides the language of each request. Here it is read from the query string, but it can be a cookie, a header or a URL segment. ```js definitions/localization.js LOCALIZE(function($) { return $.query.lang; }); ``` ```text resources/sk.resource // Total.js translation file T4oxobw : Vitajte v obchode ``` ```html views/index.html @{layout('')}

@(Welcome to the shop)

``` ```js controllers/default.js exports.install = function() { ROUTE('GET /', home); }; function home($) { $.view('index'); } ``` ## Run code on a schedule with CRON Source: https://forge.totaljs.es/en/total5/cron-jobs/ Framework: total5@0.0.19 Content-SHA256: 1e42e869db5a82463754c80c867472d8194d27b6f0858093ca51ce16e18ded54 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `CRON(line, fn)` runs `fn(date)` whenever the current time matches `line`. The line has five fields, as in Unix cron: `minute hour day-of-month month day-of-week`. Each field accepts `*` (any value), `1,5,9` (a list), `1-5` (a range) or an exact number. Day names such as `mon` or `fri` work in the last field. **Write the values as a list**, `0,15,30,45`: it matches exactly the times you name. Total.js checks the registered jobs once a minute, so the finest resolution is one minute. `CRON()` returns an object: `job.remove()` unregisters it and `job.check(date)` tells you whether a date matches the line, which is also the easiest way to test a schedule without waiting for it. ```js controllers/cron.js exports.install = function() { ROUTE('GET /cron/matches/', matches); ROUTE('GET /cron/runs/', runs); }; var counter = { runs: 0 }; // Every 15 minutes, from Monday to Friday, between 09:00 and 17:59 var job = CRON('0,15,30,45 9-17 * * 1-5', function(date) { counter.runs++; }); function matches($) { var dates = { monday_0930: new Date(2026, 0, 5, 9, 30), monday_0931: new Date(2026, 0, 5, 9, 31), monday_1830: new Date(2026, 0, 5, 18, 30), sunday_0930: new Date(2026, 0, 4, 9, 30) }; var output = {}; for (var key in dates) output[key] = job.check(dates[key]); $.json(output); } function runs($) { $.json(counter); } ``` ## Run heavy work in a thread or a child process Source: https://forge.totaljs.es/en/total5/workers-and-threads/ Framework: total5@0.0.19 Content-SHA256: 6be8eed8f5c6fc8d1a9a88a066519dbcd1b8884933677a534fc44d7c4d95f0d1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Node.js runs your code on one thread, so a long calculation blocks every request. `NEWTHREAD(name, data)` starts `workers/.js` in a worker thread and returns a standard Node.js `Worker`: send it messages with `worker.postMessage(value)`, receive replies with `worker.on('message', fn)`, and stop it with `worker.kill()`. The second argument (`data`) is handed to the worker as its starting data. `NEWFORK(name)` has the same shape but starts a separate child process, which is isolated from the main process (a crash in it does not affect your app). Inside the worker file, `NEWTHREAD()` without arguments returns the worker handle: `worker.data` holds the starting data, `worker.message = fn` receives messages and `worker.postMessage(value)` answers. Pass a name prefixed with `~` to use a file by path instead of `workers/.js`. ```js workers/sum.js require('total5'); const worker = NEWTHREAD(); const start = worker.data.start; worker.message = function(message) { let total = start; for (let i = 1; i <= message.to; i++) total += i; worker.postMessage({ total: total }); }; ``` ```js controllers/sum.js exports.install = function() { ROUTE('GET /sum/{to}/', sum); }; var thread = NEWTHREAD('sum', { start: 1000 }); function sum($) { var to = +$.params.to; var timeout = setTimeout(() => $.invalid('timeout'), 4000); thread.once('message', function(response) { clearTimeout(timeout); $.json(response); }); thread.postMessage({ to: to }); } ``` ## Share a few worker threads with NEWTHREADPOOL() Source: https://forge.totaljs.es/en/total5/thread-pool/ Framework: total5@0.0.19 Content-SHA256: 6fbb579ec2a9b0a43ee3b6a86ea83738bde754d17a73392805d15250c0db98d6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `NEWTHREAD()` starts one worker. When many requests need the same heavy job, one worker per request is too many and a single worker makes them wait for each other without any order. `NEWTHREADPOOL(name, count, [isfork])` starts `count` workers of `workers/.js` (a thread; with `isfork` set to `true` a child process, like `NEWFORK()`) and hands them out one at a time. - `pool.exec(function(worker, release) {})` waits until a worker is free and calls your function with it. Send it the work with `worker.postMessage(value)`, read the answer with `worker.once('message', fn)` and **call `release()` when you are done**: the worker goes back to the pool and the next waiting job takes it. - Without a function, `pool.exec()` returns a promise that resolves with `worker` (and the worker has `worker.release()`), so it works with `await`. - The jobs are served in the order in which they asked. The pool does not queue the messages of a worker: one job at a time has it. - The pool is also kept in `F.workers[name]`. `pool.workers` is the list of the workers. The worker file is the same as for `NEWTHREAD()`: `NEWTHREAD()` inside it returns the handle with `worker.message` and `worker.postMessage()`. Here every worker adds up the numbers and says which thread did it. ```js workers/total.js require('total5'); const worker = NEWTHREAD(); worker.message = function(message) { let total = 0; for (let i = 1; i <= message.to; i++) total += i; worker.postMessage({ to: message.to, total: total, thread: require('worker_threads').threadId }); }; ``` ```js controllers/total.js exports.install = function() { ROUTE('GET /total/{to}/', total); ROUTE('GET /await/{to}/', total_await); ROUTE('GET /workers/', workers); }; const pool = NEWTHREADPOOL('total', 2); function total($) { pool.exec(function(worker, release) { worker.once('message', function(response) { release(); $.json(response); }); worker.postMessage({ to: +$.params.to }); }); } async function total_await($) { const worker = await pool.exec(); worker.once('message', function(response) { worker.release(); $.json(response); }); worker.postMessage({ to: +$.params.to }); } function workers($) { $.json({ workers: pool.workers.length, registered: F.workers.total === pool }); } ``` ## Call other servers with REQUEST and save files with DOWNLOAD Source: https://forge.totaljs.es/en/total5/request-and-download/ Framework: total5@0.0.19 Content-SHA256: 53c1ccdf8b9d50fa08069f0f719cced7ec9528bd28bd251c9307fff966f9aaec Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `REQUEST(options)` is the low-level HTTP client that `RESTBuilder` is built on. Pass an object and `await` it (or give it a callback as the second argument). The useful options are `url`, `method` (default `GET`), `query` (an object, appended to the URL), `headers`, `cookies`, `body` (a string or a Buffer), `type` (`json`, `text`, `html`, `xml`, `urlencoded` or `raw`, which sets `content-type`), `timeout` in milliseconds and `noredirect`. The result is an object with `status`, `headers`, `cookies` and `body` (a string; parse JSON yourself with `.parseJSON()`). A response with an error status such as 404 is **not** an error: check `status`. The promise only rejects when the request itself fails (connection refused, timeout, invalid host). `DOWNLOAD(url, filename)` streams the response into a file and resolves with `{ status, size, filename }`. It does not look at the status, so check it before using the file. ```js controllers/request.js exports.install = function() { ROUTE('GET /remote/', remote); ROUTE('POST /remote/ @json', remote_post); ROUTE('GET /remote/text/', remote_text); ROUTE('GET /call/', call); ROUTE('GET /download/', download); }; function remote($) { $.json({ hello: 'world', name: $.query.name || null }); } function remote_post($) { $.json({ received: $.body, token: $.headers['x-token'] || null }); } function remote_text($) { $.plain('first line\nsecond line\n'); } async function call($) { var get = await REQUEST({ url: $.hostname('/remote/'), query: { name: 'Louis' } }); var post = await REQUEST({ method: 'POST', url: $.hostname('/remote/'), type: 'json', body: JSON.stringify({ a: 1 }), headers: { 'x-token': 'abc' } }); var missing = await REQUEST({ url: $.hostname('/does-not-exist/') }); var failed = null; try { await REQUEST({ url: 'http://127.0.0.1:1/' }); } catch (e) { failed = true; } $.json({ get: get.body.parseJSON(), post: post.body.parseJSON(), status: [get.status, missing.status], failed: failed }); } async function download($) { var filename = PATH.tmp('forge-download.txt'); var response = await DOWNLOAD($.hostname('/remote/text/'), filename); var content = require('fs').readFileSync(filename).toString('utf8'); $.json({ status: response.status, size: response.size, content: content }); } ``` ## Send an email from a view Source: https://forge.totaljs.es/en/total5/send-email/ Framework: total5@0.0.19 Content-SHA256: 82d673e47df8e2c89407aa68da87b54706364712401f9ee8742dd3918b58e706 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js sends mail over SMTP. The server and the sender go in the `config` file: `mail_smtp` is the server, `mail_smtp_options` an object with the rest of the connection settings (`port`, `user`, `password`, `secure`...) and `mail_from` / `mail_from_name` the sender. `mail_reply`, `mail_cc` and `mail_bcc` add the same headers to every message. `MAIL(email, subject, view, model, [language], [callback])` renders `views/.html` with the model (the same views as for pages, including `@(...)` localization) and sends the result as the HTML body. `email` can be one address or several separated by commas. `HTMLMAIL(email, subject, html, [language], [callback])` sends a string you built yourself. Both return the message; `callback(err)` runs when the server has accepted or rejected it, and `err` is `null` on success. Messages are queued and sent right after the current tick, so `MAIL()` never blocks the request. Wait for the callback only when the user has to know whether it worked. ```text config name : Mail example mail_smtp : 127.0.0.1 mail_smtp_options : { port: 2526 } mail_from : hello@example.com mail_from_name : Example ``` The view is rendered **with the layout**, like any page, so `views/layout.html` must exist (the app crashes the request with an `ENOENT` error otherwise). A mail layout can be as small as the one below, or you can use your page layout. ```html views/layout.html @{body} ``` ```html views/welcome.html

Welcome, @{model.name}!

Your account is ready.

``` ```js controllers/mail.js exports.install = function() { ROUTE('POST /welcome/ @json', welcome); ROUTE('POST /note/ @json', note); }; function welcome($) { MAIL($.body.email, 'Welcome aboard', 'welcome', { name: $.body.name }, function(err) { $.json({ sent: !err, error: err ? err.toString() : null }); }); } function note($) { HTMLMAIL($.body.email, 'A short note', '

Plain HTML message

', function(err) { $.json({ sent: !err, error: err ? err.toString() : null }); }); } ``` ## Customize the 404 and 401 pages Source: https://forge.totaljs.es/en/total5/error-pages/ Framework: total5@0.0.19 Content-SHA256: 379ed76a90c99ff5446f0f9679ef0c1fd1662cde467d0b7e43332f76bcc6db32 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded When Total.js cannot serve a request it shows a built-in error page. A route whose URL is `#` plus the status code replaces it: `ROUTE('#404', fn)` for "not found", `ROUTE('#401', fn)` for "not authorized", and the same for `#400`, `#431` and others. The handler receives `$` like any route, but **you set the status yourself** with `$.response.status`: Total.js does not do it for you when a custom handler exists. Without a custom handler the built-in page is used and AJAX requests (header `x-requested-with`) get a JSON error instead of HTML. `$.fallback(code)` sends the current request to the handler for `code`, which is how you answer 404 for a record that does not exist or 403 for a forbidden resource from inside your own code. ```js controllers/errors.js exports.install = function() { ROUTE('#404', not_found); ROUTE('#401', unauthorized); ROUTE('GET /items/{id}/', item); ROUTE('+GET /private/', private_page); }; var items = { '1': 'First item' }; function item($) { var name = items[$.params.id]; if (name) $.json({ name: name }); else $.fallback(404); } function private_page($) { $.plain('secret'); } function not_found($) { $.response.status = 404; $.html('

Nothing here

' + $.url.encode() + ' does not exist.

'); } function unauthorized($) { $.response.status = 401; $.json({ error: 'Please sign in first' }); } AUTH(function($) { $.invalid(); }); ``` ## Mail yourself a message with LOGMAIL() Source: https://forge.totaljs.es/en/total5/logmail/ Framework: total5@0.0.19 Content-SHA256: 28902e3036b56ddecd785939f8350520d582fbf2dea6e5755e97920246b2352e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `LOGMAIL(email, [subject], body, [callback])` sends a message made for the developer, not for a customer: no view, no layout. The body is a text. The text goes inside a `
`, in a small HTML page, so line breaks and spaces survive; it is put as it is, so do not send untrusted HTML. Without a `subject` the subject is the name of the application (`name` in the `config`).

**Pass the body as a text.** For an object use `JSON.stringify(object, null, 2)`, as the second route below does.

It uses the same SMTP server, sender and queue as `MAIL()` (`mail_smtp`, `mail_smtp_options`, `mail_from` in the `config`). It is meant for things like "the import failed" with the data that you need to see.

```text config
name : Log mail example
mail_smtp : 127.0.0.1
mail_smtp_options : { port: 2527 }
mail_from : hello@example.com
mail_from_name : Example
```

```js controllers/log.js
exports.install = function() {
	ROUTE('POST /alert/ @json', alert);
	ROUTE('POST /alert-object/ @json', alert_object);
	ROUTE('POST /alert-raw/ @json', alert_raw);
};

function alert($) {
	LOGMAIL('ops@example.com', 'Import failed', 'Line 1\nLine 2', function(err) {
		$.json({ sent: !err, error: err ? err.toString() : null });
	});
}

function alert_object($) {
	// without a subject: the subject is the name of the application; the object is written by us
	LOGMAIL('ops@example.com', JSON.stringify({ rows: 12, failed: ['a', 'b'] }, null, 2), function(err) {
		$.json({ sent: !err, error: err ? err.toString() : null });
	});
}

function alert_raw($) {
	// the object itself: it throws in total5 0.0.19
	try {
		LOGMAIL('ops@example.com', { rows: 12 }, NOOP);
		$.json({ thrown: false });
	} catch (e) {
		$.json({ thrown: true, error: e.message });
	}
}
```

## Send files and streams to the client

Source: https://forge.totaljs.es/en/total5/file-download/
Framework: total5@0.0.19
Content-SHA256: c21ebfd97c7af12b738ceba0374203c527f79fc70b1373c215c4a4462f8009d4
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`$.file(path, [download])` sends a file from disk. The `content-type` comes from the extension. Pass `true` as the second argument to make the browser download the file under its own name, or a string to choose the name (`attachment; filename*=...` is set for you, UTF-8 safe). A path that does not exist ends with the 404 page.

`$.stream(type, stream, [download])` sends any readable stream with the given content type: a generated file, a response from another server or a database export. It sets no length, so the response is chunked. `PATH.public()`, `PATH.private()` and `PATH.tmp()` build absolute paths into the project folders; files in `public/` are already served without any route, so use `$.file()` for the files that must stay private or need a check first.

```js controllers/download.js
const Fs = require('fs');

exports.install = function() {
	ROUTE('GET /report/', report);
	ROUTE('GET /report/save/', report_save);
	ROUTE('GET /export/', export_csv);
	ROUTE('GET /missing/', missing);
};

function filepath() {
	var filename = PATH.tmp('report.txt');
	Fs.writeFileSync(filename, 'Total.js report\n');
	return filename;
}

function report($) {
	$.file(filepath());
}

function report_save($) {
	$.file(filepath(), 'my report.txt');
}

function export_csv($) {
	var stream = Fs.createReadStream(filepath());
	$.stream('text/csv', stream, 'export.csv');
}

function missing($) {
	$.file(PATH.tmp('does-not-exist.txt'));
}
```

## Forward requests to another server

Source: https://forge.totaljs.es/en/total5/proxy/
Framework: total5@0.0.19
Content-SHA256: a5143999f45cb88cba286cb0dfca70e97c0f40c381830c2860aeb38043de9342
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`PROXY(prefix, target)` forwards every request below a URL prefix to another server and streams the answer back, so one Total.js app can sit in front of several services. It runs before the routes, so a prefix handled by `PROXY()` never reaches `ROUTE()`. The request is passed on with its method, headers and body; the headers `x-forwarded-for`, `x-forwarded-url` and `x-forwarded-host` tell the upstream about the original request. `PROXY(prefix)` without a target removes the proxy.

The object it returns configures the proxy: `.copy(type)` chooses which part of the path is sent upstream (see below), `.timeout(ms)` limits the wait, `.check(fn)` makes the proxy apply only when `fn(ctrl)` returns true and `.before(uri, ctrl)` can change the outgoing request, for example to add a header.

`.copy()` takes `none` (the default), `extend` or `replace`. With **`none`** the upstream only receives the path of the target plus the query string: `/none/a/b/?q=1` becomes `/base/?q=1` for the target `http://host/base/`. With **`extend`** the rest of the request path is appended to the target path: `/extend/a/b/?q=1` becomes `/base/a/b/?q=1`, which is what you want for a gateway. `replace` behaves like `extend` when the target has a path of its own; when the target is just a host it sends the rest of the path **without the query string**, so prefer `extend`.

For a single route use `$.proxy(url)`: it sends the current request (method, query string, body and headers) to `url` and returns the upstream answer with its status code.

```js controllers/proxy.js
const Http = require('http');

// A small upstream server that reports what it received
Http.createServer(function(req, res) {
	res.writeHead(200, { 'content-type': 'application/json' });
	res.end(JSON.stringify({ method: req.method, url: req.url, token: req.headers['x-token'] || null, forwarded: !!req.headers['x-forwarded-url'] }));
}).listen(9411, '127.0.0.1');

// One proxy per copy mode, to see the difference (the target has the path /base/)
PROXY('/none/', 'http://127.0.0.1:9411/base/');
PROXY('/extend/', 'http://127.0.0.1:9411/base/').copy('extend');
PROXY('/plain/', 'http://127.0.0.1:9411/base/').copy('replace');

// Everything below /service/ goes to the upstream, and a header is added on the way
PROXY('/service/', 'http://127.0.0.1:9411/').copy('extend').before(function(uri, ctrl) {
	uri.headers['x-token'] = 'secret';
});

exports.install = function() {
	ROUTE('GET /single/', single);
};

function single($) {
	$.proxy('http://127.0.0.1:9411/from-route/');
}
```

## Publish a local server through a tunnel with PROXYSERVER() and PROXYCLIENT()

Source: https://forge.totaljs.es/en/total5/proxy-tunnel/
Framework: total5@0.0.19
Content-SHA256: 6c7bccccd48386b830d20ab4b33001d93abc21834308e84c8fd99c0210bab471
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`PROXY()` forwards a request to a server that the proxy can reach. A tunnel is for the opposite case: the program is on a laptop or behind a firewall, so nobody can connect to it, but it can connect out. `PROXYSERVER()` and `PROXYCLIENT()` make that with one WebSocket that the private side opens:

- `PROXYSERVER([endpoint], [socketendpoint], [logger])` runs on the public server. Every request below `endpoint` (default `/`) is sent through the tunnel; `socketendpoint` (default `/`) is the WebSocket address where the client connects. Use **different** addresses when the same application serves anything else: a proxy on `/` takes every request, also the ones of your own routes (it runs before them). `logger` is a function (default: prints with the date); pass `null` for none.
- `PROXYCLIENT(serverurl, port, [logger])` runs on the private side (in this example the address of the server is built with `CONF.$port`, the port of the application). `serverurl` is the address of the WebSocket of the server (`ws://` or `wss://`; `http` is changed to `ws`) and `port` is `3000` or `ip:3000`, the local program that receives the requests. It returns the WebSocket client.
- **One client at a time:** when a second client connects, the server closes it with the code `4001`. Without a client the answer of the server is `Not yet available.`.
- The local program receives the **whole path of the original request**, including the `endpoint` (`/tunnel/hello`), the headers of the visitor and an `x-proxy: Total.js` header, with `host` set to the local address.
- The WebSocket route has no authentication of its own: do not publish it without something in front of it that decides who can connect (the address is the secret, a `check` of your own, a firewall).

Here one application is both sides: a small local program on port 9511 (any program would do), the server on `/tunnel/` and the client that connects to the same application.

```js definitions/local.js
// The program that is "private": an ordinary HTTP server that only listens on the loopback address
require('http').createServer(function(req, res) {
	res.writeHead(200, { 'content-type': 'application/json' });
	res.end(JSON.stringify({ path: req.url, via: req.headers['x-proxy'] || null, host: req.headers.host }));
}).listen(9511, '127.0.0.1');
```

```js controllers/tunnel.js
exports.install = function() {
	ROUTE('GET /status/', status);
	ROUTE('POST /connect/', connect);
};

// The public side: /tunnel/* goes through the tunnel, the WebSocket of the client is /tunnel-socket/. No logger.
PROXYSERVER('/tunnel/', '/tunnel-socket/', null);

let client = null;

function connect($) {
	client = PROXYCLIENT('ws://127.0.0.1:' + CONF.$port + '/tunnel-socket/', '9511', null);
	$.json({ connecting: true });
}

function status($) {
	$.json({ connected: !!client });
}
```

## Protect forms and requests with CSRF tokens

Source: https://forge.totaljs.es/en/total5/csrf-protection/
Framework: total5@0.0.19
Content-SHA256: e10434ff98f2737ef66f4645652b5c226dd2bc4b75b4c4a3bc5d348b2d366762
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

A CSRF attack makes a logged-in user's browser send a request they never intended. The defence is a token that the page receives from your server and that has to come back with every state-changing request. Total.js creates and verifies the token for you, but only when `secret_csrf` is set in the `config` file (without it the check always passes).

`$.csrf()` returns a token (and `@{csrf}` prints it in a view). It is an encrypted value tied to the **IP address** and the **user agent** of the client and it expires after the time in `$csrfexpiration` (30 minutes by default). `DEF.onCSRFcheck($)` verifies the token that came back, read from the `x-csrf-token` header or the `csrf` query string parameter, and returns `true` or `false`. For ordinary routes you call it yourself, most conveniently from a middleware that you add with `#csrf` to every route that changes data. WebSocket routes with the `@csrf` flag are checked automatically.

```text config
secret_csrf : change-this-secret-in-production
```

```js definitions/csrf.js
MIDDLEWARE('csrf', function($, next) {
	if (DEF.onCSRFcheck($))
		next();
	else
		$.invalid(403);
});
```

```js controllers/csrf.js
exports.install = function() {
	ROUTE('GET /form/', form);
	ROUTE('POST /transfer/ @json #csrf', transfer);
};

function form($) {
	$.json({ csrf: $.csrf() });
}

function transfer($) {
	$.json({ ok: true, amount: $.body.amount });
}
```

## Group actions in a schema and reuse input definitions

Source: https://forge.totaljs.es/en/total5/schemas/
Framework: total5@0.0.19
Content-SHA256: 951ce36fc3ea0cd16be8f91ca9a8f5e5b115d12205262a6c67c6e3f7ed178117
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`NEWSCHEMA(name, fn)` groups the actions of one entity. The function receives the schema object and `schema.action(name, meta)` registers an action called `Name/action`, with the same options as `NEWACTION()` (`input`, `output`, `params`, `user`, `permissions`, `action`...). Everywhere else the action is used by its full name, exactly as if it had been declared with `NEWACTION('Users/insert', ...)`: `ROUTE('POST /users/ --> *Users/insert')` or `ACTION('Users/insert', payload)`.

A fragment of an input definition that several actions share, such as an address, goes in its own file in `jsonschemas/`. A `.txt` file holds the same `name:Type` list as `input`; the name of the file is the name of the schema. Reference it from an `input` with `@Name`, and its fields (and which of them are required) are added to the action's own fields.

```text jsonschemas/Address.txt
*street:String, *city:String, zip:String
```

```js schemas/users.js
NEWSCHEMA('Users', function(schema) {

	schema.action('insert', {
		name: 'Create a user',
		input: '*name:String, @Address',
		output: 'id:UID, name:String, city:String',
		action: function($, model) {
			$.callback({ id: UID(), name: model.name, city: model.city });
		}
	});

	schema.action('count', {
		name: 'Count users',
		action: function($) {
			$.callback({ count: 2 });
		}
	});

});
```

```js controllers/users.js
exports.install = function() {
	ROUTE('POST /users/ --> *Users/insert');
	ROUTE('GET /users/count/ --> *Users/count');
};
```

## Build a processing pipeline with transforms

Source: https://forge.totaljs.es/en/total5/transforms/
Framework: total5@0.0.19
Content-SHA256: c9dfc7d277360f14463537cdbe813208627c535f75555adae2c6f31bf79557f3
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

A transform is a named chain of steps. `NEWTRANSFORM(name, fn, [id])` adds a step to the chain `name`; steps run in the order they were registered, and each one receives the options object `$` and the current value. Change the value with `$.value = ...` and call `$.next()` to continue with the next step. `$.invalid(message)` adds an error. `TRANSFORM(name, value)` starts the chain and returns a promise with the final value; the promise rejects when a step has reported an error. With a callback instead, `TRANSFORM(name, value, function(err, value) {})`. A name without any step returns the value as it is.

Use it for work that has to be extended from several places, such as cleaning a comment before it is saved: a spam filter, a trimmer and a link checker can each live in their own file and be added or removed without touching the code that calls `TRANSFORM()`. The optional `id` lets you remove one step later with `NEWTRANSFORM(name, null, id)`.

```js definitions/transforms.js
NEWTRANSFORM('comment', function($, value) {
	$.value = value.trim();
	$.next();
}, 'trim');

NEWTRANSFORM('comment', function($, value) {
	if (/spam/i.test(value))
		$.invalid('Spam is not allowed');
	$.next();
}, 'spam');

NEWTRANSFORM('comment', function($, value) {
	$.value = value.replace(/\s+/g, ' ');
	$.next();
}, 'spaces');
```

```js controllers/comments.js
exports.install = function() {
	ROUTE('POST /comment/ @json', comment);
	ROUTE('DELETE /comment/spaces/', remove_step);
};

async function comment($) {
	try {
		var text = await TRANSFORM('comment', $.body.text);
		$.json({ text: text });
	} catch (err) {
		$.json({ error: true });
	}
}

function remove_step($) {
	NEWTRANSFORM('comment', null, 'spaces');
	$.success();
}
```

## Exchange messages with the Total Messaging Service

Source: https://forge.totaljs.es/en/total5/tms/
Framework: total5@0.0.19
Content-SHA256: 821100b4707c6d136070bfa640d0a05c702215e66bf7abe7101bcf0f64bf3ca0
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

TMS (Total Messaging Service) is a small message bus on top of a WebSocket. Turn it on in the `config` file with `$tms : true`; the endpoint is `/$tms/` and `secret_tms` is the token that every client must send in the `x-token` header (a wrong token closes the connection with code 4001, and an address that fails more than 5 times is blocked for a while). When a client connects it receives a `meta` message that lists what the app publishes, what it accepts and what it can do.

Three things can be exposed, each one described by a schema in the same `name:Type` format as an action `input`:

- `NEWPUBLISH(name, schema)` declares a message the app **sends**; `PUBLISH(name, value)` sends it to every client that asked for it by sending `{ type: 'subscribers', subscribers: [name] }`.
- `NEWSUBSCRIBE(name, schema, callback)` declares a message the app **receives**: a client sends `{ type: 'subscribe', id: name, data: {...} }` and `callback(message, client)` runs only when the data is valid. The validated data is in `message.response` (`message.error` is always `null` there) and `client` is the sender.
- `NEWCALL(name, schema, callback)` declares a function the client **calls**: the client sends `{ type: 'call', id: name, data: {...}, callbackid: '1' }`, and the app answers with the same message carrying `success: true` and the result in `data`, or `error: true` when the data is invalid. `callback(data, done, client)` produces the result with `done(null, result)`.

Passing `null` as the schema of `NEWPUBLISH` or `NEWSUBSCRIBE` removes the declaration. The official client of Total.js (`TMSCLIENT`) speaks this protocol for you from another Total.js app; any WebSocket client works.

`UNSUBSCRIBE(name, [callback])` removes the listeners of a message that the app receives: only `callback` when you pass it, all of them when you do not. It returns `true` when it removed something and `false` when there was nothing to remove.

```text config
$tms : true
secret_tms : my-tms-token
```

```js definitions/tms.js
NEWPUBLISH('news', 'title:String');

NEWSUBSCRIBE('orders', 'id:String, qty:Number', function(message, client) {
	MAIN.orders.push(message.response);
});

NEWCALL('sum', 'a:Number, b:Number', function(data, done) {
	done(null, { total: data.a + data.b });
});

MAIN.orders = [];
```

```js controllers/tms.js
exports.install = function() {
	ROUTE('POST /news/ @json', news);
	ROUTE('GET /orders/', orders);
	ROUTE('GET /unsubscribe/', unsubscribe);
};

function news($) {
	PUBLISH('news', { title: $.body.title });
	$.success();
}

function orders($) {
	$.json(MAIN.orders);
}

function unsubscribe($) {
	const first = UNSUBSCRIBE('orders');
	const second = UNSUBSCRIBE('orders');
	$.json({ first: first, second: second });
}
```

## Build a complete REST resource with actions

Source: https://forge.totaljs.es/en/total5/actions-crud/
Framework: total5@0.0.19
Content-SHA256: 54d1adaf485ed805011ae1c7cc61741866509242ce858ba3819af61ed0065ab5
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

A REST resource is six operations: list (`query`), `read`, `insert`, `update` (replace), `patch` (change a few fields) and `remove`. In Total.js each one is an action with its own validation, so the route table stays a plain map from URL to action. `params` validates the id of the URL, `query` the filters of the list, `input` the body. Inside an action `$.params`, `$.query` and the validated body (second argument of `action`) are already clean values.

Report a missing record with `$.invalid(404)`: it answers with the status code and a JSON error, the same way for every action. `$.success()` answers `{ "success": true }` and `$.callback(value)` answers with a value, which is also filtered by the `output` of the action. `UID()` creates the id of a new record.

**`patch` needs `partial: true`.** Without it a field that was not sent is still filled with the default of its type (`''` for a `String`), and `update()` would overwrite the stored value with that empty text. With `partial: true` only the fields present in the request reach the action.

```js actions/products.js
NEWACTION('Products/query', {
	name: 'List products',
	query: 'page:Number, search:String',
	output: 'items:[id:UID, name:String, price:Number], page:Number',
	action: function($) {
		var page = $.query.page || 1;
		var builder = NOSQL('products').find().sort('name').take(10).skip((page - 1) * 10);
		if ($.query.search)
			builder.search('name', $.query.search);
		builder.callback((err, items) => $.callback({ items: items, page: page }));
	}
});

NEWACTION('Products/read', {
	name: 'Read a product',
	params: '*id:UID',
	output: 'id:UID, name:String, price:Number',
	action: function($) {
		NOSQL('products').read().where('id', $.params.id).callback(function(err, item) {
			if (item)
				$.callback(item);
			else
				$.invalid(404);
		});
	}
});

NEWACTION('Products/insert', {
	name: 'Create a product',
	input: '*name:String, *price:Number',
	action: function($, model) {
		model.id = UID();
		NOSQL('products').insert(model).callback(() => $.callback({ id: model.id }));
	}
});

NEWACTION('Products/update', {
	name: 'Replace a product',
	params: '*id:UID',
	input: '*name:String, *price:Number',
	action: function($, model) {
		NOSQL('products').update(model).where('id', $.params.id).callback(function(err, count) {
			if (count)
				$.success();
			else
				$.invalid(404);
		});
	}
});

NEWACTION('Products/patch', {
	name: 'Change some fields of a product',
	partial: true,
	params: '*id:UID',
	input: 'name:String, price:Number',
	action: function($, model) {
		NOSQL('products').update(model).where('id', $.params.id).callback(function(err, count) {
			if (count)
				$.success();
			else
				$.invalid(404);
		});
	}
});

NEWACTION('Products/remove', {
	name: 'Remove a product',
	params: '*id:UID',
	action: function($) {
		NOSQL('products').remove().where('id', $.params.id).callback(function(err, count) {
			if (count)
				$.success();
			else
				$.invalid(404);
		});
	}
});
```

```js controllers/products.js
exports.install = function() {
	ROUTE('GET    /products/            --> *Products/query');
	ROUTE('GET    /products/{id}/       --> *Products/read');
	ROUTE('POST   /products/            --> *Products/insert');
	ROUTE('PUT    /products/{id}/       --> *Products/update');
	ROUTE('PATCH  /products/{id}/       --> *Products/patch');
	ROUTE('DELETE /products/{id}/       --> *Products/remove');
};
```

## Configure a WebSocket route with flags, auth and parameters

Source: https://forge.totaljs.es/en/total5/websocket-flags/
Framework: total5@0.0.19
Content-SHA256: 153249a5572bf8c2fd9e77659ca65a7b282a94a9600af87f3e59004c290776ab
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

A `SOCKET` route takes the same building blocks as an HTTP route. By default messages are JSON objects. `@text` makes the incoming messages plain strings and `@binary` makes them `Buffer`s. In a text route `send(message)` still encodes what it sends as JSON, so a string arrives with quotes; pass `true` as the second argument, `send(message, true)`, to send the string as it is. A `+` before `SOCKET` accepts only users that `AUTH()` approves (the connection is refused otherwise), and `{name}` segments are available in `self.params`. `@csrf` checks a CSRF token before the connection is accepted: send it as the `csrf` query string parameter (`/secure/?csrf=...`), and see the CSRF recipe for `secret_csrf` and `$.csrf()`. A middleware is attached with `#name` as on any route.

```text config
secret_csrf : change-this-secret-in-production
```

```js definitions/auth.js
AUTH(function($) {
	if ($.query.token === 'letmein')
		$.success({ id: '1', name: 'Louis' });
	else
		$.invalid();
});
```

```js controllers/sockets.js
exports.install = function() {
	ROUTE('SOCKET /text/ @text', text);
	ROUTE('SOCKET /bin/ @binary', binary);
	ROUTE('+SOCKET /private/', private_socket);
	ROUTE('SOCKET /room/{name}/', room);
	ROUTE('SOCKET /secure/ @csrf', secure);
	ROUTE('GET /where/', where);
	ROUTE('GET /csrf/', csrf);
};

function text() {
	this.on('message', function(client, message) {
		client.send(typeof(message) + ':' + message.toUpperCase(), true);
	});
}

function binary() {
	this.on('message', function(client, message) {
		client.send(Buffer.from(Buffer.isBuffer(message) ? 'buffer:' + message.length : 'other'));
	});
}

function private_socket() {
	this.on('open', function(client) {
		client.send({ hello: client.user.name });
	});
}

function room() {
	var self = this;
	self.on('open', function(client) {
		client.send({ room: self.params.name });
	});
}

function secure() {
	this.on('open', function(client) {
		client.send({ welcome: true });
	});
}

function where($) {
	$.json({ url: $.hostname('/bin/') });
}

function csrf($) {
	$.json({ csrf: $.csrf() });
}
```

## Minify and merge CSS, JavaScript and HTML

Source: https://forge.totaljs.es/en/total5/minification/
Framework: total5@0.0.19
Content-SHA256: 194c1898038bdd990369cbcb263bcd01f76642eea7059467e5d1544e067099d9
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

Total.js minifies what it serves without any build step. A `.css` or `.js` file from `public/` is sent with comments and whitespace removed (the code is not renamed or restructured, only compacted), and a string sent with `$.html()` or a rendered view has its HTML comments removed and repeated spaces collapsed. A file whose name contains `.min.` (such as `library.min.js`) is considered minified already and is sent as it is.

Three settings in the `config` file control it, all `true` by default: `$minifyjs`, `$minifycss` and `$minifyhtml`. Set one to `false` to serve that type untouched, which is handy when you debug in the browser.

`MERGE(url, file1, file2, ...)` registers a virtual file that is the concatenation of the given files, minified. The browser makes one request instead of many. File paths are URLs of the `public/` folder.

```css public/css/app.css
/* the page style */
body {
	margin: 0;
	color: #000000;
}
```

```js public/js/app.js
// greeting
function hello(name) {
	var message = 'Hello ' + name;
	return message;
}
```

```js public/js/library.min.js
function   untouched ( ) { return  1 }
```

```js public/js/two.js
function two() { return 2; }
```

```js controllers/minify.js
exports.install = function() {
	ROUTE('GET /page/', page);
	MERGE('/all.js', '/js/app.js', '/js/two.js');
};

function page($) {
	$.html('\n\n  \n    \n    

Hello world

\n \n'); } ``` ## Resize and convert images Source: https://forge.totaljs.es/en/total5/images/ Framework: total5@0.0.19 Content-SHA256: 59df6959402e9050bed76d06e7696a95cec76f8421f71a17fc7bff28bef220a9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js processes images by calling **GraphicsMagick** (`gm`) or ImageMagick, which must be installed on the server (`brew install graphicsmagick`, `apt install graphicsmagick`). The `$imageconverter` setting chooses the program: `gm` (default), `im` or `magick`. `Image.load(filename)` (or a `Buffer` or a stream) returns a chain that records the operations and runs them when you call `.save(filename, callback)`. The useful operations are `resize(width, height)` (keeps the proportions inside the box), `thumbnail(width, height)` (a fast, small preview), `miniature(width, height)` (fits the image in the box and fills the rest with the background), `crop(width, height, x, y)`, `rotate(degrees)`, `grayscale()`, `blur(radius)`, `quality(percentage)` and `output('jpg')` to convert the format. Uploaded files do it directly: `file.image()` in a handler for `@upload` routes returns the same chain. Reading the size does not need GraphicsMagick: `Image.measure('png', buffer)` returns `{ width, height }` from the first bytes of PNG, JPG, GIF and WebP data. `$.image(options)` is for a route that creates a picture on demand: `ext` is the format, `load(next)` hands over the source (a stream or a path) with `next(...)`, `image(img)` describes the operations and `cache` is a name under which the result is kept in `tmp/` for the next requests. ```js controllers/images.js const Zlib = require('zlib'); const Fs = require('fs'); exports.install = function() { ROUTE('GET /resize/', resize); ROUTE('GET /thumb/', thumb); }; // Builds a solid red PNG so that the example needs no file function makepng(width, height) { function chunk(type, data) { var length = Buffer.alloc(4); length.writeUInt32BE(data.length); var body = Buffer.concat([Buffer.from(type), data]); var crc = Buffer.alloc(4); crc.writeUInt32BE(Zlib.crc32(body)); return Buffer.concat([length, body, crc]); } var header = Buffer.alloc(13); header.writeUInt32BE(width, 0); header.writeUInt32BE(height, 4); header[8] = 8; // bit depth header[9] = 2; // RGB var row = Buffer.alloc(1 + width * 3); for (var x = 0; x < width; x++) row[1 + x * 3] = 255; var raw = Buffer.concat(Array(height).fill(row)); return Buffer.concat([ Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]), chunk('IHDR', header), chunk('IDAT', Zlib.deflateSync(raw)), chunk('IEND', Buffer.alloc(0)) ]); } function source() { var filename = PATH.tmp('source.png'); Fs.writeFileSync(filename, makepng(200, 100)); return filename; } function resize($) { var target = PATH.tmp('small.jpg'); Image.load(source()).resize(50, 50).output('jpg').save(target, function(err) { if (err) { $.invalid(err); return; } var size = Image.measure('jpg', Fs.readFileSync(target)); $.json({ width: size.width, height: size.height, original: Image.measure('png', Fs.readFileSync(source())) }); }); } function thumb($) { $.image({ ext: 'png', cache: 'thumb-example', load: function(next) { next(Fs.createReadStream(source())); }, image: function(img) { img.resize(40, 40); } }); } ``` ## Verify numeric schema boundaries instead of assuming integer coercion Source: https://forge.totaljs.es/en/total5/numeric-schema-boundaries/ Framework: total5@0.0.19 Content-SHA256: 164490677c2f9a2f3852886b573a46742243ade192a31b09fb8cad9656e73591 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded In `total5@0.0.19`, the compact numeric types all enter the native number validator. **`Int` does not guarantee an integer**: `7.9` is preserved. `Number2` also preserves this fraction; do not interpret its name as rounding to two decimal places. Required numeric zero is accepted. `TinyInt` accepts values from 0 through 255. `SmallInt` accepts -32767 through 32767; notably, -32768 is rejected in this version. These subtype checks enforce bounds but do not require integral values: `TinyInt` accepts `1.5`. Apply an explicit `Number.isInteger()` check for identifiers, counters or quantities that must be integers. These observations describe this version and the tested values, not SQL column semantics. ```js controllers/numbers.js var schema = NEWSCHEMA('NumericBoundaries', '*integer:Int,*small:SmallInt,*tiny:TinyInt,*decimal:Number2'); exports.install = function() { ROUTE('POST /numbers/ @json', numbers); }; function numbers($) { var result = schema.transform($.body); if (result.error) { $.response.status = 400; $.json({ error: 'invalid numeric input' }); return; } $.json(result.response); } ``` ## Use the built-in string, number, date and array helpers Source: https://forge.totaljs.es/en/total5/utilities/ Framework: total5@0.0.19 Content-SHA256: d746997c3cbc0c0a1fa153c1794c7f9bb910cc42ba745b6782ca68e08e6f57ea Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js adds a set of methods to the JavaScript built-ins. They are available everywhere in the app, so they are worth knowing before you write a helper of your own. The ones below are exercised by the example. **String:** `slug([max])` makes a URL-safe text (lowercase, no accents or symbols); `format(a, b)` replaces `{0}`, `{1}`; `encode()` / `decode()` escape and restore HTML; `padLeft(length, char)` / `padRight()`; `parseInt2()` and `parseFloat2()` read a number out of a text and return `0` when there is none; `isEmail()`, `isURL()` and `isJSON()` validate; `parseJSON()` parses JSON and returns `null` on error; `md5()`, `sha1()` and `sha256()` return hex hashes; `capitalize()` upper-cases the first letter of every word. **Number:** `format(decimals, thousands, decimal)`, for example `(1234567.891).format(2)` gives `1 234 567.89`. **Date:** `format('yyyy-MM-dd HH:mm')`, `add('1 day')` and `diff(date, 'days')`. **Array:** `take(n)` and `skip(n)`, `first()` and `last()`, `trim()` (trims the texts and removes the empty ones), `findItem(field, value)` and `findIndex(field, value)`, `remove(value)` (removes every match and returns the array), `group(field)` (returns `[{ name, items }]`) and `quicksort(field)`. **Objects:** `U.extend(target, source)` merges `source` into `target` and returns it; `U.clone(object)` makes a deep copy. ```js controllers/utilities.js exports.install = function() { ROUTE('GET /utils/', utils); }; function utils($) { var items = [{ type: 'a', n: 1 }, { type: 'b', n: 2 }, { type: 'a', n: 3 }]; var original = { a: { b: 1 } }; var copy = U.clone(original); copy.a.b = 2; $.json({ slug: 'Hello Wörld & Co!'.slug(), slugmax: 'Hello brave new world'.slug(11), format: '{0} has {1} items'.format('Ann', 3), encode: '&'.encode(), decode: '<b>'.decode(), pad: ['7'.padLeft(3, '0'), '7'.padRight(3, '0')], numbers: ['abc12x'.parseInt2(), '3,5kg'.parseFloat2(), 'none'.parseInt2()], is: ['a@b.cz'.isEmail(), 'nope'.isEmail(), 'https://totaljs.com'.isURL(), '{"a":1}'.isJSON(), 'abc'.isJSON()], json: ['{"a":1}'.parseJSON(), 'not json'.parseJSON()], md5: 'abc'.md5(), sha1: 'abc'.sha1(), capitalize: 'hello big world'.capitalize(), number: [(1234567.891).format(2), (1234567.891).format(2, ' ', ',')], date: [new Date(2026, 0, 5, 9, 7).format('yyyy-MM-dd HH:mm'), new Date(2026, 0, 31).add('1 day').format('yyyy-MM-dd'), new Date(2026, 0, 5).diff(new Date(2026, 0, 1), 'days')], take: [[1, 2, 3, 4, 5].take(2), [1, 2, 3, 4, 5].skip(3), [1, 2, 3].first(), [1, 2, 3].last()], trim: ['a', '', ' b '].trim(), find: [[{ id: 1 }, { id: 2 }].findItem('id', 2), [{ id: 1 }, { id: 2 }].findIndex('id', 2)], remove: [1, 2, 3, 2].remove(2), group: items.group('type'), sort: [{ n: 'b' }, { n: 'a' }].quicksort('n'), extend: U.extend({ a: 1 }, { b: 2 }), clone: [original.a.b, copy.a.b] }); } ``` ## Record action audit events with a native audit sink Source: https://forge.totaljs.es/en/total5/action-audit/ Framework: total5@0.0.19 Content-SHA256: b949a031d439b733931dd095add9923cac6304897ab4528084ca59651f89a176 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded An action can set `audit` to a text template. On successful completion, the framework sends an audit record to `DEF.onAudit(name, data, context)`. The automatic record uses the sink name `actions` and includes the action id. An action can also call `$.audit(message, type)` explicitly; this emits its own record and can carry a type such as `info`. The example replaces the audit sink with an in-memory collector to inspect its contract. It records only the name, action id, message and type. The framework also prepares contextual data and serialized request data: a real sink needs an explicit policy for secrets, retention, access and failures. An audit event is not evidence that a business transaction committed; the action should call its success callback only after the intended write succeeds. In this version the automatic audit event occurs after the successful action callback path. It does not automatically log validation failures or failed actions. ```js definitions/audit.js MAIN.auditEvents = []; DEF.onAudit = function(name, data) { MAIN.auditEvents.push({ sink: name || null, action: data.action, message: data.message || '', type: data.type || null }); }; NEWACTION('AuditExample|save', { input: '*name:String', audit: 'Saved the example', action: function($) { $.callback({ ok: true }); } }); NEWACTION('AuditExample|explicit', { action: function($) { $.audit('Explicit example event', 'info'); $.success(); } }); NEWACTION('AuditExample|fail', { audit: 'This must not become a success event', action: function($) { $.invalid(409); } }); ``` ```js controllers/audit.js exports.install = function() { ROUTE('POST /save/ --> *AuditExample|save'); ROUTE('POST /explicit/ --> *AuditExample|explicit'); ROUTE('POST /fail/ --> *AuditExample|fail'); ROUTE('GET /events/', function($) { $.json(MAIN.auditEvents); }); }; ``` ## Run in debug and release mode Source: https://forge.totaljs.es/en/total5/release-mode-and-debugging/ Framework: total5@0.0.19 Content-SHA256: 6b9c467dade4b69e103b12fa2687c66dae398141f5b622497f90a81bba6e01b9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js runs in one of two modes, **debug** for development and **release** for the server, and the global boolean `DEBUG` tells your code which one is active. In debug mode the app runs under a file watcher that restarts it when you change a file, errors show details and source maps are generated. Release mode has no watcher and error pages without the technical details. The mode is chosen by how the app is started, in the start script (`index.js`) that calls `Total.run(options)`: - the default is debug, with the watcher; - `options.release = true` starts release mode; the start script that Total.js generates sets it from the command line, so `node index.js --release` is the way to start production; - `options.watcher = false` runs a single process without the watcher, and that is always release mode (it is what the examples of this cookbook use). Before `Total.run()` has decided, `DEBUG` has a default taken from `NODE_ENV`: it is `false` when `NODE_ENV=production` and `true` otherwise. Code that runs at the moment a module is loaded sees that default, so do not rely on `NODE_ENV` for the final mode, only on `DEBUG` after the app has started. The routes can follow the mode. The flag `@debug` makes a route exist only in debug mode and `@release` only in release mode; in the other mode the URL answers 404. Use `@debug` for tools you need while developing (a database viewer, a seed route) so they can never reach production by accident. ```js controllers/mode.js exports.install = function() { ROUTE('GET /mode/', mode); ROUTE('GET /tools/ @debug', tools); ROUTE('GET /status/ @release', status); }; function mode($) { $.json({ debug: DEBUG }); } function tools($) { $.json({ tools: true }); } function status($) { $.json({ status: 'ok' }); } ``` ## Test the application with the built-in test runner Source: https://forge.totaljs.es/en/total5/tests/ Framework: total5@0.0.19 Content-SHA256: 86c51b7edfa17059a77abaa717c02fc9a5330e98f06d50fca0798bcb7ec815df Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Total.js has a small test runner, `total5/test`. A test file is a normal Total.js script: it loads the framework and the runner, starts the application and, when it is `ready`, registers its tests. `Test.push(name, fn)` adds a test; `fn(next)` does its work and calls `next()` to continue with the following one. `Test.print(message, error)` reports one check: pass `null` as `error` for success (`[OK]` is printed) or a message for failure (`[FAIL]` is printed and the process exits with code 1). `Test.run()` runs the registered tests in order and exits with code 0 at the end. Because failure ends the process with a non-zero code, the file can be called by `npm test` and by any CI service. Wait a moment (about 500 ms) after `ready` before the first request: a request sent right away can still get a 404. Use `RESTBuilder` (or `REQUEST`) against the local server to test routes, and call actions directly with `ACTION()`. ```js controllers/sum.js exports.install = function() { ROUTE('GET /sum/{a}/{b}/', sum); ROUTE('GET /dir/', dir); }; function sum($) { $.json({ total: +$.params.a + +$.params.b }); } function dir($) { $.json({ dir: PATH.root() }); } ``` ```js test.js require('total5'); require('total5/test'); // Another port than the application uses, so both can run Total.run({ port: 8765, release: false, watcher: false }); ON('ready', function() { // A request sent in the same tick as "ready" can still get a 404, so give the routes a moment setTimeout(runtests, 500); }); function runtests() { Test.push('The sum route', function(next) { RESTBuilder.GET('http://127.0.0.1:8765/sum/2/3/').exec(function(err, response) { Test.print('2 + 3 = 5', response && response.total === 5 ? null : 'Expected 5, got ' + JSON.stringify(response)); next(); }); }); Test.push('Unknown route', function(next) { RESTBuilder.GET('http://127.0.0.1:8765/missing/').exec(function(err, response, output) { Test.print('/missing/ answers 404', output.status === 404 ? null : 'Expected 404, got ' + output.status); next(); }); }); Test.run(); } ``` ## Use all CPU cores with the cluster mode Source: https://forge.totaljs.es/en/total5/cluster/ Framework: total5@0.0.19 Content-SHA256: 99d3248ff978a66dc94b11b8e9618643225d23dc06e9d6f4278b01bbb9f41e09 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A Node.js process uses one CPU core. `Total.run({ cluster: N })` starts a **master** that forks `N` worker processes, each running your whole application, and the operating system shares the incoming connections between them (`'auto'` instead of a number lets the master add threads as the load grows). Run it in release mode (`release: true`, which the generated start script sets with `--release`); the debug watcher is not meant for a cluster. In the start script it is one option: ```js Total.run({ cluster: 4, release: true }); // or cluster: 'auto' ``` Every worker is a separate process with its own memory, so anything kept in a variable, in `CACHE` or in `MEMORIZE` exists once **per worker** and is not shared: two requests of the same user can land on different workers. Keep shared state in a database, in a file storage or in a message service, and keep sessions in a store all workers can read. Scheduled work such as `CRON()` also runs in every worker, so guard it if it must run once. **Check that all the workers are up.** After a deploy, request a URL like `/pid/` below repeatedly and count the distinct ids: you should see as many as the workers you asked for. Each worker has its own process id. The example starts two workers and includes that id in the response. ```js controllers/pid.js exports.install = function() { ROUTE('GET /pid/', pid); ROUTE('GET /dir/', dir); }; function pid($) { $.json({ pid: process.pid }); } function dir($) { $.json({ dir: PATH.root() }); } ``` ```js cluster.js require('total5'); Total.run({ cluster: 2, port: 8766, release: true }); ``` ## Load a JavaScript module from a URL with IMPORT() Source: https://forge.totaljs.es/en/total5/import-remote-module/ Framework: total5@0.0.19 Content-SHA256: d9ee8c3000dc6dc3cbcd81c5a4523bfb6863dca95d50aafed96c8f1755a91c0a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `IMPORT(url, [callback])` downloads a JavaScript file, saves it in the `tmp` folder of the application and returns what the file exports (`module.exports`), as `require()` would. With a callback it is `callback(err, module, response)`; without it, `IMPORT()` returns a promise for the module. The address is remembered: calling `IMPORT()` again with the same address does **not** download the file again, it requires the one in `tmp` (and the file stays there between restarts, but the memory of "already downloaded" does not: after a restart it is downloaded again). **This runs code that comes from the network with all the rights of your application.** Import only from an address that you control and that you reach with `https`, never one that a user sent you or that anyone else can change. The file is a CommonJS module. **The status of the answer is not checked:** an address that answers `404` (or any error page) is saved as if it were the module, and `require()` then throws a `SyntaxError` inside the download, so in `total5` 0.0.19 the callback is **never called** and the promise never settles. Always give `IMPORT()` a limit of time of your own, as the last route does, and check the address before you depend on it. Here the file comes from a route of the same application, so that the example needs no network. The route counts the downloads. ```js controllers/import.js exports.install = function() { ROUTE('GET /lib/tax/', lib); ROUTE('POST /use/', use); ROUTE('POST /use-twice/', use_twice); ROUTE('POST /missing/', missing); ROUTE('GET /downloads/', downloads); }; let count = 0; function lib($) { count++; $.plain('module.exports = { vat: function(price) { return Math.round(price * 121) / 100; } };'); } function downloads($) { $.json({ downloads: count }); } function base() { return 'http://127.0.0.1:' + CONF.$port; } async function use($) { const tax = await IMPORT(base() + '/lib/tax/'); $.json({ price: tax.vat(100) }); } function use_twice($) { IMPORT(base() + '/lib/tax/', function(err, tax) { $.json({ err: err ? err.toString() : null, price: tax ? tax.vat(200) : null }); }); } async function missing($) { // the address does not exist: the answer is the 404 page of the application const winner = await Promise.race([ IMPORT(base() + '/lib/missing/').then(() => 'answered', () => 'answered'), new Promise(resolve => setTimeout(() => resolve('no answer'), 1500)) ]); $.json({ result: winner }); } ``` ## Build a flow of components with Flow.load() and run it with exec() Source: https://forge.totaljs.es/en/total5/flowstream/ Framework: total5@0.0.19 Content-SHA256: 8bb7bd513b4f12b9d58eafbd976efdc76a26cc9b10ead6bb184f67b0e7af38c6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A **FlowStream** is a small program made of **components** (boxes with inputs and outputs) and **connections** between them. Total.js runs it inside your application: a message enters one component, the component sends results to its outputs, and the connections carry them to the next components. The same schema is what the Flow designer of Total.js draws; here it is written by hand. `Flow.load(schema, [callback])` starts a FlowStream and gives the callback `(err, instance)`. The schema is an object: - `id` and `name`: the id is the key in `Flow.instances` (`Flow.instances.demo`); without an id a random one is made. - `components`: an object with the **source code** of each component, as text. The text is a script, `` (the form that the designer saves). - `design`: the instances of the components. Each one has an `id`, the `component` that it uses, its `config` and `connections`, an object whose keys are **output ids** and whose values are lists of `{ id, index }`: the instance and the **input id** that receive what is sent to that output. - `variables`: values that components can read. A component is a module: `exports.id`, `exports.name`, `exports.inputs` and `exports.outputs` (lists of `{ id, name }`), `exports.config` (the defaults) and `exports.make = function(instance, config)`. In `make()` the component sets `instance.message = function($) {}`, which receives each message: `$.data` is the data, `$.send(outputid, data)` sends it to an output and `$.destroy()` ends a message that does not go any further. To use the flow from your code, `instance.exec({ id, data, callback })` sends `data` to the instance `id` and calls `callback(err, message)` when the message ends; the last message of the chain is `message` (so `message.data` is what the last component received). `instance.reconfigure(id, config)` changes the configuration of a running instance and `Flow.remove(id)` stops the FlowStream and forgets it. `FlowStream` is the same object as `Flow`: two names for the manager. **A component is code that runs with all the rights of the application** (in the same thread unless the schema says `worker`). Never load a schema or a component that a visitor can write. ```js definitions/flow.js const upper = ``; const collect = ``; MAIN.collected = []; MAIN.flow = null; Flow.load({ id: 'demo', name: 'Demo', components: { upper: upper, collect: collect }, design: { a: { id: 'a', component: 'upper', config: { prefix: '> ' }, connections: { output: [{ id: 'b', index: 'input' }] } }, b: { id: 'b', component: 'collect', config: {}, connections: {} } }, variables: {} }, function(err, instance) { MAIN.flow = instance; }); ``` ```js controllers/flow.js exports.install = function() { ROUTE('GET /shout/', shout); ROUTE('POST /prefix/ @json', prefix); ROUTE('GET /collected/', collected); ROUTE('GET /info/', info); ROUTE('POST /stop/', stop); }; function shout($) { if (!MAIN.flow) return $.invalid('The flow is not running'); MAIN.flow.exec({ id: 'a', data: $.query.text, callback: (err, message) => $.json({ result: message ? message.data : null }) }); } function prefix($) { MAIN.flow.reconfigure('a', { prefix: $.body.prefix }); $.json({ ok: true }); } function collected($) { $.json(MAIN.collected); } function info($) { $.json({ flows: Object.keys(Flow.instances), instances: Object.keys(MAIN.flow.flow.meta.flow), same: Flow === FlowStream }); } function stop($) { Flow.remove('demo'); MAIN.flow = null; $.json({ flows: Object.keys(Flow.instances) }); } ``` ## Test a Flow component alone with Flow.test() Source: https://forge.totaljs.es/en/total5/flowstream-component-test/ Framework: total5@0.0.19 Content-SHA256: c9944def331db1296e725f6200d7bcf3bf60c1265eed77a225d7c71d3864d64e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `Flow.test(name, source, [config], [init])` builds a flow with **one** component (the `source` is its code, like in the recipe of FlowStream, and `config` replaces its configuration) and a dummy component that collects its outputs. `init(test)` is called when the flow is ready, with the object `test`: - `test.send(inputid, data)` (also `test.input`) sends a message to an input of the component and returns it. - `test.message = function($, data)`: called with every message that the component sends to **any of its outputs**; `$` is the message and `data` its data. - `test.reconfigure(config)` changes the configuration; `test.configure = function(config)` is called after it. `test.variables(object)` sets the variables of the flow. - `test.assert(ok, message)`, `test.ok(message)` and `test.fail(message)` print `[OK]` or `[NO]` with the date, and a failure throws. The functions are plain properties: replace `test.ok` and `test.fail` to send the result somewhere else, as the example does. - The test flow always has the id `test`: only one `Flow.test()` at a time. It is meant for the tests of a component that is written for a Flow, run with `node index.js` in a small application of its own. ```js definitions/component-test.js MAIN.results = []; const source = ``; ON('ready', function() { Flow.test('tax', source, { rate: 10 }, function(test) { test.ok = message => MAIN.results.push('ok: ' + message); test.fail = message => MAIN.results.push('no: ' + message); test.message = function($, data) { test.assert(data.net === 100, 'the net amount comes back'); test.assert(data.total === 110, 'the configuration of the test (10 %) is used, got ' + data.total); MAIN.results.push('message: ' + JSON.stringify(data)); }; test.send('input', 100); }); }); ``` ```js controllers/results.js exports.install = function() { ROUTE('GET /results/', results); }; function results($) { $.json(MAIN.results); } ``` ## Call a Python program that keeps running with PYPELINE() Source: https://forge.totaljs.es/en/total5/pypeline/ Framework: total5@0.0.19 Content-SHA256: c346fc22c80a08961b4ed4e5da21cc650cb0f3fac63fddec6f03504e6f5bcaf7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `PYPELINE(name, [options])` starts `pypelines/.py` with `python3` and keeps a connection to it, so the application can use Python libraries (data, models, image processing) without starting a new process for every request. It returns an object with `send(data)` to send a message, `on('data', fn)` to receive the answers and `close()` to stop the script. A name that starts with `~` is the path of a file instead (`~/opt/job.py`), and a text that is code (it has line breaks or looks like Python) is run as an inline program with `python3 -c`. - **The protocol.** The script is started as `python3 -u script.py `: the **last argument is the path of a Unix socket** that the application listens on, and the script connects to it. Every message, in both directions, is a frame: 4 bytes with the length (big endian) followed by the body, which is JSON by default. - **Options:** `type` (`'json'` default, `'text'`, or anything else for raw `Buffer`s), `autorestart` (`false` to not restart the script when it ends; by default it is started again), `threads` and `socket: false` (no socket, only start the program). - Messages sent before the script has connected wait and are delivered when it does. - Events: `open` (the script connected), `data` (a message), `restart` and `close`. - **The path of the socket has a limit.** The socket is a file in the `tmp` folder of the application and the system limits the whole path (about 104 characters on macOS and 108 on Linux). In a project that is deep in the disk the server fails with `listen EINVAL`, the script never connects and the messages wait forever. The path is the property `pypeline.socket`: set it right after `PYPELINE()` (the file is checked and the server started afterwards) to a short one, as the example does. - The Python program is a **normal program that runs with the rights of the application**: it is only as safe as the code of the file, and Python 3 has to be installed (`python3` in the `PATH`). ```python pypelines/shout.py import json import socket import struct import sys # The last argument is the socket that the application listens on sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(sys.argv[-1]) def read(count): data = b'' while len(data) < count: chunk = sock.recv(count - len(data)) if not chunk: raise SystemExit(0) data += chunk return data while True: size = struct.unpack('>I', read(4))[0] message = json.loads(read(size).decode('utf-8')) answer = json.dumps({ 'id': message['id'], 'upper': message['text'].upper(), 'words': len(message['text'].split()) }).encode('utf-8') sock.sendall(struct.pack('>I', len(answer)) + answer) ``` ```js controllers/py.js exports.install = function() { ROUTE('POST /shout/ @json', shout); }; const pypeline = PYPELINE('shout'); // A short path for the socket: the folder of a project can be too deep for a Unix socket pypeline.socket = require('os').tmpdir() + '/forge-shout-' + process.pid + '.socket'; const pending = {}; let counter = 0; // Every answer says which message it is for pypeline.on('data', function(answer) { const callback = pending[answer.id]; if (callback) { delete pending[answer.id]; callback(answer); } }); function shout($) { const id = ++counter; const timer = setTimeout(() => $.invalid('The script did not answer'), 5000); pending[id] = function(answer) { clearTimeout(timer); $.json(answer); }; pypeline.send({ id: id, text: $.body.text }); } ``` ## Enums and string-format validation boundaries Source: https://forge.totaljs.es/en/total5/schema-enums-and-formats/ Framework: total5@0.0.19 Content-SHA256: 7170c1adf5f76b4f2a6754b93b35b731172e178c0fabc248d6e3043eadc8a83c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Compact enums use `status:{draft|published}` (semicolon also separates choices). The string is trimmed before exact, case-sensitive membership checking. A required enum rejects an omitted/empty value. Nested objects use `{name:Type}`; they are not enum declarations. In `total5@0.0.19`, `Color` accepts hexadecimal `#RGB`, `#RRGGBB` and `#RRGGBBAA`; it does not accept CSS color names. `Icon` validates a class-name pattern, not the presence of the icon asset. `Base64` and `Zip` use the framework's validators: format acceptance is not content verification. In the compact-schema parser of this version, **`JSON` and `IP` are not recognized subtypes and fall back to plain strings**. Malformed JSON and invalid IP text are accepted. The explicit JSON Schema below sets native `subtype` values to enable these checks; it does not parse a JSON string into an object. Do not use `SafeString` in place of bound SQL parameters or output escaping. ```js controllers/formats.js var schema = NEWSCHEMA('FormatBoundaries', '*status:{draft|published},*color:Color,*blob:Base64,*zip:Zip,*icon:Icon,*document:JSON,*address:IP'); var explicit = Total.newjsonschema('ExplicitFormats', { $id: 'ExplicitFormats', type: 'object', required: ['document','address'], properties: { document: { type: 'string', subtype: 'json' }, address: { type: 'string', subtype: 'ip' } } }); exports.install = function() { ROUTE('POST /explicit/ @json', function($) { var result = explicit.transform($.body); if (result.error) { $.response.status = 400; $.json({ error: 'invalid format' }); } else $.json(result.response); }); ROUTE('POST /formats/ @json', formats); }; function formats($) { var result = schema.transform($.body); if (result.error) { $.response.status = 400; $.json({ error: 'invalid format' }); } else $.json(result.response); } ``` ## TotalAPI and Componentator service boundaries Source: https://forge.totaljs.es/en/total5/remote-service-boundaries/ Framework: total5@0.0.19 Content-SHA256: 5524e132d24137a2f048bb67797b5f5cbee93beb1b855059c50d44c081d0e2d4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `TotalAPI(operation, data)` delegates to `API('TAPI', operation, data)`. The built-in driver sends requests to the regional endpoint selected by `CONF.$tapiurl`, using a configured token such as `CONF.secret_totalapi`. `.promise()` and `.callback()` use the same API builder as other drivers. With `$tapi:false`, operations other than the driver's special `check` operation fail locally with `totalapi_inactive`. `COMPONENTATOR(name, components, removeprev=true, attrs='')` determines a public bundle filename, stores its URL in `REPO[name]` and fetches it from Componentator only when the file is absent. With `removeprev:true`, older matching files may be deleted. The `componentator` event receives the name/component metadata before the lookup. This function returns before its async filesystem/download work has finished; the repo URL alone is not proof of download success. For locally vendored frontend assets, serving known files avoids dependence on remote bundle availability. For live TotalAPI/Componentator integration, separately verify your exact service, credentials, network behavior and returned content. These services are optional and are not dependencies needed to start a native Total.js application. ```text config $tapi : false ``` ```js controllers/remote.js exports.install = function() { ROUTE('GET /disabled-api/', async function($) { try { await TotalAPI('forge-fixture-no-service', {}).promise(); $.json({ unexpected: true }); } catch (e) { $.json({ error: String(e) }); } }); ROUTE('GET /cached-componentator/', function($) { var components = 'forge-local-fixture'; var relative = 'ui-' + components.makeid() + '.min.js'; F.Fs.writeFileSync(PATH.public(relative), '/* local fixture */'); COMPONENTATOR('fixture', components, false); $.json({ url: REPO.fixture, expected: '/ui-' + components.makeid() + '.min.js' }); }); }; ``` ## QueryBuilder operations, filters and driver contract Source: https://forge.totaljs.es/en/total5/query-builder-contract/ Framework: total5@0.0.19 Content-SHA256: f155d117230e8d40e4895b685b1dec15b996d5a867b5d917fe2972d66bac8e8e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded This page covers the native `total5@0.0.19` QueryBuilder (`querybuilder.js`). `DB()` returns a queue controller. Each operation schedules a driver call; append filters and callbacks synchronously before it executes. `NEWDB(name, driver)` registers a connection. `NEWDB(name)` unregisters it. There is no implicit database engine or transaction in this queue. The example driver returns the received options. To execute a database operation, implement that operation in the driver. For actual SQL execution and rollback see [query-builder-sqlite](/en/total5/query-builder-sqlite/). | Operations | Driver receives | |---|---| | `find/all(table)`, `read/one(table)`, `list(table)` | `exec`, `table`; `read` sets `first:true`, `take:1`; `list` defaults to `take:100`, `skip:0` | | `check(table)`, `count(table)` | `check` sets `first:1`, `take:1`; the driver defines the result value | | `insert/ins(table, data)` | `payload` | | `update/modify/mod/upd(table, data, upsert)` | `payload`, `upsert`; a zero result triggers a second `insert` when upsert is enabled | | `remove/rem(table)`, `truncate/clear(table)`, `drop(table)` | The corresponding `exec`; destructive operations need driver support | | `scalar(table, type, key, key2)` | `scalar:{type,key,key2}`; omitted `key` becomes `*` | | `command(table, name)` | `command:name` | | `query(sql, params)` or `query(connection, sql, params)` | Raw text in `query`, values in `params`, table is empty; SQL binding is the driver's responsibility | | Query methods | Options / behavior | |---|---| | `where(name, [comparer], value)`, `equal(object)`, `id(value)`, `userid(value)` | Equality shorthand; `==` becomes `=`, `!=` becomes `<>`; array IDs use `in` | | `in/notin(name, values, [idField])`, `between(name,a,b)`, `or(fn)` | Filter records; `or` groups the records added inside `fn(builder)` | | `array(name,[comparer],value)` | Default comparer `&&`; interpretation belongs to driver | | `month/day/year/hour/minute(name,[comparer],value)` | Date-part filters; default comparer `=` | | `search(name,value,[where])`, `contains(name)`, `empty(name)` | Filter records; matching semantics belong to driver | | `query(fragment)`, `join(name,table,type,a,b)`, `permit(name,type,values,userid,required)` | Driver-specific filters; raw fragments must come from trusted application code | | `fields(csv)`, `returning(csv)` | Arrays of trimmed field names, not SQL escaping or authorization | | `sort(name, descending)`, `gridsort(csv,[localized])` | Sort strings; `true` or `desc` select descending | | `take/limit(n)`, `skip(n)`, `page(page,limit)`, `paginate(page,limit,max)` | Offsets/limits; `paginate` caps the limit, `page` does not | | `first()`, `primarykey(name)`, `schema(name)`, `language(value,prefix,skip)`, `debug()` | Metadata for driver; `first` also unwraps an array result | | `gridfilter(name,query,type,[key])`, `autoquery(query,schema,sort,max)` | Convert grid query parameters into options. `autoquery` restricts requested fields and sort keys to its declared schema | | `gridfields(fields,allowed)` | Use `fields()` with your own allowlist: it is the tested way to choose the columns | | `callback/pipe(fn)`, `promise()`, `done($,fn,param)` | Completion; promises reject on driver error | | `data(fn)`, `fail(fn)`, `error/err(message,reverse)` | Success/failure hooks; `error()` rejects empty results, `reverse:true` rejects truthy results (including an empty array) | | `set(name)`, `nobind()` | Name the queued result, or do not replace queue output | | `insert(fn,param)` on an update builder | Mutate the payload before the fallback insert of an upsert | | `audit($,message,type)` | Calls the supplied context's `variables()` and `audit()` after a successful driver response | Controller methods: `callback/pipe`, `promise`, `done`, `debug`, `language`, `load(connection, options)` and `exec(options, callback)`. `load` copies a defined subset of serialized options; `exec` dispatches supported operation names. `next/free` are lifecycle internals. A queue stops after a driver error; it does not undo earlier writes. ```js definitions/contract.js NEWDB('contract', function(options, callback) { if (options.table === 'failure') return callback(new Error('driver failed')); if (options.table === 'empty') return callback(null, []); if (options.table === 'upsert') { MAIN.upsert.push(JSON.parse(JSON.stringify(options))); return callback(null, options.exec === 'update' ? 0 : options.payload); } if (options.exec === 'list') return callback(null, { items: [], count: 12 }); callback(null, options.first ? [options] : options); }); MAIN.upsert = []; ``` ```js controllers/contract.js exports.install = function() { ROUTE('GET /contract/', contract); }; async function contract($) { try { var out = {}; var methods = ['find', 'all', 'read', 'one', 'list', 'check', 'count', 'insert', 'ins', 'update', 'modify', 'mod', 'upd', 'remove', 'rem', 'truncate', 'clear', 'drop']; out.operations = {}; for (var method of methods) out.operations[method] = await DB()[method]('contract/items', { name: 'Ann' }).promise(); out.scalar = await DB().scalar('contract/items', 'sum', 'amount', 'group').promise(); out.command = await DB().command('contract/items', 'vacuum').promise(); out.raw = await DB().query('contract', 'SELECT ?', [7]).promise(); out.filters = await DB().find('contract/items').id([1, 2]).userid({ id: 'u1' }).equal({ active: true }).where('age', '!=', 0).in('team', [{ id: 'a' }], 'id').notin('team', 'b').between('age', 18, 65).or(function(q) { q.where('role', 'a').where('role', 'b'); }).array('tags', ['x']).month('created', 1).day('created', 2).year('created', '>=', 2020).hour('created', 3).minute('created', 4).search('name', 'ann', 'beg').contains('email').empty('deleted').query('trusted_fragment').join('team', 'teams', 'left', 'a.id', 'b.id').permit('permissions', 'RW', ['team'], 'u1', false).promise(); out.options = await DB().find('contract/items').fields('id, name').returning('id, name').sort('name', true).gridsort('id_asc').limit(5).skip(2).primarykey('uid').schema('public').language({ language: 'es' }, '_').debug().promise(); out.page = await DB().list('contract/items').paginate('2', '500', 10).promise(); out.grid = await DB().find('contract/items').autoquery({ fields: 'id,password', sort: 'password_desc,name_desc', page: '2', limit: '500', age: '>18' }, 'id:String,name:String,age:Number', 'id_asc', 10).promise(); out.gridfields = await DB().find('contract/items').gridfields('id', 'id,name').promise(); var queue = DB(); queue.read('contract/items').set('one'); queue.count('contract/items').set('count'); queue.find('contract/items').nobind(); out.queue = await queue.promise(); var hooks = []; await DB().read('contract/empty').data(function(v) { hooks.push(v === null ? 'null' : 'value'); }).promise(); try { await DB().read('contract/empty').error('missing').fail(function() { hooks.push('fail'); }).promise(); } catch (e) { out.missing = String(e); } try { await DB().find('contract/failure').promise(); } catch (e) { out.failure = String(e); } out.hooks = hooks; out.upsert = await DB().update('contract/upsert', { name: 'new' }, true).where('id', 7).insert(function(payload, role) { payload.role = role; }, 'member').promise(); out.upsertCalls = MAIN.upsert; out.load = await DB().load('contract', { table: 'items', exec: 'find', take: 2, filter: [] }).promise(); $.json(out); } catch (e) { $.invalid(e); } } ``` ## Compile and run a native server component Source: https://forge.totaljs.es/en/total5/native-components/ Framework: total5@0.0.19 Content-SHA256: 9445f3e45dbdb4d6c027386dcc52d91d2904a31c44893a2f970d9e3ab5324aaf Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `NEWCOMPONENT(html, [callback])` compiles a **server component**, distinct from a browser jComponent. It accepts source text containing `'; var component = await NEWCOMPONENT(source); component.debugger = false; var instance = component.create(); var first = await new Promise(resolve => instance.input('input',{name:'Ann'},message => resolve(message.data))); var invalid = await new Promise(resolve => instance.input('input',{},message => resolve(message.data))); instance.reconfigure({prefix:'two:'}); var second = await new Promise(resolve => instance.input('input',{name:'Bob'},message => resolve(message.data))); instance.remove(); var rejected = false; try { await NEWCOMPONENT('no backend script'); } catch (e) { rejected = true; } $.json({first:first,invalid:invalid,second:second,remaining:component.instances.length,closed:MAIN.componentClosed,rejected:rejected}); } catch (e) { $.invalid(e); } } ``` ## Controller callbacks, manual authorization and conditional responses Source: https://forge.totaljs.es/en/total5/controller-completion-and-cache/ Framework: total5@0.0.19 Content-SHA256: 787a7a2bd01ce5f203e2d87e26c6bd63f6e6db685bd180c8648853021e8f2bd0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded These are ordinary route-controller methods, distinct from the action context. `$.jsonstring()` takes already-serialized JSON. `$.respond()` selects the method named by `$.response.output`, defaulting to JSON. `$.done(true)` forwards the callback result inside the success envelope; another argument selects a fixed value. `$.successful(fn)` calls your function only when there is no error. `await $.authorize()` resolves with the authorization result; an anonymous result must still be handled by your code. For conditional responses pass a **UTC header string** to `$.notmodified()`: in 0.0.19 comparison is exact string equality. `$.httpcache()` sets headers but `$.json()` overwrites cache policy, so the example sends a raw buffer after setting them. Use public caching only for public representations. `$.custom()` transfers response ownership to your handler; finish the Node response yourself. ```js definitions/auth.js AUTH(function($) { if ($.headers['x-demo-user'] === 'alice') $.success({ id: 'alice' }); else $.invalid(); }); ``` ```js controllers/completion.js exports.install = function() { ROUTE('GET /serialized/', $ => $.jsonstring('{"ok":true}')); ROUTE('GET /respond/', function($) { $.response.output = 'plain'; $.respond('hello'); }); ROUTE('GET /done/', $ => $.done(true)(null, { id: 7 })); ROUTE('GET /successful/', $ => $.successful(value => $.json({ value: value }))(null, 9)); ROUTE('GET /callback-error/', $ => $.successful(() => $.json({ wrong: true }))('failure')); ROUTE('GET /manual-auth/', async function($) { var user = await $.authorize(); if (user) $.json({ id: $.user.id }); else $.invalid(401); }); ROUTE('GET /conditional/', function($) { var modified = 'Mon, 05 Jan 2026 00:00:00 GMT'; if ($.notmodified(modified)) return; $.httpcache(modified); $.binary(Buffer.from('public version 1'), 'text/plain'); }); ROUTE('GET /custom/', function($) { $.custom(); $.res.writeHead(202, { 'content-type': 'text/plain' }); $.res.end('accepted'); }); }; ``` ## Action transport options and explicit TMS publishing Source: https://forge.totaljs.es/en/total5/action-transport-boundaries/ Framework: total5@0.0.19 Content-SHA256: 8baa757137eb3c808eb19ae317806f99304c91c1a20c49ff788442cfce32e39c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded In `total5@0.0.19`: `NEWACTION()` stores `csrf`, `encrypt` and `compress` in action metadata, but they do not establish the HTTP guarantees their names might suggest on HTTP routes: - `csrf:true` alone accepts a POST without a token. Use a middleware that calls `DEF.onCSRFcheck()` with `secret_csrf` configured, as in [csrf-protection](/en/total5/csrf-protection/). - `encrypt:true` on a declared route adds `@encrypt` metadata, but this version still accepts plaintext JSON and returns plaintext JSON. Use HTTPS for transport. - `compress:false` does not disable ordinary HTTP gzip; response compression follows `$httpcompress`, the client's accepted encoding and response size. A large JSON response can be gzipped even when this action option is false. - `publish` declares a TMS topic/schema. Completing an action does not automatically publish its result. Call `$.publish(value)` explicitly and construct the public payload deliberately. Select the fields to publish before calling `$.publish(value)`. Configure the TMS token for your application. TMS messages go to subscribers of that topic; application permission and tenancy rules still belong in your code. ```text config secret_csrf : local-csrf-fixture-only $tms : true secret_tms : local-tms-fixture-only $httpcompress : true ``` ```js definitions/transport.js NEWACTION('Transport|csrf', { csrf: true, input: '*value:String', action: function($, model) { $.callback(model); } }); NEWACTION('Transport|encrypted', { encrypt: true, route: 'POST /encrypted/', input: '*value:String', action: function($, model) { $.callback(model); } }); NEWACTION('Transport|compressed', { compress: false, action: function($) { $.callback({ text: 'abcdefghij'.repeat(400) }); } }); NEWACTION('Transport|notice', { publish: 'value:String', input: '*value:String', action: function($, model) { $.publish({ value: model.value }); $.success(); } }); ``` ```js controllers/transport.js exports.install = function() { ROUTE('POST /csrf-option/ @json --> Transport|csrf'); ROUTE('GET /compression-option/ --> Transport|compressed'); ROUTE('POST /notice/ @json --> Transport|notice'); }; ``` ## Invalidate release-mode static caches with TOUCH Source: https://forge.totaljs.es/en/total5/touch-static-cache/ Framework: total5@0.0.19 Content-SHA256: 74d53a2b7d1a609a9c88ee5f5d38268ea8eb33b899b80fd78848ba95b5ae4e8c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `TOUCH(url)` clears three cache entries for that URL: `F.temporary.minified`, `tmp` and `notfound`. `TOUCH()` clears those maps. It does not clear `CACHE`, NoSQL documents or every view/configuration cache. Call it after changing a generated asset in release mode. Keep this operation in trusted server code; the write endpoint below is only a local fixture. Cache invalidation applies to the running process. When an application runs in several processes, coordinate invalidation across those processes. ```text public/generated.txt before ``` ```js controllers/assets.js exports.install = function() { ROUTE('POST /regenerate/', function($) { F.Fs.writeFileSync(PATH.public('generated.txt'), 'after'); F.Fs.writeFileSync(PATH.public('appeared.txt'), 'created'); TOUCH('/generated.txt'); TOUCH('/appeared.txt'); $.success(); }); }; ``` ## OPENCLIENT RPC, events and shared connections Source: https://forge.totaljs.es/en/total5/openclient-protocol/ Framework: total5@0.0.19 Content-SHA256: 3debacfd6c900cdaaedcd3e3d489b7a1403f947f09e98c01bd4c4e42509ccf42 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `OPENCLIENT(url, [id])` is the native Open Platform protocol client. It converts `http`/`https` URLs to `ws`/`wss`. Logical clients with the same URL share a WebSocket. `.online(fn)` receives the server's `{type:'init',id:...}` metadata; `.message(fn)` receives unsolicited messages. `.rpc(message)` returns a promise; `.send(message, callback, [filter], [timeoutMs])` uses a callback; `.cmd(message)` sends without waiting. `.remove()` closes the physical socket only after its last logical client is removed. The example includes a local protocol server. `callbackid`, `error` and `response` are protocol fields. A callback timeout is opt-in; set one for requests that need a deadline. Keep real platform credentials and URLs in server configuration. ```js controllers/open.js exports.install = function() { ROUTE('SOCKET /fixture/', fixture); ROUTE('GET /openclient/', exercise); }; function fixture() { var server = this; server.on('open', function(client) { client.send({ type: 'init', id: 'local-fixture', version: 1 }); }); server.on('message', function(client, message) { if (message.type === 'ignore') return; if (message.type === 'event') { client.send({ type: 'notice', value: message.value }); return; } client.send({ callbackid: message.callbackid, error: message.type === 'fail' ? 'denied' : null, response: { value: message.value } }); }); } async function exercise($) { var a; var b; try { var url = $.hostname('/fixture/'); a = OPENCLIENT(url, 'first'); await new Promise(function(resolve, reject) { var timer = setTimeout(() => reject(new Error('init deadline')), 2000); a.online(function(meta) { if (meta) { clearTimeout(timer); resolve(); } }); }); b = OPENCLIENT(url, 'second'); var shared = a.ws === b.ws; var sum = await a.rpc({ type: 'echo', value: 7 }); var event = new Promise(resolve => a.message(resolve)); a.cmd({ type: 'event', value: 9 }); var notice = await event; var denied = await new Promise(resolve => a.send({ type: 'fail' }, err => resolve(String(err)), 300)); var timeout = await new Promise(resolve => a.send({ type: 'ignore' }, err => resolve(String(err)), 50)); a.remove(); a = null; var alive = await b.rpc({ type: 'echo', value: 11 }); var meta = b.meta; b.remove(); b = null; $.json({ shared: shared, sum: sum, notice: notice, denied: denied, timeout: timeout, alive: alive, meta: meta }); } catch (e) { $.invalid(e); } finally { if (a) a.remove(); if (b) b.remove(); } } ``` ## Load FlowStream files and execute isolated workers Source: https://forge.totaljs.es/en/total5/flow-files-and-workers/ Framework: total5@0.0.19 Content-SHA256: 141aa8d246eacc9f5b9663819e73f10218ac1ebaff06febc7bd0e8e79a85eb9f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `Flow.init(directory, callback)` reads `.flow` JSON files and loads each trusted schema; names containing `-bk` or `_bk` are skipped. The default directory is `flowstreams/`. `Flow.load(schema, callback)` also accepts `worker:'worker'` for a Node worker thread and `worker:true` for a child process in this version. Flow workers have separate globals: do not expect the parent's `MAIN` objects or closures to be available inside a component. The visual Flow designer and its product-specific UI are separate from this backend API. Components are executable trusted code; workers are process/thread isolation, not an untrusted-code sandbox. ```js controllers/flows.js exports.install = function() { ROUTE('GET /flow-workers/', exercise); }; async function exercise($) { var ids = []; try { var source = ''; var out = []; for (var worker of ['worker', true]) { var id = worker === true ? 'file-process' : 'file-thread'; ids.push(id); var schema = { id: id, name: id, worker: worker, components: { echo: source }, design: { a: { id: 'a', component: 'echo', config: { prefix: 'one:' }, connections: {} } }, variables: {} }; var dir = PATH.root(id); F.Fs.mkdirSync(dir, { recursive: true }); F.Fs.writeFileSync(dir + '/demo.flow', JSON.stringify(schema)); F.Fs.writeFileSync(dir + '/ignored-bk.flow', JSON.stringify({ id: 'must-not-load' })); await new Promise(resolve => Flow.init(dir, resolve)); var instance = Flow.instances[id]; var first = await new Promise((resolve, reject) => instance.exec({ id: 'a', data: 'hello', callback: (err, msg) => err ? reject(err) : resolve(msg.data) })); instance.reconfigure('a', { prefix: 'two:' }); var second = await new Promise((resolve, reject) => instance.exec({ id: 'a', data: 'again', callback: (err, msg) => err ? reject(err) : resolve(msg.data) })); out.push({ worker: worker, first: first, second: second, isolated: !!instance.flow.isworkerthread }); Flow.remove(id); } $.json({ results: out, removed: ids.every(id => !Flow.instances[id]), backupSkipped: !Flow.instances['must-not-load'] }); } catch (e) { $.invalid(e); } finally { for (var id of ids) if (Flow.instances[id]) Flow.remove(id); } } ``` ## Action lifecycle hooks, result extension and administrator guards Source: https://forge.totaljs.es/en/total5/action-hooks-and-admin/ Framework: total5@0.0.19 Content-SHA256: 96d006ef7a49b5e38bca290fca66dc60e4ee9d0bd9b5924585c9a2bbf2646d17 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `oninput($)` runs after input validation and declared middleware, immediately before the action function. `onoutput(error,response,$)` runs on the successful completion path after output filtering and optional extension. In 0.0.19 an invalid input or `$.invalid()` does not call this hook; do not treat it as a universal error/finally hook. `extend:'result'` adds the action result to its validated input under that key and returns the extended input. A dotted path uses nested assignment. It is useful for deliberate action composition; it changes the public response contract. Either `sa:true` or `su:true` requires a user with either administrator flag. They do not define two different privilege tiers. Normal permissions checks remain separate. Set these administrator flags only from trusted server authentication. ```js definitions/hooks.js MAIN.hooks = []; AUTH(function($) { var role = $.headers['x-demo-role']; if (role === 'sa' || role === 'su') $.success({ id:'admin', [role]:true }); else if (role === 'member') $.success({id:'member'}); else $.invalid(); }); NEWACTION('Hooks|extend', { input: '*name:String', extend: 'result', oninput: function($) { MAIN.hooks.push('input:' + $.payload.name); }, onoutput: function(err, response) { MAIN.hooks.push('output:' + response.result.greeting); }, action: function($, model) { $.callback({greeting:'Hello ' + model.name}); } }); NEWACTION('Hooks|fail', { onoutput: function() { MAIN.hooks.push('unexpected'); }, action: function($) { $.invalid('failed'); } }); for (var flag of ['sa','su']) { var action = { action:function($) { $.success(); } }; action[flag] = true; NEWACTION('Hooks|' + flag, action); } ``` ```js controllers/hooks.js exports.install = function() { ROUTE('POST /extend/ @json --> Hooks|extend'); ROUTE('GET /fail/ --> Hooks|fail'); ROUTE('GET /sa/ --> Hooks|sa'); ROUTE('GET /su/ --> Hooks|su'); ROUTE('GET /hook-events/', $ => $.json(MAIN.hooks)); }; ``` ## Real SQL with native QueryBuilder and SQLite transactions Source: https://forge.totaljs.es/en/total5/query-builder-sqlite/ Framework: total5@0.0.19 Content-SHA256: 0d9c3083d0b11d65b113fcf1df348e839a572228f30f311ffd0b6c58ffdd5cd4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded This example connects Total.js's native `DB()/NEWDB()` to a real file-backed SQLite database using Node's built-in `node:sqlite`. The example uses **Node 24.14.1 and total5@0.0.19**, without an npm SQL dependency. Check the [Node 24 SQLite documentation](https://nodejs.org/docs/latest-v24.x/api/sqlite.html) for runtime availability and API stability. `DatabaseSync` is synchronous: this small driver demonstrates correctness, not a recommendation for heavy blocking work on a busy HTTP thread. This is an application-owned driver, **not the separate Total.js QueryBuilder SQL package**, nor a PostgreSQL/MySQL compatibility claim. It deliberately supports only one allowlisted table, equality filters, selected columns, sort, bounded pagination and basic CRUD. Unsupported operations fail closed. The broader builder contract is in [query-builder-contract](/en/total5/query-builder-contract/). Values use bound `?` parameters. Table/column names and order directions are selected by server allowlists; never concatenate arbitrary identifiers from requests. Update/delete require a filter. The HTTP fixture uses fixed demonstration data; add authentication and ownership constraints before exposing real records. A queue of `DB()` operations is not an atomic transaction. The transfer function explicitly owns one connection, begins a transaction, makes both changes synchronously, commits on success and rolls back on any error. Do not insert asynchronous waits into this single shared connection transaction. Multi-connection async drivers need connection reservation and their own transaction API. ```js definitions/sqlite.js var DatabaseSync = require('node:sqlite').DatabaseSync; var db = new DatabaseSync(PATH.root('ledger.sqlite')); db.exec('CREATE TABLE accounts (id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, balance INTEGER NOT NULL CHECK(balance >= 0)) STRICT'); db.prepare('INSERT INTO accounts VALUES (?, ?, ?)').run('a', 'Alice', 100); db.prepare('INSERT INTO accounts VALUES (?, ?, ?)').run('b', 'Bob', 50); function column(name) { if (!['id', 'name', 'balance'].includes(name)) throw new Error('Column not allowed'); return '"' + name + '"'; } function where(options, params) { var filters = options.filter.map(function(f) { if (f.type !== 'where' || f.comparer !== '=') throw new Error('Filter not supported'); params.push(f.value); return column(f.name) + ' = ?'; }); return filters.length ? ' WHERE ' + filters.join(' AND ') : ''; } function integer(value, fallback, max) { if (value == null) return fallback; if (!Number.isInteger(value) || value < 0 || value > max) throw new Error('Invalid pagination'); return value; } NEWDB('sqlite', function(options, callback) { try { if (options.table !== 'accounts') throw new Error('Table not allowed'); var params = []; var condition = where(options, params); var result; if (['find','read','list','count'].includes(options.exec)) { var count = db.prepare('SELECT COUNT(*) AS value FROM accounts' + condition).get(...params).value; if (options.exec === 'count') result = count; else { var fields = (options.fields || ['id','name','balance']).map(column).join(','); var sort = (options.sort || ['id_asc']).map(function(s) { var match = /^(id|name|balance)_(asc|desc)$/.exec(s); if (!match) throw new Error('Sort not allowed'); return column(match[1]) + ' ' + match[2]; }).join(','); var take = integer(options.take, 100, 100); var skip = integer(options.skip, 0, 100000); var rows = db.prepare('SELECT ' + fields + ' FROM accounts' + condition + ' ORDER BY ' + sort + ' LIMIT ? OFFSET ?').all(...params, take, skip); result = options.exec === 'list' ? { items: rows, count: count } : rows; } } else if (options.exec === 'insert') { var p = options.payload; db.prepare('INSERT INTO accounts (id,name,balance) VALUES (?,?,?)').run(p.id,p.name,p.balance); result = { id: p.id }; } else if (options.exec === 'update') { if (!condition) throw new Error('Filter required'); var keys = Object.keys(options.payload); if (!keys.length) throw new Error('Empty update'); var set = keys.map(key => column(key) + ' = ?').join(','); result = db.prepare('UPDATE accounts SET ' + set + condition).run(...keys.map(key => options.payload[key]), ...params).changes; } else if (options.exec === 'remove') { if (!condition) throw new Error('Filter required'); result = db.prepare('DELETE FROM accounts' + condition).run(...params).changes; } else throw new Error('Operation not supported'); callback(null, result); } catch (e) { callback(e); } }); MAIN.transfer = function(amount, fail) { if (!Number.isSafeInteger(amount) || amount <= 0) throw new Error('Positive integer amount required'); db.exec('BEGIN IMMEDIATE'); try { db.prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?').run(amount, 'a'); if (fail) throw new Error('Simulated failure'); db.prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?').run(amount, 'b'); db.exec('COMMIT'); } catch (e) { db.exec('ROLLBACK'); throw e; } }; // Reopen the actual file to verify persisted values on a second connection. MAIN.sqlSnapshot = function() { var reader = new DatabaseSync(PATH.root('ledger.sqlite'), { readOnly: true }); try { return reader.prepare('SELECT id,balance FROM accounts ORDER BY id').all(); } finally { reader.close(); } }; ``` ```js controllers/sqlite.js exports.install = function() { ROUTE('GET /sql/', exercise); }; async function exercise($) { try { var out = {}; out.initial = await DB().find('sqlite/accounts').fields('id,balance').promise(); MAIN.transfer(10, false); out.committed = MAIN.sqlSnapshot(); try { MAIN.transfer(20, true); } catch (e) { out.rollback = e.message; } out.afterRollback = MAIN.sqlSnapshot(); try { MAIN.transfer(999, false); } catch (e) { out.constraint = e.message; } out.afterConstraint = MAIN.sqlSnapshot(); var name = "x'); DROP TABLE accounts; --"; await DB().insert('sqlite/accounts', { id: 'c', name: name, balance: 25 }).promise(); out.literal = await DB().read('sqlite/accounts').where('name', name).promise(); out.updated = await DB().update('sqlite/accounts', { balance: 30 }).id('c').promise(); out.page = await DB().list('sqlite/accounts').sort('balance', true).page(2, 1).promise(); try { await DB().insert('sqlite/accounts', { id: 'd', name: 'Alice', balance: 1 }).promise(); } catch (e) { out.duplicate = e.message; } try { await DB().find('sqlite/accounts').fields('password').promise(); } catch (e) { out.column = e.message; } try { await DB().remove('sqlite/accounts').promise(); } catch (e) { out.unsafe = e.message; } out.removed = await DB().remove('sqlite/accounts').id('c').promise(); out.missing = await DB().read('sqlite/accounts').id('c').promise(); out.count = await DB().count('sqlite/accounts').promise(); $.json(out); } catch (e) { $.invalid(e); } } ``` ## Load application resources and avoid runtime package surprises Source: https://forge.totaljs.es/en/total5/load-and-npminstall/ Framework: total5@0.0.19 Content-SHA256: b0349301366b0df42a87c482e3d35d66cf8cc6fa1505cc377a34aea6d934523f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `LOAD(types, [callback], [clear=true])` is the application loader. `types` is an array or comma-separated list of resource groups (such as `config`, `definitions`, `controllers`, `actions`, `modules`, `resources`, `jsonschemas`, `flowstreams`). With no list it loads the normal application groups. It extracts bundles first and clears temporary files by default. Use it in a standalone script when you need application definitions without starting an HTTP listener; do not repeatedly call it in a request handler. `NPMINSTALL(name, [callback])` checks the package under `CONF.$nodemodules`: an already-installed matching version returns without running npm. Otherwise it invokes `npm install` there. The name must be a trusted fixed application value, never request input. Deploy dependencies through a pinned package manifest/lockfile when reproducibility matters. The test below covers only the installed-package branch: it does not download, upgrade or certify any third-party package. ```js controllers/loading.js exports.install = function() { ROUTE('GET /loader-contract/', function($) { $.json({ available: typeof LOAD === 'function' && typeof NPMINSTALL === 'function' }); }); }; ``` ## Query a real local LDAP directory Source: https://forge.totaljs.es/en/total5/ldap-openldap/ Framework: total5@0.0.19 Content-SHA256: acf740f174412263663ffdc967c13b624ab592c51d4cde00e0cd491fb1103357 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded `LDAP(options, callback)` is the native read client. `options.ldap` supplies `host` and `port`; `user` is the bind DN, `password` its password, `dn` the search base, and `type` the requested object class (`person` or `group`). `type:'profile'` uses `login` to search `sAMAccountName` and returns one object or `null`. `noauth:true` skips bind; it does not grant directory permissions. Always specify a search base explicitly. `attributes` maps returned attribute names to conversion types (`string`, `number`, `date`, `buffer`, `hex`, `base64`, etc.); it is **not** an allowlist of attributes to retrieve. A directory may return scalar values or arrays when an attribute repeats. Restrict the data your HTTP API exposes. This executable fixture requires local **OpenLDAP** tools: `slapd`, `ldapadd` and the core/cosine/inetorgperson schema files. On macOS the defaults below use the system tools; other installations can set `FORGE_SLAPD`, `FORGE_LDAPADD` and `FORGE_LDAP_SCHEMA`. It runs a separate unprivileged loopback server and temporary LDIF database, then terminates it. It never uses an existing directory. The test covers search, multiple attribute values and an invalid-bind boundary; it does not certify Active Directory compatibility, TLS/StartTLS, groups or reconnect behavior. Never send real credentials over an unprotected network. **Decide authentication from the bind.** Check the result of the bind in your own code, and treat a returned profile as authenticated only after the bind has succeeded. ```js controllers/directory.js exports.install = function() { ROUTE('POST /directory-fixture/ @json', directory); }; function directory($) { var port = Number($.body.port); if (!Number.isInteger(port) || port < 1024 || port > 65535) return $.invalid(400); LDAP({ ldap: { host: '127.0.0.1', port: port }, user: 'cn=admin,dc=forge,dc=test', password: $.body.wrong ? 'incorrect' : 'local-fixture-only', dn: 'dc=forge,dc=test', type: 'person', attributes: { cn: 'string', mail: 'string' } }, function(err, people) { if (err) $.json({ failed: true }); else $.json({ people: people.map(person => ({ cn: person.cn, mail: person.mail })) }); }); } ``` ## Package application files as a Total.js bundle Source: https://forge.totaljs.es/en/total5/application-bundles/ Framework: total5@0.0.19 Content-SHA256: 0d5c2183cc37e702073e256ef69943b26b22add5405e25c67915140353b0a76c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded A Total.js application bundle is an archive created with `BACKUP()`, placed in the application's `bundles/` directory with the `.bundle` suffix. At startup `LOAD()` extracts bundles and combines application files into `.src/`; the framework then uses that directory as its application root. Bundle filenames containing `-bk.bundle` or `_bk.bundle` are ignored. A `bundles.debug` file reuses the already extracted `.src` directory. The source also supports `.url` files that fetch remote bundle archives. Bundle files contain executable application code: load trusted archives only. Keep credentials, runtime databases and private files out of distributable archives. `BACKUP` is packaging, not encryption. ```js controllers/bundles.js exports.install = function() { ROUTE('GET /bundle-loader/', $ => $.json({ load: typeof LOAD, backup: typeof BACKUP })); }; ``` ## Own uploaded-file cleanup and build query links Source: https://forge.totaljs.es/en/total5/upload-lifecycle-and-href/ Framework: total5@0.0.19 Content-SHA256: 5d7d9072b52f3dcc841f23b413c213e6a47f83eae4a521c8252f4f81d7f3f3c9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: total5-installed@total5@0.0.19 Review: not-recorded Uploaded temporary files normally disappear when the request is released. `$.autoclear(false)` keeps them for work that outlives the response: your application must then move or remove them. `$.clear()` schedules removal of removable uploads and empties `$.files`; disk deletion is asynchronous. Never store arbitrary paths supplied by a client for later deletion. In 0.0.19 build query links with the public `QUERIFY()` helper and a copy of the query, as this recipe shows. It produces a query string, not a redirect or an absolute URL. The retained-file map and cleanup endpoints below are a local fixture; an application should use scoped ownership and durable storage rather than expose these endpoints. ```js controllers/lifecycle.js var paths = Object.create(null); exports.install = function() { ROUTE('POST /upload/{mode}/ @upload <1mb', function($) { var file = $.files[0]; if (!file) return $.invalid(400); var id = UID(); paths[id] = file.path; if ($.params.mode === 'retain') $.autoclear(false); if ($.params.mode === 'clear') $.clear(); $.json({ id: id, files: $.files.length }); }); ROUTE('GET /exists/{id}/', $ => $.json({ exists: !!paths[$.params.id] && F.Fs.existsSync(paths[$.params.id]) })); ROUTE('POST /cleanup/{id}/', function($) { var path = paths[$.params.id]; if (path) { F.Fs.rmSync(path, { force: true }); delete paths[$.params.id]; } $.success(); }); ROUTE('GET /link/', function($) { var broken = false; try { $.href('page', '2'); } catch (e) { broken = e instanceof TypeError; } $.json({ broken: broken, link: QUERIFY('', Object.assign({}, $.query, { page: '2 & more' })) }); }); }; ``` ## Get started with jComponent 20 Source: https://forge.totaljs.es/en/jcomponent/getting-started/ Framework: jcomponent@20 Content-SHA256: d000a133f8599ffc3236793b3d02f382adbbf017f136adfafbc88bff4f39c05d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded jComponent 20 is a single file (`spa.min@20.js`) that already contains jQuery. It keeps a global **state** object: you write to it with `SET(path, value)`, read from it with `GET(path)`, and elements react to changes. The bundle also has a stylesheet, `spa.min@20.css`, with the Total.js icon font. Load both from the CDN, as every example of this site does: `` and ``. If you only want the icons, load just `//cdn.componentator.com/icons.min.css` (no script is needed). The checks of this site answer the requests for `spa.min@20.js` and `spa.min@20.css` with a local copy of the same version and do not load the icons file. `` binds an element to a path in the state. The `config` attribute lists commands separated by semicolons; `text:value` sets the text of the element to the value of the path. ```html public/index.html jComponent

Hello

``` Call `SET('user.name', 'Louis')` again and the heading changes without any DOM code of yours. ## Read, change and watch the state Source: https://forge.totaljs.es/en/jcomponent/state-api/ Framework: jcomponent@20 Content-SHA256: 2211f1567f71e3f701549215ecc3a1e32c676105199a4d8d5a61a52708a78c4c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded The state is one global object addressed by **paths** such as `cart.items`. The functions to work with it: - `SET(path, value)` writes a value and notifies everything bound to the path - `GET(path)` reads a value - `UPD(path)` notifies the path after you changed the object in place (`GET('cart').discount = 5; UPD('cart')`) - `PUSH(path, value)` appends to an array and notifies; with a `^` before the path it adds the value to the beginning - `WATCH(path, callback)` runs the callback with the new value every time the path changes; join several paths with `+` ```html public/index.html jComponent

``` ## Write a custom jComponent Source: https://forge.totaljs.es/en/jcomponent/custom-component/ Framework: jcomponent@20 Content-SHA256: e7cce28ba59dc0aeba03d3e4d38b42f387d4ab3717e831f55440d79e4914233b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded A component is declared with `COMPONENT(name, config, declaration)`. The second argument is the default configuration as a string (`key:value;key:value`). The declaration receives `self` (the component instance) and `config` (the parsed configuration). - `self.make` runs once, when the component is created. Build the DOM here. - `self.setter(value)` runs every time the value of the component's `path` changes. - `self.set(value)` writes a new value to the `path`; `self.get()` reads it. Use the component with a `` element. `name` selects the declaration, `path` the state and `config` overrides the defaults. ```html public/index.html jComponent

Total:

``` The `ui-bind` next to the component shows that both read the same state: clicking the button changes the path and every element bound to it updates. ## Configure a component and reconfigure it later Source: https://forge.totaljs.es/en/jcomponent/component-config/ Framework: jcomponent@20 Content-SHA256: 0029f1b2c2a136827eb199e9ed2afef07a7637807acf316edd4f61f7011cad76 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded The second argument of `COMPONENT()` holds the default options. The `config` attribute of the element overrides them, and the declaration reads the merged values from `config`. Implement `self.configure(key, value)` to react when an option is set or changed. At runtime `self.reconfigure('key:value;key2:value2')` (or `CONFIG(selector, config)` for many components) changes options and calls `configure` for each changed key. ```html public/index.html jComponent ``` ## Component lifecycle: make, setter and destroy Source: https://forge.totaljs.es/en/jcomponent/component-lifecycle/ Framework: jcomponent@20 Content-SHA256: a91ae5a1c166759e760b643f70e1f3cfe3cd06a062d201b231e646ef7081f169 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded A component goes through three moments you can hook into: - `self.make()` runs once, when the component is created and its element is ready: build the DOM and register events here - `self.setter(value, path, type)` runs every time the value of the `path` changes (also the first time) - `self.destroy()` runs after the element was removed from the page: stop timers and release what you created. jComponent detects removed elements with a cleanup that runs every minute; call `FREE()` to run it immediately `self.readonly()` tells jComponent the component never writes to its path, which turns off its validation state. ```html public/index.html jComponent
``` ## Validate input with a component's validate() Source: https://forge.totaljs.es/en/jcomponent/validation/ Framework: jcomponent@20 Content-SHA256: da083e2d978ec1a4472abb4b2d8a9ae7b2b3d28b560d6e54ea3a9114ed7be5f7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded A component that edits a value can validate it. Define `self.validate(value)` and return `true` (or an empty string) when the value is valid, or `false` (or a message) when it is not. Write the value back with `self.modify(value)`: it also marks the component as **modified** and **touched**. jComponent keeps these states in `config` (`invalid`, `touched`, `modified`) and as CSS classes (`ui-invalid`, `ui-touched`, `ui-modified`), so styling needs no code. `ERRORS(path, callback)` returns the invalid components below a path, which is what a form needs before it submits, and `RESET(path)` clears the touched and modified states. ```html public/index.html jComponent ``` ## Path prefixes: common, code lists, temporary state and plugin paths Source: https://forge.totaljs.es/en/jcomponent/path-prefixes/ Framework: jcomponent@20 Content-SHA256: bb875905d62b28b998f81784d6ebbe4244d28c88f46adfb3bfbf9b45754c2c9b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded A path is where a value lives in the state of the page, and in jComponent 20 its **first character** can change the place. | Prefix | Example | Where it points | |---|---|---| | `*` | `*user.name` | the common state: `common.user.name` (`*` alone is `common`) | | `#` | `#countries` | the code lists: `DEF.cl.countries`, where `CL()` stores the lists it loads | | `%` | `%step` | the temporary state: `DEF.tmp.step`, for values that do not belong to the model | | `?` | `?.items` | inside a ``: the path of that plugin (see the plugin recipe) | | `plugin\|path` | `cart\|items` | a property of the plugin object called `cart`, from anywhere: `PLUGINS["cart"].items` (it is **not** the state path `cart.items`) | The flags of a path (`@visible`, `@change`...) are a different thing: they come after a space (see the custom flags recipe). Paths without a prefix are plain paths of the state (`user.name`). ```html public/index.html jComponent ``` ## Load a library before a component starts Source: https://forge.totaljs.es/en/jcomponent/component-dependencies/ Framework: jcomponent@20 Content-SHA256: 1343e12a6dec77d0fadee875a09f8a990ec5f2291032789c23e3d9ad97689498 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded The fourth argument of `COMPONENT()` is a list of **dependencies**: URLs of scripts (`.js`) or styles (`.css`) that the component needs. jComponent downloads each one only once, in order, and creates the component after they are loaded, so `make()` can rely on the library being there. This is the way to wrap a third-party library into a component without loading it on pages that do not use it. ```js public/js/starslib.js window.starslib = { render: function(count) { var html = ''; for (var i = 0; i < count; i++) html += '*'; return html; } }; ``` ```html public/index.html jComponent ``` ## Extend components and plugins with EXTENSION Source: https://forge.totaljs.es/en/jcomponent/extensions/ Framework: jcomponent@20 Content-SHA256: 36d8b89a461439666c01affaa521ef83de6b58de563a0bdc49c5d9cc976298f2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `EXTENSION(name, config, callback)` adds code to every instance of the component `name` (or of the plugin `@name`) when it is created. The callback receives the instance and its config, exactly like a declaration, so you can add methods, change options or listen to events. It is how an application customizes third-party components without forking them. ```html public/index.html jComponent ``` ## Show, hide and style elements with ui-bind Source: https://forge.totaljs.es/en/jcomponent/ui-bind/ Framework: jcomponent@20 Content-SHA256: 482f5f41510459159e22387a9b057687f79a009fb31c96783b3cff31a0a33fd7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `` applies **commands** to its element whenever the value of the path changes. Commands are separated by semicolons. Each command is `name:expression`, where `value` is the current value of the path: - `show:value` / `hide:value` shows or hides the element - `html:value` / `text:value` replaces the content - `.classname:value` adds the class when the expression is truthy ```html public/index.html jComponent You are a guest - ``` ## Render lists with a ui-bind template Source: https://forge.totaljs.es/en/jcomponent/ui-bind-templates/ Framework: jcomponent@20 Content-SHA256: 7e72862392e0c19c808e973b30a82d3c1551828fea364d0b3e1bb0f65556d668 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded With the `template` command, `` renders a **Tangular** template instead of setting one value. The template is the ` ``` ## More ui-bind commands: attributes, values, state and formatting Source: https://forge.totaljs.es/en/jcomponent/ui-bind-more-commands/ Framework: jcomponent@20 Content-SHA256: d2eab2bb102a37f53d6827705cb5c632ede7dd263e6cc9a51ba6b2b0ba931523 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded Besides `text`, `show` and `hide`, `ui-bind` has commands for the common DOM changes. Each command is `name:expression` (or `name selector:expression` to apply it to an inner element), and `value` is the value of the path: | Command | Does | |---|---| | `html:expr` | sets the inner HTML (escape it yourself!) | | `title:expr`, `href:expr`, `src:expr` | sets that attribute | | `attr name:expr` | sets any attribute | | `value:expr` | sets the value of a form control | | `disabled:expr` / `enabled:expr` | disables or enables the controls inside | | `checked:expr` | checks the checkbox inside | | `.class:expr` | adds or removes the class | Options of the whole element: `format:yyyy-MM-dd` formats a date value before it is printed (for numbers call `format()` in the expression: `text:value.format(2)`), `empty:none` is shown when the value is empty, `changes` skips updates when the value did not change, and `delay:200` waits that many milliseconds before rendering. ```html public/index.html jComponent ``` ## ui-bind reference: every command, option and attribute Source: https://forge.totaljs.es/en/jcomponent/ui-bind-reference/ Framework: jcomponent@20 Content-SHA256: d7dd2942e0d87bb5a180224f41aef86edbd3df78da67e6f6a52dc048d81fa14a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `` is the element that applies **commands** to the DOM when the value of its path changes. This page lists what each command does, the options that decide *when* it runs and the attributes that choose *which element* it changes. The format is `config="command:expression;command:expression"`. In an expression `value` is the value of the path and `element` (also `el`) is the element that is changed. A command can have a selector (`text .name:value` applies it to the elements `.name` inside) and `attr` takes the attribute name first (`attr title:value`). ## Commands that change the element | Command | What it does | |---|---| | `text:expr` | sets the text; an empty value shows the `empty` text | | `html:expr` | sets the inner HTML (escape it yourself) | | `value:expr` | sets the value of a form control | | `title:expr`, `href:expr`, `src:expr` | sets that attribute | | `attr name:expr` | sets any attribute | | `.class:expr` | adds the class when the expression is true and removes it when false | | `show:expr` / `hide:expr` | adds or removes the class `hidden` | | `visible:expr` / `invisible:expr` | adds or removes the class `invisible` (the element keeps its space) | | `checked:expr` | checks or unchecks the `input` inside | | `disabled:expr` / `enabled:expr` | disables or enables the controls inside (`input`, `select`, `textarea`, `button`) and the `ui-component` elements inside | | `required:expr` | sets the `required` option of the `ui-component` elements inside (it does not touch a plain `input`) | | `template` | renders the Tangular template of the element (see the template recipe) | | `exec:path` / `refresh:path` | calls the function at that path with the value, the path and the element, for every `SET` of the path of the binder | `show` and `hide` run first, then `visible` and `invisible`, and `text`, `html` and `template` run last, so that the visibility of the element is already known when the content is written. `text`, `html` and `template` are only written while the element is visible, unless `forcerender:true` is in the same config: then they are written even when the element is hidden. ## Options: when the commands run | Option | What it does | |---|---| | `changes` | skips the update when the value is the same as the last one | | `strict` | only runs when the path of the binder itself changed, not when a child path changed (`user.name` does not run a binder of `user`) | | `track:a,b` | only runs when one of those paths changed (a binder of `user` that tracks `user.name` ignores `user.age`); it runs again for every `SET` of a tracked path, even with the same value | | `once` | runs once and then the binder is removed | | `check:path` | calls the function at that path with `(value, path, element)`; the commands only run when it returns true | | `delay:ms` | waits that many milliseconds and renders once, even if the value changed several times meanwhile (100 when no value is given) | | `empty:text` | the text shown instead of an empty value (`---` when no text is given) | | `format:pattern` | formats the value of `text`, `html`, `value`, `attr`, `title`, `href` and `src` with `String.format` | | `class:name` | adds that class to the `ui-bind` element once, after the first render | | `assign:path` | stores the binder instance at that path | | `helpers:path` | the object at that path provides the helpers of the template: with `helpers:hh` and `hh = { shout: fn }`, the template can use `{{ value | shout() }}` | ## Attributes: which element changes By default the commands change the `ui-bind` element. These attributes pick another one: - `element="#target"` any element of the page (a jQuery selector) - `child=".inner"` an element inside the `ui-bind` - `parent=".card"` the closest ancestor that matches The path can start with `!` (`path="!user.nick"`): the binder then ignores the moments when the value is `null` or `undefined`. A command name can also start with `!` or `~`: the prefix is accepted and ignored, the command works as without it. ## Attribute commands - **Use one attribute per command: write `title:value` and `alt:value` as two commands.** ```html public/index.html jComponent adult minor
``` ## Component instance reference: properties and methods of self Source: https://forge.totaljs.es/en/jcomponent/component-instance-reference/ Framework: jcomponent@20 Content-SHA256: 33a85f3da8d2937168f5392eef1f0018b207e7f63c15b0a4e71d55753f94e6b8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded A component is declared with `COMPONENT(name, defaultConfig, function(self, config, cls) { ... })`. The declaration runs once for every `` of the page and receives the instance (`self`), its configuration (`config`, the same object as `self.config`) and the class prefix (`cls`). This page lists what `self` has. ## Hooks you define | Member | When it runs | |---|---| | `self.make` | once, when the element is ready: build the DOM here | | `self.setter(value, path, flags)` | every time the value of the path changes, and when the component starts; `flags` is an object | | `self.destroy` | after the element was removed (see the lifecycle recipe) | ## Properties | Property | Value | |---|---| | `self.name` | the name of the component (`probe`) | | `self.path.path` | the path as a string (`form.name`) | | `self.element` | the `` element as a jQuery collection | | `self.dom` | the same element as a DOM node | | `self.config` | the configuration: the defaults of the declaration, then the `config` attribute of the element. It also holds the state flags: `invalid` from the start, `modified` and `touched` once the value is modified | | `self.id` | a unique id of the instance | | `self.ready` | `true` after `make` | ## The value | Method | What it does | |---|---| | `self.get()` | reads the value of the path | | `self.set(value)` | writes the value and runs the `setter` of every component of that path, this one too | | `self.update()` | runs the `setter` again with the current value, without changing it | | `self.rewrite(value)` | writes the value **without** running the `setter` of this component (the others are notified) | | `self.modify(value)` | writes the value and marks the component as modified and touched: `config.modified` and `config.touched` become 1 | | `self.reset()` | clears those flags: `config.modified` and `config.touched` go back to 0 | | `self.GET(path)`, `self.SET(path, value)` | read and write any path of the state | | `self.EXEC(name, a)` | calls the global function `name` | ## The DOM of the component `self.html(html)`, `self.text(text)`, `self.append(html)` and `self.empty()` change the content. `self.find(selector)` returns the elements inside as jQuery. `self.css(name, value)` sets a style, `self.attr(name, value)` an attribute and `self.attrd(name, value)` a `data-` attribute (`self.attrd('x')` reads `data-x`). The classes: `self.aclass(name)` adds, `self.rclass(name)` removes, `self.hclass(name)` tells whether it has it, and `self.tclass(name, [state])` toggles it or sets it to `state`. `self.width()` and `self.height()` return numbers. ## Events, watchers and commands | Method | What it does | |---|---| | `self.on(name, fn)` / `self.emit(name, a)` | listens to and sends a named event of the page | | `self.watch(path, fn, [autoinit])` | calls `fn(value, flags, path)` when that path changes; with `autoinit` also once at the start. `+` joins several paths | | `self.reconfigure('size:9')` | changes the configuration at runtime: `self.config.size` is 9 | | `self.command(name, fn)` / `self.CMD(name, a)` | registers a command of this instance and calls it | ## Do not rely on these - **`self.unwatch(path, [fn])` does not remove the watcher** in jComponent 20: it compares the parsed path of the watcher with a string, so nothing matches. The watcher keeps running after `unwatch`. If you need to stop a watcher, check a flag inside `fn`. - **The global `CMD(name)` did not call a command registered with `self.command`**: only `self.CMD(name)` did. ```html public/index.html jComponent ``` ## Group state and logic in a jComponent plugin Source: https://forge.totaljs.es/en/jcomponent/plugin/ Framework: jcomponent@20 Content-SHA256: 918277cc4bfc0f66aebf54064e58421a46ea131fb2fb2ec1acefc647442b9b4b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded A plugin is the controller of a section of the page. `PLUGIN(name, declaration)` registers it and `` attaches it to an element. Inside the section, `?` in a path means "the path of the plugin", so the markup does not depend on where the plugin lives in the state. The declaration receives `self` (the plugin instance) and `config`. `self.get()` and `self.set()` work relative to the plugin path, and `self.element` is the jQuery element of the ``. Implement `self.make` to run code once the plugin is ready. Use `self.element` for DOM events: `self.on()` is for jComponent events, not for clicks. ```html public/index.html jComponent

Items:

``` ## Route pages in the browser without reloading Source: https://forge.totaljs.es/en/jcomponent/spa-routing/ Framework: jcomponent@20 Content-SHA256: 0653d2df8ce5713c551c0651206dcb143244d26558dd299359751f41b40ae700 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded jComponent has its own router for single page applications. `ROUTE(url, fn)` registers a route: `{name}` segments are passed to `fn` as arguments in order. `REDIRECT(url)` changes the address with the History API (no page load) and runs the route that matches. Routes are compared segment by segment: a route and a URL must have the same number of segments, and `*` matches any value at its position. `NAV` describes the current location: `NAV.url` is the path, `NAV.query` the parsed query string and `NAV.params` the route arguments. `NAV.back()` and `NAV.forward()` move through the history that jComponent keeps. For the server this is still one page, so every URL below your app has to return the same HTML (a `ROUTE('GET /*')` that renders the shell), otherwise a reload on `/users/5/` would give a 404. ```html public/index.html jComponent

``` ## Load parts of a page with ui-import Source: https://forge.totaljs.es/en/jcomponent/ui-import/ Framework: jcomponent@20 Content-SHA256: 7ac2231a7f413cd4d9e85011909290452b95eae379496c91fab2f1b18347f18f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `` downloads an HTML file and puts it into the page, so a big screen can be split into parts that are loaded when needed. The address goes in the `config` attribute (`url:/parts/card.html`); `target` can name another element to fill instead of the `ui-import` itself. In code use `IMPORT(url, target, callback)`: the target is a selector or element, and the callback runs when the part is in the page. Each address is downloaded once. The same function loads scripts (`.js`) and styles (`.css`). Components and bindings inside the loaded part start working automatically. ```html public/parts/card.html
Hello
``` ```html public/parts/note.html
A note
``` ```html public/index.html jComponent
``` ## Call code with commands and EXEC Source: https://forge.totaljs.es/en/jcomponent/commands/ Framework: jcomponent@20 Content-SHA256: 39dc5c5a78e25e6e23174948c2caa281a46d2d0b99027a9540e82ac791c548fa Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded Two ways to trigger code without a direct reference to the object that owns it: - A component registers a **command** with `self.command(name, fn)`, and the code that holds the component instance runs it with `instance.CMD(name, a, b, c)` (`element[0].$uicomponent` is the instance of a ``). Use it for actions such as "open this window" or "refresh that list". The global `CMD(name)` is declared to reach every component, but in jComponent 20.014 it cuts a name that has no space, so it does nothing: use the instance, or `EXEC()`. - `EXEC('plugin/method', a, b)` calls the method `method` of the plugin that lives on the path `plugin`; a plain function name (`EXEC('myfunction')`) calls a global function. The `exec` command of `ui-bind` and the `exec` option of many components take the same names. ```html public/index.html jComponent

Items:

``` ## Send events between components with ON and EMIT Source: https://forge.totaljs.es/en/jcomponent/events/ Framework: jcomponent@20 Content-SHA256: e7d942ca05d5a424fe982d323480c094f46cf37282715241724cac08fd6952b7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded Global events let independent parts of a page talk without knowing each other. `ON(name, callback)` registers a listener, `EMIT(name, a, b, c, d)` calls every listener with up to four arguments, and `OFF(name, [callback])` removes one listener or all the listeners of the name. Components and plugins have the same functions on `self` (`self.on()`, `self.emit()`), and the listeners they register are removed together with the component. ``` EMIT('cart.changed', 3) -> ON('cart.changed', function(count) { ... }) ``` ```html public/index.html jComponent

``` ## Store data in the browser with CACHE, PREF and COOKIES Source: https://forge.totaljs.es/en/jcomponent/storage-cache-pref-cookies/ Framework: jcomponent@20 Content-SHA256: bdb8f20a9c8cdbd741b0e9c31c4c330560cfbbead4075c9e1a7b00df8746650a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded Three helpers store data in the browser: - `CACHE(key, value, expiration)` stores any value for a period (`'10 minutes'`, `'1 day'`) and `CACHE(key)` reads it, giving `null` once it expired. The data lives in the browser storage, so it survives a reload. - `PREF.set(name, value)` stores a user preference for a year; read it back as `PREF.name`. - `COOKIES.set(name, value, expiration)`, `COOKIES.get(name)` and `COOKIES.rem(name)` work with real cookies, which the server receives on every request. ```html public/index.html jComponent

``` ## Share settings with ENV and the [key] syntax Source: https://forge.totaljs.es/en/jcomponent/environment-variables/ Framework: jcomponent@20 Content-SHA256: bc463ba39c988765498f2434cfafd091e63bc7d3b4acc44df26da46b70c5b105 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `ENV(name, value)` registers a value for the whole page and `ENV(name)` reads it. Wherever jComponent accepts a text that may contain `[name]` (for example the URL of `AJAX()` and `IMPORT()`), the placeholder is replaced with the value, so you set the address of your API in one place. `'[name]'.env()` does the same replacement on any string. ```html public/index.html jComponent

``` ## Load data from a Total.js route with AJAX Source: https://forge.totaljs.es/en/jcomponent/ajax/ Framework: jcomponent@20 Content-SHA256: 72d9f15885081fa9a0eb755ef2c0e76646960a862b815ae9cf970b6cdb2de691 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `AJAX('METHOD /url/', [data], callback)` sends a request and calls the callback with the response. JSON responses are parsed for you. Combine it with `SET()` and any `ui-bind` or component bound to the path updates by itself. ```js controllers/api.js exports.install = function() { ROUTE('GET /api/hello/', hello); }; function hello($) { $.json({ message: 'Hello from Total.js' }); } ``` ```html public/index.html jComponent

Loading...

``` ## Call Total.js API routes with API() Source: https://forge.totaljs.es/en/jcomponent/api-calls/ Framework: jcomponent@20 Content-SHA256: 7d1c02bbcfea4e2f336b0f7c326061679b2258d315e46891c6b4e67046dc2b94 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `API(url, name, data, callback)` is the client side of the Total.js `ROUTE('API ...')` endpoints. It sends `POST url` with the body `{ schema: name, data: data }` and calls the callback with the response. When the server answers with an error (for example a validation error) the callback receives an array of errors: use the `ERROR(response, success, error)` helper to handle both cases in one place. Put the address of the endpoint in `ENV()` once and reuse it. ```js definitions/math.js NEWACTION('Math/add', { name: 'Add two numbers', input: '*a:Number, *b:Number', action: function($, model) { $.callback({ sum: model.a + model.b }); } }); ``` ```js controllers/api.js exports.install = function() { ROUTE('API /api/ +math_add --> Math/add'); }; ``` ```html public/index.html jComponent

``` ## Upload files with UPLOAD() and progress Source: https://forge.totaljs.es/en/jcomponent/upload/ Framework: jcomponent@20 Content-SHA256: da88694097efc0c028b9c3f06e8e97cf47f582786aa0d893029af4e08f134cef Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded `UPLOAD('POST /url/', formdata, callback, onprogress)` posts a `FormData` (the address starts with the HTTP method, like in `AJAX()`) and calls the callback with the parsed response. The optional fourth argument receives the percentage while the upload runs. Build the `FormData` from a file input (`new FormData()` and `append('file', input.files[0])`); the server side is the `@upload` route of the file upload recipe. ```js controllers/upload.js exports.install = function() { ROUTE('POST /upload/ @upload <5mb', upload); }; function upload($) { var file = $.files[0]; file.read(function(err, buffer) { $.json({ filename: file.filename, text: buffer.toString('utf8'), title: $.body.title }); }); } ``` ```html public/index.html jComponent ``` ## Small helpers: GUID, HASH, parseConfig, format and group Source: https://forge.totaljs.es/en/jcomponent/utilities/ Framework: jcomponent@20 Content-SHA256: b9e420d51ad53b7df7e6efd61f353dd2e8437a96bbefa7c096a92090eb39e52c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded jComponent adds a few helpers that save you from loading a utility library: - `GUID(length)` returns a random id; `HASH(value)` returns a numeric hash of any value - `'key:value;key2:value2'.parseConfig()` parses a configuration string into an object, converting numbers and booleans - `'{0} is {1}'.format('a', 'b')` replaces `{index}` placeholders - `number.format(decimals, thousandsSeparator, decimalSeparator)` and `date.format('yyyy-MM-dd')` format numbers and dates - `array.group('field')` groups objects by a field into `[{ name, items }]` - `PARSE(json)` parses JSON and converts date strings into `Date` objects; `date.add('1 day')` moves a date ```html public/index.html jComponent

``` ## State shortcuts: INC, TOGGLE, NUL, UPDATE, UNWATCH, WAIT, BLOCKED and CACHEPATH Source: https://forge.totaljs.es/en/jcomponent/state-shortcuts/ Framework: jcomponent@20 Content-SHA256: ba5b6aa6fcd769def5a014d40e4f3a44daaac5d6226829ae150b35912a5664de Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded These functions work on the state of jComponent by **path** (`'user.visits'`), like `SET()` and `GET()`, and every one of them notifies the components and the watchers of the path. - `INC(path, [value])` adds `value` (default `1`) to a number; when the value is empty it starts from `0` and when it is a text it is read as a number first. - `TOGGLE(path)` changes a boolean (an empty value becomes `true`). `NUL(path)` and its alias `NULL(path)` set the value to `null`. - `UPDATE(path)` (alias `UPD`) notifies everybody who uses the path **without changing the value**: use it after you changed an object or an array in place. - `UNWATCH(path, [fn])` removes the watchers of the path made with `WATCH()`; with `fn` only that one. - `WAIT(fn or path, callback)` runs `callback` as soon as the function returns something true, or the path has a value. It checks at once and then **every 500 ms**. - `BLOCKED(key, timeout, [callback])` returns `false` the first time and `true` for the next `timeout` ms (`'5 seconds'` also works): it is a guard against a double click or a repeated request. The `callback` runs only when it is not blocked. - `CACHEPATH(path, expire, [default])` keeps a value of the state in the cache (`CACHE()`): it sets the path to the cached value when there is one (or to `default`, which can be a function) and saves every change under the key `path_`. - A path is a path in the state of the page, so a name like `name` or `location` is a property of `window`: use names of your own (`person`, `prefs.mode`). - `setTimeout2(id, fn, ms, [limit], [param])` is a debounced `setTimeout()`: calling it again with the same `id` restarts the timer, so `fn` runs once, `ms` after the last call. With `limit` the timer is restarted at most that many times and the following calls are ignored until `fn` has run, so a stream of calls cannot postpone it forever. `clearTimeout2(id)` cancels it and returns `true` when there was one. - `CLONE(value)` makes a deep copy (dates stay dates), `COPY(from, to)` copies the properties of one object into another, deep, and returns `to`. `NOOP` is a function that does nothing and `WARN(...)` writes to `console.warn`. ```html public/index.html jComponent

``` ## Data helpers: QUERIFY, STRINGIFY, ENCRYPT, FN, CL, TRANSLATE, UNAUTHORIZED and Thelpers Source: https://forge.totaljs.es/en/jcomponent/data-helpers/ Framework: jcomponent@20 Content-SHA256: dffd31596690d343866ae9498b493c7db67dcd3147728ef8175a0bd4c2523204 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded - `QUERIFY([url], object)` makes a query string: `null` values are skipped, arrays are joined with commas, dates become ISO texts and everything is encoded. With a url it is added to it (`?` or `&`), also after a method as in `'POST /api/x'`. - `STRINGIFY(object, [compress], [fields])` is `JSON.stringify()` with two options: `compress: true` leaves out empty texts, `null` and `false`, and trims the texts; `fields` is a list of the names that are kept, a function `(key, value)` that decides, or an object where `name: false` leaves a field out. - `ENCRYPT(value, [key], [type])` turns a text or an object into a hexadecimal text that ends with a check of the key, and `DECRYPT(text, [key], [type])` gives the value back, or `undefined` when the key or the type are not the same. **It is an obfuscation for the browser, not security:** anybody can read it without the key. - `FN('n => n * 2')` compiles an expression into a function and remembers it; without `=>` the text is the body and the argument is called `value`. - `NOOP`, `EMPTYARRAY` and `EMPTYOBJECT` (frozen: they cannot be changed by mistake), `MONTHS` and `DAYS` (the names in English) and `NOW` (a `Date` that jComponent keeps up to date). - **Code lists:** `CLINIT(name, function(next) {}, [expire], [init])` registers a list that `function` loads (it calls `next(value)`; with a text instead of a function, an address like `GET /api/countries/`). `CL('a,b', callback)` loads the lists that are not loaded and stores each one in `DEF.cl.` (and in the state at that path); `CLRELOAD(name, callback)` loads them again. - **Translation:** `LOCALIZE(text)` loads a dictionary in the format of the Total.js resource files (`key : translation`, one by line, `//` for comments) and `TRANSLATE(text)` replaces every `@(text)` with its translation (the same text when there is none). The key is `T` plus the `HASH()` of the text in base 36. - `UNAUTHORIZED(...names)` returns `false` when `window.user` has one of the permissions (`user.permissions` or `user.roles`, a list or an object) or is `sa` / `su`, and `true` otherwise (also when there is no user). - `Thelpers` (the same object as `Tangular.helpers`, and `Ta` is `Tangular`) holds the helpers of the templates: add one with `Thelpers.name = function(value, ...arguments)`, where `this` is the model, and use it as `{{ value | name(argument) }}`. ```html public/index.html jComponent

``` ## DOM helpers: ATTRD, HIDDEN, VISIBLE, WIDTH, STYLE, NODEMOVE, DIFFDOM and APPEARANCE Source: https://forge.totaljs.es/en/jcomponent/dom-helpers/ Framework: jcomponent@20 Content-SHA256: 03844133175a14c82a371246bc135818ff6e040648985e9be5866b997a1b4e84 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b Review: not-recorded - `ATTRD(element or event, [name])` reads `data-` (default `data-id`) of an element, a jQuery object or the element of an event; for a plain object it reads the property. - `HIDDEN(element)` is `true` when the element is not shown (it or a parent is `display: none`; **an element that is a direct child of the body is always reported as not hidden**, the check starts from its parent); `VISIBLE(element, [threshold], [mode])` is `true` when it is inside the visible part of the window (`mode` `'above'` or `'below'` asks where it is when it is not). `NOTFOCUSED()` is `true` when the browser tab is in the background and `inDOM(element)` is true while the element is in the document. - `WIDTH([element])` returns the size class of the width of the element (default: the window): `'xs'`, `'sm'`, `'md'` or `'lg'` (the limits are in `DEF.devices`). `WW` and `WH` are the size of the window; `$W` is the jQuery object of the window; `SCROLLBARWIDTH()` is the width that a scrollbar takes. - `SCROLLBAR(element, [options])` wraps an element with a custom scrollbar and returns it; `scrollbar.resize()` recalculates it after the content changed. - `isTOUCH`, `isMOBILE`, `isROBOT`, `isSTANDALONE`, `isPRIVATEMODE` and `isIE` are booleans about the browser, set when the page starts. - `STYLE(css, [id], [selector])` adds a ` Users Products Settings ``` ## j-Attachments Source: https://forge.totaljs.es/en/components/attachments/ Framework: jcomponent@20 Content-SHA256: 73585e39ce9439d9f3720ad8cfa19bf7be8910e6e207b5048251a99982743dde Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component displays attachments in the simple list. A user can remove attachments. A value be `Array` in the form: ``` [ { name: 'attachment.docx', url: 'url_to_download', size: 1024, // in bytes dtcreated: Date } ] ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Audio Source: https://forge.totaljs.es/en/components/audio/ Framework: jcomponent@20 Content-SHA256: 581947923f6c15cbdb76624cf7cc6ec18080d483b8ef315a4eef3833a630991a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - the component can `play` and `stop` audio/sound `mp3` - `path` represents a volume control __Methods__: - `component.play(url)` can play audio/sound from URL - `component.stop(url)` can stop audio/sound __Properties__: - `component.items` contains all audio objects Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-AutoComplete Source: https://forge.totaljs.es/en/components/autocomplete/ Framework: jcomponent@20 Content-SHA256: b7d7adaadc9d372189cb39ccd7cc511c9f039c0092418853497296a9618d0f11 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - works with ` selected value:', value); // input.val(''); }; // opt.callback {Function} // OR: // opt.path {String} a path to variable (for result) // opf.offsetWidth {Number} "width" offset // opt.offsetX {Number} "x" offset // opt.offsetX {Number} "y" offset // opt.autoselect {Boolean} selects first suggestion automatically (default: false) SETTER('autocomplete/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-AutoDarkMode Source: https://forge.totaljs.es/en/components/autodarkmode/ Framework: jcomponent@20 Content-SHA256: 4ce08caa1a61338051e3869333a3db06bbc2d0991f329cd285d8a75d3188fd2a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - readonly The component automatically applies dark mode according to the operation system. __Configuration__: - `exec {String}` optional, a link to the `function(is_darkmode)` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-AutoExec Source: https://forge.totaljs.es/en/components/autoexec/ Framework: jcomponent@20 Content-SHA256: 81e4f9406413d93e08ef32e832409dc8d8d9545b974786ae1cb01c115213af57 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component automatically executes a method defined in `exec` option. __Configuration__: - __IMPORTANT__ `exec {String}` a path to the method `function(el, value)` - `delay {Number}` a delay for evaluating code (default: `0`) - `init {Boolean}` executes initial value (default: `false`) - `input {Boolean}` executes value binded by the input (default: `true`) - `manually {Boolean}` executes value binded manually via e.g. `SET()` method (default: `false`) - `track {String}` can contain partial paths divided by the comma Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-AutoFill Source: https://forge.totaljs.es/en/components/autofill/ Framework: jcomponent@20 Content-SHA256: 4aeb3b248f1b239cd1520f15c56fc0f2f4b1d1b9c59ebeeb2367170c27c3cfe9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component wraps all nested elements into the `
` element with disabled form events. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Name ``` ## j-AutoSelect Source: https://forge.totaljs.es/en/components/autoselect/ Framework: jcomponent@20 Content-SHA256: 4e0c7372a832ec191efe44cc481869979c176fdb208253ec729135469c0d46ff Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton The component automatically adds `.selected` class according to the selector `class="autoselect"` within the entire HTML document. This component is a perfect solution for server-side rendering and subsequent highlighting. __Configuration__: - `selector {String}` is a jQuery selector (default: `.autoselect a`) - `class {String}` is a class name for selected element (default: `selected`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Avatar Source: https://forge.totaljs.es/en/components/avatar/ Framework: jcomponent@20 Content-SHA256: 979bd45a30450b1d777fde37685a390e473c963ddbe0607683151c1951d11c28 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports themes - it's singleton - inspiration from `react-user-avatar` __Themes__: Avatar component needs to register your own theme. It contains `default` theme. ```javascript SETTER(true, 'avatar', 'register', 'THEME_NAME', 'options') ``` Options can contain: - `size` {Number} Optional, a size in pixels (default: `100`) - `lighten` {Number} Optional, the font color will be lightened by lighten factor of background color (default: `80` | from -255 to 255) - `radius` {Number} Optional, how rounded border corners will be (default: `50`) - `background` {Hex} Optional, set background color (default: selected from colors `Array`) - `color` {Hex} Optional, set font color (default: generated from background color by lighten) - `font` {String} Optional, set font family (default: `Arial`) - `weight` {String} Optional, font-weight (default: `bold`) - `class` {String} Optional, this property perfoms `toggleClass` for this class __Usage__: Each element of avatar needs to contain `avatar` class like this: `
`. Here are custom attributes: - `data-a="THEME_NAME"` Optional, can contain a theme name (default: `default`) - `data-a-url="URL_TO_PICTURE"` Optional, can contain a URL for user photo - `data-a-class="class_for_toggle_effect"` Optional, can contain a class for `toggleClass` effect Element needs to contain a user name, for example: - `
Peter Širka
` or - `Peter Širka` __Good to know__: - avatar component binds all new avatars in all new components automatically - `SETTER('avatar', 'refresh')` performs refreshing Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-BackToTop Source: https://forge.totaljs.es/en/components/backtotop/ Framework: jcomponent@20 Content-SHA256: 2cddcd9df40a38c54632f7336a8016b6e24eaea92539bf9553bddb39d020b715 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - works as singleton __Configuration__: - `icon {String}` Default button icon Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Martin Jirku. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Backup Source: https://forge.totaljs.es/en/components/backup/ Framework: jcomponent@20 Content-SHA256: d8597d14b01b327b11f32642eb89553c8a29254c5c9a74da9f303490f0248703 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component for data saving data to and loading from the local storage of the browser. - supports __dark mode__ __Configuration__: - `exec {String}` Optional property which contains a link to a function, which will be executed after clicking on a button of the component. The function can have an argument, which is the name of a clicked button - function(name). - `expire {String}` Optional property, which specifies the period during which the data will be stored in the local storage. The default value is '1 day'. The value of the property should be written in the following format: "number [seconds, minutes, hours, days, weeks, months, years]" Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Kirill Zlobin. Source: the Componentator components repository, MIT license. ```html example.html
First name
Last name
``` ## j-Banners Source: https://forge.totaljs.es/en/components/banners/ Framework: jcomponent@20 Content-SHA256: abb8a74c2e502bc28f3b3b919249b7a0eaf06002d72c6c3593aaf28b51ed2aab Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - fully responsive - simple CSS animation - it needs an empty picture for width/height defined in config: `empty:/download/banner-empty.gif` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-BarChart Source: https://forge.totaljs.es/en/components/barchart/ Framework: jcomponent@20 Content-SHA256: cea304818ea5d9fec74a7586217cf05c3faceb61a4baf158589fc9914f743240 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Please review an example and keep a data-source. __Configuration__: - `paddingbars {Number}` padding between bars (default: `5`) - `paddinggroup {Number}` padding between groups of bars (default: `10`) - `radius {Number}` enables presentation mode (default: `2`) - `offsetX {Number}` An offset X for value tooltip (default: `10`) - `offsetY {Number}` An offset Y for value tooltip (default: `10`) - `templateX {String}` Tangular template for X axis (default: `{{ value }}`) - `templateY {String}` Tangular template for Y axis (default: `{{ value | format(0) }}`) - `height {Number/String}` height (default: `0` = auto-height) or `string` is meant as a parent element - `width {Number/String}` width (default: `0` = auto-width) or `string` is meant as a parent element - `limit {Number}` a maximum limit of value for Y axis (default: `0`) - `pl {Number}` left padding for axis (default: `0`) - `pr {Number}` lines right padding (default: `10`) - `pt {Number}` lines top padding (default: `10`) - `pb {Number}` lines bottom padding (default: `25`) - `prselected {Number}` right padding for selected value (default: `0`) - `marginW {Number}` a margin for `width` - `marginH {Number}` a margin for `height` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Box Source: https://forge.totaljs.es/en/components/box/ Framework: jcomponent@20 Content-SHA256: 9cfbaa16fa1c7ab6a0947124e4baefe5ad033123f91f8dcdb153d3a874d3f634 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `title {String}` form title - `if {String}` condition for showing of the form, it's compared with the value within of `path` - `icon {String}` Font-Awesome icon without `ti-` or __new__: `ti ti-home` - `reload {String}` link to a global `function(fullform_component)` and it's executed if the form is displaying - `submit {String}` link to a global `function(hide)` and it's executed if the submit button is pressed - `cancel {String}` link to a global `function(hide)` and it's executed if the cancel button is pressed - `enter {Boolean}` captures `enter` key automatically and performs submit (default: `false`) - `center {Boolean}` centers the form to middle of screen - `autofocus {Boolean/String}` can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `closebutton {Boolean}` can hide `x` button (default: `false`) - `zindex {Number}` can affect z-index (default: `12`) - `scrollbar {Boolean}` enables custom scrollbar (default: `true`) - `scrolltop {Boolean}` enables scrolling to top after form is displayed (default: `true`) - `scrollbarshadow {Boolean}` optional, enables a shadow in scrollbar (default: `false`) - `style {Number}` supports two styles (1: classic (default), 2: box bottom without padding, 3: box top without padding) - `closeoutside {Boolean}` closes the form when the user clicks outside of the form (default: `false`) - `closeesc {Boolean}` closes the form when the user presses `ESC` key - `independent {Boolean}` closing doesn't depent on the condition according to the path - `padding {Number}` padding for the box (default: `30`) - `width {Number}` optional, a maximal width (default: `0` - full width) - `background {Boolean}` optional, enables/disables background (default: `true`) - `transparent {Boolean}` optional, all elements on the background of the box will be clickable (default: `false`) - `align {String}` optional, `center` (default), `left`, `right` - `close {String}` link to a global `function()` and it's executed if the form is closing - __NEW__ `hide {String}` link to a global `function()` and it's executed if the form hides The component supports dynamic evaluation of the content of `
``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Breadcrumb Source: https://forge.totaljs.es/en/components/breadcrumb/ Framework: jcomponent@20 Content-SHA256: f6b15bf709de4fa96624418a2a37ea0d0d5e417740570d94dbbc285ac02e4157 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `icon {String}` home icon (default: `ti ti-home`) - `exec {String}` path to the method `function(url, el)` for manual processing of links - `historyapi {Boolean}` enables redirecting via `REDIRECT()` (default `true`) - `style {Number}` supports two styles `1` classic (default), `2` with bigger padding and only with bottom border - `root {String}` a label for root item (default: `Root`) - `rooturl {String}` a relative URL address for root item (default: `/`) - `title {String}` enables generating `document.title` from the last item of the breadcrumb (default: `null`) - __NEW__: `arrowicon {String}` arrow icon (default: `ti ti-angle-right`) ## Data-source example ```js [ { name: 'Home', // A link label url: '/' // URL address callback: Function(el, e) // Optional, a callback for the click event }, { name: 'Products', // A link label url: '/' // URL address } ]; ``` ## Methods - `component.add(name1, url1, [callback])(name2, url2)(name3, url3)...` - `component.root()` it resets a breadcrumb Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Here you can use j-VirtualWire component
``` ## j-Button Source: https://forge.totaljs.es/en/components/button/ Framework: jcomponent@20 Content-SHA256: f5648b9c9e95a91ed8d9b26516e759e0205fa1be2394e7a03e357aa0ee7ab53f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple button component with great features. - fully responsive - supports validation __Configuration__: - `exec {String}` __required__ a path to the `function(el, path)` method - `icon {String}` Total JS icons (default: `undefined`) - `color {String}` An icon color (default: `undefined`) - `validation {Boolean}` Enables validation for all components on the path (default: `true`) - `delay` {Number} a timeout for validation (default: `100`) - `name {String}` a name for the `name` attribute (default: `submit`) - `size {String}` a size: - `small` - `normal` (default) - `large` - `big` - `ddos {String}` A simple DDOS prevetion for multiple clicks, possible values: - `undefined` disables prevention - `10 seconds` - `session` - `1 day` - etc. - `if` {String} can contain JS condition for evaluation(optional) - `value` {Object} contains entire model - `path` {String} contains changed path - __must return boolean__ - `track` {String} can contain paths divided by comma which evaluate validation (executors for paths aren't components, but these methods `SET()`, `UPD()`, `INC()`, etc.) - `validonly` {Boolean} skips `dirty` state (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Calendar Source: https://forge.totaljs.es/en/components/calendar/ Framework: jcomponent@20 Content-SHA256: 92c1d1b46586864f93ac3c32e61f0b4464c046ba8e569d2f3f5bc8166fdbc36f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ - supports __touch gestures (swipe)__ and fixed full size on mobile __Configuration__: - `firstday` {Number} (optional) first day in the week - `today` {String} (optional) label for `Set today` button - `days` {String} (optional) days e.g. `SU,MO,TU,WE,TH,FR,SA` (default). - `months` {String} (optional) months e.g. `January,February,...` (default). - `yearselect` {Boolean} (optional) dropdown with years (default `true`). - `monthselect` {Boolean} (optional) dropdown with months (default `true`). - `yearfrom` {String} (optional) set minimum year limit in dropdown e.g. `-5 years` `current` (default `-100 years`). - `yearto` {String} (optional) set maximum year limit in dropdown `+5 years` `current` (default `current`). The component must be called manually or works with `textbox` or `j-Input` component automatically. The component is a singleton. - works __only__ with Bootstrap Grid System (otherwise is need to fix CSS) - __important__ add the calendar component under `` element ## Usage ```javascript var ELEMENT = $(document); var PATH = 'some.path.to.date'; var X_OFFSET = 100; FIND('calendar').toggle(ELEMENT, PATH, function(date) { console.log('SELECTED DATE:', date); }, X_OFFSET); // OR FIND('calendar').toggle(ELEMENT, 'path.to.date OR date object', 'path.to.binding.date'); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html SHOW CALENDAR ``` ## j-Carousel Source: https://forge.totaljs.es/en/components/carousel/ Framework: jcomponent@20 Content-SHA256: fca3689ed6fa253b2423d4a8a24fa02f15edc44212d522aac9cb1c74a7be648a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __touch gestures (swipe)__ and fixed full size on mobile __Configuration__: - `animate {Number}` animation interval (default: `3000`, zero `0` disables animation) __Methods__: - `left` moves the content to left - `right` moves the content to right Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html


``` ## j-Carousel2 Source: https://forge.totaljs.es/en/components/carousel2/ Framework: jcomponent@20 Content-SHA256: e640ec637380217158b019a93f382ea446c13a588ceab66302c581cad8dbd7d0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Is a simple carousel component optimized for desktop computers and mobile devices. Each elemet must be wrapped into the `
` element (look to example). __Configuration__: - `selector {String}` a selector for cell element (default: `figure`) - `margin {Number}` left margin between items (default: `10`) - `animate {Number}` animation timeout, `0` disables animation (default: `5000`) - `delay {Number}` A delay between animation (default: `2000`) - `parent {String}` optional, a selector for obtaining of height - `marginheight {Number}` optional, a margin for `height` (default: `0`) - `scrolldivider {Number}` optional, if the `count` isn't declared then the __element width__ will be divided according to this value, and the value will be used for `scrollLeft` (default: `3`) - `offsetwidth {Number}` optional, increases the content width (default: `0`) - `duration {Number}` optional, animation duration between scrolling items (default: `300`) - `durationsnap {Number}` optional, duration for snap animation (default: `200`) - `count {Number}` count of visible items (default: `1`) - __NEW__: `countxs {Number}` optional - __NEW__: `countsm {Number}` optional - __NEW__: `countmd {Number}` optional - __NEW__: `countlg {Number}` optional __Methods__: - `component.move('next|right/prev|left')` scrolls the content right or left - `component.focus('data-id value')` scrolls to the specific figure with `data-id` attribute __Good to know__: If the component's path is changed then the component summarizes all cells again. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Centered Source: https://forge.totaljs.es/en/components/centered/ Framework: jcomponent@20 Content-SHA256: 14ac41f4a09f1ee183bcd1ac8ce4c0d0106c93a19e16013ba91cbd146b29f0ff Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - The component moves the content of this component under `` tag (because of positioning) __Configuration__: - `if {String}` condition for showing of the form, it's compared with the value within of `data-jc-path` - `reload {String}` link to a global `function(form_component)` and it's executed if the form is displaying - `autofocus {Boolean/String}` can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `zindex {Number}` can affect z-index (default: `12`) - `closebutton {Boolean}` can hide `x` button (default: `false`) - `closeoutside {Boolean}` closes the form when the user clicks outside of the form (default: `false`) - or `closeoutside {String}` can contain a jQuery selector which will be included to a close event - `closeesc {Boolean}` closes the form when the user presses `ESC` - `scrollbar {Boolean}` enables custom scrollbar (default: `true`) - `visibleY {Boolean}` shows vertical scrollbar (default: `false`) - `close {String}` link to a global `function()` and it's executed if the form is closing __Good to know__: New version of this component supports dynamic evaluation of the content of ` ``` - all buttons with `name="close"` attribute closes the component automatically - all elements with `data-name="close"` attribute closes the component automatically Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sed, nam distinctio numquam dolore neque impedit, voluptate quam fugiat culpa minus.

Show ``` ## j-Checkbox Source: https://forge.totaljs.es/en/components/checkbox/ Framework: jcomponent@20 Content-SHA256: 4f41c404c48d787b0546211c2343ec82152968f7ebb48820ef16aa8230b23271 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required` {Boolean} optional, enables "required" (default: `false`) - `label` {String} optional, label (default is HTML content) - `disabled` {Boolean} optional, disables this component - `checkicon` {String} optional, a check icon without `fa-` (default: `check`) - `reverse` {Boolean} optional, enables reverse behaviour (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html I want to receive a newsletter I agree with terms and conditions ``` ## j-Checkboxlist Source: https://forge.totaljs.es/en/components/checkboxlist/ Framework: jcomponent@20 Content-SHA256: 3251fbc7735fe1228efee43f8329cb89a39e90d37d6f26a8217b3d81016408ce Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - for custom design you can use __j-CheckboxListExpert__ - now supports darkmode __Configuration__: - `required` {Boolean} (optional) enables "required" (default: `false`) - `items` {String} (optional) static items `key1|value1, key2 with value, key3|value` - `icon` {String} (optional) icon for label without `fa-` e.g. `home`, `cog`, etc. - `checkicon` {String} (optional) check icon without `fa-`, (default: `check`). - `label` {String} (optional) label (default is HTML content) - `type` {String} (optional) can be `number` (converts `String` values to `Number`) - `datasource` {String} path to data-source (must be array) - `text` {String} determines a property name for text (in data-source), default: `name` - `value` {String} determines a property name for value (in data-source) default :`id` - `empty` {String} (optional) empty text for empty data-source - `disabled` {Boolean} (optional) disables this component Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Frameworks

Frameworks
``` ## j-CheckboxListExpert Source: https://forge.totaljs.es/en/components/checkboxlistexpert/ Framework: jcomponent@20 Content-SHA256: b79ffb404b9273a732e49891ac3a7b224bf6b58d101fd1581d1502167978439a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Perfect component for checboxlist with custom styles. It's a little bit advanced but absolutely worth it! __Configuration__ - `label {String}` can change the title label - `required {Boolean}` enables `required` (default: `false`) - `disabled {Boolean}` disables this control (default: `false`) - `type {String}` can contain `number` (default: `string`) - `class {String}` inserts a class into an element with class `.ui-checkboxlistexpert-container` - `datasource {String}` path to data-source (must be array or array of objects) or __NEW__: `id|name,id|name` - `value {String}` determines a property name for value (in data-source) (default: `id`) - `disabledkey {String}` determines a property name for disabled item (in data-source) (default: `disabled`) - __NEW__ `selector {String}` a jQuery selector for custom template (outside of the component). Works like `custom template` in [data-binding](https://wiki.totaljs.com/jcomponent/08-data-binding/) __Good to know__ - You must write **all the styles** - Example object `{ name: 'My item', id: 1, disabled: false, classname: 'color-highlighted' }` - You can use `$index` and `$path` in template __Basic Styles__ ```css .my-button { display: inline-block; padding: 20px 40px; margin-right: 10px; border: 1px solid gray; cursor: pointer; border-radius: 2px; position: relative; user-select: none; } .my-button .checkbox { position: absolute; top: 10px; left: 10px; } .my-button.selected .checkbox i:before { content: "\f14a"; font-weight: 900; } .my-button:hover { border-color: #4285F4; } .my-button.selected { color: white; background: #4285F4; border-color: rgba(0, 0, 0, 0.2); } .my-button[data-disabled="1"] { background-color: #dcdcdc; color: gray; border-color: #dcdcdc; cursor: not-allowed; } .ui-disabled .my-button .checkbox { color: #c3c3c3; } .ui-disabled .my-button { background-color: #dcdcdc; color: gray; border-color: #dcdcdc; cursor: not-allowed; } .ui-disabled .my-button:hover { background-color: #dcdcdc; color: gray; border-color: #dcdcdc; } .ui-disabled .my-button.selected { border-color: gray; background: #efefef; color: #5a5a5a; } /* Dark mode */ .ui-dark .my-button { border-color: 1px solid #404040; color: #adadad; } .ui-dark .my-button.selected { color: white; } .ui-dark .my-button[data-disabled="1"] { background-color: #525252; color: gray; border-color: #525252; } .ui-dark .ui-disabled .my-button { background-color: #525252; color: gray; border-color: #525252; } .ui-dark .ui-disabled .my-button:hover { background-color: #525252; color: gray; border-color: #525252; } .ui-dark .ui-disabled .my-button.selected { border-color: rgba(0, 0, 0, 0.2); background: #969696; color: #ffffff; } /* Large mode */ .ui-large .my-button { font-size: 16px; } ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-CheckPath Source: https://forge.totaljs.es/en/components/checkpath/ Framework: jcomponent@20 Content-SHA256: 1709748fb1b02b8eed2b0947e57eac7cd256122f1bb456a20643a817e1143b48 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Singleton - Development tool __Configuration__: - `position {Number}` - `1` top right, `2` bottom right, `3` bottom left (default), `4` top left Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Kirill Zlobin. Source: the Componentator components repository, MIT license. ```html example.html
Title
``` ## j-Children Source: https://forge.totaljs.es/en/components/children/ Framework: jcomponent@20 Content-SHA256: f95274001185d41d2fe27982f66f2b59631854af969288b56960e98d13429e1b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component renders draggable items as a tree without the possibility of collapsing. Data-Source must be `Object Array` in the form: `{ id: String, children: [ ], YOUR PROPERTIES }, { ... }` __Configuration__: - `empty {String}` an empty text (default: `null`) - `onchange {String}` optional, a link to the `function(arr)` - captures items when resorted __Template__: ```html {{ level }} contains a level (number) {{ value }} contains an item (object) ``` Try to understand the functionality from the example. __Good to know__: - `component.items {Object}` contains all references of all items in the form `items[item.id] = item` - `component.parents {Object}` contains all references of all parents in the form `parents[item.id] = parent` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Choose Source: https://forge.totaljs.es/en/components/choose/ Framework: jcomponent@20 Content-SHA256: d97d49258dd12977f00a1cfec05abc5d69f22550424aa28c6f280ed3d7cfd106 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component is alternative to `CheckboxListExpert` and `RadioButtonListExpert`. __Configuration__: - `limit {Number}` selection limit, `1` will return a value, `>1` will return array of values (default: `1`) - `datasource {String}` a path to the datasource (default: empty) - `required {Boolean}` enables validation (default: `false`) - `key {String}` an `identifier` key name for the datasource (default: `id`) - `attr {String}` a `data-[attr]` for storing of `identifier` (default: `id`) - `selector {String}` a jQuery selector for elements (default: `.selection`) - `class {String}` selected class (default: `selected`) - `type {String}` converting type, supports `string` or `number` (default: `string`) - `uncheck {Boolean}` allows to uncheck selected value for `limit:1` (default: `false`) - `disabled {Boolean}` disables the component - `click {String}` a link to the `function(val)` that is evaluted when the user changes the value - __NEW__: `indexer {String}` a HTML selector for binding of the selected index Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Male
Female
Male
Female
Unknown
Output single:
Output multiple:
``` ## j-ChunkyScroll Source: https://forge.totaljs.es/en/components/chunkyscroll/ Framework: jcomponent@20 Content-SHA256: d89e270677139f7f35649bbc70fdcf15d30f942d67b7195f18d555c1310e37e1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - can handle thousands items/elements __Configuration__: - `rowheight {Number}` __Important__, a row height (default: `30` with auto obtaining of size) - `parent {String}` optional, a container with fixed height, can be `window`. Default value: `parent` element. - `margin {Number}` optional, a top/bottom margin together (default: `0`) - `scrolltop {Boolean}` scrolls to top automatically if the `path` is changed (default: `false`) - `marginxs {Number}` optional, a top/bottom margin together for `xs` screen width - `marginsm` optional, a top/bottom margin together for `sm` screen width - `marginmd` optional, a top/bottom margin together for `md` screen width - `marginlg` optional, a top/bottom margin together for `lg` screen width Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Awesome! Awesome! Awesome! Here you can scroll 30000 records without laggy scrolling:

Free and open-soruce alternative to Clusterize.js
``` ## j-Cl Source: https://forge.totaljs.es/en/components/cl/ Framework: jcomponent@20 Content-SHA256: 5f3e33d524cacf124a201cd7da66e960e8e5571c7620e7e472bde03498b6c846 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component parses inline data defined in the component's element. Data is parsed to the code list format. - Data source format: `id1|name1|icon1,id2|name2|icon2,id3|name3|icon3` - Parsed to: `[{ id, name, icon }]` __Example__: ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

``` ## j-ClBind Source: https://forge.totaljs.es/en/components/clbind/ Framework: jcomponent@20 Content-SHA256: 33e141ae2d66fc7e95b8a002d044972fd987ef16dc51d88b7c60be89b049b955 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component reads an item with a linked data source. The component supports Tangular template inside the element (optional). As the value is stored in the `{{ value.something }}` variable. __Configuration__: - `datasource {String}` or `dirsource {String}` __required__ a data-source - `id {String}` a pair key (default: `id`) - `nullable {Boolean}` renders `null` value (default: `true`) - `exec {String}` executes `function(value, element)` method - `bind {String}` binds a read value according to the defined path Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Click Source: https://forge.totaljs.es/en/components/click/ Framework: jcomponent@20 Content-SHA256: 09cf2ecb4bf9b2d71805f552ef77dd46e5757ae9e76234a1bcb0f0740ec30849 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component calls a method or can set a value according to the path. __Configuration__: - `enter` {String} (optional) is a jQuery selector - `value` {String/Number/Boolean} (optional) this value will be set to `data-jc-path` - `disabled` {Boolean} disables this control Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

``` ## j-ClickBox Source: https://forge.totaljs.es/en/components/clickbox/ Framework: jcomponent@20 Content-SHA256: 0bfb6b09f523cbf8b1d3ac2ea2ec2f1328be96a0782120e83ecd6f899a85a187 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component is optimized for SEO. It reads all links and creates a clickable box. The component automatically highlight a value according to the URL param. __Configuration__: - `param {String}` name of URL param for selecting value Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Clipboard Source: https://forge.totaljs.es/en/components/clipboard/ Framework: jcomponent@20 Content-SHA256: 82080a68b47aa642d392c7a681fd8845a68edede928d9bce5ff17e578d9cb2bc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - It works as singleton - Uses `navigator.clipboard.writeText()` or `document.execCommand('copy')` as fallback __Methods__: - `SETTER('clipboard/copy', 'TEXT TO CLIPBOARD')` or `FIND('clipboard').copy('TEXT TO CLIPBOARD')` __Configuration__: - `oncopy {String}` a link to the `function(value)` - `native {Boolean}` enables native clipboard (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Copy to clipboard: My value to clipboard
Copy to clipboard: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium, voluptatem?
``` ## j-ClipboardImage Source: https://forge.totaljs.es/en/components/clipboardimage/ Framework: jcomponent@20 Content-SHA256: 484e3e0c8f4322826fe035c6fd609550366388ced0b5c94ae4c0e14465b38200 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component automaticaly captures images in Clipboard. __Configuration__: - `quality {Number}` JPEG quality, (default: `90`) - `maxwidth {Number}` a maximum width (default: `1024`) - `maxheight {Number}` a maximum height (default: `768`) - `exec {String}` a link to execute method if the image is obtained - `disabled {Boolean}` can disable this component - `type {String}` output type, supports `png` or `jpg` (default) - __NEW__ `output {String}` output type `base64` (default) or `file` __How to capture data?__ ```javascript // Attach event ON('clipboardimage', function(base64) { // We have to send data on the server in Base64 format AJAX('POST /upload/', { file: base64 }, function(response) { }); }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Create a screenshot into the clipboard and press shortcuts CMD+V or CTRL+V into the iFrame (iFrame has to be focused).

``` ## j-Clock Source: https://forge.totaljs.es/en/components/clock/ Framework: jcomponent@20 Content-SHA256: 7ff4602d1f067cc7944921c979b37dd2d36bf9647f61a86122b3ac1b43e4c87f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ - works __only__ with Bootstrap Grid System (otherwise is need to fix CSS) - thanks [weareoutman](https://github.com/weareoutman/) for some things __Configuration__: - `twelvehour` {Boolean} (optional) the clock will be 12-hour (default `false`). ## Usage ```javascript var ELEMENT = $(document); var PATH = 'some.path.to.date'; var X_OFFSET = 100; SETTER('clock', 'toggle', ELEMENT, PATH, function(date) { console.log('SELECTED DATE:', date); }, X_OFFSET); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html SHOW CLOCK ``` ## j-CloudEditor Source: https://forge.totaljs.es/en/components/cloudeditor/ Framework: jcomponent@20 Content-SHA256: ee6919e8a1a54ff3d6d06f60bc718ba6151478a6fd5f43b03202f78adfbf9e53 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - it works in the iframe - supports multiple cursors (`shift + cmd + arrow-down/up`) - supports finding selected text (`cmd + d`) - supports custom scrollbars - supports diff tracker - supports a simple emmet plugin - supports real-time collaboration - source-code: - it uses editor: [CodeMirror](https://codemirror.net/) - very small code __Configuration__: - `parent {String}` a selector for the main container (default: `auto`) - `autosave {Boolean}` auto rebinds value from the editor to the component's path (default: `true`) - `event {String}` a path to the `function(name, value)` - `click` - `errors` - `shortcut` - `cursor` contains cursor position - `change` contains partial changes for real-time collaboration (`config.realtime` must be `true`) - `contextmenu {String}` a path to the `function(opt)` - `realtime {Boolean}` enables realtime sending changes to the `event` method (event name is `change`) - `keywords {String}` custom keywords in the form e.g. `ID,PATH` - `minheight {Number}` optional, a minimal height (default: `0`) - `margin {Number}` optional, a vertical margin (default: `0`) - __NEW__: `url {String}` optional, a link to the editor (default: `//cdn.componentator.com/editor/1.min.html`) __Method__: - `component.insert('some text')` - `component.replace('text', 'newvalue')` - `component.search('text', callback(output))` - `component.select(from, [to])` - `component.goto(pos)` - `component.focus()` - `component.save(callback(value))` - `component.marker(name, [from], [to], [color])` adds + modifies (with `from`) and removes (without `from` argument) marker - `component.change(changes)` for the real-time collaboration (`changes` can be generated in the `config.event` function) - `component.clear()` clears all changes - `component.replaceselections(selections)` - `component.replaceselection(selection)` - `component.replacerange(value, from, [to])` - `component.command(cmd)` executes `codemirror.execCommand()` method - `component.exec(a, [b], [c])` executes `document.execCommand(a, b, c)` method __IMPORTANT__: `from`, `to`, `pos` arguments must be in the form: `{ line: Number, ch: Number }`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

``` ## j-CloudEditorSimple Source: https://forge.totaljs.es/en/components/cloudeditorsimple/ Framework: jcomponent@20 Content-SHA256: 48d28d7160ba07748099e29681b4e02e9afbd6e174eeca0a4f13a541b22f878f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded It's a simple alternative to `j-CloudEditor`. You can specify the main configuration in the config, and the value is `{String}` (in `j-CloudEditor` is configuration part of value). - it works in the iframe - supports multiple cursors (`shift + cmd + arrow-down/up`) - supports finding selected text (`cmd + d`) - supports custom scrollbars - supports diff tracker - supports a simple emmet plugin - supports real-time collaboration - source-code: - it uses editor: [CodeMirror](https://codemirror.net/) - very small code __Configuration__: - `parent {String}` a selector for the main container (default: `auto`) - `autosave {Number}` auto rebinds value from the editor to the component's path (in milliseconds, default: `500`) - `event {String}` a path to the `function(name, value)` - `click` - `errors` - `shortcut` - `cursor` contains cursor position - `change` contains partial changes for real-time collaboration (`config.realtime` must be `true`) - `contextmenu {String}` a path to the `function(opt)` - `realtime {Boolean}` enables realtime sending changes to the `event` method (event name is `change`), default: `true` - `keywords {String}` custom keywords in the form e.g. `ID,PATH` - `minheight {Number}` optional, a minimal height (default: `0`) - `margin {Number}` optional, a vertical margin (default: `0`) - `linenumbers {Boolean}` optional, enables line numbers (default: `true`) - `type {String}` optional, content-type (default: `clientside`) - __NEW__: `url {String}` optional, a link to the editor (default: `//cdn.componentator.com/editor/1.min.html`) __Method__: - `component.insert('some text')` - `component.replace('text', 'newvalue')` - `component.search('text', callback(output))` - `component.select(from, [to])` - `component.goto(pos)` - `component.focus()` - `component.save(callback(value))` - `component.marker(name, [from], [to], [color])` adds + modifies (with `from`) and removes (without `from` argument) marker - `component.change(changes)` for the real-time collaboration (`changes` can be generated in the `config.event` function) - `component.clear()` clears all changes - `component.replaceselections(selections)` - `component.replaceselection(selection)` - `component.replacerange(value, from, [to])` - `component.command(cmd)` executes `codemirror.execCommand()` method - `component.exec(a, [b], [c])` executes `document.execCommand(a, b, c)` method __IMPORTANT__: `from`, `to`, `pos` arguments must be in the form: `{ line: Number, ch: Number }`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Code Source: https://forge.totaljs.es/en/components/code/ Framework: jcomponent@20 Content-SHA256: 1d189f35478c63e2c18b92c1a4934116e18f5d2d1c1265f68ea9cee85814027b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded It's a simple alternative to `j-CloudEditor`. You can specify the main configuration in the config, and the value is `{String}` (in `j-CloudEditor` is configuration part of value). It's the same component as `j-CloudEditorSimple`. - it works in the iframe - supports multiple cursors (`shift + cmd + arrow-down/up`) - supports finding selected text (`cmd + d`) - supports custom scrollbars - supports diff tracker - supports a simple emmet plugin - supports real-time collaboration - source-code: - it uses editor: [CodeMirror](https://codemirror.net/) - very small code __Configuration__: - `parent {String}` a selector for the main container (default: `auto`) - `autosave {Number}` auto rebinds value from the editor to the component's path (in milliseconds, default: `500`) - `event {String}` a path to the `function(obj)` - `obj.type {String}` - `click` - `errors` - `shortcut` - `cursor` contains cursor position - `change` contains partial changes for real-time collaboration (`config.realtime` must be `true`) - `obj.instance {Editor}` - `contextmenu {String}` a path to the `function(opt)` - `realtime {Boolean}` enables realtime sending changes to the `event` method (event name is `change`), default: `true` - `keywords {String}` custom keywords in the form e.g. `ID,PATH` - `minheight {Number}` optional, a minimal height (default: `0`) - `margin {Number}` optional, a vertical margin (default: `0`) - `linenumbers {Boolean}` optional, enables line numbers (default: `true`) - `type {String}` optional, content-type (default: `clientside`) - `url {String}` optional, a link to the editor (default: `//cdn.componentator.com/editor/1.min.html`) - __NEW__: `lint {Boolean}` optional, enables lint (default: `true`) __Method__: - `component.insert('some text')` - `component.replace('text', 'newvalue')` - `component.search('text', callback(output))` - `component.select(from, [to])` - `component.goto(pos)` - `component.focus()` - `component.save(callback(value))` - `component.marker(name, [from], [to], [color])` adds + modifies (with `from`) and removes (without `from` argument) marker - `component.change(changes)` for the real-time collaboration (`changes` can be generated in the `config.event` function) - `component.clear()` clears all changes - `component.replaceselections(selections)` - `component.replaceselection(selection)` - `component.replacerange(value, from, [to])` - `component.command(cmd)` executes `codemirror.execCommand()` method - `component.exec(a, [b], [c])` executes `document.execCommand(a, b, c)` method - __NEW__: `component.setoption(name, value)` sends `setOption` command to the CodeMirror __IMPORTANT__: `from`, `to`, `pos` arguments must be in the form: `{ line: Number, ch: Number }`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-CodeMirror Source: https://forge.totaljs.es/en/components/codemirror/ Framework: jcomponent@20 Content-SHA256: 14caca6469063f506170b25f135534f1bee7d131f3e93b4a49e1684f29b9acb7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports multiple cursors (`shift + cmd + arrow-down/up`) - supports finding selected text (`cmd + d`) - supports custom scrollbars __Configuration__: - `type {String}` type for syntax highlighting (default: `htmlmixed`) - `required {Boolean}` enables "required" (default: `false`) - `linenumbers {Boolean}` shows line numbers (default: `false`) - `icon {String}` icon for label without `fa-` e.g. `home`, `cog`, etc. - `height {Number}` control height (default: `200` px) - `label {String}` label (default is HTML content) - `disabled {Boolean}` disables this component - `tabs {Boolean}` enables indent with tabs (default: `false`) - `trim {Boolean}` performs auto-trim and removes empty begin/end lines (default: `false`) - `parent {String}` can set height by parent element - `margin {Number}` a margin for height - `minheight {Number}` a minimal height for `parent` option (default: `200`) __Method__: - `component.insert('some text')` inserts a text to the current position of the cursor Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
HTML editor
``` ## j-ColorPicker Source: https://forge.totaljs.es/en/components/colorpicker/ Framework: jcomponent@20 Content-SHA256: 84ee07ce8fa88a978c47b0652aeeca48ac152ef9cb0e593b870aa82361df5844 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Component is __singleton__ - Simple color picker - Supports __Dark theme__ ## Usage ```javascript var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align `left` (default), `center` or `right` // opt.position {String} : position `top` (default) or `bottom` // opt.opacity {Number} : converts hex color to RGBA with the opacity e.g. 0.3 opt.element = YOUR_ELEMENT; // or if you want to use a fixed position: // opt.x {Number} : `x` position // opt.y {Number} : `y` position opt.callback = function(color) { console.log(color); // callback parameter has string with HEX color (like #bada55) }; SETTER('colorpicker/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-ColorPickerButton Source: https://forge.totaljs.es/en/components/colorpickerbutton/ Framework: jcomponent@20 Content-SHA256: ec402d9c32fe305cebeda6d38e9b5dfca49cb7bff6e9ab26b5219e62ed14a88e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Component is __singleton__ - Supports __Dark theme__ - It uses `j-ColorPicker` __Configuration__: - `default` a default color (default: `#FFFFFF`) - `align` align for j-ColorPicker (default: `left`) - `position` position for j-ColorPicker (default: `top`) - `offsetX` offset-x for j-ColorPicker (default: `0`) - `offsetY` offset-y for j-ColorPicker (default: `0`) - `disabled` can disabled this component (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-ColorSelector Source: https://forge.totaljs.es/en/components/colorselector/ Framework: jcomponent@20 Content-SHA256: 6e21e13525dd080fc7dd2111d8ee47cff95164c0cb5d16a17265d6e1119c13e6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `disabled {Boolean}` can disable this control - `required {Boolean}` (optional) enables "required" (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
Select color:
``` ## j-Columns Source: https://forge.totaljs.es/en/components/columns/ Framework: jcomponent@20 Content-SHA256: df37b4402bd25c3de6e00764bd53aed681deaf6858ad5e886700fb16ccf7d4d9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component `Columns` is a very simple alternative to `j-Layout` and `j-Layout2`. With this component you can set columns with 100% height by your needs. __Configuration__: - `parent {String}` can contain `parent`, `window` or jQuery selector for the `closest` method (default: `window`) - `margin {Number}` add margin to `height` (default: `0`) - `marginlg {Number}` adds margin to `height` for `LG` display (default: `margin`) - `marginmd {Number}` adds margin to `height` for `MD` display (default: `margin`) - `marginsm {Number}` adds margin to `height` for `SM` display (default: `margin`) - `marginxs {Number}` adds margin to `height` for `XS` display (default: `margin`) - `noborder {Boolean}` disables border (default: `false`) - `fontsize {Boolean}` enables percentual font-size according to the size of rows (default: `false`) __Methods__: - `SETTER('columns/refresh')` - reloads all `section` and sets sizes - `SETTER('columns/add', size, html_node)` - adds a new column and performs refresh __Good to know__: Each column must be wrappend in `
`, try to understand from example. __Attributes__: - `data-size` contains a size of section `LG,MD,SM,XS` --> in pixels or percentage, example: `200,200,200,0` (`0` means hidden) - section without `data-size` attribute will be counted from the residual value Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Configuration Source: https://forge.totaljs.es/en/components/configuration/ Framework: jcomponent@20 Content-SHA256: e93c0ff449451c5bba8dafdccd0988c86f601e073a23db266833de9ba94913b9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ __Configuration__: - `dateformat {String}` a default date format (default: `DEF.dateformat`) ### Declaration __Allowed properties__: - `type {String}` supports: - `string` - `number` - `date` - `boolean` - `dropdown` - `color` - `icon` - `multiline` - `selectable` - `text {String}` a text/title - `name {String}` a name of property in the model - `align {Number}` align for inputs (`0` left (default), `1` center, `2` right) - `icon {String}` optional, Total JS or font-awesome icon identifier - `summary {String}` optional, a summarization - `note {String}` optional, a note - `required {Boolean}` optional, is the property required? - `disable {String}` optional, declaration of arrow function in the form `value.interval === 100` - `visible {String}` optional, declaration of arrow function in the form `value.interval === 100` - `button {String}` optional, creates a small button - `click {String}` optional, a link to the method (depends on the `button`) - `maxlength {Number}` optional, supports only `string` type - `min {Number}` optional, supports only `number` type - `max {Number}` optional, supports only `number` type - `increment {Number}` optional, an increment count - supports only `number` type (default: `1`) - `multiple {Boolean}` optional, works with `selectable` type (a value will be array) - `monospace {Boolean}` optional, works with `string` and `number` types - `bold {Boolean}` optional, works with `string` and `number` types - `placeholder {String}` optional - `items {String/Object Array}` optional for `dropdown` and `selectable` in the form `[{ id: 'VALUE', name: 'TEXT' }]` - type `string` a path to the `Object Array` (works with scopes) - type `Object Array` fixed defined array - `dirplaceholder {String}` optional, placeholder for `j-Directory` - `dirsearch {Boolean}` optional, enables/disables `search` field in `j-Directory` (default: `true`) - __NEW__: `datasource {String}` optional, a path to the data-source for config items Declaration must be defined in the component's element body wrapped in the ` ``` ## j-Confirm Source: https://forge.totaljs.es/en/components/confirm/ Framework: jcomponent@20 Content-SHA256: f766b24d177d455133038c658236ff68f2d0e46a20a4f506db0257c9cc6a15ba Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - works with Bootstrap - supports __dark mode__ - modal __Usage__: ```javascript SETTER('confirm/show', message, ['Yes', 'No'], function(index) { // @index {Number} a button index // In this case: // index == 0: Yes // index == 1: No }); SETTER('confirm/show2', message, ['Yes', 'No'], function() { // In this case will be the callback executed if the user will click on "yes" button only }); ``` ## A simple styling of buttons ```javascript // "Remove" button will be with Font-Awesome icon called: "trash-o" SETTER('confirm', 'show2', 'Are you sure you want to remove selected item?', ['"trash" Remove', 'Cancel'], REMOVE_FUNCTION); // "Confirm" button will be "green" with Font-Awesome icon called: "checked-circle" SETTER('confirm', 'show2', 'Are you sure you want to confirm selected items?', ['"checked-circle" Confirm #2BA433', 'Cancel'], REMOVE_FUNCTION); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Console Source: https://forge.totaljs.es/en/components/console/ Framework: jcomponent@20 Content-SHA256: 6fa2d1fc1e00c079f77751851d7e29f10ea1e9cfdd8ecd359265a2454f46b960 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - supports app tabs - supports __dark mode__ __Configuration__: - `datasource {String}` a path to data-source (learn from example) - __NEW__ `clear {String}` clear logs, link to the `function(source)` __Good to know__: - `path` can be `{String}` with the `appid` due to focusing logs Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Console2 Source: https://forge.totaljs.es/en/components/console2/ Framework: jcomponent@20 Content-SHA256: 14ec42d6f701ca031ba95aaf10e9aae5704ddb690361abd7ce3f217a9c2ce580 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ __Configuration__: - `icon {String}` a label icon (default: `ti ti-script`) - `name {String}` a label (default: `Console`) - `datasource {String}` __required__ a path to a data-source `Array` - `clear {String_LinkToFunction/Boolean}` adds a clear button (default: `true`) - `autoclose {Boolean}` console automatically closes after clearing (default: `true`) - `autoshow {Boolean}` console automatically opens after new logs (default: `true`) - `height {Number}` console height in pixels (default: `150`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ContentEditable Source: https://forge.totaljs.es/en/components/contenteditable/ Framework: jcomponent@20 Content-SHA256: 5e4a42aa60e661bcabf702e258a5acf50ba893ddf2e673b6914984750f02662d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports great features - works with Bootstrap Grid System - easy for customization - supports basic shortcuts `CMD+B` __bold__, `CMD+U` __underline__, `CMD+I` __italic__ and `CMD+L` __creates a link__ __Attributes__: - `data-required="true"` optional, default `false` - `data-clipboard="text/plain"` optional, default `text/plain` (for support of `html` use `text/html`) __Methods__: - `component.getNode()` returns a select `node` in text `{Object}` - `component.getSelection()` returns a current selection `{String}` - `component.insert(value, [encode])` inserts a custom HTML or PLAIN text to the current cursor position, `encode` (optional) is by default `false` - `component.exec('Bold', false, null)` has same functionality as `document.execCommand()` __Handlers__: `component.event(type, value)` handles all events from the editor. ```html type = bold - when a text is bolded (value is boolean) type = italic - when a text is italic (value is boolean) type = underline - when a text is underlined (value is boolean) type = link - when a link is created (value is a temporary URL) type = current - when a current element is changed in the text (value is NODE) type = paste - when the clipboard is used (value is a clipboard value) type = select - when a text is selected (value is selected text) type = focus - editor is focused (value is undefined) type = blur - editor is not focused (value is undefined) type = click - click on the specific element in the text (value is NODE) ``` __Default declaration__: ```javascript self.event = function(type, value) { if (type === 'paste') self.insert(value, true); }; ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-ContentSlider Source: https://forge.totaljs.es/en/components/contentslider/ Framework: jcomponent@20 Content-SHA256: 785dc8ee948c35edfb6082748a6f3a757d61b310fdf471a712f7acd9468825d6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports great features - works with Bootstrap Grid System __Configuration__: - `selector {String}` Optional, default `a` - `interval {Number}` Optional, refresh interval (default `3000`) - `cache {String}` Optional, when it's filled then the component saves a current state into the `localStorage` - so when the user refreshes the page then the component continues from the last state __Redraw__: The code below solves a problem with rendering component when the the component is dynamically displayed. ```javascript SETTER('contentslider/refresh'); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-ContextMenu Source: https://forge.totaljs.es/en/components/contextmenu/ Framework: jcomponent@20 Content-SHA256: 955e3a56eee2f17f84285a1096e6dee94784e5884f6771a37ccc016f7c95079b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports 3 orientations `left`, `center` and `right` - singleton - works with Bootstrap Grid System - works with touches __Methods__: Method: `component.show(orientation, targetElement, [items], clickCallback, [offsetX], [offsetY])` - `orientation {String}` can be `left`, `center` or `right` - `targetElement {Selector/jQuery/Element}` a target where the component will be visible - `items {Array}` optional and must have this structure: `[{ name: String, value: String, icon: String }]` otherwise will be items read from the target's `data-options` attribute. - `callback(selectedValue) {Function}` is triggered when the user clicks on the item - `offsetX {Number}` optional can change offset X - `offsetY {Number}` optional can change offset Y Method: `component.hide()` __Attributes__: `targetElement` can contain `data-options="Name 1|fa-building|Value 1;Name 2|fa-github|Value 2;"` attribut with all items of the context menu. If the `value` isn't defined then the component uses `name` as `value`. __Global events__: ```javascript ON('contextmenu', function(visible, component, target) { console.log('ContextMenu is', visible ? 'visible' : 'hidden'); }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Controls Source: https://forge.totaljs.es/en/components/controls/ Framework: jcomponent@20 Content-SHA256: 10418a41b16f48c256974faaab6a5b8315c0e495deafdf6d3ba2ee79a12f5933 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton ## Usage ```javascript var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align `left` (default), `center` or `right` // opt.position {String} : position `top` (default) or `bottom` // opt.hide {Function} : NEW: is executed when the menu is hidden // opt.classname {String} : NEW: adds class to the parent // opt.large {Boolean} : NEW: it'll make menu bigger opt.element = YOUR_ELEMENT; // or if you want to use a fixed position: // opt.x {Number} : `x` position // opt.y {Number} : `y` position opt.items = ['Label', { name: 'Item 1', icon: 'print', classname: 'custom_class_name' }, { name: 'Item 2', icon: 'home', title: 'A tooltip' }, '-', { name: 'Item 3', icon: 'far fa-envelope', children: [{ name: 'Submenu item 1', icon: 'cog' }, { name: 'Submenu item 2', icon: 'home' }] }, { name: 'Selected', icon: 'check-circle', selected: true }, { name: 'Item 4', icon: 'gear', disabled: true }]; // Item properties // name {String} : item name // icon {String} : icon // classname {String} : class to be added to li element // title {String} : tooltip // selected {Boolean} : item will be highlighted // disabled {Boolean} : item will be disabled(not clickable) // children {Array} : array of subitems opt.callback = function(item) { console.log(item); }; SETTER('controls/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Cookie Source: https://forge.totaljs.es/en/components/cookie/ Framework: jcomponent@20 Content-SHA256: 4772d6641378900c435c00f73ecb7e40579c40381bbfda031b231289f9f71b33 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - uses __localStorage__ - supports `cancel` operation (removes cookies, localStorage and redirects to `about:blank`) __Configuration__ - `agree` {String} a label for the agree button (default: `OK`) - `cancel` {String} a label for the cancel button (default: `Cancel`) - `redirect` {String} URL to redirect if the user pressed cancel button (default: `about:blank`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
CONTENT
CONTENT
CONTENT
CONTENT
CONTENT
CONTENT
CONTENT
``` ## j-Cookie2 Source: https://forge.totaljs.es/en/components/cookie2/ Framework: jcomponent@20 Content-SHA256: 70707a85b6c0394c0ff53589f3b16c7d97ed3eb30255a781d463deac355ebaba Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - uses __localStorage__ - supports `cancel` operation (removes cookies, localStorage and redirects to `about:blank`) __Configuration__ - `agree` {String} a label for the agree button (default: `OK`) - `cancel` {String} a label for the cancel button (default: `Cancel`) - `redirect` {String} URL to redirect if the user pressed cancel button (default: `about:blank`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
CONTENT
CONTENT
CONTENT
CONTENT
CONTENT
CONTENT
CONTENT
``` ## j-CountDown Source: https://forge.totaljs.es/en/components/countdown/ Framework: jcomponent@20 Content-SHA256: e1ca9c20dcd2485cdddec71d4cd11a66fc5a804aa2bef5a3a51021bc725373ad Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can show an action when time is expired. __Configuration__ - `text {String}` optional, a text for countdown Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Tomáš Novák. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Crop Source: https://forge.totaljs.es/en/components/crop/ Framework: jcomponent@20 Content-SHA256: 1ecbea80c498d4266f39259a180aa38ff9562bd83bbf9035ff30e0b1aa732222 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Supports__: - zoom - drag and drop - local files - responsive - automatically rotates image according to the EXIF information __Configuration__: - `width {Number}` target width, required - `height {Number}` target height, required - `dragdrop {Boolean}` enables drag&drop (default: `true`) - `background {String}` a background color (default: transparent) - `format {String}` a format for URL file generator (default: `{0}`) __Attributes__ - `path="path-with-url-to-image"` - must contain URL to picture __Methods__: ```js // e.g. var component = FIND('croper'); // Resize canvas component.reconfigure('width:500;height:200'); // Get cropped image // component.output([type], [return_object]) var png = component.output('image/png'); var jpg = component.output('image/jpeg'); // Below method automatically detects the transparency and sets the output var data = component.output(); // var data = component.output(true); // data.filename {String} // data.data {String} base64 // New method for clearing of canvas component.clear(); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Dashboard Source: https://forge.totaljs.es/en/components/dashboard/ Framework: jcomponent@20 Content-SHA256: e0a4c8735d0c2c4a3c58a78273cbd1deb6bf6c13290d4a4175bdf11b1f294da5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Supports mobile devices - Supports touches - Movable - Draggable - Resizable The component expects `Array` of objects. __Configuration__: - `axisX {Number}` a size of grid of X axis (default: `12`) - `axisY {Number}` a size of grid of Y axis (default: `144`) - `padding {Number}` a padding between widgets (default: `10`) - `delay {Number}` init delay (default: `200`) - `serviceinterval {Number}` a service interval (default: `5000`) - `ondrop {String}` a path to method `function(meta) {}`, is executed if someone drops some element into area - `meta.x` X grid position - `meta.y` Y grid position - `meta.el` dragged element - `meta.pageX` - `meta.pageY` - `meta.offsetX` - `meta.offsetY` - `meta.target` - `meta.d` a display mode `xs`, `sm`, `md` or `lg` - `noemitresize` disables executing of `resize` method in all nested component (default: `false`) - `parent {String}` a parent container which sets a minimal height (default: `null`) - `margin {Number}` a top/bottom margin for the `parent` option (default: `0`) - `minsizexs {Number}` a minimal column/row size for extra small displays (default: `2`) - `minsizesm {Number}` a minimal column/row size for small displays (default: `2`) - `minsizemd {Number}` a minimal column/row size for mediun displays (default: `1`) - `minsizelg {Number}` a minimal column/row size for large displays (default: `1`) - `iconsettings {String}` settings icon - `iconremove {String}` remove icon - `change {String}` a path to the method `function(type, id)` (executed if the dashboard captures a change `move` or `remove`) - `animation {Number}` style of animation: - `1` opacity - `2` scale from big to normal - `3` scale from small to normal (__default__) - `4` rotation Z - `5` changing of X position - `6` changing of Y position - `grid {Boolean}` renders background grid (default: `false`) - __NEW__: `reanimate {Boolean}` enables animation for changing widgets (default: `false`) ```js // Component declaration var component = { // Component ID id: 'COMPONENT_ID', // Positioning // You can define specific display size and if the display size is not specified then the component tries to find a size for larger display offset: { xs: { x: 1, y: 1, width: 6, height: 6 }, // Number means the position in the grid, so e.g. width "2" takes "2" columns in X axis lg: { x: 1, y: 1, width: 6, height: 6 } }, html: 'THE CONTENT OF COMPONENT', // or can be raw HTMLElement // Default settings actions: { move: true, remove: true, resize: true, resizeX: true, resizeY: true, resizeP: false, settings: true }, // resizeP means: resize "proportionally" // Can disable header (default: true) header: true, // Can delay displaying (in "ms", default: config.delay) delay: 0, // A component title title: 'Title for the component', // Custom properties which will be assigned to the instance template: Object, config: Object, // reset: true, // NEW: reloads the component again // class: String // adds a class to the item make: function(exports, config, el) { // @exports {Object} // @config {Object} // @el {jQuery} a content of the component // Handlers (optional): exports.destroy = function() { // @el {jQuery} a content of the component // @this {Instance} // is executed when the component is destroyed }; exports.data = function(data, el) { // @data {Object} // @this {Instance} // @el {jQuery} a content element of the component // It can be executed via SETTER('dashboard/send', ....) }; exports.service = function(counter, el) { // @counter {Number} count of calls // @el {jQuery} a content of the component // @this {Instance} // dashboard will execute this handler each 5 seconds }; exports.focus = function() { // Optional, when the "window" is focused the delegate will be executed }; exports.resize = function(width, height, el, display) { // @width {Number} // @height {Number} // @el {jQuery} a content of the component // @display {String} a current display size "xs", "sm", "md" or "lg" // @this {Instance} // is executed when the component is resized // @this {Instance} }; exports.settings = function(config, el, elbtn) { // @config {Object} // @el {jQuery} a content element of the component // @elbtn {jQuery} button element // is executed when the users clicks on the settings icon }; exports.remove = function(remove) { // remove {Function} removes that widget remove(); }; exports.configure = function() { // is executed when the configuration is changed }; // this.meta {Object} a reference to component object // this.element {jQuery} a content element of the component // this.container {jQuery} a main content element of the component // this.main {Object} a reference to Dashboard component // this.width {Number} a width of "this.element" // this.height {Number} a height of "this.element" // this.display {String} a current display size "xs", "sm", "md" or "lg" // is executed when the component is making } }; PUSH('components', component); ``` __Methods__: - `SETTER('dashboard/send', id, body)` sends data to all widgets which contain `data` delegate - `id {String}` - `null` sends to all components - `@component` sends to the specific components according to the component name - `string` sends to a specific component according to the identifier - `SETTER('dashboard/call', method_name, [a], [b], [c], [d])` executes a method in each widget - `RETURN('dashboard/pixel')` returns a size of the pixel (square) - `RETURN('dashboard/display')` returns a current display width __Good to know__: - component adds classes to component's body: - `d_colNUMBER` determins count of taken columns e.g. `d_col2` - `d_rowNUMBER` determins count of taken rows e.g. `d_row3` - `d_square` the component has same width/height - `d_vertical` the component has only 1 step of width and more than 1 steps of height - `d_horizontal` the component has only 1 step of height and more than 1 steps of width Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-DataGrid Source: https://forge.totaljs.es/en/components/datagrid/ Framework: jcomponent@20 Content-SHA256: a1870ef33788ac6c75a248614700c48166bdcfe6939c2f5a12110ad40316270c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This grid was created for single page applications and enterprise applications. - needed `bootstrap` grid system - you can render more than 30 000 rows without any problem - supports drag&drop columns - supports sorting - supports resizing of columns - supports vertical/horizontal scrolling - supports filters - supports checkboxes - custom scrollbars independent on OS - responsive - supports __dark mode__ - __IMPORTANT__ column options filter needs `j-Directory` component __TO-DO__: - multisort - resizing columns for touch devices - re-ordering columns for touch devices __Data-source__ needs to contain: ```js { schema: 'schema_id', // NEW: optional, DataGrid supports multiple schemas (it means: multiple declaration of columns) items: [{ name: 'Row 1' }, { name: 'Row 2' }, ...] // items page: 1, // current pages pages: 30, // count of pages limit: 5, // items limit per page count: 150 // count of items in DB } ``` or raw `Array` but you can't use pagination and external filters: ```js [{ name: 'Row 1' }, { name: 'Row 2' }]; ``` __Configuration__: - `filterlabel {String}` a default placeholder for all filters (optional) - `rememberfilter {Boolean}` with true it remembers filters for every schema (default: `true`) - `schema {String}` a default schema (default: `default`) - `pluralizepages {String}` pluralization for pages (optional, default: `# pages,# page,# pages,# pages`) - `pluralizeitems {String}` pluralization for items (optional, default: `# items,# item,# items,# items`) - `height {Number/String}` height of grid, supported values: `auto` (default), __NEW__ `fluid`, `parent` (or `parent1`, `parent2`) or `NUMBER` as height or `selector` for jQuery.closest() - `minheight {Number}` minimal height of grid, works with `fluid` and `auto` height (default: `200`) - `parent {String}` selector for `auto` height option (default: `window`) - `margin {Number}` a top margin for height (optional, default: `0`) - `boolean {String}` a values for filtering of boolean values (optional, default: `true|on|yes`) - `resize {Boolean}` enables resizing of columns (optional, default: `true`) - `reorder {Boolean}` enables re-ordering of columns (optional, default: `true`) - `sorting {Boolean}` enables sorting (optional, default `true`) - `remember {Boolean}` remembers re-ordering and resizing columns (optional, default `true`) - `checkbox {Boolean}` enables checkboxes - `colwidth {Number}` a default column width in pixels (optional, default `150`) - `rowheight {Number}` a default row height in pixels (optional, default: `24`) + it depends on CSS - `alignheader {String/Number}` align for header `right` (or `2`) or `center` (or `1`) (optional, default: `left`) - `alignfilter {String/Number}` align for filter input `right` (or `2`) or `center` (or `1`) (optional, default: `left`) - `align {String/Number}` align for a column value `right` (or `2`) or `center` (or `1`) (optional, default: `left`) - `click {String}` a link to a path or `function(row, grid, row_el)`, a record will be assigned/executed if the user clicks on a row - `clickid {String}` an identificator/property name for backwards redrawing (for previous row highlight), default: `id` - `highlight {Boolean}` each selected row (after `click`) will be highlighted (default: `false`) - `unhighlight {Boolean}` enables `undo highlighting` of selected row (default: `true`) - `checked {String}` `path` to a variable or path to `function(rows, grid)` is executed if the user selected/checked some rows - `autoselect {Boolean}` enables auto-select of first row in grid, it performs `EXEC(config.click)`, default: `false` - `limit {Number}` a cluster limit, default: `80` - `numbering {Boolean}`, optional default `false` - `allowtitles {Boolean}`, enables titles for all row values, optional default `false` - `button {String}` a link to `function(btn_name, row, btn_element, event, name)` is executed if the user clicks on a __button__ in the row - `exec {String}` a link to `function(type, filter, sort, page)` for server-side operations only (it disables client-side sorting & filtering), supported types: `refresh` or `page` - `changed {String}` `path` to a variable or path to `function(rows, grid)` is executed if the user changed some rows - `change {String/Boolean}` boolean enables internal editing or string must contain a `path` to a variable or path to `function(meta, next(meta))` is executed if the user double clicks on a column (`meta` can be `null` if the grid is refreshed) + `next(null)` replaces previous content again - `columns {String}` a path to definition of `columns {Array}` - `dblclick {String}` a link to `function(row, grid, row_el)` method, it's executed if the user double-clicks on a row - `noborder {Boolean}` can disable a border around the grid (default: `false`) - `clusterize {Boolean}` can disable clustered scrolling (default: `true`) - `contextmenu {String}` a link to `function(e, grid)` when the user raises context menu - `autoformat {Boolean}` enables auto-format types like `email`, `phone` and `number` (default: `true`) - `controls {Boolean}` enables controls defined in `columns` (default: `true`) - `hfunc {String}` a link to `function(el)` method, it's executed if the user clicks on the icon added to very first header row. usefull to integrate other component with DataGrid. e.g. j-filter - `hfuncicon {String}` hfunc icon e.g. home, cog, etc. - `pagination {Boolean}` enables/disables pagination (default: `true`) - `config.exec` will be executed if the scrollbar is at the end, and you can use as the raw response `array` of rows - `ovalue {String}` a default key for obtaining of `value` from `column.options` (default: `id`) - `otext {String}` a default key for obtaining of `text` from `column.options` (default: `name`) __Column properties__: - `name {String}` a name of field in the row object - `text {String}` a column label, text with `.ti ti-home` will render Total icon - `title {String}` a column tooltip (optional) - `width {Number}` a column width (optional, default `config.colwidth`) - `filter {String/Boolean}` a placeholder for the filter or `boolean` can disable filter for this column (optional) - `filtervalue {Object}` optional, a preddefined filter value (default: `undefined`) - `filtertype {Number/String}`, `1` disables smart searching (default: `0` - it means enabled smart searching) - `align {String}` can be `center` or `right` (optional, default: `left`) - `template {String}` can be a Tangular template and the model is the entire object of row - `sorting {Boolean}` enables sorting (optional, default: `true`) - `search {Boolean/String}` `true` will filter a value according to the `template` result or `String` can be a Tangular template which will be used as a value for search - `format {String/Number}` can be used for date and numbers (count of decimals) field (optional), e.g. `dd.MM.yyyy` - `hide {Boolean}` hides a column - `listcolumn {Boolean}` default:true, false for removing column from columns list - `hidden {String}` as an arrow function `column => true` --> column will be hidden (e.g. for restricting user) - `options {Object Array}` optional, a custom filter for example `[{ text: 'yes', value: true }, { text: 'no', value: false }]` o {String}r link to data-source - `otext {String}` optional, a key for `text` field in `options`, default `config.otext` - `ovalue {String}` optional, a key for `value` field in `options`, default `config.ovalue` - `buttonapply {String}` optional, a label for `Apply` button in columns, default: `Apply` - `class {String}` optional, a custom column class name - `empty {String/Boolean}` optional, can rewrite empty value with the value defined in empty field (`true` value uses `---` as a default value) - `min {Number}` __editable only__ a min. number value - `max {Number}` __editable only__ a max. number value - `required {Boolean}` __editable only__ - `dirsearch {String/Boolean}` a placeholder for `j-Directory` search, boolean with `false` will disable search - `type {String}` optional, can contain a data-type (`string`, `boolean`, `date`, `number`, `email`, `phone` or `url`) for the field - `editable {Boolean}` enables editing - `currency {String}` a currency name (must be defined in `DEF.currencies`) - `editable {String}` A path to custom editable `function(meta)`, important: `meta.next(new_value)` or `meta.cancel()` - `colorize {Boolean}` enables a colorization of the value - `monospace {Boolean}` enables monospace font type - __NEW__ `raw {Boolean}` enables/disables HTML escaping in column filters (default: `false`) - __NEW__ `pair {Boolean}` enables/disables auto value pairing with `options` configuration (default: `false`) __Row controls (NEW)__: - can be defined as column type `controls` - must defined column `template` (Tangular, `row` is a model for Tangular for each row) - look to example - button `click` event is captured to `config.button` __Filtering__: - `numbers`: (1) `number` searches an exact number, (2) `number - number` is an interval between numbers - `strings`: (1) `string` searches an exact string, (2) `string1, string2, string3` is a multiple search criterium - `dates`: (1) year `2017` searches all dates in this year, (2) `2017-02-12 - 2017-03-13` <--> `02.12.2017 - 13.03.2017` is an interval between dates, (3) `12-20 - 12-31` <--> `20.12 - 31.12` an interval between dates in the current year ir (4) `2017-01 - 2018-05` <--> `01.2017 - 05.2018` or (5) `-5 days` <--> `-1 week` <--> `-10 years` __Methods__: - `component.redraw([reselect_again])` can redraw rows again (only for modifications, if you will remove some row you need to update the entire model) - `component.resetfilter()` can reset a filter - `component.exportrows(page_from or true from the current page, pages_count, callback(rows, internal_options), [reset_to_page or true for the current page])` can export rows with server-side rendering - `component.appendrow(row_object, [scrolldown], [prepend])` appends and render row - `component.redrawrow(row_object, [new_object_row])` redraws row or __NEW__: replaces+redraws `row_object` with a new `new_object_row` - `component.clear()` clears all changes - `component.select(row)` selects `row` must be the same object as in data-source - `component.editcolumn(row_index, col_index)` executes `config.change` internally (only for advanced usage) - `component.applyfilter(obj)` can apply a custom filter `{ name: 'Peter', age: '20 - 50' }` - `component.resetcolumns()` resets columns - `component.readfilter()` returns a current filter - `component.rebind(schemaname__or__columnsdeclaration)` the method rebinds the schema - `component.reload()` executes `config.exec` with the current filter and sorting - `component.empty()` empties all rows - `component.redrawcolumns()` redraw columns without reset them - __NEW__: `component.schema(name)` changes a schema and refreshes data __Properties__: - `component.meta` returns internal meta info about filters, columns and rows __Good to know__: - `NULL('link.to.data')` evaluates `config.exec` - `SET('link.to.data', data, 'noscroll')` --> `noscroll` type disables reseting of scrolling __How to extend a class of row?__ - look to the `{{ if active }}` line, it extends a class of row by adding `dg-active-class` if the `active` will be valid ```javascript [ '{{ if active }} dg-active-class{{ fi }}', { name: 'name', text: 'Name', width: 200 }, // other columns ... ] ``` __Multiple schemas__: ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-DataSource Source: https://forge.totaljs.es/en/components/datasource/ Framework: jcomponent@20 Content-SHA256: 9f6c58aecb899aeb714d265b23ace97db8e569e98b0aa09f29f47187b0087efb Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component loads data from the external source via `AJAX()` method and it binds the value according to the `config.path`. __Configuration__: - `path {String}` __required__ a path where the value will be set - `url {String}` optional, a URL address for obtaining data - `delay {Number}` optional, a delay (in milliseconds) for obtaining data (defaul: `0`) __Good to know__: - `config.path = '#codelist'` sets a value in code lists `DEF.cl.codelist` - `config.path = '%codelist'` sets a value in as temporary - `config.path = '?.path` sets a value according to the plugin path - `config.path = 'absolute.path` sets a value according to the path __Can I use dynamic URL address?__ Yes, you can use ` ``` __How can I modify data before binding?__ ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

``` ## j-DataTable Source: https://forge.totaljs.es/en/components/datatable/ Framework: jcomponent@20 Content-SHA256: 07b9c16945d8a7effe1760ca889312a66c92c690828035a97358d42bc9132576 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __BETA__: This component is targeted for SPA and server-side listing. - supports pagination - needed `bootstrap` grid system - supports sorting - supports vertical/horizontal scrolling - responsive - supports __dark mode__ __Data-source__ needs to contain: ```js { cols: [{ name: 'id', ... }], // optional, can be defined inline in HTML items: [{ name: 'Row 1' }, { name: 'Row 2' }, ...] // items page: 1, // current pages pages: 30, // count of pages limit: 5, // items limit per page count: 150 // count of items in DB } ``` __Configuration__: - `pluralizepages {String}` pluralization for pages (optional, default: `# pages,# page,# pages,# pages`) - `pluralizeitems {String}` pluralization for items (optional, default: `# items,# item,# items,# items`) - `height {Number/String}` height of grid, supported values: `auto` (default), __NEW__ `fluid`, `parent` or `NUMBER` as height or `selector` for jQuery.closest() - __NEW__ `minheight {Number}` minimal height of grid, works with `fluid` and `auto` height (default: `300`) - __NEW__ `parent {String}` selector for `auto` height option (default: `window`) - `margin {Number}` a top margin for height (optional, default: `0`) - `click {String}` a link to `function(row, grid, row_el)`, it's executed if the user clicks on a row - `highlight {Boolean}` each selected row (after `click`) will be highlighted (default: `false`) - `unhighlight {Boolean}` enables `undo highlighting` of selected row (default: `true`) - `checked {String}` `path` to a variable or path to `function(rows, grid)` is executed if the user selected/checked some rows - `autoselect {Boolean}` enables auto-select of first row in grid, it performs `EXEC(config.click)`, default: `false` - `exec {String}` a link to `function(type, page, sort)` for server-side operations only (it disables client-side sorting & filtering), supported types: `refresh` or `page` - `changed {String}` `path` to a variable or path to `function(rows, grid)` is executed if the user changed some rows - `dblclick {String}` a link to `function(row, grid, row_el)` method, it's executed if the user double-clicks on a row - `noborder {Boolean}` can disable a border around the grid (default: `false`) - `colwidth {Number}` a default width for columns (default: `150`) - `editable {String}` a link to `function(opt)` when the user performs editing - `contextmenu {String}` a link to `function(e, grid)` when the user raises context menu __Column properties__: - `name {String}` a name of field in the row object - `text {String}` a column label, text with `.fa fa-home` will render FontAwesome icon - `width {Number}` a column width (optional, default `config.colwidth`) - `align {String}` can be `center` or `right` (optional, default: `left`) - `template {String}` can be a Tangular template and the model is the entire object of row - `sort {Boolean}` enables sorting (optional, default: `false`) - `format {String/Number}` can be used for date and numbers (count of decimals) field (optional), e.g. `dd.MM.yyyy` - `currency {String}` a currency formatter, just add a currency - `class {String}` optional, a custom column class name - `empty {String/Boolean}` optional, can rewrite empty value with the value defined in empty field (`true` value uses `---` as a default value) - `type {String}` optional, can contain a data-type (`boolean`, `date` or `number`) for the field - `editable {Boolean}` enables editing __Methods__: - `component.redrawrow(row_object/index)` redraws row or __NEW__: replaces+redraws `row_object` with a new `new_object_row` - `component.clear()` clears all changes - `component.select(row)` selects `row` must be the same object as in data-source - `component.rebind(columnsdeclaration)` the method rebinds the schema - __NEW__: `component.reload()` executes `config.exec` with the current filter and sorting - __NEW__: `component.empty()` empties all rows __Good to know__: - `SET('link.to.data', data, 'noscroll')` --> `noscroll` type disables reseting of scrolling __How to extend a class of row?__ - look to the `{{ if active` line, it extends a class of row by adding `dg-active-class` if the `active` will be valid ```js [ '{{ if active }} dg-active-class{{ fi }}', { name: 'name', text: 'Name', width: 200 }, // other columns ... ] ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-DatePicker Source: https://forge.totaljs.es/en/components/datepicker/ Framework: jcomponent@20 Content-SHA256: d0e5f28172d2d2671add1db9166395c4528153d8b805d5c2e201824783d48f99 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - it's improved clone of `j-Calendar` - supports __dark mode__ - supports __touch gestures (swipe)__ and fixed full size on mobile __Configuration__: - `firstday {Number}` first day in the week (default: `DEF.firstdayofweek`) - `today {String}` a label for the `Set today` button - `clear {String}` a label for the `Clear` button - `days {String}` days e.g. `SU,MO,TU,WE,TH,FR,SA` (default). - `months {String}` months e.g. `January,February,...` (default). The component must be called manually or works with `j-Input` component automatically. The component is a singleton. - __important__ add the calendar component under `` element ## Usage ```javascript var opt = {}; opt.element = YOUR_ELEMENT; opt.value = new Date(); // or opt.value = 'path.to.date'; --> then "opt.callback" is disabled // opt.align {String} : align "left" (default), "center" or "right" // opt.position {String} : position "top" (default) or "bottom" // NEW: opt.clock {Boolean} : enables time (default: false) // NEW: opt.ampm {Boolean} : enables AM/PM (default: false) opt.clear = false; // Removes "clear" button from datepicker. If this property is not specified as "false" - "clear" button will be shown opt.callback = function(newdate) { console.log('date has been changed'); }; // IMPORTANT - opt.callback() can receive "null" value as a parameter, so this check should be taken into consideration when callback function is being created. // opt.offsetX {Number} "x" offset // opt.offsetY {Number} "y" offset // opt.close {Function} optional, this function can determine closing of DatePicker // NEW and OPTIONAL // It's callend when the DatePicker changes year/month opt.badges = function(date, append) { // Appends small and red badges to the current view/month append([date1, date2, date3]); }; SETTER('datepicker/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html SHOW DATEPICKER: ``` ## j-Detach Source: https://forge.totaljs.es/en/components/detach/ Framework: jcomponent@20 Content-SHA256: c3f319cecfeb2447eff10067bfb8f1e06f226641865cff05a7f5cdf2fdbd2e8c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can detach/attach all children (HTML elements). For example, if you have elements inside a panel, you can move the elements e.g., to the `j-Windows`. The component `watch` path `{Boolean}` and if the value contains `true`, elements will be detached otherwise attached. __Configuration__: - `detach {String}` a link to the `function(children, element)` - `attach {String}` a link to the `function(children, element)` - `remove {String}` a link to the `function(children)` --- - `detach` is executed when the content is detached - `attach` is executed when the content must be returned back - `remove` is executed when the component (or a parent element) is removed Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

Your content

``` ## j-Detail Source: https://forge.totaljs.es/en/components/detail/ Framework: jcomponent@20 Content-SHA256: 72120fd4080e6ef594d8283420e7f7622eab2675414e881b22289806e2b6cf83 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can render values from model. Supports inline mapping - look into the source-code of the example. __Configuration__: - `dateformat {String}` a date format (default: `DEF.dateformat`) - `datetimeformat {String}` a date/time format (default: `DEF.dateformat + ' ' + DEF.timeformat`) - `numberformat {Number}` a default number format (default: empty) - `small {Boolean}` enables smaller design (default: `false`) - `style {Number}` component style (default: `1`), supports style `2`, `3` (minimal) and `4` (modern) - `defaultgroup {String}` a default group name (default: `Default`) - `notnull {Boolean}` skips nullable values (default: `false`) - `track {String}` can contain paths divided by comma, this property will watch only changes in trakced keys __Data declaration__: ```javascript var model = { firstname: 'Peter', lastname: 'Širka', age: 33 }; var items = [{ id: 2, name: 'Banská Bystrica' }, { id: 3, name: 'Bratislava' }]; var form = []; // The below values will be binded automatically from the "model" (according to the "path" field) because they contain "path" field form.push({ group: 'Personal', label: 'First name', path: 'firstname', type: 'string', value: model, note: 'This is first name' }); form.push({ group: 'Personal', label: 'Last name', path: 'lastname', type: 'string', value: model, placeholder: 'String' }); form.push({ group: 'Personal', label: 'Age', path: 'age', type: 'number', value: model }); // The below values will be binded from "value" key form.push({ group: 'Personal', label: 'Birth date', type: 'date', value: NOW }); form.push({ group: 'Additional', label: 'Newsletter', type: 'bool', value: true }); form.push({ group: 'Additional', label: 'City', type: 'list', value: 2, items: 'items' }); form.push({ group: 'Additional', label: 'Color', type: 'color', value: '#e73323' }); form.push({ group: 'Additional', label: 'Icon', type: 'fontawesome', value: 'fas fa-home' }); ``` __Data properties in data declaration__: - `group {String}` a group name (required) - `label {String}` a label (required) - `type {String}` a type (required) - `note {String}` a small note under value - `format {String}` number e.g. `2` or date format `dd.MM.yyyy` - `detail {String}` URL address for obtaining of data for `list` type, example: `/users/{0}/` and `{0}` will be replaced with the value from list - `items {Object Array/String}` items for `list` type only, string can contain a path to `Array` or `URL address` to search - `value {Object}` a value or model with values (then `path` is required) - `path {String}` a path to value in model (`value` must contain a model) - `template {String}` A Tangular template (works only with `type:'template'` and `{{ value }}` contains a raw value, and `{{ item }}` contains the entire item) - `empty {String}` An empty value when the value is nullable (default: `---`) - `show {String}` the conditional function `value.type === 'company'` then displays if the evaluated condition is `true` - __NEW__ `autoformat {Boolean}` enables auto-format for `email`, or `phones`, and only for `string` type (default: `false`) - __NEW__ `colorize {Boolean}` colorizes the value with except `list`, `color` and `icon` type - __NEW__ `plus {String}` adds a value to end of rendered value for `number` and `string` types __Allowed types in data__: - `string` - `bool` - `number` - `date` - `datetime` - `list` - `color` - `emoji` - `fontawesome` - `password` - `template` __Good to know__: - if group contains only the one char then the name of group is not rendered Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

-- OR --


-- OR FILTERED --


``` ## j-Developer Source: https://forge.totaljs.es/en/components/developer/ Framework: jcomponent@20 Content-SHA256: 693348639089929f1292c32d4ef02950b9f26b4ec851d5cf42a8b7599e3e463a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component monitors jComponent single page application. Just include component under the `` element. It works only with jComponent `+v18`. - `time` in brackets means a delay between execution - `↑NUMBER` means a maximum count of calls - `+NUMBER` means added items/operations - `-NUMBER` means removed items/operations - `NUMBERx` means a count of items/operations/calls - memory consumption works only in Chromium browsers Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Diagram Source: https://forge.totaljs.es/en/components/diagram/ Framework: jcomponent@20 Content-SHA256: 81d2acf25ecc10cba25072602d611ba768daf7ea061d10a03a326a89d2d15bf4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `parent {String}` optional, a container with fixed height, can be `window`. Default value: `parent` element. - `margin {Number}` optional, a top/bottom margin together (default: `0`) - `marginxs {Number}` optional, a top/bottom margin together for `xs` screen width - `marginsm` optional, a top/bottom margin together for `sm` screen width - `marginmd` optional, a top/bottom margin together for `md` screen width - `marginlg` optional, a top/bottom margin together for `lg` screen width - `reverse {Boolean}`, reverses diagram Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
``` ## j-Directory Source: https://forge.totaljs.es/en/components/directory/ Framework: jcomponent@20 Content-SHA256: 8995b6b7f349e33de32c69128dbac4c5e14ad1b985207dcbc865d0b0956b39cc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded It's similar component like `j-Suggestion`, but has improved design and supports more handy features. - singleton - works with touches - supports __dark mode__ > __IMPORTANT__: by default this component renders a value as a text from `name` property. __Methods__: Method: `component.show(options)` - `options.element {Element/jQuery Element}` - `options.items {Array/String/Function}` a list of items (`String` type means a link to data-source) - `options.offsetX {Number}` optional, `x` offset (default: `0`) - `options.offsetY {Number}` optional, `y` offset (default: `0`) - `options.offsetWidth {Number}` optional, `width` offset (default: `0`) - `options.placeholder {String}` optional, a placeholder for search field - __NEW__ `options.height {Number}` optional, a height of the container (default: `180`) - `options.render {Function}` optional, a function for customized render of item `function(item, text)` must return `HTML` - `options.custom {Boolean/String}` optional, enables returning a value not defined in `options.items`, default: `false` - `options.minwidth {Number}` optional, a minimal width, default `200` - `options.maxwidth {Number}` optional, a maximal width, default `infinite` - `options.callback(selected_item, element, iscustom, e) {Function}` is triggered when the user clicks on the item - `options.key {String}` optional, a default `key` for `text` value (default: `name`) - `options.empty {String}` optional, adds empty field - `options.exclude {Function}` optional, can exclude items and must return a boolean `function(item) { return item.id !== 100 }` - `options.close {Function}` optional, can determine closing of panel - `options.search {Boolean/String}` optional, can hide search field (default: `true`) or `{String}` (key name) can map a value for searching - `options.selected {Object}` optional, can contain a selected value (default: `undefined`) - `options.align {String}` optional, `left` (default), `right` or `center` - `options.position {String}` optional, `top` (default), `bottom` - `options.raw {Boolean}` optional, this option disables escaping of characters (in other words: HTML content will be allowed in labels of items, default: `false`) - `options.classname {String}` optional, a custom container class for all items - absolute positioning works only if `options.element` is not defined - `options.x {Number}` absolute position X - `options.y {Number}` absolute position y - `options.checkbox {Boolean}` optional, enables checkboxes - `options.checked {Array String}` optional, identifiers of checked items - targeted for `options.items {Function(q, next)}` - the callback returns only raw identifiers `Array {String}` - __NEW__ `options.template {String}` optional, a custom Tangular template e.g. `{{ name }}` (default: null) - __NEW__ `options.fuzzy {Boolean}` optional, it can disable fuzzy search (default: `true`) Method: `component.hide()` __Configuration__: - `placeholder` - a placeholder for the search input - `create` - a placeholder for `Create` label (default: `Create`) __Supported item fields__: - `name {String}` a label name - `template {String}` optional, a custom Tangular template - `classname {String}` optional, adds additional classes into the `
  • ` element - `disabled {Boolean}` optional, it can disable item - `selected {Boolean}` optional, it selects item __Formatting via Tangular__: ```js var opt = {}; opt.items = []; opt.push({ name: 'Total.js', template: '{{ name }}' }); ``` __Formatting via custom function__: ```js var opt = {}; opt.items = []; opt.push({ name: 'Total.js' }); opt.push({ name: 'Express.js' }); opt.push({ name: 'Koa.js' }); opt.render = function(item, name) { return '' + name + ''; }; ``` __Adding of custom class__: ```js var opt = {}; opt.items = []; opt.push({ name: 'Total.js', classname: 'your_class_name' }); ``` __Server-side searching__: ```js var opt = {}; opt.element = your_element; opt.items = function(search, next) { next([{ name: 'Item 1' }, { name: 'Item 2' }]); }; opt.callback = function(selected) { console.log(selected); }; SETTER('directory/show', opt); ``` __Good to know__: - if `checkboxes:true` then the component extend items by adding a timestamp `selectedts {Number}` due to order Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Display Source: https://forge.totaljs.es/en/components/display/ Framework: jcomponent@20 Content-SHA256: 1768e705ac6ce43d082080a400d9911dd3a890c2de7decca43d829ed73e7a554 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component measures a display size according to the current element. It uses `WIDTH()` method and appends a CSS class in the form `jc-DISPLAY_SIZE`: - `jc-xs` extra small display (mobile phone) - `jc-sm` small display (tablet) - `jc-md` medium display (laptop) - `jc-lg` large display (desktop computer) __Configuration__: - `delay {Number}` a delay for obtaining of size (default: `100` ms) - __NEW__: `xs {Number}` a maximum width for the extra small display (default: `768`) - __NEW__: `sm {Number}` a maximum width for the small display (default: `992`) - __NEW__: `md {Number}` a maximum width for the medium display (default: `1200`) The component calculates the interval between displays automatically. The default display type is `lg`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html




    ``` ## j-Dockable Source: https://forge.totaljs.es/en/components/dockable/ Framework: jcomponent@20 Content-SHA256: f10964828307c6a7e2b210407fd64d649bd67202eaa0b782fe43ab419aa61341 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Works only with `+v18` - Supports touches - Movable - Resizable __Configuration__: - `style {Number}` `1` bottom panel will be fullwidth, `2` bottom panel will be between the left and right panel - `parent {String}` jquery selector due to container height (default: `window`) - `margin {Number}` a bottom margin (default: `0`) - __NEW__ `reoffsetresize {Boolean}` all floated panels will be re-offset according to `main` window dimension (default: `false`) The `dockable` component expects `Array` of objects. ```javascript // Component declaration var panel = { // Component ID id: 'PANEL_ID', // Positioning // You can define specific display size and if the display size is not specified then the window tries to find a size for larger display html: 'THE CONTENT OF PANEL', // or can be raw HTMLElement offset: { x: 200, y: 100, width: 600, height: 400, minwidth: 200, minheight: 200, maxwidth: 1000, maxheight: 1000, dockminwidth: 200, dockminheight: 200, dockmaxwidth: 400, dockmaxheight: 400 }, // minwidth, maxwidth, maxheight, minheight, dockminheight, dockminwidth, dockmaxheight, dockmaxwidth are optional // Default settings actions: { move: true, close: true, hide: true, resize: true, autosave: false, resizeX: true, resizeY: true }, // GOOD TO KNOW: // "undefined" close or "close:false" and "hide:true" doesn't destroy the instance of panel (it will be hidden only) // A window title title: 'Title for the panel', // Handlers (optional): destroy: function() { // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is destroyed }, make: function(el) { // @el {jQuery} a content of the window // @this {Instance} // this.meta {Object} a reference to window object // this.element {jQuery} a content element of the window // this.container {jQuery} a main content element of the window // this.main {Object} a reference to "Windows" component // this.width {Number} a width of window // this.height {Number} a height of the content of the window // this.x {Number} offset X // this.y {Number} offset Y // Methods: // this.setsize(width, height); // this.setcommand(cmd); Allowed commands: "close", "maximize", "resetmaximize", "togglemaximize", "minimize", "resetminimize", "toggleminimize", "resize", "move", "focus" // this.setoffset(x, y); // is executed when the window is making }, data: function(type, data, el) { // @type {String} // @data {Object} // @el {jQuery} a content element of the window // @this {Instance} // is executed when data are sent via SETTER('windows', 'send', 'TYPE', 'DATA') }, resize: function(width, height, el, x, y) { // @width {Number} // @height {Number} // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is resized }, move: function(x, y, el) { // @x {Number} // @y {Number} // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is moved }, service: function(counter, el) { // @counter {Number} count of calls // @el {jQuery} a content of the window // @this {Instance} // the component will execute this handler each 5 seconds } }; PUSH('panels', panel); ``` __Methods__: - `component.finditem(panel_id)` finds the specific panel according to `ID` - __NEW__ `component.show(panel_id)` shows a panel - __NEW__ `component.hide(panel_id)` hides a panel - __NEW__ `component.toggle(panel_id)` toggles a panel Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    YOUR CONTENT
    ``` ## j-DonutChart Source: https://forge.totaljs.es/en/components/donutchart/ Framework: jcomponent@20 Content-SHA256: a85060c929120e55e55dc8d15d00663b21c8e2391e868f7c15e74aef9c85871a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `tooltip` {Boolean} enables tooltip (default: `true`) - `format` {String} a template (Tangular) for rendering tooltip (default: `{{ value | format(0) }}`) - `presentation` {Boolean} enables presentation mode (default: `true`) - `select` {String} a path to method if a `value` is selected - `redraw` {String} a path to method if the chart is redrawn - `animate` {Boolean} enables/disables animations (default: `false`) - `size` {Number/String} width/height of donut (default: `0` = auto) or `string` is meant as a parent element - `highlight` {Boolean} enables/disables highlight of pieces (default: `true`) - `margin` {Number} adds a margin to `size` (default: `0`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    ``` ## j-DragDropElement Source: https://forge.totaljs.es/en/components/dragdropelement/ Framework: jcomponent@20 Content-SHA256: 807981153ff3aa03435fd846f8ecd4c24e27b43515d6e84c0d196623f9e40e84 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded On `drag` event displays modal inside given element with text `Drop & drop files here`. On moving dragged files away from element or dropping dragged files modal will hide. Also on `drop` event `exec` function is executed. __Configuration__ - `exec {String}` the component executes this method if the files are dropped - `function(files, e, component)` - `text {String}` text to display (default `empty`) __Example__ `` __Author__ - Michal Capo and Marek Dorotovič - [License](https://www.totaljs.com/license/) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Michal Capo. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-DragDropFiles Source: https://forge.totaljs.es/en/components/dragdropfiles/ Framework: jcomponent@20 Content-SHA256: 8c46d30337241db63e47997bf358136476873eecbb21e1aadb7c548d9d9feef6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `exec {String}` - the component executes this method if the files are dropped - `class {String}` - toggles class if the drag over is emitted - `click {Boolean}` - causes open file dialog when the user click on the element (default: `true`) - `accept {String}` - change accept attribute, e.g to only accept pdfs set to `application/pdf` (default: `*/*`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Drag & Drop files here ``` ## j-Draggable Source: https://forge.totaljs.es/en/components/draggable/ Framework: jcomponent@20 Content-SHA256: 8fca58b1186c96c0f6b49444c2e4e57370fc724c4caf273bb5c2bbb8b144c384 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple component which can capture drag & drop operation. __Configuration__: - `selector {String}` jQuery selector for capturing of element for "drag" - `exec {String}` a path to method `function(meta, el)` ```javascript function method(meta, el) { // meta.pageX; {Number} // meta.pageY; {Number} // meta.offsetX; {Number} // meta.offsetY; {Number} // meta.el; {jQuery element} dragged element // meta.target; {jQuery element} target (where the element has been dropped?) } ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    • Drag me: A
    • Drag me: B
    • Drag me: C
    • Drag me: D
    • Drag me: E
    Open Web Developer console ``` ## j-Drawer Source: https://forge.totaljs.es/en/components/drawer/ Framework: jcomponent@20 Content-SHA256: 3c84e9e0cf1f4338f3e093d5a50d674f3a9f2e4238347d600254c2843a60a460 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - `if {String}` condition, it's compared with the value within of `path` - `align {String}` alignment (default: `left`) - __NEW__: `width {Number}` a default width (default: `250`) - __NEW__: `widthlg {Number}` optional, width for large displays - __NEW__: `widthmd {Number}` optional, width for medium displays - __NEW__: `widthsm {Number}` optional, width for small displays - __NEW__: `widthxs {Number}` optional, width for extra small displays Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-DrawZone Source: https://forge.totaljs.es/en/components/drawzone/ Framework: jcomponent@20 Content-SHA256: 25636de0932ae5cd9b1bf1ba4bdc00241b7046615bf38ca8cfad6301d3a9b957 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can draw a zone (polygon). This component uses [OpenLayers](https://openlayers.org/) library with the [OpenStreetMap](https://www.openstreetmap.org/) map engine. __Configuration__: - `parent {String}` a parent element (default: `undefined`) - `height {Number}` a fixed (minimal) height (default: `200`) - `color {String}` a default color for polygon (default: `#fcba03`) - `zoom {Number}` a default zoom level (default: `11`) - `readonly {Boolean}` enables readonly mode (default: `false`) - `stroke {Number}` a stroke width (default: `2`) - `radius {Number}` a radius size of points in the polygon (default: `7`) - `center {String}` a default map position (default: `48.73702478789267,19.137712002562715`) - `opacity {Number}` determines the transparency of the polygon in percentage (default: `40`) - `required {Boolean}` optional (default: `false`) - `filter {String}` optional, CSS filter e.g. `filter:grayscale(90%) invert(100%)` (default: `null`) - __NEW__: `exec {String}` optional, a link to the `function(value, component)` (it will be executed when the value is changed) __Data-source__ needs to contain: ```js { points: [{ lat: 48.75152530164132, lng: 19.13902142954625 }, { lat: 48.726826662905296, lng: 19.123238694044034 }, ...] // polygon points color: '#FD391A', // optional zoom: 13 // optional } ``` __Methods__: - `component.clear([draw])` clears the polygon `@draw {Boolean}` (default: `false`) - `component.move(lat, lng)` moves the map to the specific position - `component.export(opt, callback(base64))` exports data into the picture - `opt.width {Number}` required - `opt.height {Number}` required - `opt.zoom {Number}` (default: `13`) - `opt.type {png|jpg}` (default: `png`) - `opt.quality {Number}` only for JPEG - `opt.points {Array Number}` - `opt.color {String}` (default: `config.color`) - `opt.radius {Number}` (default: `config.radius`) - `opt.opacity {Number}` (default: `config.opacity`) __Output__: - is extended by `center { lat: Number, lng: Number }` property __Good to know__: - `double click` on vertices (created point) will delete selected point Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Sirka & Dodo Marton. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Dropdown Source: https://forge.totaljs.es/en/components/dropdown/ Framework: jcomponent@20 Content-SHA256: bd49cbc7b3fecf4d860c76177f51ccdc5308e5595fd79d4ec22592be00a7fda0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required {Boolean}` (optional) enables "required" (default: `false`) - `items {String}` (optional) static items `key1|value1, key2 with value, key3|value` - `icon {String}` (optional) icon for label e.g. `home`, `cog`, etc. - `label {String}` (optional) label (default is HTML content) - `type {String}` (optional) can be `number` (converts `String` values to `Number`) - `datasource {String}` path to data-source (must be array) - `text {String}` determines a property name for text (in data-source), default: `name` - `value {String}` determines a property name for value (in data-source) default: `id` - `empty {String}` (optional) adds an empty field - `disabled {Boolean}` (optional) disables this component - `if {String}` (optional) arrow function as a condition for filtering of datasource, example: `if:n => !n.removed` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Category
    Inline options
    ``` ## j-DropdownCheckbox Source: https://forge.totaljs.es/en/components/dropdowncheckbox/ Framework: jcomponent@20 Content-SHA256: c4b6324f743c342871595181cafc79c894f3f64626e8ce80d3a1e1a28955c0cd Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - __NEW__ now supports dark mode __Configuration__: - `required {Boolean}` (optional) enables "required" (default: `false`) - `items {String}` (optional) static items `key1|value1, key2 with value, key3|value` - `icon {String}` (optional) icon for label without `ti-` e.g. `home`, `cog`, etc. - `checkicon {String}` (optional) check icon without `ti-`, (default: `check`). - `label {String}` (optional) label (default is HTML content) - `datasource {String}` path to data-source (must be array) - `text {String}` determines a property name for text (in data-source), default: `name` - `value {String}` determines a property name for value (in data-source) default :`id` - `disabled {Boolean}` (optional) disables this component - `cleaner {Boolean}` (optional) removes non-exist values (default: `true`) - `limit {Number}` (optional) sets a limit for selected items (default: `0`) - `visible {Number}` (optional) sets a maximum visible items then show `X selected` (default: `0`) - `selectedtext {String}` (optional) sets a message for maximum visible items e.g. `{0} selected from {1}` (default: `{0} selected`) - `alltext {String}` (optional) when all items are selected this is showed (default: `All selected` you can disable it with `null`) - `placeholder {String}` (optional) sets a text for placeholder Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    My label
    My label
    ``` ## j-DropdownList Source: https://forge.totaljs.es/en/components/dropdownlist/ Framework: jcomponent@20 Content-SHA256: 1db79c7af8640781c39b6ac3e24f56923b5e6d9f2573a25b397d802063937a70 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required {Boolean}` enables validation (default: `false`) - `datasource {String}` a link to the `path {Array}` or inline defined items `key1|value1,key2 with value,key3|value` - `limit {Number}` a maximum count of selected items (default: `0` disabled) - `disabled {Boolean}` disables component - `dirplaceholder {String}` placeholder for `j-Directory` - `dirsearch {Boolean}` disables searching in `j-Directory` (default: `false`) - `check {Boolean}` compares selected values with datasource (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Category
    Inline options
    ``` ## j-DropFiles Source: https://forge.totaljs.es/en/components/dropfiles/ Framework: jcomponent@20 Content-SHA256: 8d44e9b9333463962ac80fae9ad54e6343facd02fc223b621298302d10da2402 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - captures all dropped files into the `window` - must be located under `` element due to positioning __Configuration__: - `exec {String}` a link to the `function(files, e)` - __NEW__: `check {String}` optional, a link to the `function(e)` that must return `true` (allows drag&drop) or `false` (disallow) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Duplicator Source: https://forge.totaljs.es/en/components/duplicator/ Framework: jcomponent@20 Content-SHA256: 7046aec278139d27347129333f907c179e69165264a31901d002256e9dc66fc8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __BETA VERSION__. This component is a bit special component because it can duplicate same content several times with diffferent data-source. Imaging some text editor with tabs which each tab contains different content. For this case is targeted `j-Duplicator`. Follow example. __Configuration__: - `datasource` {Array} must contain array of content for duplicating - `url` {String} optional, can contain a link to external `template` __without `JavaScript`__ __Good to know__: This component appends `.scopename()` function to each item of Array for handling of scope and each content is wrapped in to the independent `scope` with direct reference to main source. ### Advanced templating ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    Duplicator

    ``` ## j-DynamicValue Source: https://forge.totaljs.es/en/components/dynamicvalue/ Framework: jcomponent@20 Content-SHA256: aa1dc328680acd2bcb639e4e721cd6f8601b95d12052c8983cd0f54265efc04e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component is very special component. It can keep a value for example `Number` and at the same it can render another readable `text`. This component is optimized for dynamic usage, so it needs to be linked with another component or part. - `icon {String}` icon for label e.g. home, cog, etc. - `label {String}` label (default is HTML content) - `icon2 {String}` icon in the right box e.g. home, cog, etc. (default: `angle-down`) - `placeholder {String}` adds a placeholder text - `disabled {Boolean}` disables this component - `find {String}` __important__ link to `function(el, next(value))` for binding a new value - `read {String}` a link to `function(value, next(response))` for binding a readable `text` - `url {String}` tries to bind a value via `AJAX()`, argument `{0}` in URL is replaced by the value - `html {String}` Tangular template for rendering a value (default: `{{ name }}`) - `remap {String}` a remap function (default: `null`), example: `value.length ? value[0] : null` - `required {Boolean}` enables "required" (default: `false`) - `bind {String}` a path to method or variable where will be binded loaded value (optional) - `dirsource {String}` a link to method `function(search, next(items_arr))` or __NEW__: can contain URL for search in fhe form `GET /api/partners/?q={0}` - `dircustom {String/Boolean}` can contain a path to function(val, next(new_val)) or can be Boolean. This option can enable adding a custom value (value not defined in data-source) - `dirrender {String}` a path to `function(item, text)` (must return HTML for j-Directory), this function can affect list of items in j-Directory - `dirminwidth {Number}` a minimum width for j-Directory, (default: `200`) - `dirmaxwidth {Number}` a maximum width for j-Directory - `dirplaceholder {String}` a placeholder for j-Directory - `dirempty {String}` adds an empty field for j-Directory - `dirkey {String}` a key name for reading of text in dirsource (default: `name`) - `dirvalue {String}` a key name for reading of value in dirsource (default: `id`) - `onresponse {String}` a path to property or `function(response)`, executed if the response is processed (default: `undefined`) - __NEW__ `tapi {Boolean}` enables calling `TAPI()` insteadof `AJAX()` (default: false) ### AJAX usage If the `value` will be changed then the component performs `AJAX` call automatically. ```html ``` ### Inline usage If the `value` will be changed then the component performs `config.exec` for obtaining a readable text of a value. ```html ``` __Good to know__: - `component.response` contains a raw response from the result Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    User
    ``` ## j-DynamicValueList Source: https://forge.totaljs.es/en/components/dynamicvaluelist/ Framework: jcomponent@20 Content-SHA256: c4e030d56b17f6696fa824cd0e7c72bc502ae014845a64212cfdc77ebf0d25db Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component is very special component. It can keep values for example `Number` and at the same it can render another readable `text`. This component is optimized for dynamic usage, so it needs to be linked with another component or part. This component works with array. __Configuration__: - `icon {String}` icon for label e.g. home, cog, etc. - `label {String}` label (default is HTML content) - `icon2 {String}` icon in the right box e.g. home, cog, etc. (default: `angle-down`) - `placeholder {String}` adds a placeholder text - `disabled {Boolean}` disables this component - `find {String}` __important__ link to `function(el, next(value))` for binding a new value - `read {String}` a link to `function(array_of_values, next(array_response))` for binding a readable `text` - `url {String}` tries to bind a value via `AJAX()`, argument `{0}` in URL is replaced by the value - `html {String}` Tangular template for rendering a value (default: `{{ name }}`) - `remap {String}` a remap function (default: `null`), example: `value.length ? value[0] : null` - `required {Boolean}` enables "required" (default: `false`) - `bind {String}` a path to method or variable where will be binded loaded value (optional) - `dirsource {String}` a link to method `function(search_string, next(items_arr))` or __NEW__: can contain URL for search in fhe form `GET /api/partners/?q={0}` - `dircustom {String/Boolean}` can contain a path to function(val, next(new_val)) or can be Boolean. This option can enable adding a custom value (value not defined in data-source) - `dirrender {String}` a path to `function(item, text)` (must return HTML for j-Directory), this function can affect list of items in j-Directory - `dirminwidth {Number}` a minimum width for j-Directory, (default: `200`) - `dirmaxwidth {Number}` a maximum width for j-Directory - `dirplaceholder {String}` a placeholder for j-Directory - `dirempty {String}` adds an empty field for j-Directory - `dirkey {String}` a key name for reading of text in dirsource (default: `name`) - `dirvalue {String}` a key name for reading of value in dirsource (default: `id`) - `key {String}` a primary key name (default: a value from `dirvalue`) - __NEW__ `tapi {Boolean}` enables calling `TAPI()` insteadof `AJAX()` (default: false) ### AJAX usage If the `value` will be changed then the component performs `AJAX` call automatically. Server must response with `Array`. ```html ``` ### Inline usage If the `value` will be changed then the component performs `config.exec` for obtaining a readable text of a value. ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Users
    ``` ## j-EAN13 Source: https://forge.totaljs.es/en/components/ean13/ Framework: jcomponent@20 Content-SHA256: 7bb7ca516a0a30faab2507d745c8eda850e5cc9d44bbdefd8ea952ceed3bf4e1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component will draw EAN-13 barcode according to the path value. - Included library (Johannes Mittendorfer, MIT license) --- __Configuration__: - `width {Number}` barcode width, height is automatically calculated (default: `200`) - `padright {Boolean}`if `true`, it fills the value `0` from the right side and `false` from the left side Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Edit Source: https://forge.totaljs.es/en/components/edit/ Framework: jcomponent@20 Content-SHA256: 932bda43cc5628615fe094453501b336f6f999201fbf48cc755da49a475eb1cb Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component enables `contenteditable` attribute for elements with `edit` or `edit2` classes. - singleton - put the component under ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Name:
    Email:
    @
    HTML:
    ``` ## j-Editable Source: https://forge.totaljs.es/en/components/editable/ Framework: jcomponent@20 Content-SHA256: 5e8bdef0daa2b7b2bf0a4f18bd5d64b65d10a2fa39449bf17f5cd5b8d3af2157 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can edit all elements with `editable` class. It works with `data-bind` or dynamic values. Learn more from example. __Configuration__: - `autofocus` {Boolean} focuses first item (default: `false`) - `validate` {Boolean} can disable validation (default: `true`) - `disabled` {Boolean} can disable editing (it adds `ui-editable-disabled` and `ui-editable-enabled` class), default: `false` - `changed` {String} optional, a link to a method or path --> it will contain the object with changed values only - `enter` {String} optional, a link to a method `method(path, value, el)`, the method is executed if the user presses `ENTER` - `escape` {String} optional, a link to a method `method(path, value, el)`, the method is executed if the user presses `ESC` - `can` {String} optional, a link to method `method(opt, el)` must return `boolean`, it means `can edit?` - `error` {String} optional, a link to method `method(el, isInvalid, meta)` is evaluated when the item is invalid and vice-versa - __NEW__ `class {String}` optional, adds a class name in the form `ui-editable-CLASS` (default: `default`) --- `data-editable` attribute describes behaviour: - `path` {String} a __relative path__ to property (can be inherited from `data-bind` automatically) - `required` {Boolean} optional, enables "required" (default: `false`) - `type` {String} optional, can be `string` (default), `date`, `number`, `boolean`, `email` or `html` __NEW__ `tags` - `can` {String} optional, a path to `function(opt, el)` must return `boolean`, it means `can edit?` - `save` {String} optional, a path to `function(opt, accepted(boolean))`, `accepted` function must be evaluated - `format` {String} optional, a format for `date`, default: `yyyy-MM-dd` - `dirsource` {String} optional, path to a data-source - `dircustom` {String/Boolean} optional, can contain a path to `function(val, next(new_val))` or can be `Boolean`. This option can enable adding a custom value (value not defined in data-source) - `dirrender` {String} optional, a path to `function(item, text)` (must return HTML for `j-Directory`), this function can affect list of items in `j-Directory` - `dirminwidth` {Number} optional, a minimum width for `j-Directory`, default: `200` - `dirmaxwidth` {Number} optional, a maximum width for `j-Directory` - `dirplaceholder` {String} optional, a placeholder for `j-Directory` - `dirempty` {String} optional, adds an empty field for `j-Directory` - `dirkey` {String} optional, a key name for reading of `text` in `dirsource` (default: `name`) - `dirvalue` {String} optional, a key name for reading of `value` in `dirsource` (default: `id`) - `dirsearch` {Boolean} optional, can disable search for `j-Directory` - `autosource` {String} a path to `search` function in `autocomplete`, `function(search, render(arr))` - `autovalue` {String} a property path for the value in `autosource` - `maxlength` {Number} a maxlength - `minvalue` {Number} a min. value for number type (default: `undefined`) - `maxvalue` {Number} a max. value for number type (default: `undefined`) - `rebind` {Boolean} if `true` rebinds `data-bind` on this element only (default: `0`) - `validate` {String} optional, a condition for validating of value, can contain a link to `function(value)` or `!!value.match(/[a-z]+/)` - `multiline` {Boolean} optional, enables multiline + appends class `editable-multiline` (`inline-block` + `width:100%`) when it's editing (default: `false`) - `raw` {Boolean} optional, when `true` then the current HTML content will be as a placeholder if the value is `nullable` (default: `true`) - `accept` {String} optional, a condition for accepting of value, can contain a link to `function(value)` or `!!value.match(/[a-z]+/)` is similar to `validate` - `empty` {String} optional, enables empty value and can contain empty label or `1` or `true` for auto `rebind` of binder - `invalid` {String} optional, a link to method `method(el, isInvalid, meta)` is evaluated when the item is invalid and vice-versa __Methods__: - __NEW__: `component.changed()` returns an object with changed data __Good to know__: - if the user presses some `key` then the editable element will contain `keypressed` class as long as they haven't left the control - each changed element will contain class `changed` - if the component changes some values, the main element will contain class `ui-editable-changed` - if the element has `data-bind` with `empty`, it will be cleared after focus - __NEW__ now supports `tags` type. For now supports only with `rebind` and `data-bind`. (data-bind `template` with `{jQuery selector}` works from `+v18`) - __NEW__ if the element (__or parent, or parent of parent__) contains attribute `data-disabled="1"`, the control will be disabled - __NEW__ hidden and disabled elements won't be validated Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Name:
    Email:
    Nickname:
    Framework:
    Country:
    Date:
    ``` ## j-ElementID Source: https://forge.totaljs.es/en/components/elementid/ Framework: jcomponent@20 Content-SHA256: c71e940a7509ba88a97dc0f76cfa1d7bbcbd7839e88e7fad2014916ecc11b4c1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component fills the `data-id` attribute with the value read from the path. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Check the data-id attribute via Web Developer tools. ``` ## j-Emoji Source: https://forge.totaljs.es/en/components/emoji/ Framework: jcomponent@20 Content-SHA256: 63148ed1835fb8a2760513e89d5e83a91adc54e4d7c7499bea812eb132bada1a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Using UTF emoji - Personal history with frequently used emoticons - Great search tool - Changeable skin tones __Configuration__: - `categories {String}` change emoticons in categories. Use unicode without special characters (default: `128342,128578,128161,127944,128008,128690,128172,127828,127937`) - `height {Number}` set component height (default: `295`) - `history {Number}` history limit for frequently used emoticons (default: `49`) - `empty {String}` a message when no emoticons are found (default: `No emoji match your search`) - `emptyemoji {Number}` change emoticon when no emoticons are found. Use unicode without special characters (default: `128557`) - `speed {Number}` scroll speed in ms (default: `500`) - `footer {String}` footer message (default: `Choose skin tone`) - `toneemoji {String}` skin tones emoticon. Use unicode without special characters (default: `9995`) - `search {String}` a placeholder for search field (default: `Search`) __Good to know__: - This component implements `FUNC.parseASCI(string)` function. The function will parse string and transform text like `:D` or `:joy:` into UTF emoticons. ```javascript var message = 'This one was good. :joy: See you soon :P'; console.log(FUNC.parseASCI(message)); // This one was good. 😂 See you soon 😛 ``` ## Usage ```javascript var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align `left` (default), `center` or `right` // opt.position {String} : position `top` (default) or `bottom` opt.element = YOUR_ELEMENT; // or if you want to use a fixed position: // opt.x {Number} : `x` position // opt.y {Number} : `y` position opt.callback = function(emoji) { console.log(emoji); // callback parameter has String.fromCodePoint() value }; SETTER('emoji/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-EmojiButton Source: https://forge.totaljs.es/en/components/emojibutton/ Framework: jcomponent@20 Content-SHA256: 057a59a5001d4dc96f6fd1c118a347b9e5434ae256353a8628dd09dc99a2bf6e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Component is __singleton__ - Supports __Dark theme__ - It uses `j-Emoji` __Configuration__: - `default` a default color (default: `#FFFFFF`) - `align` align for j-ColorPicker (default: `left`) - `position` position for j-ColorPicker (default: `top`) - `offsetX` offset-x for j-ColorPicker (default: `0`) - `offsetY` offset-y for j-ColorPicker (default: `0`) - `disabled` can disabled this component (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Empty Source: https://forge.totaljs.es/en/components/empty/ Framework: jcomponent@20 Content-SHA256: 61388ac2a0375b169fb21a7aa1a421bc67a23d77f6e6fc7e04bc1d2ced787240 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - `path` must contain a data-source which will be watched __Configuration__: - `icon {String}` a default icon (default: `ti ti-database`) - `parent {String}` a parent container which sets a minimal height (default: `parent`) - `height {Number}` height size (if you don't want to use `parent`, default: `undefined`) - `margin {Number}` a margin (default: `0`) - `topoffset {Boolean}` applies `element.offset().top` as a margin (default: `false`) - `topposition {Boolean}` applies `element.position().top` as a margin (default: `false`) - __NEW__ `wait {Boolean}` waits for the data (default: `false`) __Use-case 1__: ```html ``` __Use-case 2__: ```html `. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-EmptyInline Source: https://forge.totaljs.es/en/components/emptyinline/ Framework: jcomponent@20 Content-SHA256: cadd4d596ef0d89a1525ee97c98a714d9c47f4b27ae29b40320290fa2e88228e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component will display text inside the element if the value is empty or the array doesn't contain an item. __Configuration__: - `icon {String}` a default icon (default: `ti ti-ban`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Without pictures ``` ## j-Enter Source: https://forge.totaljs.es/en/components/enter/ Framework: jcomponent@20 Content-SHA256: 43f68249e264bc13ba103db4b35ea697808b5ab84d1012e715dd3e9819e36618 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component evaluates some method if the user press `enter`. Important: component finds all `input` elements and performs `CAN()` for the path. __Configuration__: - `exec {String}` a method name for execution - `validate {Boolean}` enables validate (default: `true`) - `trigger {String}` can contain a selector for triggering a real `click` event (default: `button[name="submit"]`) - `timeout {Number}` a timeout as a prevention for multi-press of `enter` key (default: `1500`) - __NEW__ `delay {Number}` a delay for submitting data (default: `500` ms) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Login

    Password
    ``` ## j-Enterbox Source: https://forge.totaljs.es/en/components/enterbox/ Framework: jcomponent@20 Content-SHA256: 58464634463f50f166381db1834bce694716a5a6fc0abeab75e825dffcea1c88 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple EnterBox. Each value needs to be confirmed via `enter` key or clicking on the button. __Configuration__: - `maxlength {Number}` optional, a maximum length of value (default: `50`) - `icon {String}` icon - `placeholder {String}` a placeholder for the input control - `exec {String}` optional, a link to a function in the window scope (otherwise `data-jc-path` is required) - `button {String}` adds a label to the button (default: `empty`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Error Source: https://forge.totaljs.es/en/components/error/ Framework: jcomponent@20 Content-SHA256: 88efcbf55060f16869e3614e6b98ea2b2aadf80e9afb3c15532ae977d8996e0c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - errors are displayed only if the path contains an array in the form below: ```js [ { error: 'Error Message 1' }, { error: 'Error Message 2' } ] ``` __Configuration__: - `icon {String}` an error icon (default: `warning`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ErrorHandler Source: https://forge.totaljs.es/en/components/errorhandler/ Framework: jcomponent@20 Content-SHA256: d0eff3067a30ff275b0b6037ad8ad0c00145d6e3a7792849ada3138938f37047 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component captures the `ON('ERROR', function(err` event trigger from the `ERROR()` method and tries to display form more comfortably. - singleton __Configuration__: - `keywords {String}` which will be searched in the error messages (default value: `401=login`) - must be in the form `search1=target_property,search2=target_property` - `exec {String}` a link to the `function(response)`, output: - `response.items {String Array}` - `response.message {String}` - `response.keyword_target_property {Boolean}` optional, according to the `keywords` settings - __NEW__: `offline {String}` an offline message, default: `No internet connection` The component tries using `j-Message`, `j-Snackbar`, `j-NotifyBar` or `j-Notify` for displaying of errors if you don't have defined `exec` configuration. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Exec Source: https://forge.totaljs.es/en/components/exec/ Framework: jcomponent@20 Content-SHA256: f991dd13f60f1964d740611e087fa98613535d4f28b5458f8eff001006486c11 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component executes a method when the user clicks on the same element with the `exec`, `exec2`, or `exec3` class. More information is below. The component is a singleton, and it works for the whole HTML document. __Elements__: - Elements can contain `data-exec` attribut with a method name which will be execute when the user click on the element. - Elements can contain `data-href` attribute and the component performs `REDIRECT()`. __Attributes__: - `data-exec="METHOD_NAME"` executes a method when user clicks (supports plugin calls via `?` character) - `data-prevent="true"` prevents continuing in the `click` event - `data-href="URL"` performs `REDIRECT()` __Attributes for the double click__: - `data-exec2="METHOD_NAME"` executes a method when user clicks (supports plugin calls via `?` character) - `data-prevent2="true"` prevents continuing in the `click` event - `data-href2="URL"` performs `REDIRECT()` __Attributes for the context-menu__: - `data-exec3="METHOD_NAME"` executes a method when user clicks (supports plugin calls via `?` character) - `data-href3="URL"` performs `REDIRECT()` __Good to know__: - the component executes a target function in the form `function(element, event)` - `data-exec=`, `data-exec2=`, `data-exec3=` can contain `@METHOD_NAME` that will be executed in the current component plugin calls `component/METHOD_NAME(element, e)` __NEW: Extensions__: ```js SETTER('exec/register', function(exec, el, e, type) { // @exec {String} a value from data-exec // @el {jQuery element} // @e {Event} // @type {String} empty '': click, '2': double-click '3': context menu // registers a new extension if (exec.charAt(0) === '/') { EXEC('customplugin/' + exec.substring(1), el, e); // "return true" stops the next processing of Exec return true; } }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html 1 2

    3

    4
    5
    ``` ## j-Expander Source: https://forge.totaljs.es/en/components/expander/ Framework: jcomponent@20 Content-SHA256: 6b6bd4062f07ae1775662ed6d936d0297ea69cea8ffa847a17057ebef40541ef Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `expand {Boolean}` expands content (default: `false`) - __NEW__ `height {Number}` a max. height (default: `150`) - __NEW__ `iconup {String}` icon up (default: `ti-angle-double-up`) - __NEW__ `icondown {String}` icon down (default: `ti-angle-double-down`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html BEG
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    END
    ``` ## j-ExpansionPanel Source: https://forge.totaljs.es/en/components/expansionpanel/ Framework: jcomponent@20 Content-SHA256: d43385300569704d6c795effbbfd366af1848cddcac9a6dedf8053029b9f1d8e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `multiple {Boolean}` allows multiple opening of panels (default: `false`) - `icon {String}` a label icon for every panel (default: `ti ti-caret-right`) ### How to define panels? ```html ``` __Attributes__: - `data-id` __required__, it must contain an identifier of the panel - `title` __required__, it must contain a panel name - `icon` optional, it can contain Total.js Icon (default: `config.icon`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Extend Source: https://forge.totaljs.es/en/components/extend/ Framework: jcomponent@20 Content-SHA256: 3246ce39351407d1048c86711b27c1346f4aa1a0dcbfedbaa3c0dee3c0d4f644 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component is a specific component with powerful functionality. When the component is evaluated then it executes two events in the form below. The component can be helpful in web applications that can be dynamically extended. __Configuration__: - `name {String}` A name for extend, the component will emit `ON('extend_' + name)` event The component emits only two events that you can catch somewhere: ```js // NAME: is defined in the component configuration ON('extend_NAME', function(opt) { // opt.name {String} with a value according to the "config.name" // opt.component {Instance of j-Extend} // opt.element {jQuery element} // opt.dom {Node} }); ON('extend', function(opt) { // opt.name {String} with a value according to the "config.name" // opt.component {Instance of j-Extend} // opt.element {jQuery element} // opt.dom {Node} }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Pete Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-FaIcons Source: https://forge.totaljs.es/en/components/faicons/ Framework: jcomponent@20 Content-SHA256: 9a6c2b7adbfa219b1f139ac74c487140658b4834fac3d75a506b1ec62589dc9e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Font-Awesome Icons - singleton - supports pro icons __Configuration__: - `search {String}` a placeholder for search field (default: `Search`) ## Usage ```js var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align `left` (default), `center` or `right` // opt.position {String} : position `top` (default) or `bottom` // opt.empty {Boolean} : adds empty icon (default: false) opt.element = YOUR_ELEMENT; // or if you want to use a fixed position: // opt.x {Number} : `x` position // opt.y {Number} : `y` position opt.callback = function(icon) { console.log(icon); }; SETTER('faicons/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-FaIconsButton Source: https://forge.totaljs.es/en/components/faiconsbutton/ Framework: jcomponent@20 Content-SHA256: a9680c0a55081a8b1ed15b9e6e4913306a0c7806948004f4ba8972dfb708e834 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - it uses `j-FaIcons` __Configuration__: - `default {String}` a default color (default: `#FFFFFF`) - `align {String}` align for j-ColorPicker (default: `left`) - `position {String}` position for j-ColorPicker (default: `top`) - `offsetX {Number}` offset-x for j-ColorPicker (default: `0`) - `offsetY {Number}` offset-y for j-ColorPicker (default: `0`) - `disabled {Boolean}` can disabled this component (default: `false`) - `empty {Boolean}` adds an empty icon (default: `true`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-FaviconUnread Source: https://forge.totaljs.es/en/components/faviconunread/ Framework: jcomponent@20 Content-SHA256: e85bbffc5ac16797818516a34d4f92c9d67ebfeeade3134935cbbdb3c88386d1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__ - `fg {String}` foreground color (default: `white`) - `bg {String}` backround color (default: `red`) - `selector {String}` optional, selector for a specific image element (default: `favicon` in `head` of HTML) - __NEW__ `badge {Boolean}` optional, enables usage of `navigator.setAppBadge()` (default: `true`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Features Source: https://forge.totaljs.es/en/components/features/ Framework: jcomponent@20 Content-SHA256: 80d4d34e5615578831bf6c9dd696eb7b313fc9e371955e7156ceebdba94922c5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - only for desktop computers - singleton - works with Bootstrap Grid System ### Methods Method: `component.open(opt)` - `opt.placeholder {String}` a placeholder for search input (default: `config.placeholder`) - `opt.items {Object Array}` with list of features (required): - `name {String}` a feature name - `icon {String}` (optional) icon without `fa-` - `keywords {String}` (optional) additional keywords for searching - `value {Object/String/Number}` a value - `opt.scrolltop {Boolean}` scrolls to top until it's displaying the window (default: `false`) - `opt.callback(selected) {Function}` a callback which is called when the user performs click for some feature. `selected` argument contains selected item. Method: `component.hide()` __Configuration__: - `placeholder {String}` a placeholder for the search input - `height {Number}` height of list item (optional, default `35`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FeedbackButton Source: https://forge.totaljs.es/en/components/feedbackbutton/ Framework: jcomponent@20 Content-SHA256: 7d0cb03032c3ca7c10a308989a3932d7a1f17f7e8a2eb820397c6d70a4be71f2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - universal usage - supports background-color change - supports left or right position - supports expiration time __Configuration__: - `color {String}` background color setting (default: `#333`) - `position {String}` a position, can be `left` or `right` (default: `right`) - `expire {String}` sets the expiration date (default: `3 days`) - `icon {String}` a font-awesome icon name (default: `fa fa-comment-alt`) - `animate {Boolean}` enables animation (default: `true`) - `label {String}` a label for the button (default: `Feedback`) - `url {String}` a link to URL address which will be open if the user click on the button - or `exec {String}` a link to method `function(hide)` which will be executed after click on the button Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Jozef Marton. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FileBrowser Source: https://forge.totaljs.es/en/components/filebrowser/ Framework: jcomponent@20 Content-SHA256: 8669e92a3c5d0bd8069ed75378492a6c3111e62f6e69162f9060a3776075daac Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component will open a file browser and returns selected files. __Methods__: - `component.open(opt)` - opens file browser - `opt.multiple {Boolean}` enables multiple files (default: `false`) - `opt.accept {String}` allows only specified content-type (default: `undefined`) - `opt.callback {Function(files, e)}` a callback Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html OPEN FILE ``` ## j-FileReader Source: https://forge.totaljs.es/en/components/filereader/ Framework: jcomponent@20 Content-SHA256: 5c394280e9c16c796e245f9c9667eb9d2b862d74ce3500d6ec431a99a3b68d3f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - only for text files __Methods__: - `component.open(opt)` - opens file browser - `opt.multiple {Boolean}` enables multiple files (default: `false`) - `opt.accept {String}` allows only specified content-type (default: `undefined`) - `opt.base64 {Boolean}` reads a file in Base64 encoding (default: `false`) - __NEW__: `opt.files {HTTP Files}` reads files e.g. from Drag & Drop - `opt.callback {Function(file)}` a callback - __NEW__: `opt.progress {Function(percentage, file)}` optional ```js var opt = {}; opt.accept = 'text/*'; // opt.files = e.files; opt.callback = function(file) { console.log(file); }; SETTER('filereader/open', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html OPEN FILE ``` ## j-FileSaver Source: https://forge.totaljs.es/en/components/filesaver/ Framework: jcomponent@20 Content-SHA256: b7bd27ae5922a8ec9f48cb64cd5c34e50035deb3b15170a503d212a3a1c6634a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component is a wrapper for the [FileSaver.js library](https://github.com/eligrey/FileSaver.js/). With this component you can easily save locally generated files directly in the web browser. - singleton ### Methods - `component.save(filename, string/blob, [contentType])` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FileUpload Source: https://forge.totaljs.es/en/components/fileupload/ Framework: jcomponent@20 Content-SHA256: 7121cf1c353c6ba4843c67c5a0d9e02911090d8f3f6584cfb37726f014d965ec Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Is very helpful component for uploading e.g. profile photos. I consider this component as inline file upload. Look into the html source. The component uploads files via `multipart/form-data`. __Configuration__: - `url` {String} a target URL for the uploading - `accept` {String} (optional) can contain a content-type frow browsing files e.g. `image/*` - `multiple` enables `multiple` files upload (default: `false`) - `array` {Boolean} enables pushing an uploaded value to array (`path` must be the array) - `label` {String} (optional) changes a current `innerHTML` (default: `innerHTML`) - `disabled` {Boolean} disables __Friendly components__: This component works with `loading` (when the file is uploading) and `message` (when server throws an error) component. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Upload ``` ## j-FileUploader Source: https://forge.totaljs.es/en/components/fileuploader/ Framework: jcomponent@20 Content-SHA256: 0bf0e5010e88a88d8ab03a2096071e4d462904f248953f0ebfda53e2140a173c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple component for uploading files. It supports auto-resizing images. - __IMPORTANT__: in jComponent v20, the value of `opt.url` must be in the form `POST /url/` __Configuration__: - `url {String}` a default URL address for uploading __Methods__: - `fileuploader/upload(opt)` shows a file dialog - `opt.url {String}` __important__ URL where will be image uploaded - `opt.callback(response, errors) {Function}` a callback __important__ - `opt.multiple {Boolean}` supports multiple files (default: `false`) - `opt.progress(percentage)` {Function} - `opt.accept {String}` accept type (default: `*/*`) - `opt.prefix {String}` a name prefix ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FileUploadList Source: https://forge.totaljs.es/en/components/fileuploadlist/ Framework: jcomponent@20 Content-SHA256: 5ce004b5f58d35be3b8f602313b8706c516c6198990dedce7b766351dbb9dda1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can upload files and the result adds into the model. Model must be the `array`. __Configuration__: - `url` {String} URL to upload (default: `/api/upload/`) - `accept` {String} Optional, a content type for filtering files e.g. `image/*` - `multiple` {Boolean} Optional, enables multiple files uploading (default: `true`) - `progress` {String} a path to `function(percentage)` - `text` {String} a key name for rendering of `text` value (default: `name`) __Model__: Server must return `Array` in the form below: ```javascript [ { name: String, length: Number, url: String } ] ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-FixedModal Source: https://forge.totaljs.es/en/components/fixedmodal/ Framework: jcomponent@20 Content-SHA256: 761d418e38615c750d7232c782fea7deac80d87579d1aa74204d98fe7128bf34 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Works only with `+v17` - The component moves the content of this component under `` tag (because of positioning) __Configuration__: - `width {Number}` modal max-width - `if {String}` condition for showing of the modal, it's compared with the value within of `path` - `reload {String}` link to a global function and it's executed if the form is showing - `submit {String}` link to a global function and it's executed if the submit button is pressed - `cancel {String}` link to a global function and it's executed if the cancel button is pressed - `enter {Boolean}` captures `enter` key automatically and performs submit (default: `false`) - `autofocus {Boolean/String}` can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `zindex {Number}` can affect z-index (default: `12`) __Good to know__: The content of the `j-FixedModal` is divided to 3 parts: `header`, `body` and `footer`. Each part must be defined. The component adds CSS classes to each part, for example first `div` will contain `ui-fixedmodal-header`, second `ui-fixedmodal-body` and third `ui-fixedmodal-footer`. --- This component supports dynamic evaluation of the content of `
    ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolores illum quaerat quisquam voluptatem soluta necessitatibus accusamus possimus consequuntur nihil nam. Fugiat unde nemo, ratione magnam. Placeat minima, fugiat quo a. Esse commodi temporibus quos numquam suscipit! Mollitia accusantium temporibus nisi quibusdam alias provident rerum impedit, fuga officia non illum unde magni recusandae eos ducimus, maiores, dolore voluptates reiciendis accusamus odit quo ipsum veniam. Consectetur vitae minima dolor, possimus earum quae necessitatibus quia! Ex reiciendis nam eius adipisci harum ad. Atque fuga sint deleniti repellat quisquam. Deserunt laudantium maiores dicta, aliquid quidem id veritatis sint rem iusto. Ab similique culpa quasi! ``` ## j-FloatingBox Source: https://forge.totaljs.es/en/components/floatingbox/ Framework: jcomponent@20 Content-SHA256: 95f26345022d440ded35794e13b782909a3a37f0abcfbd6a19f2b6b970106daf Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ __Configuration__: - `zindex {Number}` a default z-index for forms (default: `10`) __Methods__: - `component.show(opt)` shows a box - `opt.id {String}` __required__ - a box identifier - `opt.element {HTML Element}` __required__ - target element - or you can use absolute position: - `opt.x {Number}` - `opt.y {Number}` - `opt.offsetX {Number}` affects offset X - `opt.offsetY {Number}` affects offset Y - `opt.align {String}` align `left` (default), `center` or `right` - `opt.position {String}` align `top` (default), `bottom` - `opt.minwidth {Number}` - `opt.maxwidth {Number}` - `opt.mouseleave {String}` a link to the method, it's executed when the mouse cursor leaves the box `function(e, close)}` - `opt.autofocus {Boolean}` tries to focus first input/textarea - `opt.hide {String}` a link to the method `function(box_element)` - `opt.show {String}` a link to the method `function(box_element)` - `opt.autohide {Boolean}` enables hiding a box after clicking on it - `opt.delay {Number}` a simple delay for rendering (default: `0`) - `opt.scrolltop {Boolean}` it deducts scroll top position from the current offset Y (default: `false`) - `opt.url {String}` optional, URL address for the content - `opt.path {String}` will replace all `~PATH~` phrases in the downloaded template - `opt.ID {String}` will replace all `~ID~` phrases in the downloaded template - `component.hide()` hides the last open box - `component.hide([box_id])` hides the specific box and its all nested boxes - `component.hide(true)` hides all boxes ### Boxes ```html
    Your content
    ``` __Configuration__: - `init {String}` a link to the method, it's executed when the box is initialized the first time `function(element)` - `reload {String}` a link to the method `function(element)` - `hide {String}` a link to the method, it's executed when the box is going to hide `function(element)` - `scope {String}` a custom scope/plugin name - `zindex {Number}` a custom z-index for this box Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Box 1



    Box 2



    Show box 3
    Box 3
    Show box 1
    Show box 2
    Show box 3
    ``` ## j-FloatingInput Source: https://forge.totaljs.es/en/components/floatinginput/ Framework: jcomponent@20 Content-SHA256: 1d8849edd82125c5ed13f81986cda4fa2656e6edee9974ca9a3851ffb5d4dfe2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - supports __dark mode__ __Methods__: Method: `component.show(options)` - `options.element {Element/jQuery Element}` - `options.offsetX {Number}` optional, `x` offset (default: `0`) - `options.offsetY {Number}` optional, `y` offset (default: `0`) - `options.offsetWidth {Number}` optional, `width` offset (default: `0`) - `options.placeholder {String}` optional, a placeholder for search field - `options.minwidth {Number}` optional, a minimal width, default `200` - `options.maxwidth {Number}` optional, a maximal width, default `infinite` - `options.maxlength {Number}` optional, a maximal length of value, default `50` - `options.callback(value, element) {Function}` is triggered when the user clicks on the item - `options.icon {String}` optional, Font-Awesome icon - `options.close {Function}` optional, can determine closing of panel - `options.align {String}` optional, `left` (default), `right` or `center` - `options.value {String}` optional, a default value for the input - `options.position {String}` optional, `top` (default), `bottom` - `options.summary {String}` additional help content - `options.monospace {Boolean}` enables monospace font - `options.select {Boolean}` selects text - __NEW__ `options.multiline {Boolean}` enables multiline - __NEW__ `options.height {Number}` a height for multiline (default: `100`) Method: `component.hide()` __Configuration__: - `placeholder` - a placeholder for the input Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FloatingPanel Source: https://forge.totaljs.es/en/components/floatingpanel/ Framework: jcomponent@20 Content-SHA256: 45ba6e92b0aa5454f04971ad8204afac4a82864bd9ebc1e20173c2fc295f873a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - supports custom scrollbars - supports __dark mode__ __Methods__: Method: `component.show(options)` - `options.element {Element/jQuery Element}` - `options.offsetX {Number}` optional, `x` offset (default: `0`) - `options.offsetY {Number}` optional, `y` offset (default: `0`) - `options.offsetWidth {Number}` optional, `width` offset (default: `0`) - `options.minwidth {Number}` optional, a minimal width (default `200`) - `options.maxwidth {Number}` optional, a maximal width (default `infinite`) - `options.height {Number}` optional, a height (default: `200`) - `options.callback(element) {Function}` is triggered when the user clicks on the element with `.selectable` class - `options.init {Function}` is triggered before the component is displayed - `options.close {Function}` optional, can determine closing of panel - `options.align {String}` optional, `left` (default), `right` or `center` - `options.position {String}` optional, `top` (default), `bottom` - `options.classname {String}` optional, a custom container class for all items Method: `component.hide()` __HTML rendering__: ```js var opt = {}; opt.html = 'Your HTML code'; ``` __RAW element rendering__: ```js var opt = {}; opt.html = YOUR_DOM_ELEMENT; // IMPORTANT: if the FloatingBox will be closed, then the element will be moved to the previous parent. ``` __Importing content__: ```js var opt = {}; opt.import = '/url/part.html'; // IMPORTANT: the content will be cached for the future usage ``` ### Good to know - elements with `selectable` class will be selectable __Methods__: - `component.up()` selects item above - `component.down()` selects item below - `component.select([el])` selects item You can combine methods with `j-Shortcuts` component. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Show panel ``` ## j-FloatingSearch Source: https://forge.totaljs.es/en/components/floatingsearch/ Framework: jcomponent@20 Content-SHA256: b49f0da6f8d84554d8903bb0d8a5e8af4f65ecd100d1e35956f0dc762f3a0502 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple floating search input. It uses absolute position and it's targeted above of toolbars because it can overlay the toolbar. __Configuration__ - `placeholder {String}` A placeholder for input (default: empty) - `height {Number}` A height in pixels (default: `45`) __Methods__: - `floatingsearch/show` shows the component in the current position - `floatingsearch/hide` hides the component Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    TOOLBAR

    You're searching: ``` ## j-Flow Source: https://forge.totaljs.es/en/components/flow/ Framework: jcomponent@20 Content-SHA256: 3b8273cd136e6c4c996d703a1fb9fa22830599cedd6871114d8061a17a1820cc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - identifiers can't contain `__` char __Configuration__: - `width {Number}` a width of Flow designer, default: `6000` - `height {Number}` a height of Flow designer, default: `6000` - `grid {Number}` a size of background grid, default: `25` - `paddingX {Number}` internal padding, default: `6` - `curvedlines {Boolean}` enables curved lines, default: `false` - `infopath {String}` a path to variable/method, response: `{ zoom: Number, selected: Object }` - `undopath {String}` a path to variable/method, response is Object array - `redopath {String}` a path to variable/method, response is Object array - `ondrop {String}` a path to method `fn(dropmeta, grid)` - `onmake {String}` a path to method `fn(el, com)`, it's executed when the component is creating - `ondone {String}` a path to method `fn(el, com)`, it's executed when the component is created - `onmove {String}` a path to method `fn(el, com/group, type)`, it's executed when the component/group is moving - `onremove {String}` a path to method `fn(el, com)`, it's executed when the component is removed - `onconnect {String}` a path to method `fn(meta)`, it's executed when the two components are connected - `ondisconnect {String}` a path to method `fn(meta)`, it's executed when the two components are disconnected - __NEW__ `onpause {String}` a path to method `fn(path, is)`, it's executed when the output/input is paused - `steplines {Boolean}` enables step lines (default: `false`) - `animationradius {Number}` animation radius in pixels (default: `5`) - `contextmenu {String}` a path to `function(e, type, component/meta)` (type can be `map`, `component`, `connection`, `group`) - `dblclick {String}` a path to `function(component)` - `outputoffsetX {Number}` a default X offset for output point (default: `10`) - `outputoffsetY {Number}` a default Y offset for output point (default: `12`) - `inputoffsetX {Number}` a default X offset for input point (default: `10`) - `inputoffsetY {Number}` a default Y offset for input point (default: `12`) - `snapping {Number}` snapping in pixels (default: `0` = disabled) - `multiple {Boolean}` enables multiple selecting of the component (default: `true`) - `history {Number}` a count of steps in the undo/redo history (default: `100`) - `animationlimit {Number}` a maximum count of dots for all animations (default: `100`) - `animationlimitconnection {Number}` a maximum count of dots per connection (default: `5`) - `allowpause {Boolean}` allows pausing on outputs/inputs (default: `true`) - `markers {Boolean}` adds arrow markers to the connection (default: `true`) __Commands__: - `flow.refresh` recalculates positions - `flow.selected.disconnect` disconnects selected connection - `flow.selected.remove` removes selected component - `flow.selected.clear` removes selected component or connection - `flow.zoom` performs zoom, argument: `type` (can be: `in`, `out`, `reset` or `percentage {Number}`), second optional argument: `percentage` - `flow.undo` performs undo step - `flow.redo` performs redo step - `flow.reset` resets editor - `flow.components.add` adds a new component, argument: `component_declaration` - `flow.components.find` finds a component, argument: `component_id` - `flow.clean` cleans data and non-exist connections - `flow.traffic(componentid__outputid, { count: 3, speed: 3, limit: 20, delay: 50, reverse: false })` loads animation - `reverse` animation can be enabled by adding `_` as a starting char of identifier `_componentid__outputid` - __NEW__ `flow.groups.find` finds a group, argument: `group_id` - __NEW__ `flow.check` a new faster alternative to the `flow.refresh` command - __NEW__ `flow.find` finds a component or group, argument: `component_id` or `group_id` __Adding a new component__: - the component automatically creates ID of component - `connections` is `{Object}` ```js // Component declaration var component = { x: 100, y: 50, html: 'Component test', outputs: ['1 output name', '2 output name'], // or // outputs: [{ id: 'A', name: 'A output name' }, { id: 'B', name: 'B output name', color: '#FF8E37' }], connections: { '0': [{ id: '0002', index: '2', disabled: false }] }, // Look to the connection object below // or // connections: { 'A': [{ id: '0002', index: 'B', disabled: false }] }, actions: { select: true, move: true, disabled: false, remove: true, connect: true } }; // Appends component CMD('flow.components.add', component); ``` ```js // Connection object // connections: { '0': [CONNECTION_OBJECT1, CONNECTION_OBJECT2, CONNECTION_OBJECT3] } { id: 'TARGET_ID_COMPONENT', index: '0', // An input index or index id, must be string!!! disabled: false // Optional, it's the connection disabled? Disabled connection can't be removed } ``` __Flow output__: - returns `Object` which keys are `ID` of components ```js { 'F1562743923216': { x: 1, y: 1, connections: [], ... }, 'F1562743965303': { x: 1, y: 1, connections: [], ... }, // Contains paused endpoints paused: { 'input__COMPONENTID__INDEXID': 1, 'output__COMPONENTID__INDEXID': 1 }, // Contains groups groups: [{ id: 'GroupID', name: 'Name', x: 100, y: 100, width: 100, height: 100, background: 'rgba(0,0,0,0.1)', color: '#000', border: 'rgba(0,0,0,0.1)' }, ...]; } ``` __Good to know__: - each component (in the Flow) contains `f-COMPONENTNAME` class - `selectable` class in the component element enables copying text and disables moving - `connections` supports `type:"transform"` with dashed line Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Folder Source: https://forge.totaljs.es/en/components/folder/ Framework: jcomponent@20 Content-SHA256: 02b73fa6ac68bd8aae79cfb69761be8b8a87264b2371371601ca590cacf6c995 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can render a content like file browser. `path` must be in the form e.g. `Directory/Directory/File`. Learn from example. __Configuration__: - `up {String}` a label for Up button (default: `..`) - `delimiter {String}` a delimiter for the path (default: `/`) - `root {String}` a label for first item in breadcrumb (default: `Root`) - `scrollbar {Boolean}` enables custom scrollbar (default: `true`) - `scrollbarY {Boolean}` shows Y scrollbar always (default: `false`) - `delimiter {String}` a delimiter for path (default: `/`) - `options {String}` a path to method `function(item, el)` (user must click on the right button) - `click {String}` a path to variable or method `function(item)` (user must click on the item) - `checked {String}` a path to variable or method `function(checked_items, component)` (user must check the checkbox) - `browse {String}` __IMPORTANT__: a path to method `function(path, next(ARRAY), [item])` which must return a content for the component - `parent {String}` optional, a container with fixed height, can be `window`. Default value: `component.element()` - `margin {Number}` optional, a top/bottom margin together (default: `0`) - `drop {String}` optional, a path to method which will be executed if a file will be drag&dropped - `key {String}` optional, a key name for creating of path (default: `name`) - `raw {Boolean}` optional, disables HTML encoding `name` (default: `false`) - __NEW__: `contextmenu {String}` optional, a path to method `function(item, el, e)` (when a user displays the context menu) ```js function fn_browser(path, next, item) { // @path {String} paths divided according to the "config.delimiter" // @next {Function(Array)} importat: this function expects array with items // @item {Object} can be null var arr = []; // Object for array: // obj.name {String} a label/name // obj.checkbox {Boolean} enables checkbox (default: false) // obj.checked {Boolean} item will be checked // obj.icon {String} a icon for item // obj.type {Number} determines a type of item (1: directory, other: file) // obj.classname {String} adds a CSS class onto "label" element // Good to know: // Only directories can be drilled // Example: arr.push({ name: 'Node.js', checkbox: true, type: 1, icon: 'folder' }); arr.push({ name: 'Client-Side', checkbox: true, type: 1, icon: 'folder' }); next(arr); // next(array, noscroll); } ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html


    ``` ## j-FontAwesome Source: https://forge.totaljs.es/en/components/fontawesome/ Framework: jcomponent@20 Content-SHA256: f11bb7050dab9238a0d5fd19d49cab1aceb54438a4319b11e9ba97155f2d6c13 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple __FontAwesome__ viewer with fulltext searching. Supports a __recent__ feature and it's responsive. __Configuration__: - `search` {String} a placeholder for the search input __Methods__: - `component.show(x, y, [target], [callback(icon, target)]` and it works as `toggle` when `x` and `y` are same as previous call - `component.hide()` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FontAwesomeBox Source: https://forge.totaljs.es/en/components/fontawesomebox/ Framework: jcomponent@20 Content-SHA256: 570de3e8d748ec8881920925b6b970a7fb83cf3fae55b43fdf978663e5dce434 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple __FontAwesome__ viewer with fulltext searching. Optimized for jComponent `+v17`. __Configuration__: - `search` {String} a placeholder for the search input - `height` {Number} Optional, default: `250` - `exec` {String} Optional, can contain a link to the function Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Form Source: https://forge.totaljs.es/en/components/form/ Framework: jcomponent@20 Content-SHA256: 12df3b4f6d5d5c4b1a23f77ed2deaacbc8ef563380fe11d61442107079c66da1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `title {String}` form title - `width {Number}` form max-width - `if {String}` condition for showing of the form, it's compared with the value within of `path` - `icon {String}` Font-Awesome icon without `ti-` or __new__: `ti ti-home` - `reload {String}` link to a global `function(form_component)` and it's executed if the form is displaying - `submit {String}` link to a global `function(hide)` and it's executed if the submit button is pressed - `cancel {String}` link to a global `function(hide)` and it's executed if the cancel button is pressed - `enter {Boolean}` captures `enter` key automatically and performs submit (default: `false`) - `center {Boolean}` centers the form to middle of screen - `autofocus {Boolean/String}` can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `closebutton {Boolean}` can hide `x` button (default: `false`) - `zindex {Number}` can affect z-index (default: `12`) - `scrollbar {Boolean}` enables custom scrollbar (default: `true`) - `closeoutside {Boolean}` closes the form when the user clicks outside of the form (default: `false`) - `closeesc {Boolean}` closes the form when the user presses `ESC` key - `independent {Boolean}` closing doesn't depent on the condition according to the path - `close {String}` link to a global `function()` and it's executed if the form is closing - __NEW__ `hide {String}` link to a global `function()` and it's executed if the form hides __Good to know__: New version of this component supports dynamic evaluation of the content of `
    ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FormData Source: https://forge.totaljs.es/en/components/formdata/ Framework: jcomponent@20 Content-SHA256: aa184025d0249bd48512426da243185b52d0ab034cdbd3850581203a46cc45fa Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded With this component you can send data via the POST/PUT/DELETE method to the current window or another. - singleton ### Configuration - `method {String}` a default HTTP method (default: `POST`) - `target {String}` a default target (default: `_blank`) - `type {String}` a default form type (default: `application/x-www-form-urlencoded`) ### Methods - `component.send(opt)` - `opt.method {String}` form method, default `config.method` - `opt.target {String}` form target, default `config.target` - `opt.type {String}` form type, default `config.target` - `opt.url {String}` __required__ URL address - `opt.data {Object}` __required__ form data in the form `{ key1:value, key2:value }` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FormTab Source: https://forge.totaljs.es/en/components/formtab/ Framework: jcomponent@20 Content-SHA256: 5cb2ded0aec6e93c38d1fc1ee76d67fbc3984ff9e6a128cbf7f5ff513dcd8d17 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - The component moves the content of this component under `` tag (because of positioning) - The component expects array __Configuration__: - `width {Number}` width of form - `widthlg {Number}` width of form for `lg` devices (default: `config.width`) - `widthmd {Number}` width of form for `md` devices (default: `config.width`) - `widthsm {Number}` width of form for `sm` devices (default: `config.width`) - `widthxs {Number}` width of form for `xs` devices (default: `config.width`) - `height {Number}` height of form - `heightlg {Number}` height of form for `lg` devices (default: `config.height`) - `heightmd {Number}` height of form for `md` devices (default: `config.height`) - `heightsm {Number}` height of form for `sm` devices (default: `config.height`) - `heightxs {Number}` height of form for `xs` devices (default: `config.height`) - `margin {Number}` a default margin between forms (default: `10`) - `marginlg {Number}` a default margin for `lg` devices (default: `config.margin`) - `marginmd {Number}` a default margin for `md` devices (default: `config.margin`) - `marginsm {Number}` a default margin for `sm` devices (default: `config.margin`) - `marginxs {Number}` a default margin for `xs` devices (default: `config.margin`) - `marginfullscreen {Number}` a default margin for fullscreen mode (default: `20`) - `marginfullscreenlg {Number}` a default fullscreen margin for `lg` devices (default: `config.marginfullscreen`) - `marginfullscreenmd {Number}` a default fullscreen margin for `md` devices (default: `config.marginfullscreen`) - `marginfullscreensm {Number}` a default fullscreen margin for `sm` devices (default: `config.marginfullscreen`) - `marginfullscreenxs {Number}` a default fullscreen margin for `xs` devices (default: `config.marginfullscreen`) - `submit {String}` link to a global function `function(meta, data, hide)` and it's executed if the submit button is pressed - `cancel {String}` link to a global function and it's executed if the `cancel` button is pressed - `enter {Boolean}` captures `enter` key automatically and virtually clicks on the submit button (default: `false`) - `onclose {String}` a link to function `function(item, close)` (optional) - `onopen {String}` a link to function `function(item, el)` (optional) - `autofocus {Boolean}` enables auto-focus for the first input (default: `false`) - __NEW__ `right {Number}` right margin (defualt: `0`) - __NEW__ `bottom {Number}` bottom margin (defualt: `0`) - __NEW__ `useminheight {Boolean}` use `min-height` instead of `height` CSS attribute (default: `false`) __Good to know__: - each element with `cancel` class will be used as a cancel button __Data-Source__: ```javascript [ { // Required id: 'YOUR_ID_OF_THE_FORM', name: 'YOUR_NAME_OF_THE_FORM', // Optional minimized: true, data: { blabla: '"data" will be cloned into the form scope' } // NEW: scope: false (disables scope) // NEW: scope: mycustomscopepath } ] ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-FullForm Source: https://forge.totaljs.es/en/components/fullform/ Framework: jcomponent@20 Content-SHA256: aec5b275d9054c88355fd61dbce523e28321e359d03e7eb5e962037cbe804a72 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `title {String}` form title - `if {String}` condition for showing of the form, it's compared with the value within of `path` - `icon {String}` Font-Awesome icon without `ti-` or __new__: `ti ti-home` - `reload {String}` link to a global `function(fullform_component)` and it's executed if the form is displaying - `submit {String}` link to a global `function(hide)` and it's executed if the submit button is pressed - `cancel {String}` link to a global `function(hide)` and it's executed if the cancel button is pressed - `enter {Boolean}` captures `enter` key automatically and performs submit (default: `false`) - `center {Boolean}` centers the form to middle of screen - `autofocus` {Boolean/String} can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `closebutton {Boolean}` can hide `x` button (default: `false`) - `zindex {Number}` can affect z-index (default: `12`) - `scrollbar {Boolean}` enables custom scrollbar (default: `true`) - `scrolltop {Boolean}` enables scrolling to top after form is displayed (default: `true`) - `scrollbarshadow {Boolean}` optional, enables a shadow in scrollbar (default: `false`) - `style {Number}` supports two styles (1: classic (default), 2: full size without padding) - `closeoutside {Boolean}` closes the form when the user clicks outside of the form (default: `false`) - `closeesc {Boolean}` closes the form when the user presses `ESC` key - `independent {Boolean}` closing doesn't depent on the condition according to the path - `close {String}` link to a global `function()` and it's executed if the form is closing - `hide {String}` link to a global `function()` and it's executed if the form hides __Good to know__: The component moves the content of this component under `` tag (because of positioning) and it supports evaluation of the content of ` ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Gallery Source: https://forge.totaljs.es/en/components/gallery/ Framework: jcomponent@20 Content-SHA256: d4aea4dbf1b5d6b7f80e179424d91f0132af46f3460cb9443efdab8c7cfdbb87 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - works with Bootstrap Grid System Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Images are from https://pixabay.com


    ``` ## j-Gauge Source: https://forge.totaljs.es/en/components/gauge/ Framework: jcomponent@20 Content-SHA256: 665fdef3bf4a4e9f4c6f5987a29a9ff78aa09f0d216765f160673db872c5d689 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `decimals {Number}` a count of decimals (default: `1`) - `format {String}` a format for text (default: `{0}%`) - `colors {String}` colors in the form `PERCENTAGE #COLOR STROKEWIDTH` (default: `30 #8CC152 25,40 #EDBC5A 25,30 #DB3737 25`) - `text {Boolean}` enables text (default: `true`) - `stroke {Number}` a default stroke width (default: `25`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-GPS Source: https://forge.totaljs.es/en/components/gps/ Framework: jcomponent@20 Content-SHA256: a381e0d03b2f78fc3ec5a217394dbe7d72d03c683a7d8b956b4a00631874129e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - readonly The component tries to read GPS coordinates. __Configuration__: - `watcher {Boolean}` enables a real-time watcher for GPS (default: `true`) __Good to know__: The component emits `ON('gps', function(coords) {` event with a new GPS coordinates. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Grid Source: https://forge.totaljs.es/en/components/grid/ Framework: jcomponent@20 Content-SHA256: f681777167bcda4d24aafb2c8be7e364025e40c4aaa663bba57380e1ad59e7ce Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - needed `bootstrap` grid system __Data-source__ needs to contain: ```javascript { items: [{ name: 'Row 1' }, { name: 'Row 2' }, ...] // items page: 1, // current pages pages: 30, // count of pages limit: 5, // items limit per page count: 150 // count of items in DB } ``` __Configuration__: - `filter` {Boolean} shows a filter (optional, default: `true`) - `filterlabel` {String} a default placeholder for all filters (optional) - `external` {Boolean} is an external data-source (dynamic data loading) (optinal, default: `false`) - `pluralizepages` {String} pluralization for pages (optional, default: `# pages,# page,# pages,# pages`) - `pluralizeitems` {String} pluralization for items (optional, default: `# items,# item,# items,# items`) - `exec` {String} a link to `function(type, filter, sort, page)`, it's evaluated if the grid performs some operations - `padding` {Number} height padding (optional, default: `0`) - `autosize` {Boolean} enables full-height auto-size (optional, default `true`) - `boolean` {String} a values for filtering of boolean values (optional, default: `true|on|yes`) - `pagination` {Boolean} shows pagination panel (optional, default: `false`) - `init` {Function} an init function for e.g. custom columns - `checked` {Function} if rows will contain ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-HashChange Source: https://forge.totaljs.es/en/components/hashchange/ Framework: jcomponent@20 Content-SHA256: c241dbb8abb70e36090cfdca69291f742110a3e26a1e1cdb5dacea4e31e35330 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component captures all changes for `#hashtag` in the URL address. When change, it emits event `hash`. The component reacts to the real changes. - singleton __Configuration__: - `delay {Number}` a delay for emitting `hash` event (default: `0`) - __NEW__: `middleware {String}` a middleware (separated by the comma) for initial emit of the `hash` event __How to capture hash change?__ ```js // Global: ON('hash', function(hash) { // @hash {String} - it can be "empty" }); // Or in the Plugin declaration: exports.on('hash', function(hash) { }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-HighlightSyntax Source: https://forge.totaljs.es/en/components/highlightsyntax/ Framework: jcomponent@20 Content-SHA256: 6a7ebd4abf86a54e45af02a55d43b61d2c410cf42ce822d9fa6c650ddf3bab29 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Simple syntax highlighter with help of __Highlight.js__. __Configuration__: - `type` needs to contain a content-type for highlighting Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Icons Source: https://forge.totaljs.es/en/components/icons/ Framework: jcomponent@20 Content-SHA256: 799c6257752e70dba514dc44f3f83d92cf4430bd223473eea2569b91162bfeb0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Total.js Icons list - singleton __Configuration__: - `search {String}` a placeholder for search field (default: `Search`) - `list {String}` URL address for obtaining list of icons (default: Total.js Icons CDN) - __NEW__: `custom {String}` a link to the custom icon list (it uses `tic ti-NAME` prefix) ## Usage ```javascript var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align `left` (default), `center` or `right` // opt.position {String} : position `top` (default) or `bottom` // opt.empty {Boolean} : adds empty icon (default: false) opt.element = YOUR_ELEMENT; // or if you want to use a fixed position: // opt.x {Number} : `x` position // opt.y {Number} : `y` position opt.callback = function(icon) { console.log(icon); }; SETTER('icons/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-IdleTime Source: https://forge.totaljs.es/en/components/idletime/ Framework: jcomponent@20 Content-SHA256: 198c71ca25834ba41cfa6b2767e946f052b7f61e4bc0438292f8fe32388eb8a4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component emits event `ON('idletime', function(is) {})` when the website is in idle. It reacts on mouse, keyboard, touch events or focusing of window. And the component sets `Boolean` according to the path with the current idle state. __Configuration__: - `count {Number}` in seconds, default: `300` 5 minutes) __Events__: - `ON('idletime', function(is))` is emitted if the document is idle (`is=true`) / active (`is=false`) - `ON('reload', function() {})` is emitted if the document is transformed from invisible to visible state within `config.count` interval Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-iFrame Source: https://forge.totaljs.es/en/components/iframe/ Framework: jcomponent@20 Content-SHA256: 155a5ec5da588e902f2643a63898638460e8563abf95c81e3ccf38e65f17ff4e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component renders another URL address (stored in the `path` attribute) directly in the iframe. The biggest benefit is auto-resizing of the iframe element according to the `parent` selector. __Configuration__: - `parent {String}` optional, a container selector (default: `window`) - `scrollbar {Boolean}` optional, enables native iframe scrolling (default: `false`) - `margin {Number}` optional, a vertical margin (default: `0`) - __NEW__: `marginxs {Number}` optional, a vertical margin for extra small display - __NEW__: `marginsm {Number}` optional, a vertical margin for small display - __NEW__: `marginmd {Number}` optional, a vertical margin for medium display - __NEW__: `marginlg {Number}` optional, a vertical margin for large display - __NEW__: `message {String}` optional, a link to the `function(msg)` - __NEW__: `ready {String}` optional, a link to the `function(com)` when the iframe is ready - __NEW__: `autohide {Boolean}` optional, adds `hidden` class if the iframe is blank __Methods__: - __NEW__: `SETTER('iframe/send', { your_message_data })` for sending message to the iframe Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-iFrameEditable Source: https://forge.totaljs.es/en/components/iframeeditable/ Framework: jcomponent@20 Content-SHA256: b620daa85581caaedf7a2bd24359836df396706c6be723812fcdfa90150137b8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - can edit HTML safely - height of iframe is automatically counted from the `body` - __important__: content must contain `contenteditable` attribute __Configuration__: - `bind {String}` can contain `body` (default), `html` or `contenteditable` __Methods__: - `component.resize()` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    This component can edit HTML code safely:
    ``` ## j-iFramePreview Source: https://forge.totaljs.es/en/components/iframepreview/ Framework: jcomponent@20 Content-SHA256: 660c3ee1b7cef0cb562f1b5c9687a59cadfbcaf102ac35fb10b7a39eba90f632 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - can render HTML safely - height of iframe is automatically counted from the `body` __Methods__: - `component.resize()` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    This component can render HTML code safely:
    ``` ## j-iFrameViewer Source: https://forge.totaljs.es/en/components/iframeviewer/ Framework: jcomponent@20 Content-SHA256: 15a4655235b27c69c4d83e1d1afa3c91d776ea9b68087951638028c4f0ead584 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component show a layer (over the content) with a iframe. - singleton __Options__: - `name {String}` a label name to header - `url {String}` URL address for iframe - `ready {Function(iframe)}` optional, `onready` handler - `close {Function}` optional, `onclose` handler - `esc {Boolean}` can close the component with pressing of `ESC` key (defualt: `false`) - `width {String}` a width of iframe (default: `100%`) - `margin {Number}` a vertical (top/bottom) margin (default: `0`) - __NEW__: `html {String}` a custom HTML content for the iframe Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ImageUploader Source: https://forge.totaljs.es/en/components/imageuploader/ Framework: jcomponent@20 Content-SHA256: b13d50455eb04111ecc37861a865794402c64a99d66c54787308acb66cb010b1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple singleton component for uploading of resized images. The component uploads base64 according to the `schema` defined in `options` of caller. __Methods__: - `imageuploader/upload(opt)` shows a file dialog - `opt.width {Number}` - `opt.height {Number}` - `opt.background {String}` a default background color (__NEW__: supports the `transparent` value and output will be `.png`) - `opt.url {String}` __important__ URL where will be image uploaded - `opt.multiple {Boolean}` supports multiple files (default: `false`) - `opt.schema {String}` default `{ file: base64, name: filename }` - `opt.quality {Number}` default `90` - `opt.callback(response, errors)` a callback __important__ - `opt.keeporiginal {Boolean}` keeps the original image if the dimension is the same as the width/height defined in the configuration (default: `false`) - __NEW__ `opt.files` {FileList} optional (if you use e.g Drag & Drop) __Friendly components__: This component works with `loading` when the file is uploading. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Click to upload
    ``` ## j-ImageViewer Source: https://forge.totaljs.es/en/components/imageviewer/ Framework: jcomponent@20 Content-SHA256: 05f29f7cb10ea3951cbe7312172770e61ea7dd73cd5cfab1fa44a7e45fc93370 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - place the component under ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    ``` ## j-ImportCSV Source: https://forge.totaljs.es/en/components/importcsv/ Framework: jcomponent@20 Content-SHA256: b0e0b53fc83d44d03289519644ff4c33b5bca4f1ebca24b8774b932fb97026c1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Output of this component is mapped array. The component uses `j-Directory` component. __Configuration__: - __IMPORTANT__ `datasource {String}` a path to CSV data (`String` type) - `skipfirst {Boolean}` skips the first parsed line (default: `true`) - `notdefined {String}` a text for undefined columns (default: `---`) - `parent {String}` jQuery selector for obtaining of width/height (default: `parent`) - `dirsearch {String}` a placeholder for search field (default: `Search`) - `margin {Number}` a margin for `parent` (default: `0`) - `marginxs {Number}` optional, a top/bottom margin together for `xs` screen width - `marginsm {Number}` optional, a top/bottom margin together for `sm` screen width - `marginmd {Number}` optional, a top/bottom margin together for `md` screen width - `marginlg {Number}` optional, a top/bottom margin together for `lg` screen width Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Total items for import: 0
    ``` ## j-Importer Source: https://forge.totaljs.es/en/components/importer/ Framework: jcomponent@20 Content-SHA256: 8d223fa57188534132d8b3e14c65cff52b97ea7a47068955c24dc932146edbd3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __j-Import__ is a great component for importing HTML templates, scripts or styles according to the path and condition. The component can help with SPA applications because you can easily import templates, scripts or styles dynamically. __Configuration__: - `if {String}` needs to contain a value - `url {String}` relative/absolute URL to a subpage or subpart - `reload {String}` a link to method in the global scope, it's executed if the __condition__ is valid - `cleaner {Number}` (optional) idle time (in minutes) for running of cleaning (default: `0`) - `clean {String}` (optional) a link to function, it's executed before the importer is cleaned - `id {String}` a custom identifier for replacing `~ID~` phrases in the imported HTML (default: empty) - __NEW__: `singleton {Boolean}` it handles only the one instance of importer according to the `path + if + url` (default: `false`) - __NEW__: `parent {String}` it moves itself as a direct child of the `parent` selector - __NEW__: `adapt {Boolean}` if `true` it calls the `reload:?/soemthing` method for the nested plugin instead of the current plugin (default: `false`) __New update__: j-Importer can contain ` ``` ## j-InfiniteScroll Source: https://forge.totaljs.es/en/components/infinitescroll/ Framework: jcomponent@20 Content-SHA256: dde245162a9a70250abb3c2c52168703916776ba4fd952e640463cdf64790710 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `parent {String}` a parent element due to height of container (default: `parent`) - `margin {Number}` a margin for `height` (default: `0` px) - `padding {Number}` a bottom scroll padding for performing of reading (default: `50` px) - `autoscroll {Number}` automatically scrolls container if the content is added (default: `100` px) - `exec {String}` a link to the method which is executed if the scrollbar is at the end, look into the implementation below: ```javascript function method_append(next, element, init) { // @next {Function(new_content)} // @element {jQuery} // @init {Boolean} Is the component initialized? // element.append(...); // or next('NEW_HTML_CONTENT_or_RAW_NODE_ELEMENT'); } ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Some content
    ``` ## j-Info Source: https://forge.totaljs.es/en/components/info/ Framework: jcomponent@20 Content-SHA256: 22afaed060f24fad85fc7cf1081758b7efd87fa3b63ee12894997877febc322f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - show: `SETTER('info', 'show', options)` - hide: `SETTER('info', 'hide')` __Show options__: - `opt.element` {jQuery} an element where will be `j-Info` displayed - `opt.align` {String} align `left` (default), `center`, `right` or `half` - `opt.html` {String} a HTML content - `opt.name` {String} a name of Tangular template, must be defined in `j-Info` body like example below - `opt.value` {Object} a model for Tangular template - `opt.minwidth` {Number} a minimal width (default: `100`) - `opt.maxwidth` {Number} a maximal width (default: `280`) - `opt.offsetX` {Number} `x` offset (default: `0`) - `opt.offsetY` {Number} `y` offset (default: `0`) - `opt.offsetWidth` {Number} `width` offset (default: `0`) - `opt.callback` {Function(isvisible)} a callback is executed when the element is hidden - `opt.class` {String} a custom class name - `opt.closeclick` {Boolean} closes info when user performs mouse click (default: `false`) - __NEW__ `opt.position` {String} position `top` (default) or `bottom` - __NEW__ `opt.x` {Number} enables absolute position (`opt.y` is not required) - __NEW__ `opt.y` {Number} enables absolute position (`opt.x` is not required) ```javascript var opt = {}; opt.element = YOUR_ELEMENT; opt.html = 'TEST'; SETTER('info', 'show', opt); ``` __or with Tangular templates:__ ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-InfoWindows Source: https://forge.totaljs.es/en/components/infowindows/ Framework: jcomponent@20 Content-SHA256: d17dfdcd1e370f4c64b859ac47cdfdb3dbe2578f2bc0c6be88ac0fee1410e886 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Supports mobile devices - Supports touches - Movable - Resizable __Configuration__: - `reoffsetresize {Boolean}` all windows will be re-offset according to `main` window dimension (default: `true`) The `InfoWindows` component expects `Array` of objects. ```javascript // Component declaration var win = { // Component ID id: 'WINDOW_ID', // NEW: cachekey for similar windows // Optional, default: window ID cachekey: 'WINDOW_ID', // Positioning // You can define specific display size and if the display size is not specified then the window tries to find a size for larger display html: 'THE CONTENT OF WINDOW', // or can be raw HTMLElement offset: { x: 200, y: 100, width: 600, height: 400, minwidth: 200, minheight: 200, maxwidth: 1000, maxheight: 1000 }, // minwidth, maxwidth, maxheight, minheight are optional // Default settings actions: { move: true, close: true, hide: true, resize: true, minimize: true, maximize: true, autosave: false }, // GOOD TO KNOW: // "undefined" close or "close:false" and "hide:true" doesn't destroy the instance of window (it will be hidden only) // A window title title: 'Title for the window', // Handlers (optional): destroy: function() { // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is destroyed }, make: function(el) { // @el {jQuery} a content of the window // @this {Instance} // this.meta {Object} a reference to window object // this.element {jQuery} a content element of the window // this.container {jQuery} a main content element of the window // this.main {Object} a reference to "Windows" component // this.width {Number} a width of window // this.height {Number} a height of the content of the window // this.x {Number} offset X // this.y {Number} offset Y // Methods: // this.setsize(width, height); // this.setcommand(cmd); Allowed commands: "close", "maximize", "resetmaximize", "togglemaximize", "minimize", "resetminimize", "toggleminimize", "resize", "move", "focus" // this.setoffset(x, y); // is executed when the window is making }, data: function(type, data, el) { // @type {String} // @data {Object} // @el {jQuery} a content element of the window // @this {Instance} // is executed when data are sent via SETTER('windows', 'send', 'TYPE', 'DATA') }, resize: function(width, height, el, x, y) { // @width {Number} // @height {Number} // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is resized }, move: function(x, y, el) { // @x {Number} // @y {Number} // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is moved }, service: function(counter, el) { // @counter {Number} count of calls // @el {jQuery} a content of the window // @this {Instance} // the component will execute this handler each 5 seconds } }; PUSH('infowindows', win); ``` __Methods__: - `component.finditem(window_id)` finds the specific window according to `ID` - `component.show(window_id)` shows a window - `component.hide(window_id)` hides a window - `component.toggle(window_id)` toggles a window - `component.focus(window_id)` focuses a window - `component.close(window_id)` closes a window Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-InlineDatePicker Source: https://forge.totaljs.es/en/components/inlinedatepicker/ Framework: jcomponent@20 Content-SHA256: 7a7b71b93643565d92642bdca99aa7c34c2f6a2e0266d76b131bc2d3ef3815f8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required {Boolean}` required (default: `false`) - `firstday {Number}` first day in the week (default: `DEF.firstdayofweek`) - `today {String}` a label for `Set today` button - `days {String}` days e.g. `SU,MO,TU,WE,TH,FR,SA` (default). - `months {String}` months e.g. `January,February,...` (default). - `badges {String}` a link to the `function(date, append)` - `append([date1, date2, date3])` (must be array of dates) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-InlineForm Source: https://forge.totaljs.es/en/components/inlineform/ Framework: jcomponent@20 Content-SHA256: 684bfd52fc5849058377eb77c47c96d5f577eba8365e45917a511cc797e6bdf2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Works with Bootstrap - The component moves the content of this component under `` tag (because of positioning) __Configuration__: - `title` {String} form title - `width` {Number} form max-width - `icon` {String} Total icon without `ti-` or the whole declaration e.g. `ti ti-home` - `reload` {String} a link to a global function and it's executed if the form is showing - `submit` {String} a link to a global function and it's executed if the submit button is pressed - `cancel` {String} a link to a global function and it's executed if the cancel button is pressed - `hide` {String} a link to a global function and it's executed if the form is hiding - `enter` {Boolean} captures `enter` key automatically and performs submit (default: `false`) - `default` {String} a short alias for `DEFAULT(default, true)` - `autohide` {Boolean} enables auto-hide (default: `true`) - `autofocus` {Boolean} performs auto-focus to nearest input (default: `false`) __Methods__: - `instance.show(opt)` - shows the form - `opt.element` {jQuery element} element - `opt.align` {String} can be `left` (default), `right` or `center` - `opt.offsetX` {Number} offsetX (default: `0`) - `opt.offsetY` {Number} offsetY (default: `0`) - `opt.position` {String} can be `top` (default) or `bottom` - `opt.callback` {Function} a user defined function `callback(hide)`, `hide` attribute is `function` - `instance.hide()` - hides the form __Good to know__: New version of this component supports dynamic evaluation of the content of `
  • ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Show inline form ``` ## j-InlineProperties Source: https://forge.totaljs.es/en/components/inlineproperties/ Framework: jcomponent@20 Content-SHA256: 156c05cc9d01d63f82a3dc1484098588646d5d2b185c9c71e1ae64ee816a53a2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton __Configuration__: - `close {String}` a label for close button (default: `Close`) - `dateformat {String}` a default date format (default: `[date]`) - `dirsearch {String}` a default placeholder for j-Directory (default: `Search`) - `width {Number}` a default width (default: `200`) ## Usage ```js var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align "left" (default), "center" or "right" // opt.position {String} : position "top" (default) or "bottom" // opt.class {String} : adds class to the parent opt.element = YOUR_ELEMENT; // or if you want to use a fixed position: // opt.x {Number} : "x" position // opt.y {Number} : "y" position opt.items = [] opt.items.push({ id: 'firstname', name: 'First name', type: 'string', value: 'Peter' }); opt.items.push({ id: 'lastname', name: 'Last name', type: 'string', value: 'Širka', placeholder: 'String' }); opt.items.push({ id: 'age', name: 'Age', type: 'number', value: 33 }); // |---- id {String} : identifier/a property name // |---- name {String} : label // |---- value {Object} : a value // |---- type {String} : supported types: string, number, boolean, icon, color, date, list // |---- items {String/Array} : a list for "list" type // If you want to assign values from a model instead of filling a value in the "items" field, you can use: // opt.value {Object} opt.callback = function(model, changed) { // @model {Object} // @changed {String Array} console.log(model); }; SETTER('inlineproperties/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Input Source: https://forge.totaljs.es/en/components/input/ Framework: jcomponent@20 Content-SHA256: 25c6758b92023ff06d8a46fceab326b61921899f46c896b6967b39004a709ec9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __j-Input__ is multifuncional `input` component which supports a lot of features and it's optimized for everyday usage. It's a great alternative to `j-Textbox` and `j-Dropdown`. Works only with jComponent `+v17`. __Configuration__: - `type {String}` optional, values: - empty value means default `text` - `email`, - `multiline` - `checkbox` - `phone` - `password` - `zip` - `date` (needs `datepicker` component) - __NEW__: `datetime` (needs `datepicker` component) - `time` (needs `timepicker` component) - `color` (needs `colorpicker` component) - `icon` (needs `faicons` component) - `emoji` (needs `emoji` component) - `url` - `number` - `number2` (nullable) - `search` - `lower` - `upper` - `slug` - `id` - __NEW__: `radiobutton` - __NEW__: `tags` - __NEW__: `tags-lower` - __NEW__: `tags-upper` - __NEW__: `tags-id` - __NEW__: `tags-email` - __NEW__: `tags-slug` - __NEW__: `tags-phone` - __NEW__: `tags-url` - `required {Boolean}` optional, enables "required" (default: `false`) - `icon {String}` optional, icon for label e.g. `home`, `cog`, etc. - `licon {String}` optional, left icon e.g. `home`, `cog`, etc. - `liconclick {String}` optional, a path to method `function(component, input)` - `ricon {String}` optional, right icon e.g. `home`, `cog`, etc. - `riconclick {String}` optional, a path to method `function(component, input)` - `label {String}` optional, a label (default is HTML content) - `autofocus {Boolean}` optional, focuses the input (default: `false`) - `align {String}` optional, `left` (default), `2` / `right` or `1` / `center` - `after {String}` optional, it means a char after label (default: `:`) - `autofill {Boolean/String}` optional, enables browser's autofill feature (`string` will be used as an input name, default: `false`) - `placeholder {String}` optional, adds a `placeholder` text into the input - `maxlength {Number}` optional, sets a maximum length of chars (default: `200`) - `minlength {Number}` optional, sets a minimum length of chars - `minvalue {Number}` optional, a minimal value for `number` type - `maxvalue {Number}` optional, a maximal value for `number` type - `increment {Number}` optional, sets a value for incrementing (default: `1`) - `validate {String}` optional, a condition for validating of value, can contain a link to `function(value)` or `!!value.match(/[a-z]+/)` - `format {String}` optional, output formatting e.g. for `date` type: `yyyy-MM-dd`, for `time` type: `HH:mm`, for `number` you can define max. decimals (Default: `auto`) - `disabled {Boolean}` optional, disables this component - `error {String}` optional, adds a `string` text under the component - `autocomplete {String}` optional, needs to contain a link to a function, is triggered on `focus` event - `spaces {Boolean}` optional, enables spaces otherwise it removes them (default: `true`) - `innerlabel {Boolean}` optional, enables inner label (default: `true`) - `dirsource {String}` optional, path to a data-source or __NEW__ to `function(search, next)` (path must contain `/` or __NEW__: `id|name,id|name` - `dircustom {String/Boolean}` optional, can contain a path to `function(val, next(new_val))` or can be `Boolean`. This option can enable adding a custom value (value not defined in data-source) - `dirrender {String}` optional, a path to `function(item, text)` (must return HTML for `j-Directory`), this function can affect list of items in `j-Directory` - `dirminwidth {Number}` optional, a minimum width for `j-Directory`, default: `200` - `dirmaxwidth {Number}` optional, a maximum width for `j-Directory` - `diroffsety {Number}` optional, `Y` offset (default: `0`) - `diroffsetx {Number}` optional, `X` offset (default: `0`) - `dirplaceholder {String}` optional, a placeholder for `j-Directory` - `dirempty {String}` optional, adds an empty field for `j-Directory` - `dirkey {String}` optional, a key name for reading of `text` in `dirsource` (default: `name`) - `dirvalue {String}` optional, a key name for reading of `value` in `dirsource` (default: `id`) - `direxclude {Boolean}` optional, excludes a current value from `j-Directory` (default: `true`) - `dirsearch {Boolean|String}` optional, can disable search in `j-Directory` (default: `true`) or `{String}` (key name) can map a value for searching - `dirraw {Boolean}` optional, can disable escaping of items for `j-Directory` (default: `false`) - `dirdetail {String}` optional, a link to the function `function(val, next(NEW_TEXT))` (targeted for to `dirsource`) - `dirfilter {String}` optional, an inline filter conditional method, for example: `value.id !== 2` (targeted for to `dirsource`) - __NEW__: `dirrawrender {Boolean}` optional, if the `dirsource` doesn't include value it will render a raw value (default: `true`) - `mask {String}` optional, can contain a mask in the form `###/##` (`#` is replaced for a char) - `maskregexp {String}` optional, can contain RegExp for each char in the form `\d,\d,\d,null,\d,\d` (`,` is delimiter) - `masktidy {Boolean}` optional, the component returns only raw chars without fixed chars (default: `false`) - `autosource {String}` a path to the search source `Array` (__NEW__) or `function(search, render(arr))` for dynamic searching - `autovalue {String}` a property path for the value in `autosource`, default: `name` - `autoexec {String}` a path method `function(item, next(value_to_input))` - `searchalign {Number}` can align icon on `type:search` to left (`2`) or right (`1`, default) - `forcevalidation {Boolean}` enables for force validation for `phone` and `email` (default: `true`) - `camouflage {Boolean|String}` masks the value in the input after is triggered `blur` event (default: `false`) or it can be `String` which will be used as a camouflage - `monospace {Boolean}` enables `monospaced` font (default: `false`) - `multiple {Boolean}` enables checkboxes if `dirsource` is not empty - `tabindex {Number}` adds a tabindex (default: `0`) - `tabs {Boolean}` enables tabs for multiline (default: `true`) - `readonly {Boolean}` block text field edition (default: `false`) - `transform {String}` a link to the `function(value, config)` for transforming of entered values - `multiline {Boolean}` works only with `radiobutton` type - `separator {String|Boolean}` a separator for multiple rendered values - `realtime {Boolean}` enables real-time binding (default: `true`) - `exec {String}` a link to the `function(value, element)` which will be evaluated if the input is affected __Interesting:__ - `type:date` needs __`datepicker`__ component - `type:time` needs __`timepicker`__ component - `dirsource:path.to.datasource` needs __`directory`__ component - if `licon` or `ricon` starts with `!` then the component render a raw value instead of `icon` - `ui-input-ok` class is binded when the input is validated and filled - `SET('path', 'camouflage', 'show');` shows the value for 2000 ms ```video https://www.youtube.com/watch?v=Ne3ezaP0w34 ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Framework I agree with terms Notes Frameworks
    City
    Tags
    Date
    Search
    Password
    ZIP
    Email
    Phone
    Gender
    Gender
    Your age
    ``` ## j-InputTags Source: https://forge.totaljs.es/en/components/inputtags/ Framework: jcomponent@20 Content-SHA256: 9bdc3d697f00af9925dfd5162b3de5e9a6c9da7627c3c1d342315b45764ace24 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required {Boolean}` optional, enables "required" (default: `false`) - `icon {String}` optional, icon for label e.g. `home`, `cog`, etc. - `licon {String}` optional, left icon e.g. `home`, `cog`, etc. - `liconclick {String}` optional, a path to method `function(component, input)` - `ricon {String}` optional, right icon e.g. `home`, `cog`, etc. - `riconclick {String}` optional, a path to method `function(component, input)` - `label {String}` optional, a label (default is HTML content) - `after {String}` optional, it means a char after label (default: `:`) - `placeholder {String}` optional, adds a `placeholder` text into the input - `validate {String}` optional, a condition for validating of value, can contain a link to `function(value)` or `!!value.match(/[a-z]+/)` - `disabled {Boolean}` optional, disables this component - `error {String}` optional, adds a `string` text under the component - `spaces {Boolean}` optional, enables spaces otherwise it removes them (default: `true`) - `innerlabel {Boolean}` optional, enables inner label (default: `true`) - `dirsource {String}` optional, path to a data-source or __NEW__ can contain a link to method `function(search, next(items_arr))` - `dircustom {String/Boolean}` optional, can contain a path to `function(val, next(new_val))` or can be `Boolean`. This option can enable adding a custom value (value not defined in data-source) - `dirrender {String}` optional, a path to `function(item, text)` (must return HTML for `j-Directory`), this function can affect list of items in `j-Directory` - `dirminwidth {Number}` optional, a minimum width for `j-Directory`, default: `200` - `dirmaxwidth {Number}` optional, a maximum width for `j-Directory` - `dirplaceholder {String}` optional, a placeholder for `j-Directory` - `dirempty {String}` optional, adds an empty field for `j-Directory` - `dirkey {String}` optional, a key name for reading of `text` in `dirsource` (default: `name`) - `dirvalue {String}` optional, a key name for reading of `value` in `dirsource` (default: `id`) - `autosource {String}` a path to `search` function in `autocomplete`, `function(search, render(arr))` - `autovalue {String}` a property path for the value in `autosource` - `transform {Number}` optional, transforms the text `0 - none, 1 - lowercase, 2 - uppercase, 3 - capitalize` (Default: `0`) - `enteronly {Boolean}` optional, appends a new value after `enter` key is pressed (default: `true`) __Interesting:__ - `dirsource:path.to.datasource` needs __`directory`__ component - if `licon` or `ricon` starts with `!` then the component render a raw value instead of `icon` - `dirsource` with paths to methods can load data asynchronously Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Framework
    Country
    ``` ## j-Intro Source: https://forge.totaljs.es/en/components/intro/ Framework: jcomponent@20 Content-SHA256: 73e2696cfef57960ba8e9d20e61f28fad4e0f49b14ebf7bc41973767332a75bc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `if {String}` condition for showing of the intro, it's compared with the value within of `path` - `next {String}` optional, text for the next step button (default: `Next`) - `close {String}` optional, text for the close step button (default: `Done`) - `page {String}` optional, a link to method `function(page) {}` it's executed when page is changed - `exec {String}` optional, a link to method `function() {}` it's executed when the intro is closed - `check {String}` optional, a link to method `function(done) {}` it's executed when is clicked on button last button - `remove {Boolean}` optional, when `true` then the component will be removed after close (default: `false`) - `closebutton {Boolean}` shows close button at the right top corner (default: `false`) - `width {Number}` a maximum width (default: `400`) - `height {Number}` height (default: `300`) - __NEW__: `delay {Number}` a delay for `next` button between clicks - __NEW__: `nexticon {String}` a done icon (default: `ti ti-chevron-right`) - __NEW__: `doneicon {String}` a done icon (default: `ti ti-check-circle`) __Good to know__: - each button with `name="next"` will be used as `next` button - each button with `name="close"` will be used as `close` button - a link with `next` class provides will be used as a `next` button - a link with `close` class provides will be used as a `close` button Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-IsOpen Source: https://forge.totaljs.es/en/components/isopen/ Framework: jcomponent@20 Content-SHA256: 0e9f52d1b7a58197d95b8ddabd879915fa50e3026408aac226285fd7c86eb181 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __j-IsOpen__ is a simple component for showing opening hours. The component supports auto-refresh `datetime`. __Tangular model properties__: ```html {{ date }} - (date) current date instance {{ month }} - (number) current month (1=januar ... 12=december) {{ year }} - (number) current year {{ day }} - (number) current day number in calendar {{ daytype }} - (number) current day type (0=sunday ... 6=saturday) {{ minutes }} - (number) current minutes {{ hours }} - (number) current hours {{ week }} - (boolean) is weekend? ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-JSONTree Source: https://forge.totaljs.es/en/components/jsontree/ Framework: jcomponent@20 Content-SHA256: 55726dd4e68385849c0194f01ef246909d3030fbc3019ab38f6c1a5795cdb8f2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __j-JSONTree__ creates tree view from json data. __Configuration__: - `click {String}` a link to the `function(selected_path, component)` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Martin Smola. Source: the Componentator components repository, MIT license. ```html example.html Sample JSON data ``` ## j-Kanban Source: https://forge.totaljs.es/en/components/kanban/ Framework: jcomponent@20 Content-SHA256: c2a9890ca0363889432d4b5c459599a3cf7e2aba2ca892cabaeb61e8b01b2b04 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `parent {String}` a container with fixed height, can be `window`. Default value: `parent` element. - `margin {Number}` a top/bottom margin together (default: `0`) - `padding {Number}` a padding between panels (default: `10`) - `style {Number}` a style, `1` (default): boxes will have a full-height, `2` boxes will have `max-height ` - `move {String}` a path to method `function(group, target)`, is executed if the user moves an item to another group - `remove {String}` a path to method `function(group)`, is executed if the user removes an item in group - `dblclick {String}` a path to method `function(group)`, is executed if the user performs double click __Methods__: - `component.remove(id)` can remove an item in group - `component.findgroup(id)` returns a group instance __Important__: each item needs own ID {String}, look to example. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-KeySelection Source: https://forge.totaljs.es/en/components/keyselection/ Framework: jcomponent@20 Content-SHA256: 2729b88bf4f70616de0b0c5dbbee3ee61ad6ae3025ad56ade9a6f9e30dbd508a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component allows user to select some items by up/down keys and confirm selection by the `enter` key. - supports auto-scroll __Configuration__ - `selectoritem {String}` a selector for browsing items (default: `.item`) - `selector {String}` a default selector for capturing keys (default: `input`) - `class {String}` a selection class (default: `selected`) - `autoselect {Boolean}` it should select first item (default: `true`) - `autoscroll {Boolean}` enables/disables auto-scroll (default: `true`) - `exec {String}` a link to the `function(jqueryel)`, evaluated by the `enter` key (optional, otherwise will be trigger `click` event) - `delay {Number}` a delay for auto-selecting first value - `datasource {String}` a link to the data-source that can help you with a dynamic list Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    1
    2
    3
    4
    5
    ``` ## j-KeyValue Source: https://forge.totaljs.es/en/components/keyvalue/ Framework: jcomponent@20 Content-SHA256: 41a10b482b547525c9ae32155f9658defd0d06d5e8f050603989b2710a1e29a1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple component for create key/value pairs values. __Configuration__: - `placeholderkey {String}` a placeholder for the key input - `placeholdervalue {String}` a placeholder for the value input - `icon {String}` a label icon without `ti-` - `maxlength {Number}` max. lenght for inputs - `label {String}` a label (default: `innerHTML`) - `disabled {Boolean}` can disabled this control - `autocomplete {String}` a link to `function(input, component)` which is executed when an `input` is focused __Other functionality__ ```javascript // Binder SETTER('keyvalue/binder', function(type, value) { if (type === 'key') return value.toUpperCase(); else // type === 'value' return value; }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Key Value component ``` ## j-LargeForm Source: https://forge.totaljs.es/en/components/largeform/ Framework: jcomponent@20 Content-SHA256: 05884d5c653523aa8e34afbe39e4f60591383ec72886cc1eb368e328b2bd3b08 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `title {String}` form title - `width {Number}` form max-width - `if {String}` condition for showing of the form, it's compared with the value within of `path` - `icon {String}` Total icon without `ti-` or __new__: `ti ti-home` - `reload {String}` link to a global `function(largeform_component)` and it's executed if the form is displaying - `submit {String}` link to a global `function(hide)` and it's executed if the submit button is pressed - `cancel {String}` link to a global `function(hide)` and it's executed if the cancel button is pressed - `enter {Boolean}` captures `enter` key automatically and performs submit (default: `false`) - `center {Boolean}` centers the form to middle of screen - `autofocus {Boolean/String}` can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `closebutton {Boolean}` can hide `x` button (default: `false`) - `zindex {Number}` can affect z-index (default: `12`) - `scrollbar {Boolean}` enables custom scrollbar (default: `true`) - `scrolltop {Boolean}` enables scrolling to top after form is displayed (default: `true`) - `scrollbarshadow {Boolean}` optional, enables a shadow in scrollbar (default: `false`) - `style {Number}` supports two styles (1: classic (default), 2: bottom of for is without padding) - `closeoutside {Boolean}` closes the form when the user clicks outside of the form (default: `false`) - `closeesc {Boolean}` closes the form when the user presses `ESC` key - `independent {Boolean}` closing doesn't depent on the condition according to the path - `close {String}` link to a global `function()` and it's executed if the form is closing - __NEW__ `hide {String}` link to a global `function()` and it's executed if the form hides __Good to know__: New version of this component supports dynamic evaluation of the content of ` ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Markdown Source: https://forge.totaljs.es/en/components/markdown/ Framework: jcomponent@20 Content-SHA256: 999520d799fcf1c2993df48b696a78e33988ed312887e82fd8121f065fff360d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component contains only Markdown parser. __Configuration__: - `highlight {Boolean}` enables auto-syntax highlighter (default: `true`) - `charts {Boolean}` enables Apex charts rendering (default: `false`) - `cdn {String}` a default CDN URL address for 3rd party dependencies (default: `DEF.cdn`) __Markdown settings__: ```js var opt = {}; var text = 'YOUR_MARKDOWN_STRING'; console.log(text.markdown(opt)); ``` - `opt.wrap = true` wraps the output with `
    YOUR_MARKDOWN
    ` - `opt.linetag = 'p'` a default new line tag - `opt.ul = true` enables unordered lists - `opt.code = true` enables custom codes - `opt.images = true` enables images - `opt.links = true` enables links - `opt.formatting = true` enables basic text formatting - `opt.icons = true` enables Font-Awesome icons via `:home:` or `:cog:` - `opt.tables = true` enables tables - `opt.br = true` enables new lines via `
    ` - `opt.emptynewline = true` empty lines will be rendered as empty lines - `opt.headlines = true` enables headlines - `opt.hr = true` enables page breaks - `opt.blockquotes = true` enables blockquotes `< blockqote` - `opt.custom = function(line) { return line; }` a custom parser for each processed line - `opt.html = function(line, type) { return line; }` a custom parser for each post-processed line - `opt.sections = true` enables sections `> section` - `opt.footnotes = true` enables footnotes `#1: foot note description` and usage in links `[link](#1)` - `opt.urlify = true` converts URL addresses to links - `opt.keywords = true` parses keywords in the form `{keyword}(type)` - `opt.noredraw = true` skips redrawing of code/video/section/block parts (default: `false`) - `opt.element {jQuery}` HTML element that will be used as a default element in `FUNC.markdownredraw()` - `opt.bookmarks {Boolean}` enables/disables creating headline bookmarks `id=""` (default: `true`) - `opt.prefix {String}` a prefix for bookmarks (default: `empty`) - __NEW__: `opt.ol = true` enables ordered lists __Good to know__: - images will be with `img-responsive` class - images with `![+Image description](URL)` will be formatted as an inline image - images with `![-Image description](URL)` will be rendered as an inline image with class `gallery` instead of `img-responsive` - all links are with `_target="_blank"` attribute - markdown registers `FUNC.markdownredraw(jQuery_selector, [markdown_options])` for prerendering of Markdown dynamic elements like code highlight, videos or charts - secret section is defined like code with syntax `secret` - class `markdown-small` can decrease font sizes - event `ON('markdown', function(el, opt) {})` is executed if the markdown is pre-rendered (`el {jQuery}` is ` ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Layer Source: https://forge.totaljs.es/en/components/layer/ Framework: jcomponent@20 Content-SHA256: 163cc9211b7f715dc49741961c8235517280cbe26da04a37adbee812c6aac765 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Works with Bootstrap __Configuration__: - `title` {String} form title - `if` {String} condition for showing of layer, it's compared with the value within of `path` - `reload` {String} link to a global function and it's executed if the form is showing - `container` {String} jQuery selector for auto-height dimension (default: `.ui-layer-body`) - `default` {String} (optional) a short alias for `DEFAULT(default, true)` - `scrollbar` {Boolean} enables custom scrollbar (default: `true`) - __NEW__: `autofocus` {Boolean/String} focuses the first input, textarea (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur hic quod, asperiores dicta.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur hic quod, asperiores dicta.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur hic quod, asperiores dicta.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur hic quod, asperiores dicta.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur hic quod, asperiores dicta.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur hic quod, asperiores dicta.
    ``` ## j-Layout Source: https://forge.totaljs.es/en/components/layout/ Framework: jcomponent@20 Content-SHA256: b0c53645d08764ea6447ace7388d436af5256a381daf4d58d035cb744f290c21 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - This component can create a layout for your SPA. This component is a bit harder for understanding, but it's very helpful. `j-Layout` uses jComponent `+v17`. __Configuration__: - `parent {String}` can contain `parent`, `window` or jQuery selector for the `closest` method (default: `window`) - `margin {Number}` adds margin for the `height` (default: `0`) - `remember {Boolean}` can remember last settings of layout for resizing (default: `true`) - `space {Number}` internal, contains a space between panels (default: `1`) - `border {Number}` internal, contains a border size (default: `0`) - `resize {String}` internal, a path to method which it's executed when the layout is resized - `autoresize {Boolean}` enables auto-resize (default: `true`) __Methods__: - `component.refresh()` refreshes layout - `component.resize()` performs resize - `component.reset()` performs reset of resizing - `component.layout(name)` changes a layout (like two way data-binding) - `component.rebind(code_string)` makes a new layout configuration - `component.lock(type, [boolean])` locks the panel __Panel types__: - `left` left panel, resizable - `right` right panel, resizable - `right2` right panel will be next to the left panel and uses `right` key in the config, resizable - `top` top panel, resizable (it's panel on top of all panels) - `top2` top panel, resizable and uses `top` key in the config (it is between `left` and `right` panel) - `bottom` bottom panel, resizable (it's panel on bottom of all panels) - `bottom2` bottom panel, resizable and uses `bottom` key in the config (it is between `left` and `right` panel) - `main` main panel, __can't be resizable__ and size is counted automatically __Layout__: Making of layout is very easy and with a lot of possibilities. Layout must have own HTML structure. Look to example. The example below describes only meta data of the layout. - `size {Number/String}` can contain a height/width of panel according to the panel type. Number `120` defines pixels and String `100%` can define percentage - `minsize {Number/String}` is a minimal size of the panel while the panel is resizing (default: `size` value) - `maxsize {Number/String}` is a maximal size of the panel while the panel is resizing (default: auto-counted) - `resize {Boolean}` enables resizing of the panel with except `main` panel (it's counted automatically) - `show {Boolean}` enables visibility (default: `false`) ```js { top: { size: 80, resize: true, minsize: 50 }, // top panel right: { size: 100 }, bottom: { size: 100 }, // bottom panel left: { size: 100, resize: true }, // left panel main: {}, // main panel // Can contain a different template for various display types // lg = Large display, md = Medium display, sm = Small display, xs = Extra small display md: { top: { show: true, size: 80 }, bottom: { show: false }, left: { show: false }, main: { show: true } }, // Custom layouts detail: { // Custom display types in custom layouts md: { top: { show: true }, bottom: { show: true }, main: { show: true }, left: { show: false }, right: { show: true, size: 300 } }, xs: { top: { show: true }, bottom: { show: true }, main: { show: false }, left: { show: false }, right: { show: true, size: '100%' } } } } ``` __Good to know__: - __IMPORTANT__: this component must contain meta-data of the layout wrapped in `` - each panel is `section` element and must contain `data-type="top"` attribute with type of panel - define panels only which you will use - ordering of all `section` elements isn't important - `top2` uses `top` config key - `right2` uses `right` config key - `bottom2` uses `bottom` config key Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    ``` ## j-Layout2 Source: https://forge.totaljs.es/en/components/layout2/ Framework: jcomponent@20 Content-SHA256: d51912a9c58b3d7d7c691010eaea64c83660e1a64d2d53f50df11e7339d3b6ca Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - This component is a much simple component compared to `j-Layout`. __Configuration__: - `parent` {String} can contain `parent`, `window` or jQuery selector for the `closest` method (default: `window`) - `margin` {Number} adds margin for the `height` (default: `0`) - `autoresize` {Boolean} enables auto-resize (default: `true`) __Methods__: - __IMPORTANT__ `component.show(type)` can show a specific panel for mobile devices, `type` can be `left`, `right` or `main` - `component.resizescrollbar(panel_type)` resizes a scrollbar for a specific panel - `component.scrolltop(panel_type)` scrolls to top for a specific panel __Panel types__: - `left` left panel - `right` right panel - `top` top panel (it's panel on top of all panels) - `top2` top panel and uses `top` key in the config (it is between `left` and `right` panel) - `bottom` bottom panel (it's panel on bottom of all panels) - `bottom2` bottom panel and uses `bottom` key in the config (it is between `left` and `right` panel) - `main` main content __Layout__: Making of layout is very easy. ```html
    ``` __Attributes__: - `data-type` must contain a type of section `top`, `top2` ,`left`, `right`, `bottom`, `bottom2` or `main` - `data-size` contains a size of section `LG,MD,SM,XS` --> in pixels or percentage, example: `200,200,200,0` (`0` means hidden) or `20%` (all values will inherit `20%`) - `data-scrollbar="margin:50;visible:1"` enables scrollbar, possible values: - `selector` {String} optional, jQuery selector for scrollbar container - `margin` {Number} scrollbar margin (default: `0`) - `visible` {Boolean} shows the scrollbar __Good to know__: - each panel is `section` element and must contain `data-type="top"` attribute with type of panel - define panels only which you will use - ordering of all `section` elements isn't important Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-LazyContent Source: https://forge.totaljs.es/en/components/lazycontent/ Framework: jcomponent@20 Content-SHA256: 34629eb3b93d9f18a8dbfd1ecc34fbb405710be49d6cb154fc9c5d4fabf81f8f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component shows own content when it's visible. It supports helpful features as `redraw` and `hide`. __Configuration__: - `height:NUMBER_IN_PIXELS"` optional, a default content height. __Default value__: is height of the current element - `init:method_or_variable"` is executed when the element first time visible is (optional) - `redraw:method_or_variable"` is executed when the element again visible is (optional) - `hide:method_or_variable"` is executed when the element hidden is (optional) __Notes__: - `init` will be executed only one time - `redraw` and `hide` will be executed more times - if the attributes contains link to `variable` (not methods) then as value is stored `Boolean` value. - __important__: scroll area must be `document.body` element Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    SCROLL DOWN




















































































    .... default content ....



















































































    .... default content ....











    ``` ## j-LazyImages Source: https://forge.totaljs.es/en/components/lazyimages/ Framework: jcomponent@20 Content-SHA256: 977ab4051ff8aaffd743570a30b645bab9c368982590b0a74f9ec2414fb2a6f3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Good to know__: The component tries to find all ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    SCROLL DOWN
    ``` ## j-LazyLoad Source: https://forge.totaljs.es/en/components/lazyload/ Framework: jcomponent@20 Content-SHA256: 2191ce2af9166b31ea507bb7f4e814004eec086e56520cf68decaaec6eb04217 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - can be used for everything - vertically position only __Configuration__: - `container {String}` a selector as a scrolling container (default: `window`) - `selector {String}` (__important__) selector for lazy elements - `exec {String}` a link to method, executed if the lazy element is visible - `offset {Number}` this value extends the size of scrolling area top/bottom. (default: `50`) __Methods__: - `instance.refresh()` refreshes current state Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    SCROLL DOWN
















































































    ``` ## j-Leaflet Source: https://forge.totaljs.es/en/components/leaflet/ Framework: jcomponent@20 Content-SHA256: ba295cb1b566c08425730ecbecbab7f260aaac3d696ee7379be4d5b82963f931 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component uses [Leaflet](https://leafletjs.com/) library with the [OpenStreetMap](https://www.openstreetmap.org/) map engine. The component uses 3rd party dependencies. __Configuration__: - `height {Number/String}` fixed height or a parent element (default: `200`) - `margin {Number}` a margin for parent element (default: `0`) - `marker {Boolean}` enables marker (default: `true`) - `draggable {Boolean}` enables draggable marker (default: `false`) - `zoom {Number}` a default zoom level (default: `10`) - `maxzoom {Number}` a maximum zoom level (default: `19`) - `icon {String}` a URL to the default marker icon - `iconanchor {String}` optional, icon anchor in the for `x,y` (default: `undefined`) - `iconsize {String}` optional, icon size in the for `w,h` (default: `undefined`) - `move {String}` move event - a link to the function or variable `function(pos)` - `click {String}` a marker click event - a link to the function or variable `function(pos)` - `center {String}` a default location (e.g. `Bratislava, Slovakia`) if the `setter` value is empty/nullable - __NEW__: `exec {String}` optional, a link to the `function(value, component)` (it will be executed when the value is changed) __Methods__: - `component.search(location, callback)` searchs locality in the OpenStreetMap API (response is array) - `component.parse(pos)` returns parsed GPS to array `[lat, lon, zoom]` - `component.center(pos)` centers map to the specific position Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-LineChart Source: https://forge.totaljs.es/en/components/linechart/ Framework: jcomponent@20 Content-SHA256: 31f047d7d02801f2c38a11680386adf301c0ab8bbf412983c3612c499f81ae2e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Please review an example and keep a data-source. __Configuration__: - `offsetX {Number}` An offset X for value tooltip (default: `10`) - `offsetY {Number}` An offset Y for value tooltip (default: `10`) - `templateX {String}` Tangular template for X axis (default: `{{ value }}`) - `templateY {String}` Tangular template for Y axis (default: `{{ value | format(0) }}`) - `selected {String}` Tangular template for selected values (default: `{{ value | format(0) }}`) - `height {Number/String}` height (default: `0` = auto-height) or `string` is meant as a parent element - `width {Number/String}` width (default: `0` = auto-width) or `string` is meant as a parent element - `limit {Number}` a maximum limit of value for Y axis (default: `0`) - `fill {Boolean}` enables filling (default: `false`) - `fillopacity {Number}` filling opacity (default: `0.1`) - `point {Number}` size of `point` (default: `5`) - `pl {Number}` lines left padding (default: `10`) - `pr {Number}` lines right padding (default: `10`) - `pt {Number}` lines top padding (default: `10`) - `pb {Number}` lines bottom padding (default: `25`) - `type {String}` lines type, can be `normal`, `curves` or `step` (default: `normal`) - `prselected {Number}` right padding for selected value (default: `0`) - `avg {Number}` average value (chart renders a new black line) - `xmod {Number}` performs `modulo` for points on x-axis (default: `0`) - `yaxis {nubmer}` a count of y-axis points (default: `4`) - `exec {String}` a path to function and it's executed after some point is hovered - `marginW {Number}` a margin for `width` - `marginH {Number}` a margin for `height` __Good to know__: The `templateX`, `templateY` and `selected` config options can be defined without the use of the `{{` and `}}` brackets. The component appends them automatically. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    ``` ## j-ListBox Source: https://forge.totaljs.es/en/components/listbox/ Framework: jcomponent@20 Content-SHA256: 25ccccc15a7a4d7d78222d4f25585f2056b354d28ffb983c30cc06b65a49b012 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - __NEW__ dark mode - Works with Bootstrap __Configuration__: - `required` {Boolean} enables `required` (default: __false__) - `items` {String} static items `key1|value1, key2 with value, key3|value` - `type` {String} can be `number` (converts `String` values to `Number`) - `datasource` {String} path to data-source (must be array) - `text` {String} determines a property name for text (in data-source), default: `name` - `value` {String} determines a property name for value (in data-source) default: `id` - `empty` {String} adds an empty field - `disabled` {Boolean} disables this component - `search` {String} enables search box with this value as a placeholder - `height` {Number/String} height (default: `200`), `string` can contain `parent`, `window` or `.parent_selector` - `multiple` {Boolean} `true` expects `Array` in `path` (default: `false`) - `exec` {String} a link to function which is executed when the user click on the item Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-ListDetail Source: https://forge.totaljs.es/en/components/listdetail/ Framework: jcomponent@20 Content-SHA256: 4d0ae09df904a052289e4784c5f84ff7c7495ddc5bf0a0c30307b1c6d58c9493 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component divides the content for listing part and detail part. Displaying of detail part depends on the `path {Boolean}`. __Configuration__: - `parent {String}` parent element for obtaining of width/height (default: `auto`) - `margin {Number}` a margin for height (default: `0`) - `width {Number/String}` a detail panel width (default: `35%`) - `minwidth {Number/String}` a minimal width of the detail panel (default: `20%`) - `maxwidth {Number/String}` a maximal width of the detail panel (default: `50%`) - `resize {Boolean}` enables/disables detail panel resizing (default: `true`) - __NEW__: `position {String}` split orientation: `vertical` (side-by-side) or `horizontal` (stacked) (default: `vertical`) - __NEW__: `height {Number/String}` a detail panel height (only for `position:horizontal`; when set, it overrides `width` for sizing the detail panel) (default: `null`) - __NEW__: `minheight {Number/String}` a minimal height of the detail panel (only for `position:horizontal` + `height`) (default: `null`) - __NEW__: `maxheight {Number/String}` a maximal height of the detail panel (only for `position:horizontal` + `height`) (default: `null`) Parts: list + detail must be wrapped to independent `
    ` element, e.g. ```html
    LIST
    DETAIL
    ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ListForm Source: https://forge.totaljs.es/en/components/listform/ Framework: jcomponent@20 Content-SHA256: 643a9afb1e999c23004c60d0e861d476857792aabf44e854599de9b65ed9561a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `autofocus {String/Boolean}` focuses the first input element, `string` means a custom selector (default: `false`) - `empty {String}` empty list text (default: `---`) - `default {Boolean}` performs `DEFAULT()` method for the form scope (default: `true`) - `required {Boolean}` controll will be "required" (default: `false`) - `enter {Boolean}` allows to use `enter` as submit (default: `false`) - `disabled {Boolean}` disables the control (default: `false`) - `formclass {String}` a custom class for form container - `itemclass {String}` a custom class for item container - `create {String}` a link to a function `function(empty_object, callback(DEFAULT_ITEM_OBJECT), arr)` (`null` value skips creating) - `submit {String}` a link to a function `function(form_data, callback(NEW_DATA), arr, item_ref_in_items)` (`null` value skips updating) - `update {String}` a link to a function `function(form_data, callback(NEW_DATA), arr, item_ref_in_items)` (`null` value skips updating) - `remove {String}` a link to a function `function(remove_item, callback(really_remove?), arr)` - `selector {String}` a jQuery selector for custom template (outside of the component). Works like `custom template` in [data-binding](https://wiki.totaljs.com/jcomponent/08-data-binding/) - `footertop {Boolean}` moves the footer on the top of the component (default: `false`) - `move {String}` a link to a function `function(items)` - `newbie {String}` a property name for every new item (it will always contain `true` value) - `plugin {String}` a custom plugin name inside the component (default: `component.ID`) - `invalidform {Boolean}` disables `j-Validate` component if the `j-ListForm` is in editing mode (default: `false`) - __NEW__: `delay {Number}` initial delay for displaying detail (default: `1000` ms) The component needs to have defined 3 templates wrapped in `
    ``` ## j-Listing Source: https://forge.totaljs.es/en/components/listing/ Framework: jcomponent@20 Content-SHA256: a177ebc6513285b5648c7acfabb183abf0b150a5883b3c6e8a260d9d3a114402 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - works with the whole Arrays only on client-side __Configuration__: - `count {Number}` Optional, items per page (default: `20`) - `pages {Number}` Optional, max pages in pagination (default: `3` --> half + current page + half) - `scrolltop {Boolean}` scrolls top automatically when the user changes a page - `parent {String}` jQuery selector for obtaining of height, enables fixed area with custom scrollbars - `margin {Number}` a margin for `parent` (default: `0`) - `marginxs {Number}` optional, a top/bottom margin together for `xs` screen width - `marginsm {Number}` optional, a top/bottom margin together for `sm` screen width - `marginmd {Number}` optional, a top/bottom margin together for `md` screen width - `marginlg {Number}` optional, a top/bottom margin together for `lg` screen width - `pluralizeitems {String}` a pluralization for count of all items, form: `# zero,# one,# two-four,# five and more` - `pluralizepages {String}` a pluralization for count of all items, form: `# zero,# one,# two-four,# five and more` - __NEW__: `scrollbarshadow {Boolean}` enables scrollbar shadow __Tangular layout__: - `body {String}` contains all rendered items, output is __HTML__ - `page {Number}` current page number - `pages {Number}` count of pages - `count {Number}` count of items __Tangular item__: - `model` contains an object from `Array` - second model contains info about data-source `{ index: Number, page: Number, pages: Number, count: Number }` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    With layout


    Without layout


    ``` ## j-ListMenu Source: https://forge.totaljs.es/en/components/listmenu/ Framework: jcomponent@20 Content-SHA256: dc8f16e32afa775442856e30e75fd0501619d842616001db609508ddadf1f79c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A ListMenu component for custom list items. You need to style it. __Configuration__: - `class` {String} CSS class for selected item (default: `selected`) - `selector` {String} jQuery selector for scope of rendered item (default: `a`) - `datasource` {String} data-source path (Array) - `property` {String} Property name for comparing of values (default: `id`) - `click` {Boolean} enables clicking on items (default: `true`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ListMenuEditable Source: https://forge.totaljs.es/en/components/listmenueditable/ Framework: jcomponent@20 Content-SHA256: f718ede85688c86b6a32357da3633fd98e015c3316c210f37e303ca6e81e85d1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Component for editable list menu - You can change CSS for your needs. __Configuration__: - `iconremove {String}` optional, change `remove` button icon. It's fontawesome icon without `ti-` part (default: `times`) - `defaulticon {String}` optional, change `edit` button icon (default: `pencil-alt`) - `addicon {String}` optional, will change `add` button icon (default: `plus-square`) - `placeholder {String}` optional, a placeholder for input (default: `Write text and press ENTER`) - `class {String}` CSS class for selected item (default: `selected`) - `title {String}` optional, will add title on top of list menu (important if you want use `addicon` and `addclick`) - `key {String}` optional, a default `key` for `text` value (default: `name`) - `click {String}` optional, action after click on item in menu. Path to function(element, index) - `addclick {String}` optional, action after click on `add `button. Path to function() executes when user click on `add` icon - `editclick {String}` optional, action after click on `edit` button. Path to function(element, index) __Methods__: - `component.add(object)` - This function will push object into path (can be null) - `component.edit(index)` - Function will enable edit on element - `component.remove(index)` - Function will remove the index __Good to know__: Path __must be__ array of objects. After click on item in menu Supports dynamic evaluation of the content of ` ``` __Adding of custom class__: ```javascript var opt = {}; opt.items = []; opt.push({ name: 'Total.js', classname: 'your_class_name' }); ``` __Toggle editable__: ```javascript var opt = {}; opt.items = []; opt.push({ name: 'Total.js', editable: true }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-LiveStats Source: https://forge.totaljs.es/en/components/livestats/ Framework: jcomponent@20 Content-SHA256: a50bc5802cfe96762134533f106347e462c061fb237e263d0dc75b7b2732726b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ - responsive __Configuration__: - `width {Number/String}` width of svg, you don't need to change it (default: `500`) or `{String}` jQuery selector for obtaining of height - `height {Number/String}` height of svg, you don't need to change it (default: `100`) or `{String}` jQuery selector for obtaining of height - `colors {String}` defines custom colors for each key in the form `KEY=COLOR,KEY=COLOR,KEY=COLOR` - `max {Number}` a max. limit (default `0` - disabled) - `axislines {Number/String}` a count of X axis lines (default: `20`) or `auto` automatically counts count of lines - `marginW {Number}` a margin for `width` - `marginH {Number}` a margin for `height` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-LoadContent Source: https://forge.totaljs.es/en/components/loadcontent/ Framework: jcomponent@20 Content-SHA256: a3a08f3b2e76e53c8f767eacfb4702d273c17e4fd37620c5c7eb3084b875ef39 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component loads a content from the template `


    ``` ## j-Loading Source: https://forge.totaljs.es/en/components/loading/ Framework: jcomponent@20 Content-SHA256: fca954096b9603e12fa149fac058616bcf1f34e66131ff098dd1a559471551c5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - it automatically assigns flags `@showloading` and `@hideloading` __Configuration__: - __NEW__: `style {Number}` a loading style (default: `1`) - `1`: basic with animated spin - `2`: a blue line at the top of window __Usage__: - `SETTER('loading/show', [text])` - shows loading (`text` optional) - `SETTER('loading/hide', [sleep])` - hides loading (`sleep` optional and in milliseconds) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    ``` ## j-Locale Source: https://forge.totaljs.es/en/components/locale/ Framework: jcomponent@20 Content-SHA256: 3091033db97448f7ec8934ff82579a2a5db8a676f43327de1ccbb75f42b81016 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component sets current browser locale (number format, date format and time format) according to the `navigatior.language`. - singleton - `path` will contain current's browser locale - sets `DEF.dateformat` and it creates environment value called `[ts]` __Configuration__: - `language {String}` optional, a custom language (default: `navigator.language`) - `requests {Boolean}` optional, adds a language to the every request (it affects `DEF.languagehtml`, default: `false`) __Environments__: - `[ts]` full timestamp - `[date]` only date - `[time]` only time __Output__: ```js { dt: 'yyyy–MM–dd', // date format nf: 1, // number format: 1 = 100 000.123, 2 = 100 000,123, 3 = 100.000,123, 4 = 100,000.123 fdw: 0, // first day of week tf: 24 // time format: 12, 24 } ``` __Methods__: - `component.use(language)` __Supported special languages__: - `eu` with the dd.MM.yyyy with a 24 hour system - `us` with the MM-dd-yyyy with a 12 hour system Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-MainProgress Source: https://forge.totaljs.es/en/components/mainprogress/ Framework: jcomponent@20 Content-SHA256: e97fbb6956c9264c306cb253aa2eba30c68c29a850ea4ac3eeb65bb446be767f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component is singleton. The component is visible when the value if more than `0` and less than `100`. Data-binding expects `Number`. __Configuration__: - `position {String}` optional, can be `bottom` (default: `top`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Map Source: https://forge.totaljs.es/en/components/map/ Framework: jcomponent@20 Content-SHA256: 81614f13bb2b247e91557b7c1f2d27f48e0b1daba602bc896ff2f7736bcbf1f3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - `path="target.property"` can contain GPS `48.727903,19.157763` or text `Viestova 28, Banská Bystrica, Slovakia` - two way binding works with GPS (so the component returns GPS coordinates into the model when the `text` is used instead of GPS) - __important__: the component element (or its `CSS`) must have defined `width` and `height` style attributes __Configuration__: - `key` __IMPORTANT__ Google API key - `type` (optional) has to contain a map type (`roadmap` (default), `satellite`, `hybrid`, `terrain`) - `draggable` (optional) for drag & drop marker (default: `false`) - `click` (optional) has to contain a function name and this method is evaluated when the user click on the marker - `zoom` (optional), default `13` - `icon` (optional) has to contain a URL to a new icon marker - `animation` (optional) has to contain a animation type (`bounce` and `drop`) __Methods__: - `component.search(lat, lng)` arguments must be numbers - `component.search(text)` arguments must be a string - `component.reset()` call `resize` event (useful for modals) - `component.reset(lat, lng)` arguments must be numbers Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-MapZones Source: https://forge.totaljs.es/en/components/mapzones/ Framework: jcomponent@20 Content-SHA256: 287457598ac3fb791d14d216c667a776df7a5030b56e856266727d89c74213d1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component for drawing and displaying zones on the map. This component uses [OpenLayers](https://openlayers.org/) library with the [OpenStreetMap](https://www.openstreetmap.org/) map engine. The component uses 3rd party dependencies. __Configuration__: - `height {Number/String}` fixed height or a parent element (default: `200`) - `color {String}` enables custom color for created polygon (default: `#fcba03`) - `zoom {Number}` a default zoom level (default: `11`) - `modify {Boolean}` enables modifiyng of the polygon (default: `true`) - `opacity {Number}` determines the transparency of the polygon in percentage (default: `20`) - __NEW__ `exec {String}` a link to the `function(value)`, it's executed when the value is changed __Data-source__ needs to contain: ```js { points: [{ lat: 48.75152530164132, lng: 19.13902142954625 }, { lat: 48.726826662905296, lng: 19.123238694044034 }, ...] // polygon points color: '#FD391A', // optional zoom: 13 // optional } ``` __Good to know__: - `SHIFT + click` on vertices (created point) will delete selected point Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Dodo Marton / Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-MarkdownEditor Source: https://forge.totaljs.es/en/components/markdowneditor/ Framework: jcomponent@20 Content-SHA256: db5579b1ca83932f175d7d5485fcd137fc7bf9635d491c23c711b0bdfc6dcf2b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component use `https://simplemde.com/` editor for markdown editing. __Configuration__: - `required` {Boolean} optional, default `false` - `label` {String} optional, default `html` of the element Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Michal Capo. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-MarkdownPreview Source: https://forge.totaljs.es/en/components/markdownpreview/ Framework: jcomponent@20 Content-SHA256: b57b2722ddefdc7c68a1832ff9e5c78a504355420b4a5267968aa0e026551d1a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component depends on `j-Markdown` component. It uses `highlight.js` library for syntax highlight. - supports syntax highlighting - supports YouTube, Vimeo and custom iframes - supports barchart and linechart rendering via ApexCharts __Configuration__: - `showsecret` {String} a label for displaying of secret (default: `Show secret data`) - `hidesecret` {String} a label to hide of secret (default: `Hide secret data`) - `html` {Boolean} prepares inner HTML (it expects rendered Markdown) with Markdown utilities (syntax, secrets, links, etc.) - `headlines` {String} a link to method `method(headlines)` will be executed when the headlines will be parsed as quick bookmarks __Custom methods__: - `component.readingtime()` returns approximate reading time in minutes - `component.redraw(jquery_el)` applies syntax highlighting, iframes and charts for the `el` element Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Masonry Source: https://forge.totaljs.es/en/components/masonry/ Framework: jcomponent@20 Content-SHA256: e29219a14cca8cc372282d9015607362b650652c0facabb85a077a0cc6758d0b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple Masonry component. The component renders an Array according to the display size to columns. __Configuration__: - `lg {Number}` (large display) column width in percentage (default: `25`) - `md {Number}` (medium display) column width in percentage (default: `33.33`) - `sm {Number}` (small display) column width in percentage (default: `50`) - `xs {Number}` (extra-small display) column width in percentage (default: `100`) - __NEW__ `vdom {String}` optional, an item jQuery selector for virtual dom comparing - __NEW__ `vdomattr {String}` optional, an attribute name for comparing virtual dom elements (values from the attribute will be compared between each other) __Tangular model__: - `value {Object}` contains a raw value from the array - `index {Number}` a current processed row within the column - `column {Number}` a current column index - `counter {Number}` a current index of processed item within the array Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Menu Source: https://forge.totaljs.es/en/components/menu/ Framework: jcomponent@20 Content-SHA256: ee1f4a3cfd3e652aa83928f8236886ed5bff25ba52bc28e9c4b27854240ae20b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - works with touches - supports __Dark mode__ - singleton - __NEW__ supports large mode __Configuration__: - __NEW__ `style {Number}` changes style (supported style `2` (default) and `1`) ## Usage ```js var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align `left` (default), `center` or `right` // opt.position {String} : position `top` (default) or `bottom` // opt.hide {Function} : is executed when the menu is hidden // opt.class {String} : adds class to the parent // opt.large {Boolean} : it will make menu bigger // opt.fixedwidth {Boolean} : NEW: enables fixed width according to the target element // opt.offsetWidth {Number} : increases width of the menu // opt.nomobile {Boolean} : change size on mobile screen opt.element = YOUR_ELEMENT; // or if you want to use a fixed position: // opt.x {Number} : `x` position // opt.y {Number} : `y` position opt.items = ['Label', { name: 'Item 1', icon: 'print', class: 'custom_class_name' }, { name: 'Item 2', icon: 'home', note: 'A simple description for this item' }, '-', { name: 'Item 3', icon: 'ti ti-envelope', children: [{ name: 'Submenu item 1', icon: 'cog' }, { name: 'Submenu item 2', icon: 'home' }] }, { name: 'Selected', icon: 'check-circle', selected: true }, { name: 'Item 4', icon: 'gear', disabled: true }]; // Item properties // name {String} : Item name // icon {String} : Icon // class {String} : class to be added to li element // note {String} : text bellow Item name // selected {Boolean} : item will be highlighted // disabled {Boolean} : item will be disabled(not clickable) // children {Array} : array of subitems // color {String} : icon color opt.callback = function(item) { console.log(item); }; SETTER('menu', 'show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Message Source: https://forge.totaljs.es/en/components/message/ Framework: jcomponent@20 Content-SHA256: a793e95708c8086f7287312baec181c47ca6d2fbd28c52615e86da59ef044d11 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton __Configuration__: - `button {String}` a button label (default: `OK`) - `style {Number}` can change a style (default: `1`), style `2` is similiar to `j-Approve` component - `closeoutside {Boolean}` enables closing of message box by clicking outside of main button __Usage__: ```js SETTER('message/warning', 'Some warning'); SETTER('message/success', 'Some success message'); SETTER('message/info', 'Some info message'); ``` __Works with ASETTER__: - errors are handled automatically ```js // Without callback AJAX('POST /api/profile/', userprofile, ASETTER('message/response', 'Profile has been saved successfully')); // Or with a callback AJAX('POST /api/profile/', userprofile, ASETTER('message/response', 'Profile has been saved successfully', function(response) { console.log(response); })); // Or with a callback and without message AJAX('POST /api/profile/', userprofile, ASETTER('message/response', function(response) { console.log(response); })); // With auto-binding AJAX('POST /api/profile/', userprofile, ASETTER('message/response', '?.response')); AJAX('POST /api/profile/', userprofile, ASETTER('message/response', 'Your message', '?.response')); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-MinHeight Source: https://forge.totaljs.es/en/components/minheight/ Framework: jcomponent@20 Content-SHA256: 2a53bd9287bd687a374aedbcfba5075e55029fc99f5226853e0cd09379980cd0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component sets a minimal height for the `parent` (defined) element. The component is usefull for intranet applications. __Configuration__: - `parent {String}` a parent container which sets a minimal height (default: `parent`) - `margin {Number}` a margin (default: `0`) - `topoffset {Boolean}` applies `element.offset().top` as a margin (default: `false`) - `topposition {Boolean}` applies `element.position().top` as a margin (default: `false`) - `attr {String}` CSS attribute for setting of height (default: `min-height`) - `minheight {Number}` a min. height (default: not defined) - `disabledxs {Boolean}` disables height for `xs` display - `disabledsm {Boolean}` disables height for `sm` display - `disabledmd {Boolean}` disables height for `md` display - `disabledlg {Boolean}` disables height for `lg` display Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-MiniForm Source: https://forge.totaljs.es/en/components/miniform/ Framework: jcomponent@20 Content-SHA256: b5e45b6c6e9bb24bf2131ec352cdd6209bbff118b5c905a0e9489af839f70300 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `title {String}` form title - `width {Number}` form max-width - `if {String}` condition for showing of the form, it's compared with the value within of `ßpath` - `icon {String}` Total icon without `ti-` or __new__: `ti ti-home` - `reload {String}` link to a global `function(miniform_component)` and it's executed if the form is displaying - `submit {String}` link to a global `function(hide)` and it's executed if the submit button is pressed - `cancel {String}` link to a global `function(hide)` and it's executed if the cancel button is pressed - `enter {Boolean}` captures `enter` key automatically and performs submit (default: `false`) - `center {Boolean}` centers the form to middle of screen - `autofocus` {Boolean/String} can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `closebutton {Boolean}` can hide `x` button (default: `false`) - `zindex {Number}` can affect z-index (default: `12`) - `scrollbar {Boolean}` enables custom scrollbar (default: `true`) - `closeoutside {Boolean}` closes the form when the user clicks outside of the form (default: `false`) - `closeesc {Boolean}` closes the form when the user presses `ESC` key - `independent {Boolean}` closing doesn't depent on the condition according to the path - `close {String}` link to a global `function()` and it's executed if the form is closing - __NEW__ `hide {String}` link to a global `function()` and it's executed if the form hides __Good to know__: New version of this component supports dynamic evaluation of the content of ` ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-MobileCarousel Source: https://forge.totaljs.es/en/components/mobilecarousel/ Framework: jcomponent@20 Content-SHA256: 579950570840bbacb2b21540855f592e26e6ca26314c14b748d91440388777ca Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Works only with Bootstrap grid system and in mobile devices `xs`. __Configuration__: - `count {Number}` count of visible items (default: `1`) - `selector {String}` jQuery selector (default: `.col-sm-4`) - `margin {Number}` left margin between items (default: `15`) - `snapping {Boolean}` allows snapping (default: `true`) - `animate {Number}` animation timeout, `0` disables animation (default: `5000`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    Title 1

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, dolores.

    Title 2

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, dolores.

    Title 3

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, dolores.

    Title 4

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, dolores.

    Title 5

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, dolores.

    Title 6

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, dolores.

    Title 7

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, dolores.

    ``` ## j-Modal Source: https://forge.totaljs.es/en/components/modal/ Framework: jcomponent@20 Content-SHA256: 248c444f64eb80df7381f1a1d279ba50b8675a21f6c1f51d4eed4f22335a9748 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Is a simple alternative to `j-Form`. - Works only with `+v17` - The component moves the content of this component under `` tag (because of positioning) __Configuration__: - `title {String}` modal title (it replaces a `HTML` in label element in the header) - `width {Number}` modal max-width - `if {String}` condition for showing of the modal, it's compared with the value within of `path` - `icon {String}` Total icon without `ti-` - `reload {String}` link to a global `function(modal_component)` and it's executed if the form is displaying - `submit {String}` link to a global `function(hide)` and it's executed if the submit button is pressed - `cancel {String}` link to a global `function(hide)` and it's executed if the cancel button is pressed - `enter {Boolean}` captures `enter` key automatically and performs submit (default: `false`) - `center {Boolean}` centers the form to middle of screen - `autofocus {Boolean/String}` can focus an input. `String` === `jQuery selector` for the input - `default {String}` a short alias for `DEFAULT(default, true)` - `zindex {Number}` can affect z-index (default: `12`) - `align {Number}` aligns modal `0` centered (default), `1` right bottom, `2` left bottom, `3` left top, `4` right top - `height {Number}` a min. height if the content has less size than defined `height` - __NEW__ `bg {Boolean}` can enable/disable a background layer (default: `true`) - __NEW__ `scrollbar {Boolean}` can enable/disable the scrollbar (default: `false`) __Good to know__: The content of the `j-Modal` is divided to 3 parts: `header`, `body` and `footer`. Each part must be defined. The component adds CSS classes to each part, for example first `div` will contain `ui-modal-header`, second `ui-modal-body` and third `ui-modal-footer`. --- This component supports dynamic evaluation of the content of `
    ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Modificator Source: https://forge.totaljs.es/en/components/modificator/ Framework: jcomponent@20 Content-SHA256: 59fb60a0293297f9d9497a58e927d17487b50d6542f8f08999b6eae1d28b6115 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can modify behaviour of element according to the preddefined schema. The component can be hooked on a `body` element (because it's singleton) and it's optimized for the performance. __Supported attributes__: - `data-m="SOME.PATH"` - the component will watch this path - `data-m-schema="schema_name"` - modificator uses this registered schema - `data-m-selector=".ui-textbox-label"` (optional) a target element will be an element according to the selector (default: `null`) - __NEW UPDATE__: `data-m="SOME.PATH + schema_name"` this attribute can contain `path` and `schema_name` together __Supported classes__: - `modify` enables `click` event for this element `e.type` will contain `click` type __Registering schema__: - you can define multiple schemas ```javascript instance.register('schema_name', function(value, element, e) { // value: according to the "data-m" // element: jQuery element (target) // e: contains additional data { type: 'init/click/bind' } and can be used as a repository // here you can modify the element }); ``` __Scopes__: j-Modificator supports jComponent scopes but each path in the scope needs to contain `?` question mark e.g. `data-m="?.name"` which is replaced with a scope path. __Important:__ jComponent scope needs to contain some jComponents. ```html
    Your name
    ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-MonacoEditor Source: https://forge.totaljs.es/en/components/monacoeditor/ Framework: jcomponent@20 Content-SHA256: e0daa649a04c212871a6f09a6375ceba83e3fe5c6010430e4030a28ff2f941a1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component renders [Monaco editor](https://microsoft.github.io/monaco-editor/). __Configuration__: - `theme {String}` a default theme (default: `vs-light`) - `language {String}` language / mode (default: `javascript`) - `height {Number}` a default/minimal height (default: `200`) - `parent {String}` optional, a container with fixed height, can be `window` (default value: `auto`) - `margin {Number}` optional, a top/bottom margin together (default: `0`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-MonthlyCalendar Source: https://forge.totaljs.es/en/components/monthlycalendar/ Framework: jcomponent@20 Content-SHA256: 00ec821af6be3d6f798094e4d44acbc5e51cb89be92a94b35940f049a822639b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports only monthly view __Configuration__: - `parent {String}` a jQuery selector for obtaining of fixed height (default `auto`) - `firstday {Number}` first day in the calendar `0 = Sunday`, default `0` - `noborder {Boolean}` disables border (default: `false`) - `selectable {Boolean}` enables selecting of days (default: `true`) - `morebutton {String}` a Tangular template for __More button__ (default: `+{{ count }} more`) - `select {String}` a path to `Function(item_event, el, e)`, be careful: `item_event` can be `null` - `create {String}` a path to `Function({ beg: Date, end: Date }, beg_element, end_element)` - `dblclick {String}` a path to `Function(item_event, el, e)` - `dblclickdate {String}` a path to `Function(date, el, e)` - `contextmenu {String}` a path to `Function(item_event, el, e)` - `rebind {String}` a path to `Function({ dates: Array, date: Date })` is executed when the calendar is rebinded - `topoffset {Boolean}` subtracts `offset.top` from `height` (default: `false`) - `topposition {Boolean}` subtracts `position.top` from `height` (default: `false`) - `margin {Number}` top/bottom margin together (default: `0`) - `marginxs {Number}` top/bottom margin together for `xs` screen width - `marginsm {Number}` top/bottom margin together for `sm` screen width - `marginmd {Number}` top/bottom margin together for `md` screen width - `marginlg {Number}` top/bottom margin together for `lg` screen width - __NEW__: `keepselected {Boolean}` keeps selected (hovered) days (default: `false`) - __NEW__: `hover {String}` a path to `Function({ beg: Date, end: Date }, beg_element, end_element)` (same like `create`, but it's called on `component.hover()` and `component.unhover()` methods) - __NEW__: `scalewidth {Boolean}` scales the height according to the width of the parent element __Methods__: - `component.addevents(events)` adds events - `events` means Array of object below: - `[{ id: String, beg: Date, end: Date, html: String, icon: String, color: String, background: Boolean }]` - `component.addevent(event)` adds an event - can't be combined with `addevents` method - can be executed multiple times - event object: `{ id: String, html: String, icon: String, color: String, background: Boolean }` - __NEW__: `component.addbadge(date, [color])` adds a badge - __NEW__: `component.hover(beg, end)` - __NEW__: `component.unhover()` - `component.clear()` removes all events and badges __Localization__: Month and day names are taken from `MONTHS` and `DAYS` properties defined in jComponent library. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Movable Source: https://forge.totaljs.es/en/components/movable/ Framework: jcomponent@20 Content-SHA256: 04cdb48c16d006fc19c07be7c964da4009c3ca58d2704497ce49443c1634081f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component handles similar `draggable` element and supports movement between each other. Each element according to the selector must have defined `draggable="true"` attribute. __Configuration__: - `selector {String}` jQuery selector for watching - `exec {String}` A path to method which will be executed if the user moves element - `global {Boolean}` drag & drop events will be binded to `document` (default: `false`) - `parent {String}` selector for finding of element where will be binded drag & drop envets (default: current element) - `move {Boolean}` enables auto re-ordering elements (default: `true`) - `container {String}` a selector for finding of the main container - __NEW__ `check {Function(el)}` optional, a function for checking of draggability (it must return `true` or `false`) __Example of `Exec` method__: ```javascript function exec_method(list, dragged, target) { // @list jQuery list } ``` __Good to know__: - `path` performs `CHANGE()` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    A
    B
    C
    D
    E
    F
    ``` ## j-Movement Source: https://forge.totaljs.es/en/components/movement/ Framework: jcomponent@20 Content-SHA256: dc36c810a5e106d8bf76743899b977eba91fef76dd6a1c75f9c2d99fc74b095a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component captures basic keyboard keys like `arrows`, `enter` and `esc`. __Methods__: - `component.assign(ondown(key, e), [onunassign])` The `assign` method will clear previous assignments and applies new ones. We recommend calling the `assign` method to your elements when they are focused, or the user clicks on them. __Usage__: ```js SETTER('movement/assign', function(key, e) { // @key {String} // @ {Event} switch (key) { case 'up': case 'down': case 'right': case 'left': case 'esc': case 'enter': break; } }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Click here and press arrows/enter/esc:
    ``` ## j-MultiOptions Source: https://forge.totaljs.es/en/components/multioptions/ Framework: jcomponent@20 Content-SHA256: a1409af0f37aa0e8995529bd2d89a3f5b0079e613e11b4787d0fec613165db8e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - it expects the whole object with `key`: `value` - HTML body of the jComponent has to be `` - mapping method: `option(key, label, value, [type], [max], [min], [step])` __Basic types__: - type: `string` (when is the value `string` you don't need to define the type) - type: `number` (when is the value `number` you don't need to define the type) - type: `boolean` (when is the value `boolean` you don't need to define the type) - type: `date` (when is the value `date` you don't need to define the type) - __NEW__ type: `multiline` renders `textarea` instead of `input` __Simple Array__: ```js option('language', 'Language', 'sk', ['sk', 'en', 'de']); ``` __Advanced Array__: ```js option('language', 'Language', 1, [{ text: 'sk', value: 1}, { text: 'en', value: 2}, { text: 'de', value: 3}]); ``` __Array from URL__: ```js option('language', 'Language', 1, '/my/api/codelist/'); // It expects some "Array" ``` __Colors__: MultiOptions component uses this color scheme: and the declaration below will show all colors in the widget settings. ```js option('background', 'Background', '#FC6E51', 'Color'); ``` __Good to know__: - all properties not defined in mapping won't be shown - `date` type is linked by `Calendar` component - follow example - `component.remap(js_code)` can remap new configuration - `component.dependencies()` returns `Object` with all items `key/value` from dropdown lists Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-NativeNotifications Source: https://forge.totaljs.es/en/components/nativenotifications/ Framework: jcomponent@20 Content-SHA256: 7b27cd79d303b973bf28304c74fa69d4466cbbfbb6f6889167389edc36456dad Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton __Configuration__ - `timeout {Number}` needs to contain a timeout (milliseconds) for the expiration of notification (default: `8000`) - `icon {String}` (optional) an icon (default `/icon.png`) __Methods__ - `component.append(title, message, [callback], [icon])` for creating a new notification __Usage__ ```javascript SETTER('nativenotifications/show', 'TITLE', 'MESSAGE', function() { // optional, click }, '/img/warning-optional.png'); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Navigation Source: https://forge.totaljs.es/en/components/navigation/ Framework: jcomponent@20 Content-SHA256: b90a3476ea1af22690413e9855316e52591dadb464b6cb364ad1f3e31c887eae Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - a simple navigation component like Tree - easy for customization - supports __dark mode__ __Configuration__: - `exec {String}` a link to the function - `pk {String}` a primary key (default: `id`) for remembering last state of tree __Data-source__: ```javascript [ { id: 1, name: 'Text to navigation item', title: 'Optional, a title attribute', collapsed: true, // only for children, default "false" children: [ // Can contain same structure as the parent ] } ] ``` __Good to know__: - only items without children are clickable - `exec` returns an entire object Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-NavLayout Source: https://forge.totaljs.es/en/components/navlayout/ Framework: jcomponent@20 Content-SHA256: 89914caffa1c67080f98a5bb5d4421d863c3851f5adea4bafe2fb0498ca5d73e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple and fully responsive navigation layout. __Good to know__: - `path {Boolean}` shows the navigation panel in display modes defined in the `hide` config option - `
    ` must contain a navigation - `
    ` must contain a content __Configuration__: - `width {Number}` a size of navigation (default: `250`) - `hide {String}` hides navigation in defined display modes (default: `xs,sm`) - `autoresize {Boolean}` enables auto-resizing (default: `true`) - `position {String}` navigation position (default: `left`) - `margin {Number}` adds margin for `height` (default: `0`) - `parent {String}` can contain `parent`, `window` or jQuery selector for the `closest` method (default: `window`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-NoScrollbar Source: https://forge.totaljs.es/en/components/noscrollbar/ Framework: jcomponent@20 Content-SHA256: 61f3dae55d7cc917bdd96fcf796de95a76b4985992f20bb4fb3e2a5b6f3a0d08 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - this component is something like `j-ViewBox` without native/custom scrollbar __Configuration__: - `parent` {String} optional, a container with fixed height, can be `window`. Default value: `parent` element. - `minheight` {Number} a minimal height in pixels (default: `0` - disabled) - `delay` {Number} `msec.` resizes the box again if the value is changed according to the path (default: `100`) - `scrollto` {String} scrolls to top/bottom automatically if the `path` is changed (default: `EMPTY`, can be `top` or `bottom`) - `margin` {Number} optional, a top/bottom margin together (supports `auto` which is counted from `offset.top`, default: `0`) - `marginxs` {Number} optional, a top/bottom margin together for `xs` screen width - `marginsm` optional, a top/bottom margin together for `sm` screen width - `marginmd` optional, a top/bottom margin together for `md` screen width - `marginlg` optional, a top/bottom margin together for `lg` screen width - `invisible` {Boolean} if `true` then viewbox sets `invisible` class when is rendering (default: `true`) - `initdelay` {Number} removes `inivisible` class after specified time (default: `250` ms) __Methods__: - `component.scrolltop(val)` scrolls Y - `component.scrollbottom(val)` scrolls Y from bottom side - `component.resize()` resizes container (it reacts on `resize` events automatically) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-NoSQLcounter Source: https://forge.totaljs.es/en/components/nosqlcounter/ Framework: jcomponent@20 Content-SHA256: eb6c0718bebd5b2754b7ec18bde27720b8425332c64b7bea4f93c54fcb396d8f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - datasource must be in the form: `[{ id: 201702, year: 2017, month: 2, value: 1690 }]` __Configuration__: - `count` {Number} a maximum bars in the chart (default: `0` === `auto-count`) - `lastvalues` {Boolean} shows only the last values (default: `false`) - `months` {String} months e.g. `January,February,etc.` - __NEW__ `limit` {Number} a maximum limit for `value` (default: `0` - disabled) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Notifications Source: https://forge.totaljs.es/en/components/notifications/ Framework: jcomponent@20 Content-SHA256: e993244f72ce544c610f0171e1bf345611b9b79c12d843d0c4f7cf93b162db7d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton __Configuration__: - `date` {String} a date format (default `yyyy-MM-dd HH:mm`) - `timeout` {Number} has to contain a timeout (milliseconds) for the expiration of notification (default: `8000`) - `native` {Boolean} enables native notifications when is not focused window (default: `false`) __Methods__ - `component.append(icon, message, [datetime], [callback], [color])` for creating a new notification Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quia harum accusamus debitis aut sunt, deserunt magni alias neque unde reprehenderit ipsa ea laboriosam eveniet! Distinctio pariatur sed, a aut nobis. ``` ## j-NotificationsPanel Source: https://forge.totaljs.es/en/components/notificationspanel/ Framework: jcomponent@20 Content-SHA256: fb77d7cd8ef85e3c8a61bff0046eddb89006533e8ec6d63633e58b56cf342b68 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - learn from the example __Configuration__: - `top {Number}` top offset (default: `0`) - `visibleY {Boolean}` shows Y scrollbars (default: `true`) - `title {String}` title in notifications panel (default: `Notifications`) - `autoremove {Boolean}` removes notifications after click on it (default: `true`) - `click {String}` a path to method `function(obj, el)` when the user clicks on the notifications - `exec {String}` a path to method `function(render(ARR_OF_OBJECT))` when the user wants to show the notifications Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Notify Source: https://forge.totaljs.es/en/components/notify/ Framework: jcomponent@20 Content-SHA256: 05e4211faaf007b46dd7f30f5e9e5bf7639bda3307147c18d7fc681f2086f9a8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `timeout {Number}` has to contain a timeout (milliseconds) for the expiration of notification (default: `3000`) - `position {String}` can be `top`, `top left`, `top right` (default), `bottom` , `bottom left` and `bottom right` __Methods__: ```js SETTER('notify/warning', 'Some warning'); SETTER('notify/success', 'Some success message'); SETTER('notify/info', 'Some info message'); ``` __Works with ASETTER__: - errors are handled automatically ```js // Without callback AJAX('POST /api/profile/', userprofile, ASETTER('notify/response', 'Profile has been saved successfully')); // Or with a callback AJAX('POST /api/profile/', userprofile, ASETTER('notify/response', 'Profile has been saved successfully', function(response) { console.log(response); })); // Or with a callback and without notify AJAX('POST /api/profile/', userprofile, ASETTER('notify/response', function(response) { console.log(response); })); // With auto-binding AJAX('POST /api/profile/', userprofile, ASETTER('notify/response', '?.response')); AJAX('POST /api/profile/', userprofile, ASETTER('notify/response', 'Your message', '?.response')); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quia harum accusamus debitis aut sunt, deserunt magni alias neque unde reprehenderit ipsa ea laboriosam eveniet! Distinctio pariatur sed, a aut nobis. ``` ## j-NotifyBar Source: https://forge.totaljs.es/en/components/notifybar/ Framework: jcomponent@20 Content-SHA256: 9ce8beaab5cce3e04360e6ae1123f88c381381c043c313a474a1c072e4e398c1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - success message `SETTER('notifybar/success', 'MESSAGE')` - warning message `SETTER('notifybar/warning', 'MESSAGE')` - info message `SETTER('notifybar/info', 'MESSAGE', '[BUTTON_LABEL]', [callback_dismiss])` __Configuration__: - `timeout` {Number} A timeout in milliseconds (default: `4000`) __Methods__: - `component.success(message)` appends success message - `component.warning(message)` appends warning message - `component.info(message)` appends info message - `component.hide()` hides the bar - `component.show()` shows last message __Works with ASETTER__: - errors are handled automatically ```javascript // Without callback AJAX('POST /api/profile/', userprofile, ASETTER('notifybar/response', 'Profile has been saved successfully')); // Or with a callback AJAX('POST /api/profile/', userprofile, ASETTER('notifybar/response', 'Profile has been saved successfully', function(response) { console.log(response); })); // Or with a callback and without message AJAX('POST /api/profile/', userprofile, ASETTER('notifybar/response', function(response) { console.log(response); })); // With auto-binding AJAX('POST /api/profile/', userprofile, ASETTER('notifybar/response', '?.response')); AJAX('POST /api/profile/', userprofile, ASETTER('notifybar/response', 'Your message', '?.response')); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quia harum accusamus debitis aut sunt, deserunt magni alias neque unde reprehenderit ipsa ea laboriosam eveniet! Distinctio pariatur sed, a aut nobis. ``` ## j-ObjectEditor Source: https://forge.totaljs.es/en/components/objecteditor/ Framework: jcomponent@20 Content-SHA256: 8f1bd1247816e720a44ac09075a8c879b519a0198f26d6da8ff5385c202d2a7d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `null {Boolean}` optional, shows `null` values (default: `true`) - `skip {String}` optional, skips properties divided by commas - `dateformat {String}` optional, a default date/time format (default: `yyyy-MM-dd HH:mm:ss`) - __NEW__: `exec {String}` a path to the `function(key, value)` and it's executed if the value is changed Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ObjectTree Source: https://forge.totaljs.es/en/components/objecttree/ Framework: jcomponent@20 Content-SHA256: 54e1d303dd6930646d95f189f0232d14b0b377bf3ca28ea697edb4595bf7ad62 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Expandable/Collabsible object tree. __Configuration__: - `exec {String}` function to call when a user clicks on icon __Usage__: ```js function exec_function(type, value) { type; // 'path' or 'data' value;// copied path(string) or property value(any datatype) } ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Martin Smola. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Offline Source: https://forge.totaljs.es/en/components/offline/ Framework: jcomponent@20 Content-SHA256: 9c4338a57c0c6766fc5c0f0b97967e0bd07847ba2d90f0246b5ce1516c7f0b77 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component displays a message box when there is no internet connection. - singleton Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Use the Web Developer Tools to turn off the internet via the Network tab.
    ``` ## j-OneTime Source: https://forge.totaljs.es/en/components/onetime/ Framework: jcomponent@20 Content-SHA256: 46b792a460652756486b7bf8fdce0de9f2b5e4ee8901f75b9b6c81008d660709 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component executes a method only once and it waits for expiration. - Download templates: https://github.com/totaljs/templates __Configuration__: - __required__ `exec {String}` a path to the method that will be executed - `expire {String}` expiration, default `1 year` - `delay {Number}` a delay for executing method in milliseconds, default: `1000` ms Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Packeta Source: https://forge.totaljs.es/en/components/packeta/ Framework: jcomponent@20 Content-SHA256: fbfc6d2efbabc4053ed3af2e686fa61c74046e7e5601d6843680d5eb65ca465f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component allows customers to select a [Packeta](https://www.packeta.com/) pickup point. After selection, a complete pickup point object is retrieved, which can be processed using a callback function. - https://www.packeta.com - singleton __How to call it?__ ```js var opt = {}; opt.callback = function(point) { console.log(point); }; SETTER('packeta/show', opt); ``` __Output__: ```json { "businessDaysOpenLunchtime": false, "businessDaysOpenUpTo": 0, "city": "Badín", "claimAssistant": false, "country": "sk", "creditCardPayment": true, "currency": "EUR", "directions": "

    Z-BOX sa nachádza v obci Badín vedľa obecného úradu.

    \n\n

    Dobré vedieť:

    \n\n

    Štandardná úložná doba zásielok je 2 dni s možnosťou predĺženia o ďalší 1 deň.

    \n\n

    Čo potrebujete na vyzdvihnutie zásielky?

    \n\n

    Aktuálnu verziu mobilnej aplikácie Packeta

    \n\n
    • zapnite si Bluetooth a polohové služby
    • uistite sa, že v mobilnej aplikácii aj v objednávke zásielky máte uvedené rovnaké telefónne číslo
    • dobierku uhradenú vopred
    \n\n

    Vyzdvihujete zásielku na dobierku? Tú je treba uhradiť vopred priamo v aplikácii alebo cez odkaz na sledovanie zásielky, ktorý nájdete v e-maile.

    ", "directionsCar": "", "directionsPublic": "", "error": null, "gps": { "lat": 48.6629, "lon": 19.12581 }, "holidayEnd": null, "holidayStart": null, "exceptionDays": [], "externalId": "I_15491", "id": "15491", "isNew": false, "maxWeight": 15, "name": "Z-BOX Badín, Sládkovičova 4", "nameStreet": "Z-BOX Badín, Sládkovičova 4", "openingHours": { "compactShort": "Po–Ne Nonstop", "compactLong": "Po–Ne Nonstop", "tableLong": "
    PoNonstop
    UtNonstop
    StNonstop
    ŠtNonstop
    PiNonstop
    SoNonstop
    NeNonstop
    ", "exceptions": [], "regular": { "monday": "Nonstop", "tuesday": "Nonstop", "wednesday": "Nonstop", "thursday": "Nonstop", "friday": "Nonstop", "saturday": "Nonstop", "sunday": "Nonstop" } }, "packetConsignment": true, "photos": [ { "thumbnail": "https://files.packeta.com/points/thumb/point_15491_334b78451cdf.jpg", "normal": "https://files.packeta.com/points/normal/point_15491_334b78451cdf.jpg" }, { "thumbnail": "https://files.packeta.com/points/thumb/point_15491_4041603c5372.jpg", "normal": "https://files.packeta.com/points/normal/point_15491_4041603c5372.jpg" }, { "thumbnail": "https://files.packeta.com/points/thumb/point_15491_425a950aa53a.jpg", "normal": "https://files.packeta.com/points/normal/point_15491_425a950aa53a.jpg" } ], "photo": [ { "thumbnail": "https://files.packeta.com/points/thumb/point_15491_334b78451cdf.jpg", "normal": "https://files.packeta.com/points/normal/point_15491_334b78451cdf.jpg" }, { "thumbnail": "https://files.packeta.com/points/thumb/point_15491_4041603c5372.jpg", "normal": "https://files.packeta.com/points/normal/point_15491_4041603c5372.jpg" }, { "thumbnail": "https://files.packeta.com/points/thumb/point_15491_425a950aa53a.jpg", "normal": "https://files.packeta.com/points/normal/point_15491_425a950aa53a.jpg" } ], "place": "Z-BOX", "recommended": "quickBox", "saturdayOpenTo": 0, "special": "", "street": "Sládkovičova 4", "sundayOpenTo": 0, "url": "https://www.zasilkovna.cz/pobocky/z-box-badin-sladkovicova-4", "branchCode": "z-box-badin-sladkovicova-4", "warning": "almostFullBox", "wheelchairAccessible": false, "zip": "976 32", "pickupPointType": "internal", "carrierPickupPointId": null, "carrierId": null, "routingCode": "S96-301-15491", "routingName": "Z-BOX Badín, Sládkovičova 4", "group": "zbox" } ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Dodo Marton. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Page Source: https://forge.totaljs.es/en/components/page/ Framework: jcomponent@20 Content-SHA256: 4c9bc3a6b340c84cf238488d0ffc2d0c9cd1f737c3ad50b2f5d0a66615ebc92a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can handle different contents asynchronously. The component has same functionality like `j-Part`. __If the element doesn't contain any content__ then the component downloads the content according to the `url` defined in configuration. - __NEW__ `path` can contain `{String Array}` __Configuration__: - `url {String}` required, a relative URL address - `if {String}` required, condition, it's compared with the value within of `path` (__NEW__: supports multiple paths divided by the `comma`) - `reload {String}` optional, a link to function `function(init) {}`, it's executed when the page is visible (always) - `hidden {String}` optional, a link to function, it's executed when the page is hidden (always) - `init {String}` optional, a link to function, it's executed when the page is visible and onetime - `default {String}` optional, a short alias for `DEFAULT(default)` - `hide {Boolean}` optional, auto-hide element if the `if` condition is not valid (default: `true`) - `cleaner {Number}` optional, idle time (in minutes) for running of cleaning (default: `0`) - `clean {String}` optional, a link to function, it's executed before the page is cleaned - `loading {Boolean}` optional, enables loading via `SETTER('loading')` (default: `true`) - `path {String}` optional, the component replace all `~PATH~` and `CLASS` phrases for the value of the `path` in the downloaded template - `replace {String}` optional, a link to method `function(content) { return content }` which can modify downloaded template - `absolute {Boolean}` optional, enables absolute position (default `false`) - `check {String}` optional, a link to function `function(next) { next(); }`, it's executed when the page is wanting to show - `invisible {Boolean}` enables adding of `invisible` class when the page is going to hide (default: `false`) - `delay {Number}` a delay (in ms) for removing of `invisible` class and hiding of `loading` (default: `500`) - `autofocus {Boolean/String}` focuses the first input, textarea (default: `false`) - `delayloading {Number}` a delay (in ms) for hiding of of `loading` (default: `800`) - `id {String}` a custom identifier for replacing `~ID~` phrases in the imported HTML (default: empty) __Good to know 1__: - all `CLASS` and `~PATH~` phrases will be replaced by `config.path` or `config.if` automatically - all `~ID~` phrases will be replaced by `config.id` automatically __Good to know 2__: Page component emits an `event` in the form: `pages.` + `config.if` for extending of pages. This can be very usefull for some plugin systems. Example: __Good to know 3__: If the page component isn't within scope then the value from the `config.if` will replace `?` characters in all config keys. ```js ON('pages.YOURIFCONDITION', function(element, pagecomponent) { // It's executed only when the page is initialized }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    SET('currentpage', 'home');
    ``` ## j-Pages Source: https://forge.totaljs.es/en/components/pages/ Framework: jcomponent@20 Content-SHA256: 6fc87ca08d4fc1bc13e3789f7f73aa6203c260485656fea12680fcaf5f910c74 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component is a better alternative to the `j-Section` component. As a result, you can easily make a multi-page app with dynamic content loading when needed. The result looks very intuitive for mobile devices or desktop computers. __Main configuration__: - `margin {Number/String}` a top margin (default: `0`) - `auto` will applied `offset.top` value - `margintype {String}` can contain `offset` (default) or `position` value - `delay {Number}` animation delay (default: `220`) - `parent` {String} optional, a selector to an element with a fixed height (default: `parent` element) - `scrollbarshadow {Boolean}` enables shadow for the scrollbar (default: `false`) - `loading {String}` optional, a link to the `function(show_loading {Boolean})` __Section attribute configuration `data-config`__: - `if {String}` a condition for displaying of page - `url {String}` URL address for getting HTML content - `path {String}` the value will replace `~PATH~` pharses (default: `config.if`) - `id {String}` the value will replace `~ID~` pharses - `anim {String}` animation type, supported values `left` (default), `right`, `top` or `bottom` - `scrollbar {Boolean}` appends a custom scrollbar into the content (default: `true`) - `scrolltop {Boolean}` enables auto-scroll - `reload {String}` a link to the `function(el)`, it's executed when the page is displayed - `hide {String}` a link to the `function(el)`, it's executed when the page is hidden - `check {String}` a link to the `function(next, el)` - `next {Function}` continues with page displaying - `autofocus {Boolean}` performs autofocus for the current page Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Panel Source: https://forge.totaljs.es/en/components/panel/ Framework: jcomponent@20 Content-SHA256: 327abb9fbd3b241a1d728ff0b50f140b54bbbb76ac7933cf098e3ad60538b5e8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ __Configuration__: - `title {String}` window title - `if {String}` condition for showing of the window, it's compared with the value within of `path` - `icon {String}` Total icon without `ti-` - `reload {String}` link to a global function and it's executed if the form is displaying - `enter {Boolean}` optional, captures `enter` key automatically and performs submit (default: `false`) - `autofocus {Boolean/String}` optional, can focus an input. `String` === `jQuery selector` for the input - `default {String}` optional, a short alias for `DEFAULT(default, true)` - `closebutton {Boolean}` optional, can hide `x` button (default: `false`) - `width {Number}` optional, a default width of the panel (default: `300`) - `bg {Boolean}` optional, can disable `background` (default: `true`) - `bgclose {Boolean}` optional, if the user click on the background then the panel will be closed (default: `false`) - `zindex {Number}` optional, can affect z-index (default: `12`) - `close {String}` optional, path/method is executed as `path_to_method(com)` when the user closes the panel manually via close button - `scrollbar {Boolean}` optional, enables custom scrollbar (default: `true`) - `scrollbarY {Boolean}` optional, shows vertical custom scrollbar (default: `true`) - `scrollbarshadow {Boolean}` optional, enables a shadow in scrollbar (default: `false`) - `menu {String}` optional, a link to function (panel will show a button with burger icon in title bar) - `container {String}` optional, jQuery selector (this container means a container for scrollbar) - `margin {Number}` optional, a margin for `container` and its `scrollbar` (it works with `container` only) - `closeicon {String}` optional, Font-Awesome icon (default: `ti ti-times`) - __NEW__ `closeesc {Boolean}` closes the form when the user presses `ESC` key __Good to know__: New version of this component supports dynamic evaluation of the content of ` ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Parameters Source: https://forge.totaljs.es/en/components/parameters/ Framework: jcomponent@20 Content-SHA256: 1111e4d3ac7d5b918a0113e35abcec5a16a17672b77ef380f464a7ca698d4183 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can changed internal parameters. __Configuration__: - `dateformat {String}` optional, a date format (default: `yyyy-MM-dd`) - `search {String}` optional, placeholder for search input (default: `Search`) - `height {Number}` optional, a height of the element (default: `undefined`) - `parent {String}` optional, jQuery selector for auto setup of height (can be `window`, `parent` or `custom`) - `hidetype {Boolean}` optional, hides type (default: `false`) - `margin {Number}` optional, vertical margin (default: `0`) __Data declaration__: ```javascript var form = []; form.push({ name: 'user.firstname', label: 'First name', type: 'string', value: 'Peter Sirka' }); form.push({ name: 'user.age', type: 'number', value: 33, min: 18, max: 50 }); form.push({ name: 'user.birth', type: 'date', value: NOW }); form.push({ name: 'user.newsletter', type: 'boolean', value: true }); ``` __Allowed types in data__: - `string` - `boolean` - `number` - `date` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Part Source: https://forge.totaljs.es/en/components/part/ Framework: jcomponent@20 Content-SHA256: 62c58b5dc9ad6380b08cca03fa06d8f66c25bd1b34c41d2fbca3df357975abe0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can handle different contents asynchronously. __If the element doesn't contain any content__ then the component downloads the content according to the `url` defined in configuration. - __NEW__ `path` can contain `{String Array}` __Configuration__: - `url {String}` required, a relative URL address - `if {String}` required, condition, it's compared with the value within of `path` (__NEW__: supports multiple paths divided by the `comma`) - `reload {String}` optional, a link to function `function(init) {}`, it's executed when the part is visible (always) - `hidden {String}` optional, a link to function, it's executed when the part is hidden (always) - `init {String}` optional, a link to function, it's executed when the part is visible and onetime - `default {String}` optional, a short alias for `DEFAULT(default)` - `hide {Boolean}` optional, auto-hide element if the `if` condition is not valid (default: `true`) - `cleaner {Number}` optional, idle time (in minutes) for running of cleaning (default: `0`) - `clean {String}` optional, a link to function, it's executed before the part is cleaned - `loading {Boolean}` optional, enables loading via `SETTER('loading')` (default: `true`) - `path {String}` optional, the component replace all `~PATH~` and `CLASS` phrases for the value of the `path` in the downloaded template - `replace {String}` optional, a link to method `function(content) { return content }` which can modify downloaded template - `absolute {Boolean}` optional, enables absolute position (default `false`) - `check {String}` optional, a link to function `function(next) { next(); }`, it's executed when the part is wanting to show - `invisible {Boolean}` enables adding of `invisible` class when the part is going to hide (default: `false`) - `delay {Number}` a delay (in ms) for removing of `invisible` class and hiding of `loading` (default: `500`) - `autofocus {Boolean/String}` focuses the first input, textarea (default: `false`) - `delayloading {Number}` a delay (in ms) for hiding of of `loading` (default: `800`) - `id {String}` a custom identifier for replacing `~ID~` phrases in the imported HTML (default: empty) __Good to know 1__: - all `CLASS` and `~PATH~` phrases will be replaced by `config.path` or `config.if` automatically - all `~ID~` phrases will be replaced by `config.id` automatically __Good to know 2__: Part component emits an `event` in the form: `parts.` + `config.if` for extending of parts. This can be very usefull for some plugin systems. Example: __Good to know 3__: If the part component isn't within scope then the value from the `config.if` will replace `?` characters in all config keys. ```js ON('parts.YOURIFCONDITION', function(element, pagecomponent) { // It's executed only when the part is initialized }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    SET('currentpart', 'home');
    ``` ## j-Parts Source: https://forge.totaljs.es/en/components/parts/ Framework: jcomponent@20 Content-SHA256: f2f1ea1ed934bd8920a87933c31abd87111e4b20626007d94ad7537f82ebcdd8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This content can handle multiple `parts` stored in the `Array` and focus on one specific part. It simulates something like browser tabs. __Configuration__: - `parent {String}` parent area due to part size (default: `auto`) - `margin {Number}` vertical margin (default: `0`) - `create {String}` a link to the `function(part)`, it's executed if the part is created (called once) - `focus {String}` a link to the `function(part)`, it's executed if the part is focused - `close {String}` a link to the `function(part)`, it's executed if the part is closed __Good to know 1__: - all `~PATH~` phrases will be replaced by `item.path` automatically - all `~ID~` phrases will be replaced by `item.id` automatically __Item specification__: - `item.id {String}` very important, part identifier - `item.blur {String/Function(el, item)}` optional, a link to the `function(element, item)` if the part is focused out - `item.focus {String/Function(el, item)}` or `item.reload {String}` optional, a link to the `function(element, item)` if the part is focused - `item.remove {String/Function(el, item)}` optional, a link to the `function(element, item)` if the part is removed - `item.html {String}` a HTML content or use `item.url` - `item.import {String}` URL address for the part content - `item.path {String}` optional, it replaces all `~PATH~` phrases automatically - `item.delay {Number}` a delay for removing of `invisible` class - __NEW__ `item.attrd {Object}` adds `data-key` attributes into the item element __Extendend by the component__: - `item.focused {Boolean}` determines if the part is focused or not - `item.element {jQuery}` part element __Methods__: - `component.close(id)` closes part - `component.focus(id)` focuses part - `component.rename(id, name, [icon])` renames part Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-PasswordMeter Source: https://forge.totaljs.es/en/components/passwordmeter/ Framework: jcomponent@20 Content-SHA256: 7ab771cae19b0f95e46f6f02f065c4fc86106277c99458332d5229ead3412936 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `numbers {Boolean}` password must contain min. 1 numbers (default: `true`) - `chars {Boolean}` password must contain min. 1 chars (default: `true`) - `special {Boolean}` password must contain min. 1 special char (default: `false`) - `min {Number}` password must have min. length of characters (default: `4`) - `casesensitive {Boolean}` password must contain min. 1 lower and upper char (default: `true`) - `weak {String}` a label for weak password (default: `Weak`) - `good {String}` a label for good password (default: `Good`) - `strong {String}` a label for strong password (default: `Strong`) - `short {String}` a label for short password (default: `Short password`) - `text {String}` a label for label (default: `Password strength`) - `valid {Number}` min. valid criteria in percentage (default: `40`) - __NEW__ `showprogress {Boolean}` shows a progress bar (default: `true`) - __NEW__ `progress {String}` a path to `function({ progress: Number, rating: Number, numbers: Number, chars: Number, special: Number, upper: Number, lower: Number, unicode: Number, points: Number })` __Good to know__: This component evaluates password according to the rating. Rating is counted as a percentage: `100%` = Strong, `50%` = Good, `0%` = Weak. - `weak` rating is lower than `30` - `good` rating is between `30` and `70` - `strong` rating is greater than `70` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html


    ``` ## j-Paste Source: https://forge.totaljs.es/en/components/paste/ Framework: jcomponent@20 Content-SHA256: eee3f0ef9cf099751bd9ab197b66008e609f12abe453739d8e197f3fec3a0e35 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component captures `paste` event. ```js ON('paste', function(text, e) { // @text {String} }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Period Source: https://forge.totaljs.es/en/components/period/ Framework: jcomponent@20 Content-SHA256: 189fe23bf900cdd3bc9fd779fddfb2e2b5f012d90e7508c4f7e657d3ea71f614 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component for picking a time period. - singleton __Methods__: Method: `component.show(options)` - `options.element` {Element/jQuery Element} - all allignment calculations will be relative to this element - `options.align` Align the component relatively to the element in `options.element` property. Available properties: 'center', 'left' and 'right'. The default value - 'right' - `options.callback` Function, which will be executed by clicking on 'Apply' button of the component - receives two parameters: start and end date objects - `options.start`, `options.end` {Date} - In order to predifine selected period, **both** of these properties should be specified. __Configuration__: - `firstday` - {String} - Allows to set the first day of the week to Monday. The defaul value is 'monday' - Days of the week start from Monday. 'sunday' - days of the week start from Sunday. - `dateformat` - {String} - Specifies the date format. The default value - `DEF.dateformat` - `apply` - {String} - Label for "Apply" button - `cancel` - {String} - Label for "Cancel" button - `custom` - {String} - Label for "Custom" filter button - `month` - {String} - Label for "Current month" filter button - `thisY` - {String} - Label for "This year" filter button - `lastY` - {String} - Label for "Last year" filter button Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Kirill Zlobin. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Permissions Source: https://forge.totaljs.es/en/components/permissions/ Framework: jcomponent@20 Content-SHA256: 846a3e1a9fcb22a99979e6269ab8a51ab821a7a3e1aecffa7c0840d882b2bf92 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - - jComponent `v19|v20` __Configuration__: - `placeholder {String}` a placeholder for `j-Directory` component (default: `Search`) - `types {String}` permission types (only one character per operation!!!!) (array delimited by comma, default: `R,W`) - `dirsource {String}` optional, path to a data-source or __NEW__: `id|name,id|name` - `empty {String}` optional, adds a text into the empty permissions - `disabled {Boolean}` optional, disables this component - `default {String}` default value of `type` (default: `R`) - `dirraw {Boolean}` optional, disables HTML encoding for text in `j-Directory` (default: `false`) - `autoremove {Boolean}` optional, it automatically removes non-existent permissions (default: `true`) - `autoexclude {Boolean}` optional, it excludes the used permissions from the `dirsource` (default: `true`) - __NEW__: `exec {String}` optional, it executes a method (`path.to.method`) when the user changes the value - __NEW__: `button {String}` optional, a button label (default: `Add`) __Source__: ```js [ { id: "123456", name: 'Peter' }, { id: "654321", name: 'John' } ] ``` __Input & Output__: ```js ['R123456', 'W123456', 'W654321'] ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Permissions
    ``` ## j-Pictures Source: https://forge.totaljs.es/en/components/pictures/ Framework: jcomponent@20 Content-SHA256: bdd836b7efb637e0d883041197026841fb99ae2b19195c2f40a166a7e2ee2ef8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component displays images in a simple list. A user can remove and rearrange images. - it uses `j-Movable` component __Configuration__: - `grid {Number}` a column count in the grid (default: `4`) --- A value be `Array` in the form: ``` [ "/url_to_image_1.jpeg", "/url_to_image_2.jpeg", "/url_to_image_3.jpeg", "/url_to_image_4.jpeg" ] ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-PictureUpload Source: https://forge.totaljs.es/en/components/pictureupload/ Framework: jcomponent@20 Content-SHA256: 7a2ce19cb695f85a25d64478807ff96d7188962716da27cee0a2103e572dcabc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - works with Bootstrap Grid System - drag and drop support - uploads a raw file (without resizing) __Configuration__: - `width` {Number} a picture width (required) - `height` {Number} a picture height (required) - `icon` {String} (optional) the label icon without `ti`, (default: `null`) - `url` {String}" (optional) upload URL (default: current URL) - `background` {String} (optional) a background color (default: white) - `src` {String} an image path (default: `null`), e.g. `/img/{0}.jpg` - `extension` {Boolean} response without file extension (default: `false`) - `singlefile` {Boolean} response will be string instead of array (default: `true`) - __new__ `type` {String} preview: output type (default: `png`) - __new__ `quality` {Number} preview: output quality Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Picture
    ``` ## j-PictureUploadExpert Source: https://forge.totaljs.es/en/components/pictureuploadexpert/ Framework: jcomponent@20 Content-SHA256: c5c2a6a386b526f841a79483598d674e4740759b960e71ba59dced7af9d9e71e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - advanced usage - drag and drop support - supports `multiple` - supports EXIF orientation - multiple images are send one by one - supports j-Loading __Configuration__: - `url {String}` (__IMPORTANT__) upload URL (required) - `width {Number}` a picture width (required) - `height {Number}` a picture height (required) - `background {String}` (optional) a background color (default: white) - `schema {String}` prepared object for sending (default: `{file:base64,filename:filename}`, `base64` + `filename` is a value from preview) - `quality {Number}` JPEG quality (default: `90`) - `customize {Boolean}` resizes picture to the entire defined size (default: `true`) - `disabled {Boolean}` disables image upload (default: `false`) - `clickselector {String}` a class for custom click selector (default: `none`) - `dropselector {String}` a class for custom drop selector (default: `none`) - `class {String}` toggles class on `dropselector` if the drag over is emitted (default: `over`) - `error {String}` a path to method `method(err)` when an error is thrown Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html
    Click to upload
    Drop images here
    ``` ## j-Pin Source: https://forge.totaljs.es/en/components/pin/ Framework: jcomponent@20 Content-SHA256: cb23b44922ae8d1a8142c8426ee44741b46e7df72828fcfe49fa309f7d365d59 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple PIN maker. __Configuration__: - `count {Number}` a count of PIN inputs (default: `6`) - `required {Boolean}` enables "required" (default: `false`) - `disabled {Boolean}` can disabled this control - `hide` {Boolean} disables displaying of numbers (default: `false`) - `mask {Boolean}` disables the mask (default: `true`) - __NEW__ `exec {String}` a path to `function(pin)` - __NEW__ `allowpaste {Boolean}` enables pin pasting (default: `true`) __Good to know__: - input with no value creates a space - it expects `String` __Methods__: - `component.focus()` focuses the first input Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    PIN 1

    PIN 2 (hide:true)

    PIN 3 (visible)
    ``` ## j-Planner Source: https://forge.totaljs.es/en/components/planner/ Framework: jcomponent@20 Content-SHA256: 192e6c314650ebdc78e694b02744bfab9b7de151595dadd9e317353da6422675 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Data-source__ needs to contain: ```js { items: [{ id: '12345', name: 'A name of plan', dtbeg: NOW.add('-5 days'), dtend: NOW.add('3 days'), progress: 30, color: '#5385EA', title: 'A tooltip' }, ...] // items year: 2019 } ``` __Configuration__: - `days {String}` pluralization for days (optional, default: `# days,# day,# days,# days`) - `exec {String}` a path to variable or method `function(item, el)`, it's evaluated if the user will click on the item - `scroll {String}` a path to variable or method `function(y)`, it's evaluated if the user will scroll planner - `parent {String}` optional, a container with fixed width/height, can be `window`. Default value: `parent` element.) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Preview Source: https://forge.totaljs.es/en/components/preview/ Framework: jcomponent@20 Content-SHA256: 653ef5a3b446589d1cbc05b8dcffcda93bc283077d9b14f8732181f3a2479fc5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component resizes the picture automatically according to the settings and uploads it to the server in `base64` format. - response from server needs to contain URL address to the picture - works with Bootstrap Grid System - drag and drop support - supports EXIF orientation __Path__: The value/response (from the upload) will be used as a URL address for preview. __Configuration__: - `url {String}` (__IMPORTANT__) upload URL, can contain a method too (required) - `width {Number}` a picture width (required) - `height {Number}` a picture height (required) - `percentage {Number}` resizes a picture according to the percentage (then `width` and `height` aren't required) - `icon {String}` (optional) the label icon without `ti`, (default: `null`) - `background {String}` (optional) a background color, it can be `transparent` (default: `white`) - `schema {String}` prepared object for sending (default: `{file:base64,filename:filename}`, `base64` + `filename` is a value from preview) - `quality {Number}` JPEG quality (default: `90`) - `customize {Boolean}` resizes picture to the defined size (default: `true`) - `preview {String}` prepares a value preview URL address (default: `null`) - example: `value => '/download/' + value + '.jpg'` - `map {String}` prepares response value to a value (default: `null`) - example: `value => value.id` - `empty {String}` a link to the empty image - `keeporiginal {Boolean}` keeps the original image if the dimension is the same as the width/height defined in the configuration (default: `false`) - __NEW__ `output {String}` output type `base64` (default) or `file` - __NEW__ `convert {String}` an image type `jpg` (default) or `png` - __NEW__ `exec {String}` a path to the method `function(next(url))` (it prevents file upload dialog) - __NEW__ `center {Boolean}` aligns the image and label to the center __Methods__: - `component.reupload()` it reuploads a current image value as a base64. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Preview
    ``` ## j-PriceRange Source: https://forge.totaljs.es/en/components/pricerange/ Framework: jcomponent@20 Content-SHA256: 7b88dbcfb63f69968bb31e0a5e3ced2a4f209a6769de7bb4a126ec4569899844 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Attributes__: - `data-min="0"` a minimal value (default `0`) - `data-max="0"` a maximal value (default `10000`) - `data-step="100"` step (default `100`) - `data-currency="$ {0}"` formats current values (default `{0} €`) The component stores value as string `200-500`, explanation: `from-to`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Printer Source: https://forge.totaljs.es/en/components/printer/ Framework: jcomponent@20 Content-SHA256: dcca4835afba10a25a5393a5e97ea76fe39ef5bac353372ad65a17b107c87299 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can print a HTML content. - singleton __Configuration__: - `delay {Number}` a delay for evaluating of printer (default: `500`) - `delayprint {Number}` a delay for printing (default: `500`) - `delayclose {Number}` a delay for closing window (default: `1000`) __Methods__: ```js // SETTER('printer/print', [title], html, test); SETTER('printer/print', '

    Total.js Platform

    '); // Shows test window SETTER('printer/print', '

    Total.js Platform

    ', true); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Progress Source: https://forge.totaljs.es/en/components/progress/ Framework: jcomponent@20 Content-SHA256: d9c59847d941fe91585d1ad22f665aa9ff0233e5a0f6e8360a4e71ca37fd418f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `animate {Boolean}` enables animation (default: `true`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html


    ``` ## j-Prompt Source: https://forge.totaljs.es/en/components/prompt/ Framework: jcomponent@20 Content-SHA256: 3d45d35c15ce445e7ea07d7527b9172da86b281ce48cbba01504cb8643790c5f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component (singleton) displays a prompt window with single-line or multiline input. __Configuration__: - `zindex {Number}` optional (default: `12`) - `width {Number}` optional, max. width (default: `400`) - `cancel {String}` optional, label for the cancel button (default: `Cancel`) - `submit {String}` optional, label for the submit button (default: `OK`) __Example__: ```js var opt = {}; opt.name = 'A title'; // optional opt.summary = 'A small sumarization'; // optional opt.value = ''; // a default value, optional // opt.type = 'password'; // only for single-line mode // opt.width = config.width; // max. width, optional // opt.zindex = config.zindex; // a custom zindex, optional // opt.centered = true; // centers the window to the middle of the screen // opt.newbie = true; // allows to submit a default value // opt.multiline = true; // NEW: enables textarea with 3 rows // opt.monospace = true; // NEW: enables monospace text opt.cancel = function(val) { // @val {String} // prompt is canceled }; opt.callback = function(val) { // @val {String} // changed }; opt.hide = function() { // prompt is hidden/closed }; SETTER('prompt/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Properties Source: https://forge.totaljs.es/en/components/properties/ Framework: jcomponent@20 Content-SHA256: 800ebc73d3fac5c56576781417481bed88bd8c01c98db8afc361bcbc76525566 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component uses `j-DatePicker`, `j-TimePicker`, `j-Directory`, `j-Emoji`, `j-ColorPicker` and `j-FaIcons` components. __Configuration__: - `dateformat` {String} a date format (default: `yyyy-MM-dd`) - `timeformat` {String} a time format (default: `HH:mm`) - `datetimeformat` {String} a date/time format (default: `yyyy-MM-dd HH:mm`) - `height` {Number} a height of the element (default: `undefined`) - `parent` {String} jQuery selector for auto setup of height (can be `window`, `parent` or `custom`) - `margin` {Number} vertical margin (default: `0`) - `change` {String} a path to method `method(item, replace_text(new_text))` (executed if some value is changed) and `replace_text` argument is optional - `scrollbar` {Boolean} enables scrollbar (default: `true`) - `visibleY` {Boolean} shows a scrollbar (default: `true`) __Data declaration__: ```javascript var form = []; form.push({ group: 'Personal', label: 'First name', name: 'user.firstname', type: 'string', value: 'Peter', transform: 'capitalize' }); form.push({ group: 'Personal', label: 'Last name', name: 'user.lastname', type: 'string', value: 'Širka', placeholder: 'String' }); form.push({ group: 'Personal', label: 'Age', name: 'user.age', type: 'number', value: 33, min: 30 }); form.push({ group: 'Personal', label: 'Birth date', name: 'user.birth', type: 'date', value: NOW }); form.push({ group: 'Additional', label: 'Newsletter', name: 'user.newsletter', type: 'bool', value: true }); form.push({ group: 'Additional', label: 'City', name: 'user.city', type: 'list', value: 2, items: 'items', dirsearch: 'Search city', dircustom: true }); form.push({ group: 'Additional', label: 'Color', name: 'user.color', type: 'color', value: '#e73323' }); form.push({ group: 'Additional', label: 'Icon', name: 'user.icon', type: 'fontawesome', value: 'ti ti-home' }); form.push({ group: 'Additional', label: 'Emoji', name: 'user.emoji', type: 'emoji', value: '', show: 'n => n.age === 33' }); ``` __Data properties in data declaration__: - `name` {String} an item identifier (required) - `label` {String} a label (required) - `group` {String} a group name (required) - `type` {String} a type (required) - `placeholder` {String} a placeholder (supports few types only) - `transform` {String} for `string` type only, can contain `capitalize`, `uppercase`, `lowercase` or `slug` - `maxlength` {Number} for `string` type only - `validate` {RegExp/String} for `string` type only, can contain `email`, `phone` or `url` - `min` {Number} for `number` type only - `max` {Number} for `number` type only - `inc` {Number/String} increments a value according to the value, targeted for `number` or `date` (can contain `1 day` or `-1 day`) type only - `required` {Boolean} for type `string`, `number` or `date` - `dirsearch` {String/Boolean} a placeholder for `list` type only, boolean disables search - `dircustom` {Boolean} enables a custom value for `list` type only - `dirkey` {String} a key name for label/name, targeted for `list` type only (default: `name`) - `dirvalue` {String} a key name for value, targeted for `list` type only (default: `id`) - `detail` {String} URL address for obtaining of data for `list` type, example: `/users/{0}/` and `{0}` will be replaced with the value from list - `items` {Object Array/String} items for `list` type only, string can contain a path to `Array` or `URL address` to search - `show` {Arrow function}, example: `data => data.KEY === 'SOMETHING'` --> will show the item if the condition will valid __Allowed types in data__: - `string` - `bool` - `number` - `date` - `list` - `color` - `emoji` - `fontawesome` __Missing types__: - `datetime` - `time` - `file` - `months` ### Persistent mode ```html ``` ### Good to know The component extends the Array by adding: - `invalid` {Boolean} field determines if the `value` is invalid (default: `undefined`) - `changed` {Boolean} field determines if the `value` has been changed (default: `undefined`) - `prev` {???} field contains an initial value Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Properties2 Source: https://forge.totaljs.es/en/components/properties2/ Framework: jcomponent@20 Content-SHA256: 2577ce7a0f4076a948145469f278db0f44a448d641131530cae456faecfad429 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component uses `j-DatePicker`, `j-TimePicker`, `j-Directory`, `j-Emoji`, `j-ColorPicker` and `j-Icons` components. __Configuration__: - `dateformat {String}` a date format (default: `yyyy-MM-dd`) - `timeformat {String}` a time format (default: `HH:mm`) - `datetimeformat {String}` a date/time format (default: `yyyy-MM-dd HH:mm`) - `change {String}` a path to method `method(item, replace_text(new_text))` (executed if some value is changed) and `replace_text` argument is optional - `modalalign {String}` aligment for modal windows (default: `center`) - `style {Number}` supports a new style `2` like `iOS` settings (default: `1`) - `validation {Boolean}` enables validation for required fields (default: `true`) - `defaultgroup {String}` a default group name (default: `Default`) __Data declaration__: ```javascript var form = []; form.push({ group: 'Personal', label: 'First name', name: 'user.firstname', type: 'string', value: 'Peter', transform: 'capitalize' }); form.push({ group: 'Personal', label: 'Last name', name: 'user.lastname', type: 'string', value: 'Širka', placeholder: 'String' }); form.push({ group: 'Personal', label: 'Age', name: 'user.age', type: 'number', value: 33, min: 30 }); form.push({ group: 'Personal', label: 'Birth date', name: 'user.birth', type: 'date', value: NOW }); form.push({ group: 'Additional', label: 'Newsletter', name: 'user.newsletter', type: 'bool', value: true }); form.push({ group: 'Additional', label: 'City', name: 'user.city', type: 'list', value: 2, items: 'items', dirsearch: 'Search city', dircustom: true }); form.push({ group: 'Additional', label: 'Color', name: 'user.color', type: 'color', value: '#e73323' }); form.push({ group: 'Additional', label: 'Icon', name: 'user.icon', type: 'fontawesome', value: 'ti ti-home' }); form.push({ group: 'Additional', label: 'Emoji', name: 'user.emoji', type: 'emoji', value: '', show: 'n => n.age === 33' }); ``` __Data properties in data declaration__: - `name {String}` an item identifier (required) - `label {String}` a label (required) - `group {String}` a group name (required) - `note {String}` a small note under control - `type {String}` a type (required) - `placeholder {String}` a placeholder (supports few types only) - `transform {String}` for `string` type only, can contain `capitalize`, `uppercase`, `lowercase` or `slug` - `maxlength {Number}` for `string` type only - `validate {RegExp/String}` for `string` type only, can contain `email`, `phone` or `url` - `min {Number}` for `number` type only - `max {Number}` for `number` type only - `inc {Number/String}` increments a value according to the value, targeted for `number` or `date` (can contain `1 day` or `-1 day`) type only - `required {Boolean}` for type `string`, `number` or `date` - `dirsearch {String/Boolean}` a placeholder for `list` type only, boolean disables search - `dircustom {Boolean}` enables a custom value for `list` type only - `dirkey {String}` a key name for label/name, targeted for `list` type only (default: `name`) - `dirvalue {String}` a key name for value, targeted for `list` type only (default: `id`) - `detail {String}` URL address for obtaining of data for `list` type, example: `/users/{0}/` and `{0}` will be replaced with the value from list - `items {Object Array/String}` items for `list` type only, string can contain a path to `Array` or `URL address` to search - `show {Arrow function}`, example: `data => data.KEY === 'SOMETHING'` --> will show the item if the condition will valid - `icon {String}` Total icon, can contain a color e.g. `ti ti-home #00000` - `ricon {String}` Right Font-Awesome icon or text e.g. `!HTML text` - `riconclick {String}` a path to the method `function(item, set(new_val))` - `camouflage {Boolean}` only for `string` type - `monospace {Boolean}` it uses a monospace font __Allowed types in data__: - `string` - `bool` - `number` - `date` - `list` - `color` - `emoji` - `fontawesome` - `exec` (can exec `exec` method) - `text` (readonly value) - `menu` (it's similar to list but the component will execute `j-Menu`) __Missing types__: - `datetime` - `time` - `file` - `months` ### Good to know The component extends the Array by adding: - `invalid {Boolean}` field determines if the `value` is invalid (default: `undefined`) - `changed {Boolean}` field determines if the `value` has been changed (default: `undefined`) - `prev` {???} field contains an initial value Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-QRCode Source: https://forge.totaljs.es/en/components/qrcode/ Framework: jcomponent@20 Content-SHA256: 0b671644d91eda34269f8e120283b93e071506f44f74151b25be9a8c058aac1c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component creates a QR code. It includes the [QRCode library](https://davidshimjs.github.io/qrcodejs/). __Configuration__: - `width {Number}` a default image width (default: `128`) - `height {Number}` a default image height (default: `128`) - `fg {String}` a foreground color (default: `#000000`) - `bg {String}` a background color (default: `#FFFFFF`) - `delay {Number}` a small delay for code generating (default: `200`) __How to generate QR Code?__ ```js var opt = {}; opt.text = 'https://www.totaljs.com'; // opt.width {Number} // opt.height {Number} // opt.fg {String} // opt.bg {String} opt.callback = function(base64) { console.log(base64); }; SETTER('qrcode/create', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-QRCodeGenerator Source: https://forge.totaljs.es/en/components/qrcodegenerator/ Framework: jcomponent@20 Content-SHA256: 8225c46c98972bc2378dfb9d66ffbfc1072ed4d690c348c87741b000aebf2207 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - uses server __Configuration__: - `size {Number}` in pixels, default: `200` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-RadioButton Source: https://forge.totaljs.es/en/components/radiobutton/ Framework: jcomponent@20 Content-SHA256: 475c79010ff2d9387edc39db83d5a5f471e5d65ffdb8b884419ec94ff5eaf71a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - for custom design you can use __j-RadioButtonExpert__ - now you can use datasource __Configuration__: - `items` {String} needs to contain `text 1|value 1;text 2|value 2` or `text 1;text 2` - `required` {Boolean} enables `required` - `disabled` {Boolean} disables this control - `label` {String} can change the content (default: `innerHTML`) - `type` {String} can contain `number` - `inline` {Boolean} enables/disables inline position (default: `true`) - `datasource` {String} path to data-source (must be array or array of objects) - `text` {String} determines a property name for text (in data-source), default: `name` - `value` {String} determines a property name for value (in data-source) default: `id` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Are you crazy?
    What is the best node.js framework?
    Total.js is framework for... ``` ## j-RadioButtonExpert Source: https://forge.totaljs.es/en/components/radiobuttonexpert/ Framework: jcomponent@20 Content-SHA256: 842e66a0567d9a39ef4038a0218bd22d33085b2ecbb5443606676c3e274f264d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Perfect component for radiobutton with custom styles. It's a little bit advanced but absolutely worth it! __Configuration__ - `label {String}` can change the title label - `required {Boolean}` enables `required` (default: `false`) - `disabled {Boolean}` disables this control (default: `false`) - `type {String}` can contain `number` (default: `string`) - `class {String}` inserts a class into an element with class `.ui-radiobuttonexpert-container` - `datasource {String}` path to data-source (must be array or array of objects) or __NEW__: `id|name,id|name` - `value {String}` determines a property name for value (in data-source) (default: `id`) - `disabledkey {String}` determines a property name for disabled item (in data-source) (default: `disabled`) - __NEW__ `selector {String}` a jQuery selector for custom template (outside of the component). Works like `custom template` in [data-binding](https://wiki.totaljs.com/jcomponent/08-data-binding/) __Good to know__ - You must write **all the styles** - Example object `{ name: 'My item', id: 1, disabled: false, classname: 'color-highlighted' }` - You can use `$index` and `$path` in template __Basic Styles__ ```css .my-button { display: inline-block; padding: 20px; margin-right: 10px; border: 1px solid gray; cursor: pointer; border-radius: 2px; } .my-button:hover { border-color: #4285F4; } .my-button.selected { color: white; background: #4285F4; border-color: rgba(0, 0, 0, 0.2); } .my-button[data-disabled="1"] { background-color: #dcdcdc; color: gray; border-color: #dcdcdc; cursor: not-allowed;} .ui-disabled .my-button { background-color: #dcdcdc; color: gray; border-color: #dcdcdc; cursor: not-allowed; } .ui-disabled .my-button:hover { background-color: #dcdcdc; color: gray; border-color: #dcdcdc; } .ui-disabled .my-button.selected { border-color: gray; background: #efefef; color: #5a5a5a; } /* Dark mode */ .ui-dark .my-button { border-color: 1px solid #404040; color: #adadad; } .ui-dark .my-button.selected { color: white; } .ui-dark .my-button[data-disabled="1"] { background-color: #525252; color: gray; border-color: #525252; } .ui-dark .ui-disabled .my-button { background-color: #525252; color: gray; border-color: #525252; } .ui-dark .ui-disabled .my-button:hover { background-color: #525252; color: gray; border-color: #525252; } .ui-dark .ui-disabled .my-button.selected { border-color: rgba(0, 0, 0, 0.2); background: #969696; color: #ffffff; } /* Large mode */ .ui-large .my-button { font-size: 16px; } ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html

    ``` ## j-Range Source: https://forge.totaljs.es/en/components/range/ Framework: jcomponent@20 Content-SHA256: 41ea0b6e3dd142d2430b840e64606d13de93dc3264d680b727e7cd577e196c06 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ __Attributes__: - `max` {Number} maximum value (default: `100`) - `min` {Number} minimum value (default: `0`) - `step` {Number} step size (default: `1`) - `required` {Boolean} optional, enables "required" (default: `false`) - `type` {String} optional, can be `number` and converts the value to number (default: `string`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Select size
    ``` ## j-Rating Source: https://forge.totaljs.es/en/components/rating/ Framework: jcomponent@20 Content-SHA256: 0a9aa25b9a281aa9122de9b43a9a72f87931cc2b2e84dc85b3985ccba7a19931 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Please rate our products and services:
    ``` ## j-RawEditable Source: https://forge.totaljs.es/en/components/raweditable/ Framework: jcomponent@20 Content-SHA256: 0f36f17ea6ef34bf9119f86090d868fbe8769108d38a43546c79b3729ac1a67f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __j-RawEditable__ is a simple component with a big hidden functionality. It's targeted for additional customization. __Configuration__: - `type {String}` optional, can be `email`, `phone`, `zip`, `date`, `time`, `url`, `number`, `search`, `lower`, `upper` or empty (default) - `formatting {Boolean}` enables formatting bold, italic, etc., default: `false` - `required {Boolean}` optional, enables "required" (default: `false`) - `placeholder {String}` optional, adds a `placeholder` text into the input - `maxlength {Number}` optional, sets a maximum length of chars (default: `200`) - `minlength {Number}` optional, sets a minimum length of chars - `minvalue {Number}` optional, a minimal value for `number` type - `maxvalue {Number}` optional, a maximal value for `number` type - `validate {String}` optional, a condition for validating of value, can contain a link to `function(value)` or `!!value.match(/[a-z]+/)` - `format {String}` optional, output formatting e.g. for `date` type: `yyyy-MM-dd`, for `time` type: `HH:mm`, for `number` you can define max. decimals - `disabled {Boolean}` optional, disables this component - `autocomplete {String}` optional, needs to contain a link to a function, is triggered on `focus` event - `spaces {Boolean}` optional, enables spaces otherwise it removes them (default: `true`) - `autosource {String}` a path to `search` function in `autocomplete`, `function(search, render(arr))` - `autovalue {String}` a property path for the value in `autosource`, default: `name` - `autoexec {String}` a path method `function(item, next(value_to_input))` - `forcevalidation {Boolean}` enables for force validation for `phone` and `email` (default: `true`) - `monospace {Boolean}` enables `monospaced` font (default: `false`) - `enter {String}` a link to `function(val, com)` - evaluated when the user presses enter Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Type something: ``` ## j-RawInput Source: https://forge.totaljs.es/en/components/rawinput/ Framework: jcomponent@20 Content-SHA256: bc158aa78dafe6dbb89cf0e743df80f054479463c2d3293e0a9b95a86809fb9d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __j-RawInput__ is a simple input component with a big hidden functionality. It's targeted for additional customization. __Configuration__: - `type {String}` optional, can be `email`, `phone`, `password`, `zip`, `date`, `time`, `url`, `number`, `search`, `lower`, `upper` or empty (default) - `required {Boolean}` optional, enables "required" (default: `false`) - `autofocus {Boolean}` optional, focuses the input (default: `false`) - `autofill {Boolean}` optional, enables browser's autofill feature (default: `false`) - `placeholder {String}` optional, adds a `placeholder` text into the input - `maxlength {Number}` optional, sets a maximum length of chars (default: `200`) - `minlength {Number}` optional, sets a minimum length of chars - `minvalue {Number}` optional, a minimal value for `number` type - `maxvalue {Number}` optional, a maximal value for `number` type - `validate {String}` optional, a condition for validating of value, can contain a link to `function(value)` or `!!value.match(/[a-z]+/)` - `format {String}` optional, output formatting e.g. for `date` type: `yyyy-MM-dd`, for `time` type: `HH:mm`, for `number` you can define max. decimals - `disabled {Boolean}` optional, disables this component - `autocomplete {String}` optional, needs to contain a link to a function, is triggered on `focus` event - `spaces {Boolean}` optional, enables spaces otherwise it removes them (default: `true`) - `autosource {String}` a path to `search` function in `autocomplete`, `function(search, render(arr))` - `autovalue {String}` a property path for the value in `autosource`, default: `name` - `autoexec {String}` a path method `function(item, next(value_to_input))` - `forcevalidation {Boolean}` enables for force validation for `phone` and `email` (default: `true`) - `monospace {Boolean}` enables `monospaced` font (default: `false`) - `enter {String}` a link to `function(val, com)` - evaluated when the user presses enter - __NEW__: `realtime {Boolean}` enables real-time binding (default: `true`) - __NEW__: `exec {String}` a link to the `function(value, element)` which will be evaluated if the input is affected Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Ready Source: https://forge.totaljs.es/en/components/ready/ Framework: jcomponent@20 Content-SHA256: ddd2d91b6c665b7bc07d9bc258a8f040df467330ceb48286d42ffa336e5be9b1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component executes some operations when the component is ready. __Configuration__: - `rclass {String}` A list of CSS classes to remove divided by space - `rdelay {Number}` A delay for removing of classes (default: `config.delay`) - `aclass {String}` A list of CSS classes to add divided by space - `adelay {Number}` A delay for adding of classes (default: `config.delay`) - `delay {Number}` Initializatin delay in milliseconds (default: `800`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-reCAPTCHA Source: https://forge.totaljs.es/en/components/recaptcha/ Framework: jcomponent@20 Content-SHA256: 58ba32aec7fe161b4d86b4ecb1234b86532035a71aeb427e32658a2b3e2872df Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - [Create reCAPTCHA API KEY](https://www.google.com/recaptcha/admin) - [How to __verify reCAPTCHA response__ on the server-side?](https://blog.totaljs.com/blogs/tutorials/20161211-how-to-verify-recaptcha-with-help-of-total-js/) __Configuration__: - `key {String}` (required) Google API key - `required {Boolean}` enables `required` - `theme {String}` can be `light` or `dark` (default: `light`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Releaser Source: https://forge.totaljs.es/en/components/releaser/ Framework: jcomponent@20 Content-SHA256: c3fb66cecefc89e7a96c687a1d1c3bb6298909250557e0e16dbf2886f8267508 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can release after some time own content (DOM) + memory. We recommend to use it for `j-DataGrid`, `j-CodeMirror`, `j-CloudEditor`, etc.. __Configuration__: - `if {String}` must contain a value for comparing with the model - `delay {Number}` delay for removing of `invisible` class (default: `500`) - `release {Number}` delay for releasing of the content in idle time (default: `10000`) - `bindvisible {Boolean}` it evalutes the content if the component is visible (default: `false`) - `released {String}` a link to the `function(component_element)` when the content is released - `render {String}` a link to the `function(component_element)` when the content is going to render __Example__: ```html `. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Remember Source: https://forge.totaljs.es/en/components/remember/ Framework: jcomponent@20 Content-SHA256: 22964e1926f8dd8b3f2d93643dd73476084d4fa2d209c0e76d8c5c9171ffa26b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component calls a function within the repeat interval. Information about the previous call is stored in `localStorage`. __Configuration__: - `id {String}` a remember identifier - `repeat {String}` a repeat time e.g. `session` or `5 minutes` or `1 day` - `exec {String}` a link to the function that will be called - `delay {Number}` a caller delay in ms (default: `3000`) __Methods__: - `SETTER('remember/clear', 'id')` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Resource Source: https://forge.totaljs.es/en/components/resource/ Framework: jcomponent@20 Content-SHA256: 7104cdd07cf4875e0833983d577a07667f8a8a5c3a8c9068d593c3671e4e02bc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Resources are very great solution for e.g. translate some texts in all scripts. The component can be appended multiple-times and all components use one repository for storing keys and values. __METHODS__: - `RESOURCE(key, [def])` - is a global method - `FIND('resource').download('/my-dictionary.txt', [callback]);` - for importing new resources Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Open Web Developer console. ``` ## j-Restart Source: https://forge.totaljs.es/en/components/restart/ Framework: jcomponent@20 Content-SHA256: d1ba1333007a62d802122d9029141df69746716c645d49e75d7c11f4d304e3e8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component is very primitive and it will only display the content if the value is positive. It can be useful for single page applications that change a version in the background and the front end needs to reload. __Configuration__: - `top {Number}` a top position (default: `75`) - `bottom {Number}` a top position (default: `0`) - `right {Number}` a top position (default: `20`) - `left {Number}` a top position (default: `0`) - `url {String}` optional, a link to the editor (default: `?reload=1`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Rows Source: https://forge.totaljs.es/en/components/rows/ Framework: jcomponent@20 Content-SHA256: 17642a4d077bf0f661d77f2506ed7a783dbeb2a4cb138c21b2e8b415b3d1f70e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component `Rows` is a very simple alternative to `j-Layout` and `j-Layout2`. __Configuration__: - `parent {String}` can contain `parent`, `window` or jQuery selector for the `closest` method (default: `window`) - `margin {Number}` add margin to `height` (default: `0`) - `marginlg {Number}` adds margin to `height` for `LG` display (default: `margin`) - `marginmd {Number}` adds margin to `height` for `MD` display (default: `margin`) - `marginsm {Number}` adds margin to `height` for `SM` display (default: `margin`) - `marginxs {Number}` adds margin to `height` for `XS` display (default: `margin`) - `noborder {Boolean}` disables border (default: `false`) - `fontsize {Boolean}` enables percentual font-size according to the size of rows __Good to know__: Each row must be wrappend in `
    `, try to understand from example. __Attributes__: - `data-size` contains a size of section `LG,MD,SM,XS` --> in pixels or percentage, example: `200,200,200,0` (`0` means hidden) - section without `data-size` attribute will be counted from the residual value Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Rules Source: https://forge.totaljs.es/en/components/rules/ Framework: jcomponent@20 Content-SHA256: aaac667b2b0ac38ecfd433ab93f019b31a45463a5eff564158f628cf5641c014 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can create a simple rules which you can transform to some engines like Total.js Flow. The component uses `j-Directory` component. __Configuration__: - `dirsearc {String}h` A placeholder for search input in `j-Directory`, default: `search` __Data declaration__: ```js var form = []; form.push({ enabled: true, label: 'CPU', name: 'cpu', type: 'number', comparer: '==', value: 0, note: 'Value in mega bytes' }); form.push({ enabled: false, label: 'Memory', name: 'memory', type: 'number', comparer: '>', value: 0 }); form.push({ enabled: true, label: 'Error', name: 'error', type: 'string', comparer: '==', items: [{ name: 'Error', id: 'error' }, { name: 'Obsolete', id: 'obsolete' }] }); form.push({ enabled: false, label: 'Offline', name: 'offline', type: 'boolean', comparer: '==', value: 0 }); ``` __Data properties in data declaration__: - `name {String}` an item identifier (required) - `label {String}` a label (required) - `note {String}` a small note under control - `type {String}` a type, lower-case (required) - `items {Object Array}` items for `string` type only in the form `[{ id: String, name: String }]` - `enabled {Boolean}` enables item - `comparer {String}` can be `==`, `!=`, `>`, `>=`, `<=`, `<` (required) - `value {Number/Boolean/String}` a value __Allowed types in data__: - `string` - `boolean` - `number` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Scanner Source: https://forge.totaljs.es/en/components/scanner/ Framework: jcomponent@20 Content-SHA256: 4a6e0f0ae3e4fc351bbd0942c3e8c9629b2d68014bb56c3a7c8251d96ecc82e9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component for scanning documents. - singleton __Methods__: - `component.show(opt)` - `opt.points = [left+right {Number}, top+bottom {Number}]` mask size defined in the percentage - `opt.callback = function(base64)` The callback function, which will be executed when the user approves taken document. This callback function thakes an image in **base64** format as a parameter Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Kirill Zlobin. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Scrollbar Source: https://forge.totaljs.es/en/components/scrollbar/ Framework: jcomponent@20 Content-SHA256: 91f89113cd8f6a15c7c8664e0d8ac59c996092e5e1939864458e36ca6c8216fa Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Custom scrollbars. __IMPORTANT:__ It wraps current content by adding two nested `div` elements with `relative` position. __It works with jComponent v17 only__. __Configuration__: - `parent` {String} selector for a parent element, can contain `window` (default: `undefined`) - `visibleX` {Boolean} always shows horizontal scrollbar (default: `false`) - `visibleY` {Boolean} always shows vertical scrollbar (default: `false`) - `offset` {Boolean} adds `offset.top` of this element (default: `false`) - `reset` {Boolean} resets position if the `path` is changed (default: `true`) - `margin` {Number} a margin for all types of displays (default: `0`) - `marginxs` {Number} a margin for `XS` displays (default: `0`) - `marginsm` {Number} a margin for `SM` displays (default: `0`) - `marginmd` {Number} a margin for `MD` displays (default: `0`) - `marginlg` {Number} a margin for `LG` displays (default: `0`) - `track` {String} can track only defined paths e.g. `FIELD1,FIELD2,FIELD3`, paths will linked with `component.path` __Methods__: - `component.reset()` resets the position to `0,0` - `component.scrollleft(val)` scrolls X - `component.scrolltop(val)` scrolls Y - `component.scrollright(val)` scrolls X from right side - `component.scrollbottom(val)` scrolls Y from bottom side - `component.scroll(x, y)` scrolls X,Y - `component.resize()` resizes container (it reacts on `resize` events automatically) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ScrollPercentage Source: https://forge.totaljs.es/en/components/scrollpercentage/ Framework: jcomponent@20 Content-SHA256: 233bb5983e7c8d411dacf4c3e8b4ba134c3f7aabe9dd8da78b9039b07d101596 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Component must be attached on the element which will be as a scroll container. For the entire window use `body` element. __Configuration__: - `exec {String}` A link to the global function which is executed if the percentage is changed __IMPORTANT__: if the `exec` is not defined then the component will bind a value according to the `path`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    Text
    ``` ## j-Search Source: https://forge.totaljs.es/en/components/search/ Framework: jcomponent@20 Content-SHA256: 5a1c428d462a347a04d0a7b31478bd5690a86558a3b86824856d5b4f3eb05259 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Simple fulltext search component. This component can show/hide elements according to the searching phrase. __Configuration__: - `selector {String}` jQuery selector for searching - `attribute {String}` element attribute which contains a search phrase (default: `data-search`) - `class {String}` this class will be used if the element is not found (default: `hidden`) - `delay {Number}` typing delay (default: `50` ms) - `delaydatasource {Number}` a delay for re-search when the data-source is changed (default: `100` ms) - __UPD__ `exec {String}` a link to `function(stats:{ total: Number, count: Number, hidden: Number, search: String, is: Boolean })` which will be evaluated if the component searches for something - `datasource {String}` a path to data-source for watching of changes - `splitwords {Boolean}` tries to find word in various position (default: `true`) - __NEW__ `custom {String}` a path to the `Function(element, search) must return Boolean` for custom searching __Good to know__: This component adds the classes below automatically when: - class `ui-search-used` is added when the user searches for something - class `ui-search-empty` is added when the user searches for something and at the same time nothing was found Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Apples
    Oranges
    Pears
    Black-eye bean
    Broccoli
    ``` ## j-SearchBox Source: https://forge.totaljs.es/en/components/searchbox/ Framework: jcomponent@20 Content-SHA256: eb2f396bf24610791cca23beeb09618d8211c9d489face7c694c997b173b1493 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component contains a search box (input). __Configuration__: - `exec {String}` a link to the `function(model, component, changetype)`, it will be executed if the user presses enter - `autocomplete {String}` a link to the `function(component, input)`, it will be executed if the user focuses the search box - `init {String}` a link to the `function(component)`, it will be executed if the component is initialized - `placeholder {String}` a placeholder for the search box - `cleartype {Boolean}` clears type when the user will perform `ESC` (default: `false`) - `keypress {Boolean}` key-press binding (default: `false`) - `autotrim {Boolean}` trims the value automatically (default: `true`) - `clicktype {String}` a link to the `function(component, currenttype, currentvalue)`, it will be executed if the user clicks on the `type` (a new `type` must be set via `component.type(html, value)`) __Methods__: - `component.type(html, id, [noemit])` adds a new type before the search input - `component.enter()` performs searching manually - __NEW__: `component.show()` focuses the input Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-SearchData Source: https://forge.totaljs.es/en/components/searchdata/ Framework: jcomponent@20 Content-SHA256: 5a504ccb320d0b1ecfb497220e63518807b9f39b28283a4c3662cbb7a0e0e8e3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component tries to filter data according to the search phrase. __Configuration__: - `datasource {String}` __required__ - a path to the data-source with list of items `Array` - `output {String}` __required__ - a path for filtered items - `key {String}` __required__ - a key/property name for searching (default: `name`) - `delay {Number}` a delay (default: `50` ms) - `splitwords {Boolean}` tries to find word in various position (default: `true`) __Good to know__: This component adds classes below automatically when: - class `ui-search-used` is added when the user searches for something - class `ui-search-empty` is added when the user searches for something and at the same time nothing was found Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-SearchInput Source: https://forge.totaljs.es/en/components/searchinput/ Framework: jcomponent@20 Content-SHA256: bea6824b457621cadb59ad1871955b168aa7d17eaab4e4d62be34a38e9bfc0e3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Customizable search input. __Configuration__: - `searchicon {String}` search icon (default: `ti ti-search`) - `cancelicon {String}` cancel icon (default: `ti ti-times`) - `align {String}` icon align (default: `left`) - `placeholder {String}` a plceholder - `autofocus {Boolean/Number}` enables auto-focus for non-mobile devices (number means a delay for auto-focus, default: `false`) - `exec {String}` a link to the `function(value, element)` which will be evaluated if the input is affected - __NEW__: `realtime {Boolean}` enables real-time binding (default: `true`) __Methods__: - `component.focus()` focuses input - `component.clear()` clears input Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Search: ``` ## j-Section Source: https://forge.totaljs.es/en/components/section/ Framework: jcomponent@20 Content-SHA256: 70c4f9777c6e504d5de1eefb990bff2327c80629e0adeb29a3588e833ba2d3af Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - keeps a fixed percentage height - great usage for intranet applications - supports `releasing` __Configuration__: - `height {Number}` a percentage of height - `parent {String}` optional, a container with fixed height, can be `window`. Default value: `parent` element. - `minheight {Number}` a minimal height in pixels (default: `0` - disabled) - `scroll {Boolean}` enables vertical scrolling (default: `false` - disabled) - `scrollbar {Boolean}` shows scrollbar (default: `false`) - `delay {Number}` `msec.` resizes the box again if the value is changed according to the path (default: `100`) - `visibleY {Boolean}` still shows `Y` scrollbar (default: `false`) - `visibleX {Boolean}` still shows `X` scrollbar (default: `false`) - `scrolltop {Boolean}` scrolls to top automatically if the `path` is changed (default: `false`) - `margin {Number}` optional, a top/bottom margin together (supports `auto` which is counted from `offset.top`, default: `0`) - `marginxs {Number}` optional, a top/bottom margin together for `xs` screen width - `marginsm` optional, a top/bottom margin together for `sm` screen width - `marginmd` optional, a top/bottom margin together for `md` screen width - `marginlg` optional, a top/bottom margin together for `lg` screen width - `invisible {Boolean}` if `true` then section sets `invisible` class when is rendering (default: `true`) - `autofocus {Boolean/String}` can focus an input. `String` === `jQuery selector` for the input - `back {String}` a title for back button (default: `Back`) - `delayanim {Number}` animation delay (default: `100`) - `scrollbarshadow {Boolean}` adds shadow for scrollbars (default: `false`) - `backexec {String}` a link to the `function(parent)` that captures back button (it prevents standard behaviour) __Methods__: - `component.scrolltop(val)` scrolls Y - `component.scrollbottom(val)` scrolls Y from bottom side - `component.resize()` resizes container (it reacts on `resize` events automatically) - `component.resizescrollbar()` resizes custom scrollbar (targeted for special cases) - __NEW__: `component.import(url)` imports a new section from the URL address, response must be in the form `
    ``` __Section attributes__: - `data-if` must contain a condition for displaying - `data-parent` can contain a parent `data-if` - `data-title` contains a label/title for the section - `data-reload` can contain a link to the `function(el)` (optional) - `data-id` contains a custom identifier for replacing of all `~ID~` phrases in the content (optional) - `data-url` can contain a link to the template (optional) __Good to know__: - If you want to add an additional content into the header to right side, just append inside of component e.g. `
    BUTTON
    `. - You can dynamically insert/remove sections via `component.import()` or `component.cancel()` methods. - All section's attributes can be changed dynamically (e.g. `data-title`, `data-parent`, etc.). - all `~PATH~` phrases will be replaced for the `data-if` attribute value - all `~ID~` phrases will be replaced for the `data-if` attribute value - `SET('path', 'if', 'right')` will animated the content to the right side Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-SelectBox Source: https://forge.totaljs.es/en/components/selectbox/ Framework: jcomponent@20 Content-SHA256: c5cc8c78ae17c3080d5a7b20e5b769434f505af634f0041fe789c3477920ee97 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required {Boolean}` (optional) enables `required` (default: __false__) - `items {String}` (optional) static items `key1|value1, key2 with value, key3|value` - `type {String}` (optional) can be `number` (converts `String` values to `Number`) - `datasource {String}` path to data-source (must be array) - `text {String}` determines a property name for text (in data-source), default: `name` - `value {String}` determines a property name for value (in data-source) default: `id` - `empty {String}` (optional) adds an empty field - `disabled {Boolean}` (optional) disables this component - `search {String}` (optional) enables search box with this value as a placeholder - `height {Number}` (optional) height (default: `200`) - `if {String}` (optional) arrow function as a condition for filtering of datasource, example: `if:n => !n.removed` - __NEW__ `raw {Boolean}` (optional) allow raw HTML to be rendered as text (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Selected Source: https://forge.totaljs.es/en/components/selected/ Framework: jcomponent@20 Content-SHA256: 737d8475f3a8d262c76dfd4c597e8466405344cbe857c1e4a9cb0a0b1d822dd5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can set a specific class to a specific element according to the simple condition. __Configuration__: - `class {String}` is a class name for selected element (default: `selected`) - `selector {String}` is a jQuery selector (default: `a`) - `attr {String}` attribute for comparing (default: `if` and it means `data-if`) - `attror {String}` attribute for secondary comparing (default: `or` and it means `data-or`) - `datasource {String}` a path to data-source for list of items - `delay {Number}` a delay for rel-selecting of value (default: `50`) __Usage__: Each nested element according to the `selector` must have defined `data-if` attribute. It works only with `strings` values. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Selection Source: https://forge.totaljs.es/en/components/selection/ Framework: jcomponent@20 Content-SHA256: c19fcf1b03bb53cf998d443bad5178001ce2af70b1e1ec6963e204ea7e77a083 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component supports something like checkbox list. __Configuration__: - `remember {Boolean}` remembers selection when the `datasource` is changed (default: `true`) - `datasource {String}` a path to the datasource (default: empty) - `key {String}` an `identifier` key name for the datasource (default: `id`) - `attr {String}` a `data-[attr]` for storing of `identifier` (default: `id`) - `selector {String}` a jQuery selector for elements (default: `.selection`) - `class {String}` selected class (default: `selected`) - `dblclickselectall {Boolean}` enables reverse selection after double-click (default: `true`) - `cancel {String}` a path to the variable (if the variable is changed then the selection is resetted, default: empty) - __NEW__: `click {String}` a selector for capturing of click (default: `.selection`) __Methods__: - `component.selectall()` selects all items - `component.selectnone()` selects none - `component.selecttoggle()` reverses selection Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Item 1
    Item 2
    Item 3
    Item 4
    Item 5
    Item 6
    Item 7
    Item 8
    Item 9
    Output:
    ``` ## j-ServerGrid Source: https://forge.totaljs.es/en/components/servergrid/ Framework: jcomponent@20 Content-SHA256: eb7c2a1d99b6c5051929883316cc3763370bb2e1596a6fe9e2c798665b00ce4c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __BETA VERSION__. This grid is designed for single page and enterprise applications. It's a simple alternative to the much more powerful `j-DataGrid`. __Data-source__ needs to contain: ```js { columns: [ { id: 'name', name: 'Name', width: 150, // optional (default: config.colwidth) filtering: false, // optional (default: false) sorting: false, // optional (default: false) align: 1, // optional: 0 or left (default), 1 or center, 2 or right alignheader: 1, // optional: 0 or left (default), 1 or center, 2 or right alignfilter: 1, // optional: 0 or left (default), 1 or center, 2 or right icon: 'ti ti-home', // optional: column icon color: '#000000' // optional: color for all rows, dirsource: [{ id: 'String|Number|Boolean', name: '...' }] // optional: a dropdown filter (it needs "directory" component) } ], items: [{ name: 'Row 1 will be bold', $class: 'NEW: css class for the row', $style: 'NEW: css for the row' }, { name: 'Row 2' }, ...] // items page: 1, // current pages pages: 30, // count of pages limit: 5, // items limit per page count: 150 // count of items in DB } ``` __Configuration__: - `colwidth {Number}` a default column width in pixels (default: `150`) - `pluralizepages {String}` pluralization for pages (optional, default: `# pages,# page,# pages,# pages`) - `pluralizeitems {String}` pluralization for items (optional, default: `# items,# item,# items,# items`) - `margin {Number}` a top margin for height (optional, default: `0`) - `noborder {Boolean}` can remove a border (default: `false`) - `parent {String}` selector for `auto` height option (default: `window`) - `height {Number}` a fixed height - `filter {String}` a default placeholder for all filters (optional) - `click {String}` a link to a path or `function(row, row_element)` - `cell {String}` a link to a path or `function(row, cell_element, column)` - `exec {String}` a link to `function(type, filter, sort, page)` for server-side operations (supported types: `filter`, `page` and `sort`) - `opacity {Number}` a default background opacity for column colors (default: `0.3`); - __NEW__: `scrollbarshadow {Boolean}` enables scrollbar shadow (default: `false`) - __NEW__: `scrolltop {Boolean}` it automatically scrolls to the top after the data source is changed (default: `true`) __Good to know__: - `NULL('link.to.data')` evaluates `config.exec` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ServerList Source: https://forge.totaljs.es/en/components/serverlist/ Framework: jcomponent@20 Content-SHA256: f1255562ae293134d1a9137753a087c2e1ca9aafeaa96e6e157025eb97b7b7a3 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __BETA VERSION__. This componnet is designed for single page and enterprise applications.It has nearly the same functionality as the `j-ServerGrid`, but it gives developers more freedom to create custom item rendering. __Data-source__ needs to contain: ```js { columns: [ { id: 'name', name: 'Name', width: 150, // optional (default: config.colwidth) filtering: false, // optional (default: false) sorting: false, // optional (default: false) align: 1, // optional: 0 or left (default), 1 or center, 2 or right alignheader: 1, // optional: 0 or left (default), 1 or center, 2 or right alignfilter: 1, // optional: 0 or left (default), 1 or center, 2 or right icon: 'ti ti-home', // optional: column icon dirsource: [{ id: 'String|Number|Boolean', name: '...' }] // optional: a dropdown filter (it needs "directory" component) } ], items: [{ name: 'Row 1 will be bold', html: 'RENDER' }, { name: 'Row 2', html: 'RENDER' }, ...] // items page: 1, // current pages pages: 30, // count of pages limit: 5, // items limit per page count: 150 // count of items in DB } ``` __Configuration__: - `colwidth {Number}` a default column width in pixels (default: `150`) - `pluralizepages {String}` pluralization for pages (optional, default: `# pages,# page,# pages,# pages`) - `pluralizeitems {String}` pluralization for items (optional, default: `# items,# item,# items,# items`) - `margin {Number}` a top margin for height (optional, default: `0`) - `noborder {Boolean}` can remove a border (default: `false`) - `parent {String}` selector for `auto` height option (default: `window`) - `height {Number}` a fixed height - `filter {String}` a default placeholder for all filters (optional) - `click {String}` a link to a path or `function(row, row_element)` - `exec {String}` a link to `function(type, filter, sort, page)` for server-side operations (supported types: `filter`, `page` and `sort`) - `display {Boolean}` enables auto adding jComponent responsive class `d-xs`, `d-lg`, etc. according to the screen width (default: `true`) - `empty {String}` an empty message (default: `No records found.`) - __NEW__: `scrollbarshadow {Boolean}` enables scrollbar shadow (default: `false`) - __NEW__: `scrolltop {Boolean}` it automatically scrolls to the top after the data source is changed (default: `true`) __Good to know__: - `NULL('link.to.data')` evaluates `config.exec` ## Custom templating The ServerList component attempts to locate a Tangular template. If one exists, the component uses it. Otherwise, it tries to render a content from the `html` property of each item/row. ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-ServerListing Source: https://forge.totaljs.es/en/components/serverlisting/ Framework: jcomponent@20 Content-SHA256: 4208c1a50f7cc75a1ba796827c4e8997c324cc25ee989fdabe75822aa0a775d1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `paginate {String}` link to a function `function(page)` for pagination - `pages {Number}` max. pages in pagination (default: `3` --> half + current page + half) - `scrolltop {Boolean}` scrolls top automatically when the user changes a page - `parent {String}` jQuery selector for obtaining of height, enables fixed area with custom scrollbars - `margin {Number}` a margin for `parent` (default: `0`) - `marginxs {Number}` optional, a top/bottom margin together for `xs` screen width - `marginsm` a top/bottom margin together for `sm` screen width - `marginmd` a top/bottom margin together for `md` screen width - `marginlg` a top/bottom margin together for `lg` screen width - `pluralizeitems` a pluralization for count of all items, form: `# zero,# one,# two-four,# five and more` (if empty, counter will be hidden) - `pluralizepages` a pluralization for count of all items, form: `# zero,# one,# two-four,# five and more` (if empty, counter will be hidden) - `modulo {Number}` can append empty items with `{ EMPTY: 1 }` object (default: `0`) - `nopages {Boolean}` can hide pagination if the pages are less than `2` (default: `false`) __Model__: The model must be in the format below: ```javascript { page: Number, count: Number, pages: Number, items: [{...}, {...}] } ``` __Tangular layout__: - `body` {String} contains all rendered items, output is __HTML__ - `page` {Number} current page number - `pages` {Number} count of pages - `count` {Number} count of items __Tangular item__: - `model` contains an object from `Array` - second model `$` contains info about data-source `{ index: Number, page: Number, pages: Number, count: Number, value: YOUR_DATA }` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    With layout


    Without layout


    ``` ## j-ShoppingCart Source: https://forge.totaljs.es/en/components/shoppingcart/ Framework: jcomponent@20 Content-SHA256: 75efbac550362325a9ccdacd9e8dea579b4db66523d1a61f271f07fdfabbabc0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - supports discount - data are stored in localStorage __Configuration__: - `discount {Number}` a discount in percentage (optional, default: `0`) - `expiration {String}` data expiration (default: `6 days`) __Output__: ```js { items: [ { name: String, price: Number, total: Number, count: Number, date: Date } ], price: Number, total: Number, count: Number } ``` ### Methods - `instance.add(id, price, count, [name])` adds new product or increase count if the product exists - `instance.upd(id, [count], [price], [name])` updates product's data - `instance.buy(id, price, count, [name])` creates/updates product - `instance.rem(id)` removes product - `instance.has(id)` checks product - `instance.read(id)` reads product - `instance.clear()` clears all products - `instance.clean()` removes all products with zero count - `instance.sync(function(array_id_products, meta) {})` create data for synchronization with the server ### Global Events - `ON('shoppingcart.add', function(item) {})` - `ON('shoppingcart.upd', function(item) {})` - `ON('shoppingcart.rem', function(id) {})` - `ON('shoppingcart.sum', function(data) {})` - `ON('shoppingcart.clear', function() {})` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Shortcuts Source: https://forge.totaljs.es/en/components/shortcuts/ Framework: jcomponent@20 Content-SHA256: bfb6fe853acadcbd942b2ca141830169b259674033c9cb728213a1af67784cbd Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can help with creating keyboard shortcuts. The component __is singleton__. __Methods__: - `component.register(shortcut, callback(e), [prevent], [preparation(e)])` - registers a new shortcut - `component.exec('shortcut')` - evaluates shortcut __Shortcuts__: - `enter` - `esc` - `tab` - `cmd`, `meta`, `win` - `shift`, `capslock` - `ctrl` - `alt` - `space` - `backspace`, `del`, `delete` - `left`, `up`, `right`, `down` - `F1`, `F2`, `F3`, `F4`, `F5`, `F6`, `F7`, `F8`, `F9`, `F10`, `F11`, `F12` - or custom key-codes `{Number}` or key-characters `{String(1)}` - `ins` - `remove` means`backspace` or `delete` - `save` - `selectall` - `clone` - `undo` - `redo` - supports `.shortcut`, read more below __Example__: ```javascript // SETTER(true, ...) --> works in jComponent +v9.0.0 SETTER(true, 'shortcuts/register', 'cmd + enter', function(e) { console.log('PRESSED: CMD + ENTER'); }); SETTER(true, 'shortcuts/register', 'alt + p', function(e) { console.log('PRESSED: ALT + P'); }); SETTER(true, 'shortcuts/register', 'esc', function(e) { console.log('PRESSED: esc'); }); // +v3 supports multiple shortcuts at the one time: SETTER(true, 'shortcuts/register', 'cmd+enter, ctrl+enter', function(e) { console.log('PRESSED: CMD + ENTER'); }); // NEW: you can make preparation for the shortcut SETTER(true, 'shortcuts/register', 'cmd+enter, ctrl+enter', function(e) { console.log('PRESSED: CMD + ENTER'); }, function(e) { // You can enable/disable shortcut manually in the "preparation function" // but you need to "return {Boolean}", true will approve shortcut (it calls of the shortcut "callback") // otherwise "returning false" the shorcut will be skipped return e.target.tagName !== 'INPUT'; }); ``` __New inline declaration__: ```html ``` - `.shortcut` class will emit `click` event - property `e.shortcut` will contain Event instance from the `keydown` event __New session shortcuts__: ```javascript // Open session for new shortcuts // The methods disables all registered shortcuts while session is not end SETTER('shortcuts/session', function(register) { register('esc', function() { // Cancels session SETTER('shortcuts/end'); }); }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    PRESS ENTER or INSERT
    ``` ## j-SingleUpload Source: https://forge.totaljs.es/en/components/singleupload/ Framework: jcomponent@20 Content-SHA256: 9470c4ec93ad07158dde85007bc9b89e45801fa63a68da180b74c2b34c551d30 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `url` {String} a target URL for the uploading (default: `/api/upload/`) - `accept` {String} (optional) can contain a content-type frow browsing files e.g. `image/*` - `label` {String} (optional) changes a current `innerHTML` (default: `innerHTML`) - `title` {String} Tangular template for rendering a title of attachment (default: `{{ name }}`) - `disabled` {Boolean} disables the component - `remap` {String} (optional) a remap function (default: `null`), example: `value.length ? value[0] : null` __Friendly components__: This component works with `loading` (when the file is uploading) and `message` (when server throws an error) component. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Add attachment ``` ## j-Slider Source: https://forge.totaljs.es/en/components/slider/ Framework: jcomponent@20 Content-SHA256: fcb4bf8a9f2c65431f40cb65a3a0f5c8a58addd7d3a32c2be5ffad261f3b7168 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This slider works only with 100% X axis. Output: `percentage` (from 0 to 100). __Configuration__: - `disabled {Boolean}` can disable the component - `steps {Number}` a count of steps per 100% Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html


    ``` ## j-SnackBar Source: https://forge.totaljs.es/en/components/snackbar/ Framework: jcomponent@20 Content-SHA256: d4c159a21787d1200d216eb7ebba06929b55fd65f6a42a45795ee8983105afda Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - info message `SETTER('snackbar/show', 'MESSAGE', '[BUTTON_LABEL]', [callback_dismiss])` - success message `SETTER('snackbar/success', 'MESSAGE', '[BUTTON_LABEL]', [callback_dismiss])` - warning message `SETTER('snackbar/warning', 'MESSAGE', '[BUTTON_LABEL]', [callback_dismiss])` - __NEW__ waiting message `SETTER('snackbar/waiting', 'MESSAGE', '[BUTTON_LABEL]', [callback_dismiss])` - `message` can contain `HTML` code __Configuration__: - `button {String}` A label for dismiss button (default: `OK`) - `timeout {Number}` A timeout in milliseconds (default: `4000`) __Works with ASETTER__: - errors are handled automatically ```javascript // Without callback AJAX('POST /api/profile/', userprofile, ASETTER('snackbar/response', 'Profile has been saved successfully')); // Or with a callback AJAX('POST /api/profile/', userprofile, ASETTER('snackbar/response', 'Profile has been saved successfully', function(response) { console.log(response); })); // Or with a callback and without a message AJAX('POST /api/profile/', userprofile, ASETTER('snackbar/response', function(response) { console.log(response); })); // With auto-binding AJAX('POST /api/profile/', userprofile, ASETTER('snackbar/response', '?.response')); AJAX('POST /api/profile/', userprofile, ASETTER('snackbar/response', 'Your message', '?.response')); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Sounds Source: https://forge.totaljs.es/en/components/sounds/ Framework: jcomponent@20 Content-SHA256: a25786ca81f7a7f72a534aaa09ad7d9efc63d100a561c235d6334e150ec54ee9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component contains some predefined sounds like `beep`, `fail`, `success`, etc... Path contains a volume control in percentage, `0` disables playing. __Configuration__: - `url {String}` URL address to sound library (default: `https://cdn.componentator.com/sounds/`) - `volume {Number}` (default: `50`) __Good to know__: `path` can contain `{Number}`, which will control volume or `{Boolean}` which will enable or disable sounds. __Methods__: - `component.play(sound)` supported sounds: - `alert` - `message` - `badges` - `notifications` - `beep` - `confirm` - `done` - `drum` - `fail` - `success` - `component.success()` - `component.fail()` - `component.alert()`, `component.error()` - `component.warning()` - `component.notify()` - `component.badge()` - `component.confirm()` - `component.beep()` - `component.drum()` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-SplashScreen Source: https://forge.totaljs.es/en/components/splashscreen/ Framework: jcomponent@20 Content-SHA256: 81a1a3a71c64cf23911e2aa40c71c94e2794673ebef08a3d7818454f99884ba4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A splash screen for single page applications. The body has to be wrapped into the `` tag. The component will be destroyed automatically. __Configuration__: - `timeout` a timeout in milliseconds for destroying the splash screen (default: `3000`) - `autoremove:true {Boolean}` automatically removes component. - `remember {String}` e.g. `1 day` or `1 week` - it doesn't show a splash screen (default: `empty` = disabled) __Methods__: - `component.show([body])` will show splashscreen with a new or old body (`autoremove` must be `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    Lorem ipsum
    ``` ## j-Spotlight Source: https://forge.totaljs.es/en/components/spotlight/ Framework: jcomponent@20 Content-SHA256: 564749c00088cc64f5896bc384a7d6b3f559892892463bd1c2e9482611570436 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - works with Bootstrap Grid System __Configuration__: - `height` {Number} a default height of each item (default: `40`, must be defined in CSS too) - `placeholder` {String} a default placeholder (default: `Search`) __Methods__: Method: `component.show(opt)` - `opt.id {String}` optional, an identifier for recent items (default: `empty`) - `opt.recent {String}` enables recent items, must contain an expiration format (default: `3 days`, `empty` means disabled) - `opt.callback(selected_item) {Function}` is triggered when the user clicks on the item - `opt.cancel {Function}` is triggered then the user cancels component - `opt.search {String}` URL address for searching of values in the form `GET /api/search/?={0}` - or `opt.search {Function}` a link to `function(search, next(ARR_ITEMS))` for searching - `opt.cache {String}` enables cache, can contain an expiration format e.g. `1 day` or `session` - `opt.remap {Function}` it can remap results `items => items.map(...)` - `opt.clear {Boolean}` it clears previous results (default: `false`) - `opt.init {Boolean}` makes an empty search when the component is called (default: `false`) - `opt.delay {Number}` a delay in `ms` for performing searching (default: `100`) - `opt.height {Number}` a height of item (default: `config.height`) - `opt.class {String}` adds a custom class to the container - __NEW__ `opt.placeholder` {String} search placeholder (default: `config.placeholder`) __Good to know__: - `.items = [{ html }]` -> `html` field ( in items) will be rendered as a plain HTML Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Stash Source: https://forge.totaljs.es/en/components/stash/ Framework: jcomponent@20 Content-SHA256: b250a27f45b5d99ee5a818aecf8d0675939ce15f54c62f888b7cc45c51a8667b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can postpone elements without destructing and detaching from the DOM. This component can help you with dynamic content from the server side. We use the component in the Total.js FlowStream projects for the component's settings. - elements can contain everything like components, scopes, binders, etc. __Configuration__: - `load {String}` a path to the method `function(id, next(html/element))` that is evaluated if the content wasn't loaded before - __NEW__: `class {String}` a class name for the stash container (default: `hidden`) __Methods__: - `component.add(id, html/element)` adds new HTML/element - `component.clear([id])` clears specific ID (`id` is optional) or clears all cached content Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Stats12 Source: https://forge.totaljs.es/en/components/stats12/ Framework: jcomponent@20 Content-SHA256: fe37cbda0a67be0181ee96d044d586f6b42c84031d5f6ee0ad8e8802d0366a72 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `height {Number}` a height of chart (default: `120`) - `max {Number}` a maximal hourly value (default: `undefined`) - `border {Boolean}` enables border (default: `true`) - `highlight {Boolean}` highlights the current hour (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Stats24 Source: https://forge.totaljs.es/en/components/stats24/ Framework: jcomponent@20 Content-SHA256: f4e9f8e2cb15f15e0bbb16152d30c51522a89f510b5f065fc0518c22ba7389ee Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `height {Number}` a height of chart (default: `120`) - `max {Number}` a maximal hourly value (default: `undefined`) - `tooltiplarge {Boolean}` enables tooltips in larger mode (default: `true`) - `tooltip {Boolean}` enables tooltips (default: `true`) - `tooltiptext {String}` Tooltip text (default: `{0}`) - `border {Boolean}` enables border (default: `true`) - `highlight {Boolean}` highlights current hour (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Stats7 Source: https://forge.totaljs.es/en/components/stats7/ Framework: jcomponent@20 Content-SHA256: 3de9c228bd1e89d867296a5df59e83e9cc01c83841f534130bb7efc07309ada7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `height {Number}` a height of chart (default: `120`) - `max {Number}` a maximal hourly value (default: `undefined`) - `border {Boolean}` enables border (default: `true`) - `highlight {Boolean}` highlights the current hour (default: `false`) - `firstday {Number}` first day (default: `0`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-StatsBarSimple Source: https://forge.totaljs.es/en/components/statsbarsimple/ Framework: jcomponent@20 Content-SHA256: 91635180a7fa998f3ce932108f17a78b11e2c273afdf4712681ecb9179b73788 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `tooltip {Boolean}` enables tooltips (default: `true`) - `animate {Boolean}` enables animation (default: `true`) - `value {String}` a key for the value field (default: `value`) - `colors {String}` predefined colors The component needs to have a defined template for rendering content and a tooltip. For an understanding look to the example. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-StatusInput Source: https://forge.totaljs.es/en/components/statusinput/ Framework: jcomponent@20 Content-SHA256: 894330f8850ee3b374098b8060439ed7922406d08e6360e301bb412e84409b2a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __Dark mode__ - singleton ## Usage ```javascript var opt = {}; // opt.placeholder {String} : A placeholder and can be HTML (optional) // opt.icon {String} : An icon (optional) // opt.hide {Function} : Is executed when the StatusInput is hiding (optional) // opt.validate {RegExp} : A validator, must be RegExp or nullable (optional) // opt.valuel {String} : A default value for the input (optional) // opt.callback {Function} : A callback opt.callback = function(newvalue) { console.log(newvalue); }; SETTER('statusinput/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Sticker Source: https://forge.totaljs.es/en/components/sticker/ Framework: jcomponent@20 Content-SHA256: 19cb287f5a79726f4e731a54b0567ed8e59f22a23fb6118adfb82acb67be4049 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `on {String}` this class is enabled when the `scroll top` position is greater than this element `Y` position - `off {String}` this class is enabled when the `scroll top` position is smaller than this element `Y` position - `margin {Number}` a margin which will be deducted from the `top` position of the current element - `xs {Boolean}` enables sticker for extra small display (default: `false`) - `sm {Boolean}` enables sticker for small display (default: `true`) - `md {Boolean}` enables sticker for medium display (default: `true`) - `lg {Boolean}` enables sticker for large display (default: `true`) - `type {String}` a method name for obtaining of position `offset` (default) or `position` - `marginparent {Number}` a margin for `parent` scrolling (default: `0`) - `parent {String}` optional, a parent selector (look to example for understanding) - __NEW__: `minheight {Number}` a minimal height of scroll area for applying of classes Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    This text will depent on parent position.

    This text will be on fixed position.
    ``` ## j-Suggestion Source: https://forge.totaljs.es/en/components/suggestion/ Framework: jcomponent@20 Content-SHA256: fec33fb3c9f3732bf1a452d7e8e08c7634cac710cfee99d57c80e7f64bafc045 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports 3 orientations `left`, `center` and `right` - singleton - works with Bootstrap Grid System - works with touches - supports __dark mode__ __Methods__: Method: `component.show(orientation, targetElement, [items/function(search, next)], clickCallback)` - `orientation {String}` can be `left`, `center` or `right` - `targetElement {Selector/jQuery/Element}` a target where the component will be visible - `items {Array}` optional and must have this structure: `[{ name: String, value: String, icon: String }]` otherwise will be items read from the target's `data-options` attribute. - `callback(selectedItem) {Function}` is triggered when the user clicks on the item Method: `component.hide()` __Attributes__: - `targetElement` can contain `data-options="Name 1|ti-building|Value 1;Name 2|ti-github|Value 2;"` attribute with all items of the context menu. __Configuration__: - `placeholder` - a placeholder for the search input __Server-side searching__: ```javascript SETTER('suggestion', 'show', element, function(search, next) { next([{ name: 'Item 1' }, { name: 'Item 2' }]); }, function(selected) { console.log(selected); }); ``` If the `value` isn't defined then the component uses `name` as `value`. __Global events__: ```javascript ON('suggestion', function(visible, component, target) { console.log('Suggestion is', visible ? 'visible' : 'hidden'); }); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-SVGIcons Source: https://forge.totaljs.es/en/components/svgicons/ Framework: jcomponent@20 Content-SHA256: 1f8677cd1bf4affcf17b4ca89470f42a558aacd0e22d60732439682916846bf2 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component registers a new Web component in the form ``. - Use SVG sprites generator __Configuration__: - `url {String}` a URL address to the SVG file (default: `empty`) - `size {Number}` a default image width (default: `empty`) __Attributes ``:__ - `name {String}` optional, icon name - `size {Number}` optional, a size of image (default: `config.size`) - `selected {String}` optional, selected icon name (it will be displayed if the parent element will contain `.selected` class) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Swiper Source: https://forge.totaljs.es/en/components/swiper/ Framework: jcomponent@20 Content-SHA256: 4b36a89fe5de71f62485c2b96d511f38963c44008775b3901d630b5397d2c04a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - wrapper for [Swiper.js library](https://swiperjs.com/) __Configuration__: - `slidesperview {Number}` count of the items in the one slide (default: `1`) - `spacebetween {Number}` a space between items (default: `0`) - `navigation {Boolean}` show/hide navigation arrows (default: `false`) - `pagination {Boolean}` show/hide pagination bullets (default: `false`) - `autoplay {Boolean}` allow autoplay (default: `false`) - `delay {Number}` a delay between slides change, working with autoplay only (default: `2500`) - `loop {Boolean}` infinity loop through the slides (default: `false`) - __NEW__ `reset {Number}` idle time after which the swiper restarts and returns to the first image (enter in minutes) - __NEW__ `freemode {Boolean}` moving slides without fixed alignment to individual slides (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Dodo Marton. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-SwitchButton Source: https://forge.totaljs.es/en/components/switchbutton/ Framework: jcomponent@20 Content-SHA256: 4e87cc115f80fd162a2ada96a27c713148d71963f35a4566cd183bdde8d67cc9 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required {Boolean}` optional, enables "required" (default: `false`) - `disabled {Boolean}` optional, disables this component - `border {Boolean}` optional, allow border bottom (default: `false`) - `align {String}` left/right alignment of the switch element (default: `left`) - `description {String}` optional Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Tomáš Novák. Source: the Componentator components repository, MIT license. ```html example.html
    Receive messages from our platform Receive coupons, promotions, surveys Receive marketing somarines Documents are not ready
    ``` ## j-Table Source: https://forge.totaljs.es/en/components/table/ Framework: jcomponent@20 Content-SHA256: 651ade85a957c60b98ba9284ba40e67593b296ad9763c24befeff7b6e1088e52 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - `j-Table` is a very very very simple alternative to `j-DataGrid` targeted for UI - `data-source` expects `Array` or `Object` with `{ page: 1, pages: 10, limit: 50, items: [], count: 1000 }` __Configuration__: - `highlight {Boolean}` enables highlighting of the row (default: `true`) - `unhighlight {Boolean}` enables undo-highlighting of the row (default: `true`) - `multiple {Boolean}` enables multiple row highlighting (default: `false`) - `detail {Boolean/String}` if `string` then the value must be a link to `function(row_data, next_fn(new_data_for_detail_template_OR__new_html), tdelement)` - `exec {String}` a path to `function(row/rows)` or path to `variable` - `remember {Boolean}` enables remembering of last selected rows (default: `false`) - `pk {String}` a primary key (default: `id`) - `border {Boolean}` enables border (default: `true`) - `scrollbar {Boolean}` enables custom scrollbar (default: `false`) + important: `height` must be specified - `height {Number/String}` height of grid or can contain selector `window`, `parent` or custom selector `.ui-viewbox-body` - `paginate {String}` a link to `function(model)` for performing pagination `{ page: 1, limit: 10, sort: [] }` - `redraw {String}` a link to function, it's evaluated when the table is redrawing - `filter {String}` a link to function, it's evaluated before the table is rendering - `dblclick {String}` a link to function, it's evaluated when the user performs double-click - `datasource {String}` path to data-source (for other extra data in the template. Usage: `{{ $.data.something }}`) - `click {String}` a path to `function(button_name, row, button_element)`, is executed when the user will click on the button - `flat {Boolean}` removes padding in cells (default: `false`) - `noborder {Boolean}` removes border around (default: `false`) - __NEW__: `hidewhenempty {Boolean}` hides table when empty (default: `false`) __Good to know__: - each `tr` element contains `data-index` attribute with `row` index - each `td` __element of detail__ contains `data-index` attribute with `row` index __HTML definition__: ```html ``` __Good to know__: - `data-head` can contain Font Awesome icons, it must be wrapped like this `data-head="Name,'cog'"` or `data-name="Name,'youtube fab'"` - `NULL('link.to.data')` evaluates `config.paginate` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-TableGrid Source: https://forge.totaljs.es/en/components/tablegrid/ Framework: jcomponent@20 Content-SHA256: 8d85554e3ce4c5447c8a4dbd54836e8e59fa42799b0d4a6b034a7d721cc0a34d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component makes a simple table grid (composed of `div` elements) divided by a simple border that you can modify. __Configuration__: - `count {Number}` a default count of items per row - `countxs {Number}` items per row for mobile display - `countsm {Number}` items per row for small display - `countmd {Number}` items per row for medium display - `countlg {Number}` items per row for a large display - `parent {String}` for obtaining size (default: `window`) - `margin {Number}` a vertical margin (default: `0`) - `scrollbar {Boolean}` enables custom scrollbar (default: `false`) - `fill {Boolean}` fills the grid with empty rowsm need to define `row` and `scrollbar` - `row {Number}` a default row height for all displays (default: `0`) - `rowxs {Number}` a default row height for mobile display (default: `0`) - `rowsm {Number}` a default row height for small display (default: `0`) - `rowmd {Number}` a default row height for medium display (default: `0`) - `rowlg {Number}` a default row height for large display (default: `0`) - `scrolltop {Boolean}` scrolls to the top after change data (default: `true`) __Classes__: - `ui-tablegrid-bl` means border-left - `ui-tablegrid-bt` means border-top - `ui-tablegrid-first` first item in the row - `ui-tablegrid-last` last item in the row - `ui-tablegrid-empty` empty item Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-TabMenu Source: https://forge.totaljs.es/en/components/tabmenu/ Framework: jcomponent@20 Content-SHA256: 356a21b1d81326e4755421f6f32b3ccc9a187c8632538d642678df7f8cd8836e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `class {String}` optional, is a class name for a selected element (default: `selected`) - `selector {String}` optional, is a jQuery selector (default: `li`) - `datasource {String}` optional, a path to a data-source, content must be Tangular template - `disabled {Boolean}` optional, it can disable tabs - `exec {String}` optional, a link to the function (it will be executed when the tab is changed) - `attr {String}` optional, a default attribute for obtaining tab identifier (default: `id`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    Static tabs

    • Tab 1
    • Tab 2
    • Tab 3

    Dynamic tabs

    ``` ## j-Tabs Source: https://forge.totaljs.es/en/components/tabs/ Framework: jcomponent@20 Content-SHA256: ee2dcea90df616c20f5b94647872138a94e0d647102b4d67986e763bea48dbdb Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `icon {String}` a label icon for every panel (default: `empty`) ### How to define panels? ```html ``` __Attributes__: - `data-id` __required__, it must contain an identifier of the panel - `title` __required__, it must contain a panel name - `icon` optional, it can contain Total.js Icon (default: `config.icon`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Tagger Source: https://forge.totaljs.es/en/components/tagger/ Framework: jcomponent@20 Content-SHA256: 4d1c04153eacff41b55dda4f4e155c5192e132490d5414a645bc0ab66034d39c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Tagger can render items in the array and each item can be removed. __Configuration__: - `text` {String} a property name for the label (default: `name`) - `fullwidth` {Boolean} enables fullwidth tags (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html

    ``` ## j-Template Source: https://forge.totaljs.es/en/components/template/ Framework: jcomponent@20 Content-SHA256: 293a93cbf60aecb105c2e06e693e718518939bbee158fc63c76f85f4d389a7f0 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - when the model is `null` or `undefined` then the template will be hidden __Configuration__: - `properties {String}` watch only specific properties in the string e.g. `name,email` (optional) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Templates Source: https://forge.totaljs.es/en/components/templates/ Framework: jcomponent@20 Content-SHA256: e5f3357bc56d202555787c596f876f93207a56e17030a8c3f144706aba799bf1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - multiple templates - drag & drop - custom scrollbars - context menu __Configuration__: - `template {String}` a path to the watching a template name - `scrollbar {Boolean}` uses a custom scrollbar (default: `true`) - `scrolltop {Boolean}` scrolls to top if the source is changed (default: `true`) - `visibleY {Boolean}` shows scrollbar Y (default: `true`) - `margin {Number}` a vertical margin (default: `0`) - `parent {String}` jQuery selector to parent container due to `scrollbar` (default: `auto`) - `contextmenu {String}` a path to the method `function(e)` if the user triggers context-menu - `emptyif {String}` a condition for showing of empty content (default: `!value || !value.length`) - `drop {String}` a path to the method `function(e, target, selel)` - the method is evaluated if the user drops some files, then `selel` is undefined - or the user drags & drops element with the `draggable` attribute (`selel` argument) into the `target` argument (target must contain `droppable` class) Templates must be defined in `` element. This component supports one special template called `empty` that will be visible if the `emptyif` option will be valid. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    List Icons


    Without multiple templates:
    ``` ## j-Textarea Source: https://forge.totaljs.es/en/components/textarea/ Framework: jcomponent@20 Content-SHA256: 44bbb92890034397c6335cc86a6ab60d9f97619303388625112fb77a3ea724b4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - __NEW__ supports hidden scrollbar __Configuration__: - `required {Boolean}` (optional) enables "required" (default: `false`) - `icon {String}` (optional) icon for the label without `ti-` e.g. `home`, `cog`, etc. - `label {String}` (optional) label (default `innerHTML`) - `autofocus {Boolean}` (optional) focuses the input (default: `false`) - `placeholder {String}` (optional) adds a `placeholder` text into the input - `maxlength {Number}` (optional) sets a maximum length of chars - `disabled {Boolean}` (optional) disables this component - `height {Number}` (optional) a maximum height for the input - `error {String}` (optional) adds an `error` text under the input - `monospace {Boolean}` (optional) sets `monospace` font for the input (default: `false`) - `readonly {Boolean}` optional, default `false` - `scrollbar {Boolean}` optional, default `true` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Body
    Note
    ``` ## j-Textbox Source: https://forge.totaljs.es/en/components/textbox/ Framework: jcomponent@20 Content-SHA256: bfd0aed862812132366675bed7e4237f5fe8e87f543590157571139c2b850ee4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `type {String}` (optional) can be `email`, `phone`, `password`, `date`, `number`, `search`, `lower`, `upper` or empty (default) - `required {Boolean}` (optional) enables "required" (default: `false`) - `icon {String}` (optional) icon for label e.g. `home`, `cog`, etc. - `icon2 {String}` (optional) icon in the right box e.g. `home`, `cog`, etc. - `label {String}` (optional) label (default is HTML content) - `autofocus {Boolean}` (optional) focuses the input (default: `false`) - `align {String}` (optional) `left` (default), `right` or `center` - `autofill {Boolean}` (optional) enables the browser's autofill feature (default: `false`) - `placeholder {String}` (optional) adds a `placeholder` text into the input - `maxlength {Number}` (optional) sets a maximum length of chars - `minlength {Number}` (optional) sets a minimum length of chars - `validation {String}` (optional) a condition for `evaluation` e.g. `value.match(/[a-z]+/) !== null` - `format {String}` (optional) output formatting e.g. for dates (default: `yyyy-MM-dd`) - `increment {Boolean}` (optional) enables controls for incrementing of numbers (default: `false`) - `keypress {Boolean}` (optional) can disable real-time binding values (default: `true`) - `delay {Number}` (optional) can increase/decrease delay for real-time binding (default: `300` ms) - `disabled {Boolean}` (optional) disables this component - `error {String}` (optional) adds a `string` text under the input - `iconclick {String}` (optional) needs to contain a link to a function - `autocomplete {String}` (optional) needs to contain a link to a function, is triggered on the `focus` event - `spaces {Boolean}` (optional) enables spaces otherwise it removes them (default: `true`) - `readonly {Boolean}` optional, default `false` - __NEW__ `innerlabel {Boolean}` optional, enables inner label (default: `true`) __Interesting:__ - `type:date` uses the `calendar` component Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Name
    E-mail
    Password
    Note
    Phone
    Age
    Search

    Inner label

    Name
    ``` ## j-TextboxList Source: https://forge.totaljs.es/en/components/textboxlist/ Framework: jcomponent@20 Content-SHA256: 47684939c4f5efcc24d1a01594ac0e3a1f20e8f3d4f1512d4f2ab334ca7df025 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `icon {String}` icon for label - `label {String}` label (default `innerHTML`) - `placeholder {String}` adds a `placeholder` text into the input - `maxlength {Number}` sets a maximum length of chars - `disabled {Boolean}` disables this component - `limit {Number}` sets a maximum length of lists - `error {String}` error message when a limit is reached (default `You reach the maximum limit`) - `required {Boolean}` whether a list is required (default `false`) - `type {String}` can be `email`, `url`, `currency`, `number`, `date`, `lower`, `upper`, `a-z` or empty (default) - __NEW__ `movable {Boolean}` enables changing of position for existing items Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Redirects
    Emails
    Required
    Required Numbers ``` ## j-Time Source: https://forge.totaljs.es/en/components/time/ Framework: jcomponent@20 Content-SHA256: 95178553bfe1bdf2fd1a99d3436255f5d4bd2189a9f162d83a82ff49c24ab028 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component renders a current time. __Configuration__: - `icon {String}` icon (default: `ti ti-clock`) - `format {String}` default time format (default: `DEF.timeformat`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-TimePicker Source: https://forge.totaljs.es/en/components/timepicker/ Framework: jcomponent@20 Content-SHA256: 453c001d6268617294247689b41b0338e981e0a3dd038febb3b00c7d34abd521 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ __Configuration__: - `seconds {Boolean}` optional, enables seconds (default: `false`) - `ampm {Boolean}` optional, enables 12 hours time format (default: `false`) The component must be called manually or works with `j-Input` component automatically. This component is a singleton. - __important__ add the component under `` element ## Usage ```javascript var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.seconds {Boolean} : shows seconds (default: false) // opt.ampm {Boolean} : shows 12 hours time format (default: false) // opt.align {left|center|right} (default: left) opt.value = new Date(); // or // opt.value = 'path.to.date' (in this case you don't need to declare "opt.callback") opt.element = YOUR_ELEMENT; opt.callback = function(date) { console.log(date); }; // opt.close {Function} optional, this function can determine the closing of TimePicker SETTER('timepicker/show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html SHOW TIMEPICKER ``` ## j-Title Source: https://forge.totaljs.es/en/components/title/ Framework: jcomponent@20 Content-SHA256: d1a284aa788b61f01364da6bc4591357f0108369ab7318dc3333bab446e29ce8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton __Configuration__: - `separator {String}` a character for separation (default: `-`) - `name {String}` a name of the website (default: `document.title`) - `empty {String}` a string, which is filled, if there is no value in the path - `plus {Boolean}` adds a default title as a plus phrase (default: `true`) __Methods__: - `component.rename(value)` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Pavol Danko. Source: the Componentator components repository, MIT license. ```html example.html Title has been changed with the value defined in the common.name. ``` ## j-ToggleBox Source: https://forge.totaljs.es/en/components/togglebox/ Framework: jcomponent@20 Content-SHA256: 5179ab7dddfb7390ae7180c922d7c8f2575e6a3c7ffde1cc5951b45598933d97 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded ToggleBox can re-order or hide items in `Array`. The component expects `Array`. __Configuration__: - `dragdrop` {Boolean} Enables/Disables drag&drop (default: true) - `text` {String} A property name for text (it needs to be `String`, default: `name`) - `hidden` {String} A property for show/hide (it needs to be `Boolean`, default: `hidden`) - `disabled` {Boolean} Can disable the control (default: `false`) - `replace` {Boolean} Can replace the position of elements (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-ToggleButton Source: https://forge.totaljs.es/en/components/togglebutton/ Framework: jcomponent@20 Content-SHA256: b7010e29f7780c6a476ef1ab11238348047f1bbfc1427fabe6392f4345b460d4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `required` {Boolean} optional, enables "required" (default: `false`) - `disabled` {Boolean} optional, disables this component - `icontrue` {String} optional, toggles FontAwesome icons if the value is `true` - `iconfalse` {String} optional, toggles FontAwesome icons if the value is `false` Icons can be in the form: `circle` or `ti ti-circle`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-ToggleMore Source: https://forge.totaljs.es/en/components/togglemore/ Framework: jcomponent@20 Content-SHA256: f6ebdec8fd8072ee9e42be0e58bf52647868133afa42dc70facb2bfe9e48d187 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Is a simple component to toggle content. - You can change CSS for your needs. __Methods__: - `component.toggle(force)` can toggle the component. The parameter `force` is optional and will force the value. eg. `component.toggle(true);` will show `ui-togglemore-after`. __Good to know__: The content of the `j-ToggleMore` is divided into 2 parts: `before` and `after`. Each part must be defined. The component adds CSS classes to each part, for example first `div` will contain `ui-togglemore-before` and the second `ui-togglemore-after`. To avoid "blink" add class `hidden` to the second `div`. --- ```html
    Content before
    ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html
    BEFORE long text
    ``` ## j-Tooltip Source: https://forge.totaljs.es/en/components/tooltip/ Framework: jcomponent@20 Content-SHA256: b642a5865b590bea75ca02e6683d626c6e4190d1e4dc0190b9b3c28109923826 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - singleton - universal usage - __NEW__ hide (`SETTER('tooltip', 'hide', [force])`) now supports the `force` parameter for instant hide. __METHODS__ ```javascript var opt = {}; // opt.offsetX {Number} : adds X offset (default: 0) // opt.offsetY {Number} : adds Y offset (default: 0) // opt.align {String} : align `bottom` (default), `top`, `left` or `right` // opt.center {Boolean} : centered position for `left` and `right` align (default: false) // opt.timeout {Number} : hide timeout (in milliseconds), default: `undefined` opt.element = YOUR_ELEMENT; opt.html = 'YOUR_HTML_CONTENT'; SETTER('tooltip', 'show', opt); ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    HOVER ME 1


    HOVER ME 2
    ``` ## j-TouchMove Source: https://forge.totaljs.es/en/components/touchmove/ Framework: jcomponent@20 Content-SHA256: bc0aa851e72afc5ec9660215cf67ba31052fa87d94916289664e7e4295577e53 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Simple `touchmove` component for easy touch navigation next/prev/up/down. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html


    TRY TO TAP


    ``` ## j-Tour Source: https://forge.totaljs.es/en/components/tour/ Framework: jcomponent@20 Content-SHA256: 3d1894fc358d7d07d376e6536140f75d995603a6e5c0e61473b1afd5074c2d3b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Supports keyboard arrows - Supports `tab` key - Supports `esc` key __IMPORTANT: Put this component on the bottom of the body element__ __Configuration__: - `escape` {Boolean} toggle possibility to hide Tour with `esc` key (default: `true`) - `skiptext` {String} a text of the `skip` button (default: `Skip`) - `nexttext` {String} a text of the `next` button (default: `Next`) - `backtext` {String} a text of the `back` button (default: `Back`) - `endtext` {String} a text of the `end` button (default: `End`) - `datasource` {String} path to data-source - `bghide` {Number} toggle possibility to hide Tour by clicking on the background (default: `false`) - `hide` {String} path to method `function(type)` (type - 0: by PATH (e.g. null) 1: end button 2: skip button 3: `esc` key 4: click on bg) ```javascript // datasource var example = [ { target: '.test1', title: 'My title 1', text: 'Message 1' }, { target: '.test2', title: 'My title 2', text: 'Message with offset', offsetY: 10 } ]; ``` __PATH is the actual tour `page`__ Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html

    My First Web Page

    Headings Are Great Fun

    This is my first paragraph in my new webpage. This is going to be great. I am so excited I can hardly contain myself. Don't you just love paragraphs? I find them very useful.

    Web Pages Are Exciting Too

    Yes, that's right - web pages can be a lot of fun. Learning how to create web pages is easy and entertaining. This is my second paragraph. I hope you like it.

    Total Avengers
    • Apples
    • Bananas
    • Pears
    • Oranges
    • Grapes
    "A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Saint Exupery

    This is a DIV container

    My First Web Page

    Headings Are Great Fun

    This is my first paragraph in my new webpage. This is going to be great. I am so excited I can hardly contain myself. Don't you just love paragraphs? I find them very useful.

    Web Pages Are Exciting Too

    Yes, that's right - web pages can be a lot of fun. Learning how to create web pages is easy and entertaining. This is my second paragraph. I hope you like it.

    Total Avengers
    • Apples
    • Bananas
    • Pears
    • Oranges
    • Grapes
    "A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Saint Exupery

    This is a DIV container

    My First Web Page

    Headings Are Great Fun

    This is my first paragraph in my new webpage. This is going to be great. I am so excited I can hardly contain myself. Don't you just love paragraphs? I find them very useful.

    Web Pages Are Exciting Too

    Yes, that's right - web pages can be a lot of fun. Learning how to create web pages is easy and entertaining. This is my second paragraph. I hope you like it.

    Total Avengers
    • Apples
    • Bananas
    • Pears
    • Oranges
    • Grapes
    "A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Saint Exupery

    This is a DIV container

    My First Web Page

    Headings Are Great Fun

    This is my first paragraph in my new webpage. This is going to be great. I am so excited I can hardly contain myself. Don't you just love paragraphs? I find them very useful.

    Web Pages Are Exciting Too

    Yes, that's right - web pages can be a lot of fun. Learning how to create web pages is easy and entertaining. This is my second paragraph. I hope you like it.

    Total Avengers
    • Apples
    • Bananas
    • Pears
    • Oranges
    • Grapes
    "A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Saint Exupery

    This is a DIV container
    ``` ## j-Tree Source: https://forge.totaljs.es/en/components/tree/ Framework: jcomponent@20 Content-SHA256: 6de32fb568f7cd85c102f575c5c5cd2f47b1dc0116a3d93017bcd8ddf921c5e8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `first {Boolean}` selects the first tree item, default: `true` (optional) - `exec {String}` __required__: link to a function, this function is executed when the node is selected in the tree - `autoreset {Boolean}` resets state when datas-source is changed (optional, default: `false`) - `selected {String}` selected class (optional, default: `selected`) - `checked {String}` optional, a path to `function(arr, component)` or path to `property` - `checkednested {Boolean}` optional, checks all nested items (default: `true`) - `upload {String}` optional, a path to `function(item, files)` (enables drag & drop files) - `dragdrop {String}` optional, a path to `function(item, target_item, itemel, targetel)` (enables drag & drop items) - `options {String}` optional, a path to `function(item, el)` enables a small button for an inline context menu for each item - `rename {String}` optional, a path to `function(item, newname, fn_accept(true))` - `unselectexpand {Boolean}` optional, can `unselect` selected item when the user clicks on the expandable item (default: `false`) - `reselect {Boolean}` optional, evaluates `exec` again if the tree is refreshed (default: `false`) - `selectexpand {Boolean}` optional, enables adding `selected` class to expandable items (default: `false`) - `iconoptions {String}` icon to options (default: `ti ti-ellipsis-h`) - `expanded {Boolean}` expands all children (default: `false`) - __NEW__: `contextmenu {String}` optional, a path to `function(item, el)` enables mouse contextmenu - __NEW__: `key {String}` a value can be used as `index` in below methods (default: `path`) __Data structure__: - Object Array - Object has to contain `name:String` and `children:[another similar object]` or `children:null` (with no children) - Object item can contain `..., icon: 'home' }`, it can change a file icon - Object item can contain `..., classname: 'css_custom_class' }`, it adds a CSS class onto the "label" element - Object item can contain `..., html: 'RAW_HTML'` {String} renders HTML tags instead of `name` field __Methods__: - `component.expand([index])` - expands `index` or `all` (with no defined `index`) nodes - `component.collapse([index])` - collapses `index` or `all` (with no defined `index`) nodes - `component.clear()` - clears a cache for refreshing the source - `component.select(index)` - selects node - `component.unselect()` - unselects node - `component.rename(index)` - shows `input` for name renaming (it works with `config.rename`) __Good to know__: Setter automatically extends each object by adding `.$pointer` property with a tree index. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Open Web Developer Console

    ``` ## j-TreeView Source: https://forge.totaljs.es/en/components/treeview/ Framework: jcomponent@20 Content-SHA256: d023c6d37125937af82ac37eeb8fc4ef4720f34cdd33a4a937d07d4a1e978cbd Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component is only a beta preview. It's still under construction. __Configuration__: - `parent {String}` a container with fixed height, can be `window`. Default value: `parent` element. - `visibleY {Boolean}` still shows `Y` scrollbar (default: `true`) - `movable {Boolean}` enables the moving of nodes (default: `true`) - `cachexpand {Boolean}` remembers the previous state (default: `true`) - `arrows {Boolean}` enables arrows for folders (default: `true`) - `expanded {Boolean}` expands all nodes (default: `false`) - `autosort {Boolean}` sorts nodes according to `item.sort` (if exists) or `item.name` (if exists), default: `true` - `margin {Number}` top/bottom margin together (default: `0`) - `marginxs {Number}` top/bottom margin together for `xs` screen width - `marginsm` top/bottom margin together for `sm` screen width - `marginmd` top/bottom margin together for `md` screen width - `marginlg` top/bottom margin together for `lg` screen width - `disabled {Boolean}` disables the entire component - `parentselectable {Boolean}` parent will be selectable (default: `true`) __Data structure__: - Object Array - Object has to contain `id:String` which is the main ID of each item - Object has to contain `name:String` and `children:[another similar object]` or `children:null` (with no children) - Object has to contain `html:String` is rendered as content (if it doesn't exist then `name` is rendered) - Object item can contain `..., classname: 'css_custom_class' }`, it adds a CSS class onto the "label" element - Object item supports property `actions: { expand: true, drop: true, move: true }` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Typed Source: https://forge.totaljs.es/en/components/typed/ Framework: jcomponent@20 Content-SHA256: 7afa86321c566d14f0d9e3fa8254aaacfa6ed3a86b67308319f22ecb8ccba507 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - Based on [typed.js](https://github.com/mattboldt/typed.js/) by [Matt Boldt](https://github.com/mattboldt) - Value must be __array__ __Configuration__: Config is the same as [typed.js](https://github.com/mattboldt/typed.js#customization). The only difference is that all keys are lowercase. This is to maintain consistency with other components. The only added configuration is `id` - __NEW__: `selector {String}` can contain a nested element for rendering text - __NEW__: `text {String}` in the form `Text 1|Text 2|Text 3|Text N` otherwise text is loaded according to the `path` - `typespeed {Number}` in milliseconds (default: `0`) - `startdelay {Number}` in milliseconds (default: `0`) - `backspeed {Number}` in milliseconds (default: `0`) - `smartbackspace {Boolean}` this would only backspace the words after "This is a" (default: `true`) - `shuffle {Boolean}` shuffle the strings (default: `true`) - `backdelay {String}` time before backspacing (default: `700`) - `fadeout {Boolean}` fade out instead of backspace (default: `false`) - `fadeoutclass {String}` css class for fade animation (default: `typed-fade-out`) - `fadeoutdelay {Number}` fade out delay in milliseconds (default: `500`) - `loop {Boolean}` loop strings (default: `false`) - `loopcount {String/Number}` amount of loops (default: `Infinity`) - `showcursor {Boolean}` show cursor (default: `true`) - `cursorchar {String}` cursor character (default: `|`) - `autoinsertcss {Boolean}` insert CSS for cursor and fadeOut into HTML `` (default: `true`) - `contenttype {String}` contentType `html` or `null` for plaintext (default: `html`) __Global events__: Again, same as [typed.js](https://github.com/mattboldt/typed.js#customization). Added `component` parameter - `ON('typed.onComplete', function(typed, component) {})` - `ON('typed.preStringTyped', function(pos, typed, component) {})` - `ON('typed.onStringTyped', function(pos, typed, component) {})` - `ON('typed.onLastStringBackspaced', function(typed, component) {})` - `ON('typed.onTypingPaused', function(pos, typed, component) {})` - `ON('typed.onTypingResumed', function(pos, typed, component) {})` - `ON('typed.onReset', function(typed, component) {})` - `ON('typed.onStop', function(pos, typed, component) {})` - `ON('typed.onStart', function(pos, typed, component) {})` - `ON('typed.onDestroy', function(typed, component) {})` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Denis Granec. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-UIBuilder Source: https://forge.totaljs.es/en/components/uibuilder/ Framework: jcomponent@20 Content-SHA256: 0241ff9d567a5f070753d8a0613d99e4ed489017dbbc352808eb6e37ed87f269 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component renders the application designed via UI Builder. You can load the app via the `path` specified in the component or via the `config.url` option. The path can contain a URL address to the `JSON` app schema or the app object (parsed JSON). __Configuration__: - `app {String}` a link to the method/variable where will be stored `app` instance - `url {String}` a link to the app schema (must be in the `json` format) - `css {Boolean}` applies app style to the current element (default: `true`) - `id {String}` overwrites app ID __Methods__: - `component.load(data)` the method loads `app` into the current element __Properties__: - `component.app` contains an `app` instance ## How to handle data? ```html ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Unsaved Source: https://forge.totaljs.es/en/components/unsaved/ Framework: jcomponent@20 Content-SHA256: c6c487e3540c6881efb177ac6b9492de5d9b7d3a0e88696b99a4dbdcd253678a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - `path` optional, can contain a link to the `Boolean` value, `true` will display a confirmation message __Configuration__: - `check {String}` a link to the __check__ `function() {` that must return `Boolean` -> `true` will display a confirmation message (it's synchronous) - `message {String}` a message for the user (it may not work with most browsers because they have their own messages) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Upload Source: https://forge.totaljs.es/en/components/upload/ Framework: jcomponent@20 Content-SHA256: bbfe28b116aa688c8ab8af1fb2fccc876d4e6ab6737b889a4d94eea2e9794839 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can perform __uploading of files__. - easy and universal usage - singleton __Methods__: ```javascript var opt = {}; // Restricts files according to the content-type // opt.accept = 'image/*'; // Enables multiple files // opt.multiple = true; // IMPORTANT: // URL address for uploading opt.url = '/api/upload/'; // A callback opt.callback = function(response) { }; opt.error = function(err) { // Optional // Error handling }; // Optional, additional request data opt.data = {}; opt.data.fieldName1 = 'value'; opt.data.fieldName2 = 'value'; // Shows file browser SETTER('upload/show', opt); ``` Files are uploaded with these names/keys in the form `file1`, `file2`, `file..N`. Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Upload file ``` ## j-Validate Source: https://forge.totaljs.es/en/components/validate/ Framework: jcomponent@20 Content-SHA256: a6625dcae76fb0568325a6b98c518ee5e64b39cfb998515a91a993bcd4a3e397 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component contains the same source-code as the `j-Validation` component. __Configuration__: - `if {String}` can contain JS condition for evaluation - `value {Object}` contains entire model - `path {String}` contains changed path - __must return boolean__ - `selector {String}` jQuery selector for disabling (default: `button[name="submit"]`) - `delay {Number}` a timeout for validation (default: `100`) - `flags {String}` flags for better validation, can contain `visible,hidden,enabled,disabled` components - `enabled` validate all components which are enabled `input`, `textarea` or `select` elements - `disabled` validate all components which are disabled `input`, `textarea` or `select` elements - `hidden` validate all components which are hidden - `visible` validate all components which are visible - `track {String}` can contain paths divided by the comma, and manual changing of each path (via `SET()`, `UPD()`, `INC()`, etc. methods) will evaluate the validation - `validonly {Boolean}` skips `dirty` state (default: `false`) - __NEW__ `changes {Boolean}` enables comparing changes only between the input model and the form (default: `false`) - __NEW__ `strictchanges {Boolean}` enables strict comparing changes (otherwise `null`, `false`, `empty strings` and `0` values will be removed), default: `false` - __NEW__ `exec {String}` optional, a link to the `function(data)` that is executed when the model is validated and changed - __NEW__ `output {String}` optional, a link to the `function(valid)` or path __Good to know__: - component adds `ui-validate-ok` class to the element if the model is valid - component adds `ui-validate-no` class to the element if the model is invalid - component adds `ui-validate-modified` class to the element if the model is changed Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Name

    ``` ## j-Validation Source: https://forge.totaljs.es/en/components/validation/ Framework: jcomponent@20 Content-SHA256: af1b737e93200d8952c8cfee90de3dc857e177210426e0fbd5bdaf2a37298311 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component contains the same source-code as the `j-Validate` component. __Configuration__: - `if {String}` can contain JS condition for evaluation - `value {Object}` contains entire model - `path {String}` contains changed path - __must return boolean__ - `selector {String}` jQuery selector for disabling (default: `button[name="submit"]`) - `delay {Number}` a timeout for validation (default: `100`) - `flags {String}` flags for better validation, can contain `visible,hidden,enabled,disabled` components - `enabled` validate all components which are enabled `input`, `textarea` or `select` elements - `disabled` validate all components which are disabled `input`, `textarea` or `select` elements - `hidden` validate all components which are hidden - `visible` validate all components which are visible - `track {String}` can contain paths divided by the comma, and manual changing of each path (via `SET()`, `UPD()`, `INC()`, etc. methods) will evaluate the validation - `validonly {Boolean}` skips `dirty` state (default: `false`) - __NEW__ `changes {Boolean}` enables comparing changes only between the input model and the form (default: `false`) - __NEW__ `strictchanges {Boolean}` enables strict comparing changes (otherwise `null`, `false`, `empty strings` and `0` values will be removed), default: `false` - __NEW__ `exec {String}` optional, a link to the `function(data)` that is executed when the model is validated and changed - __NEW__ `output {String}` optional, a link to the `function(valid)` or path __Good to know__: - component adds `ui-validate-ok` class to the element if the model is valid - component adds `ui-validate-no` class to the element if the model is invalid - component adds `ui-validate-modified` class to the element if the model is changed Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Name

    ``` ## j-View Source: https://forge.totaljs.es/en/components/view/ Framework: jcomponent@20 Content-SHA256: a43f0a7e2d58519b626b00b2e07712a6efcbb2f72f9e6600691a4270107311ef Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component can be helpful for reusable views in intranet apps. The component wraps the view into the isolated scope, and the value according to the component path will be used as a model for the view. __Configuration__: - `url {String}` URL address to the view (`.html` file) - `cache {String}` download cache (default: `session`) ### Usage __app.html__: ```html - you can use an unlimited count of the same views (identifier is URL address) - each view will have an independent scope/plugin Example: ``` __view.html__: ```html

    ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-ViewBox Source: https://forge.totaljs.es/en/components/viewbox/ Framework: jcomponent@20 Content-SHA256: 02406169db5c40745ff2d8e3a087b131dfad0bab424271cb125a2bf2aedf7084 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - keeps a fixed percentage height - great usage for intranet applications - supports `releasing` __Configuration__: - `height {Number}` a percentage of height - `disabled {Boolean}` optional, can disable content with the layer - `parent {String}` optional, a container with fixed height, can be `window`. Default value: `parent` element. - `minheight {Number}` a minimal height in pixels (default: `0` - disabled) - `scroll {Boolean}` enables vertical scrolling (default: `false` - disabled) - `scrollbar {Boolean/String}` shows scrollbar (default: `true` or __new__: `native`) - `delay {Number}` `msec.` resizes the box again if the value is changed according to the path (default: `100`) - `visibleY {Boolean}` still shows the `Y` scrollbar (default: `false`) - `visibleX {Boolean}` still shows the `X` scrollbar (default: `false`) - `scrollto {String}` scrolls to top/bottom automatically if the `path` is changed (default: `EMPTY`, can be `top` or `bottom`) - `margin {Number}` optional, a top/bottom margin together (supports `auto` which is counted from `offset.top`, default: `0`) - `marginxs {Number}` optional, a top/bottom margin together for `xs` screen width - `marginsm` optional, a top/bottom margin together for `sm` screen width - `marginmd` optional, a top/bottom margin together for `md` screen width - `marginlg` optional, a top/bottom margin together for `lg` screen width - `invisible {Boolean}` if `true` then viewbox sets `invisible` class when is rendering (default: `true`) - `scrollbarshadow {Boolean}` if `true` then the custom scrollbars will contain vertical shadow (default: `false`) - `initdelay {Number}` removes the `inivisible` class after specified time (default: `250` ms) - `centered {Boolean}` enables vertical and horitonzal centering for the content (default: `false`) - `resizedelay {Number}` delay for resizing (default: `200`) - __NEW__: `togglescrolled {String}` a DOM selector for the parent elements (it appends `ui-viewbox-scrolled` class when the viewbox is scrolled) __Methods__: - `component.scrolltop(val)` scrolls Y - `component.scrollbottom(val)` scrolls Y from bottom side - `component.resize()` resizes the container (it reacts on `resize` events automatically) - `component.resizescrollbar()` resizes custom scrollbar (targeted for special cases) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html Always 30% Always 70% ``` ## j-VirtualWire Source: https://forge.totaljs.es/en/components/virtualwire/ Framework: jcomponent@20 Content-SHA256: d8a647d2e6ea7c78c2a9130fa48198dbf0f39c87883295cd0196bf74805379ce Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This is a very special UI component that can move elements from `element` to another `element` according to the selector and the value of the path. Look to the example for understanding. - `selector {String}` a selector for wires (default: `.virtualwire`) - `delay {Number}` a delay in milliseconds for movement of elements (default: `10`) - `repeat {Number}` a repeat delay for obtaining of element (default: `50` ms) - `max {Number}` a maximum count for repeating (default: `100`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    Virtual Wire Container:

    USERS
    PRODUCTS
    ``` ## j-Watch Source: https://forge.totaljs.es/en/components/watch/ Framework: jcomponent@20 Content-SHA256: 59cab19e83867e2d3e6290bde3f90398d0e0692c87bb806752e747d42f40598c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component can evaluate the method in the form `function(value, element, type, path)` when the value (according to the path) is changed. The component can simplify watching changes in the model. __Configuration__: - `exec` a link to the method `function(value, element, flags, path)` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Watcher Source: https://forge.totaljs.es/en/components/watcher/ Framework: jcomponent@20 Content-SHA256: 31f1cf7cf34096c42e1ca2f7ec8685d43f06c1c1f06954e602153e5e04fead9e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded This component executes the code defined in the `` tag. ```html ``` __Configuration__: - `delay {Number}` a delay for evaluating code (default: `0`) - __NEW__: `datasource {String}` a link to the datasource (it will be stored in `datasource` property) __IMPORTANT__: You need to use `
    ``` ## j-Wiki Source: https://forge.totaljs.es/en/components/wiki/ Framework: jcomponent@20 Content-SHA256: aae2bf92e22df5d305909ba10bbbe0cf9bf077eafa66b71a2fe7f200438abc5e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded Great component for inline Wiki/Documentation. - supports __dark mode__ __Configuration__: - `title {String}` a title (default: `Wiki`) - `datasource {String}`` a path to data-source (learn from example) - `width {Number}` a default width (default: `400`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Window Source: https://forge.totaljs.es/en/components/window/ Framework: jcomponent@20 Content-SHA256: 730f710e05f3006432f07ccd84134fa1d4caa0baaf5d4d96b1e4cd1ded038d8b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - The component moves the content of this component under the `` tag (because of positioning) __Configuration__: - `title {String}` window title - `if {String}` condition for a showing of the window, it's compared with the value within of `path` - `icon {String}` Total.js icons - `reload {String}` link to a global `function(window_component)` and it's executed if the form is showing - `enter {Boolean}` (optional) captures the `enter` key automatically and performs submit (default: `false`) - `autofocus {Boolean/String}` (optional) can focus an input. `String` === `jQuery selector` for the input - `default {String}` (optional) a short alias for `DEFAULT(default, true)` - `closebutton {Boolean}` (optional) can hide `x` button (default: `false`) - `zindex {Number}` (optional) can affect z-index (default: `12`) - `scrollbar {Boolean}` enables a custom scrollbar (default: `true`) - `scrollbarshadow {Boolean}` optional, enables a shadow in scrollbar (default: `false`) - __NEW__ `closeesc {Boolean}` closes the form when the user presses the `ESC` key - __NEW__ `independent {Boolean}` closing doesn't depend on the condition according to the path __Good to know__: A new version of this component supports dynamic evaluation of the content of ` ``` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-Windows Source: https://forge.totaljs.es/en/components/windows/ Framework: jcomponent@20 Content-SHA256: 770d41a849c326b62e7ab9f340d501d34fa073200abe0cc34d5755cc51e710c8 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded __Configuration__: - `menuicon {String}` a menu icon in the window title bar (default `ti ti-navicon`) - `reoffsetresize {Boolean}` all windows will be re-offset according to the `main` window dimension (default: `true`) - `zindex {Number}` a start z-index positioning (default: `5`) - __NEW__: `maximizemargin {String}` a margin for the maximized state in the form `left_px top_px width_px height_px` (default: `0 0 0 0`) The `windows` component expects an `Array` of objects. ```javascript // Component declaration var win = { // Component ID id: 'WINDOW_ID', // NEW: cachekey for similar windows // Optional, default: window ID cachekey: 'WINDOW_ID', // Positioning // You can define a specific display size and if the display size is not specified then the window tries to find a size for a larger display html: 'THE CONTENT OF WINDOW', // or can be raw HTMLElement offset: { x: 200, y: 100, width: 600, height: 400, minwidth: 200, minheight: 200, maxwidth: 1000, maxheight: 1000, maximized: false }, // minwidth, maxwidth, maxheight, minheight and maximized are optional // Prevents hidden state for "hide: true" option // hidden: false, // Default settings actions: { move: true, close: true, hide: true, resize: true, menu: false, minimize: true, maximize: true, autosave: false }, // GOOD TO KNOW: // "undefined" close or "close:false" and "hide:true" don't destroy the instance of window (it will be hidden only) // A window title title: 'Title for the window', // Handlers (optional): destroy: function() { // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is destroyed }, make: function(el) { // @el {jQuery} a content of the window // @this {Instance} // this.meta {Object} a reference to the window object // this.element {jQuery} a content element of the window // this.container {jQuery} a main content element of the window // this.main {Object} a reference to the "Windows" component // this.width {Number} a width of the window // this.height {Number} a height of the content of the window // this.x {Number} offset X // this.y {Number} offset Y // Methods: // this.setsize(width, height); // this.setcommand(cmd); Allowed commands: "close", "maximize", "resetmaximize", "togglemaximize", "minimize", "resetminimize", "toggleminimize", "resize", "move", "focus" // this.setoffset(x, y); // is executed when the window is making }, menu: function(el) { // @el {jQuery} a content element of the window // is executed when the user clicks on the menu icon in the window title bar }, data: function(type, data, el) { // @type {String} // @data {Object} // @el {jQuery} a content element of the window // @this {Instance} // is executed when data are sent via SETTER('windows', 'send', 'TYPE', 'DATA') }, resize: function(width, height, el, x, y) { // @width {Number} // @height {Number} // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is resized }, move: function(x, y, el) { // @x {Number} // @y {Number} // @el {jQuery} a content of the window // @this {Instance} // is executed when the window is moved }, service: function(counter, el) { // @counter {Number} count of calls // @el {jQuery} a content of the window // @this {Instance} // the component will execute this handler each 5 seconds }, // Optional, this delegate rewrites built-in functionality minimize: function(type) { // @type {String} optional, "reset", "toggle" or undefined (it means minimize right now) }, // Optional, this delegate rewrites built-in functionality maximize: function(type) { // @type {String} optional, "reset", "toggle" or undefined (it means maximize right now) }, focus: function() { // window is focused } }; PUSH('windows', win); ``` __Methods__: - `component.finditem(window_id)` finds the specific window according to `ID` - `component.show(window_id)` shows a window - `component.hide(window_id)` hides a window - `component.toggle(window_id)` toggles a window - `component.focus(window_id)` focuses a window - `component.hide(window_id)` closes a window - __NEW__: `component.title(window_id, title)` renames title Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-WizardExpert Source: https://forge.totaljs.es/en/components/wizardexpert/ Framework: jcomponent@20 Content-SHA256: 32f05cee4e8480f9ef6843570b61f8f37273b8988cfe56129d33dc872a8ed121 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded A simple solution for making of advanced wizards. Wizard downloads steps (as HTML parts) according to the schema. Steps are wrapped into custom scopes, so they are under validation. __Configuration__ - `output {String}` a path for output, the object will contain entire output (steps will be properties) - `exec {String}` a path to `method(output_object)`, it's executed if wizard doesn't contain any next step - `next {String}` a path, here will be assigned next step with `enabled {Boolean}` property - `back {String}` a path, here will be assigned previous step with `enabled {Boolean}` property - `validate {Boolean}` enables validation (default: `true`) __Schema__: ```js { 'step1': { url: 'step1.html', next: 'step2', validate: false }, 'step2': { url: 'step2.html', next: 'step3' }, 'step3': { url: 'step3.html' } } ``` - component extends each step by adding new properties `enabled {Boolean}`, `id {String}`, `prev {String}` Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Wysiwyg Source: https://forge.totaljs.es/en/components/wysiwyg/ Framework: jcomponent@20 Content-SHA256: ec88b562d940b426d5d56a479bf779a25130f9047d08fcaff580d3a5861462eb Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded - supports __dark mode__ __Configuration__: - `placeholder {String}` optional - `code {Boolean}` enables/disables word highlighting (default: `true`) - `links {Boolean}` enables/disables links (default: `true`) - `ul {Boolean}` enables/disables unordered list (default: `true`) - `required {Boolean}` optional, enables "required" mode (default: `false`) - `allowrawpaste {Boolean}` optional, enables raw pasting rich content (default: `false`) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html
    ``` ## j-Xterm Source: https://forge.totaljs.es/en/components/xterm/ Framework: jcomponent@20 Content-SHA256: f43d26911d2d7591ffed65de842c3eac83811581e34b71fc59e53c6d77baff11 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: not-recorded The component renders a terminal output/input directly in the web browser. __IMPORTANT__: the example doesn't work as you expect, it needs a real terminal output. __Configuration__: - `cols {Number}` count of cols (default: `80`) - `rows {Number}` count of rows (default: `24`) - `send {String}` a link to the `function(data)` for the communication with the server __Methods__: - `instance.write(data)` writes data into the terminal component __Used dependencies__: - [Xterm.js](https://xtermjs.org/) - [Full example](https://github.com/totaljs/examples/tree/master/remote-terminal) Use it with ``. When the component is not loaded yet, jComponent downloads it on first use from the address in `DEF.fallback` (the Componentator CDN by default). Author: Peter Širka. Source: the Componentator components repository, MIT license. ```html example.html ``` ## j-PermissionsOP Source: https://forge.totaljs.es/en/components/permissionsop/ Framework: jcomponent@20 Content-SHA256: 5cebc2e3f5ed7ea0434bf6c6bd5019dc5b3c8630b1a2620c34d60c7a6de0af79 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component edits OpenPlatform user, role and group permissions. Bind the selected permissions to a model path and configure `find` and `read` endpoints. The model contains permission strings: ``` ['C@admin', 'U@admin', 'R@admin', 'D@admin', 'R123456', 'R#employees'] ``` - first letter means allowed type, defined in `types` - `@admin` means a role `admin` - `#employees` means a group `employees` - `123456` means a specific `userid` __Configuration__: - `placeholder` {String} a placeholder for `j-Directory` component (default: `Search`) - `types` {String} types of permission (array delimited by char, default: `CRUD`) - `disabled` {Boolean} optional, disables this component - `default` {String} default value of `type` (default: `R`) - `dirkey` {String} optional, a key for text in `j-Directory` (default: `name`) - `labelrole` {String} optional a label for roles (default: `Role`) - `labelgroup` {String} optional a label for groups (default: `Group`) - `limit` {Number} a count of allowed permissions (default: `0` = unlimited) - `pk` {String} a primary key which value will be binded into the model (default: `id`) - __IMPORTANT__ `find` {String} URL address for finding roles, groups and users, the component sends `url?q=SEARCH_QUERY` (it sends empty value) - __IMPORTANT__ `read` {String} URL address for reading roles, groups and users, the component sends `url?id=@role,#group,userid,...` ```javascript // The component expects data: ['C@admin', 'U@admin', 'R@admin', 'D@admin', 'R123456', 'R#employees']; // The component tries to find data: // The component tries to read data and it pairs them with the model automatically: [{ id: '123456', name: 'Peter Širka' }, { id: '@admin', name: 'Administrators' }, { id: '#employees', name: 'Employees' }]; ``` ## Usage ```html ``` Declare `j-Directory` for the selection menu. Both endpoints return an array of objects with `id` and `name` strings. The `find` endpoint receives the search text in `q`. The `read` endpoint receives comma-separated identifiers in `id` and resolves the permissions already in the model. Use `pk` to choose the identifier field; its default is `id`. Prefix role identifiers with `@` and group identifiers with `#`. Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-PermissionsOP). Copyright Peter Širka and contributors. [MIT license](/knowledge-licenses.json). ## j-UIStudio Source: https://forge.totaljs.es/en/components/uistudio/ Framework: jcomponent@20 Content-SHA256: a5e5ce2d319ac83c9ff4cd666dee3ad9c188b842feff9e5995385fbeaa3e3f78 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component loads a Flow UI Studio application through its configured endpoint. Set url to that endpoint and handle metadata or application updates with onmeta and onapp. This component renders the app according to the Total.js Flow UI Studio schema. __Configuration__: - `url {String}` the navigation endpoint that accepts POST requests and returns JSON step metadata - `css {Boolean}` applies app style to the current element (default: `true`) - `ssid {String}` optional, adds a session identifier to the URL address for the Flow - `title {Boolean}` optional, rewrites `document.title` by the app name - `plus {String}` optional, it works only with `title:true` and it adds `title - config.plus` - `onmeta {String}` optional, a link to the `function(meta)` captures a meta data - `onapp {String}` optional, a link to the `function(app)` captures a new UI design - `origin {String}` optional - `onrequest {String}` optional, a link to the `function(payload)` can modify request data - `flowoutput {Boolean}` optional, enables outputs only from FlowOutput component (default: `true`) __Properties__: - `component.app` contains an `app` instance __Good to know__: The component extends the `app` instance by adding `breadcrumb {Array}` property. ## Usage ```html ``` ## Navigation endpoint The component sends a POST request to the configured endpoint. The request carries the current navigation state, including `origin`, `query`, an optional `ssid`, and the current `id`, `output` and `data` when an application emits an output. Return an `id` for the step and a `url` for its exported UI Builder design: ```json { "id": "home", "url": "/ui/home.json", "data": {} } ``` Serve the design exported from UI Builder at `/ui/home.json`. The component downloads it with GET and creates the application through `UIBuilder.build()`. If the response includes an `input`, the component calls the application input with `input` and `data`. The `onmeta` callback receives the step response, and `onapp` receives the created application instance. `loading:false` disables the loading indicator. To display it, declare a `j-Loading` component and enable `loading`. Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-UIStudio). Copyright Peter Širka and contributors. [MIT license](/knowledge-licenses.json). ## j-FlowEditor Source: https://forge.totaljs.es/en/components/floweditor/ Framework: jcomponent@20 Content-SHA256: 1c4735d504ec12b9c0f6b8946c1d8b8323ae948f951c6925f9fd24491963a7cc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component opens the Flow designer in an iframe. Bind its path to the WebSocket URL of the FlowStream to edit. Set the path to null to close the designer. The component opens Flow editor in the iframe. - Flow editor/designer repository (if you don't want to use cloud version) __Configuration__: - `url {String}` a link to the Flow editor (default: `https://flow.totaljs.com`) - `top {Number}` default: `1` - `left {Number}` default: `1` - `right {Number}` default: `0` - `bottom {Number}` default: `0` - `zindex {Number}` default: `30` - `language {String}` default: `eu` (english) - `closebutton {Boolean}` default: `true` __Model__: It must be a WebSocket URI to access the FlowStream. ## Usage ```html ``` Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-FlowEditor). Copyright Peter Širka and contributors. [MIT license](/knowledge-licenses.json). ## j-UIEditor Source: https://forge.totaljs.es/en/components/uieditor/ Framework: jcomponent@20 Content-SHA256: c5382071ed0d83170e1897275e901dcc5989c57e5da4ddf341fb1deb6110470d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component opens UI Builder in an iframe. Bind its path to an object containing the design and callbacks for saving, publishing or previewing it. Set the path to null to close the editor. The component opens UI Builder in the iframe. - UI Builder editor repository (if you don't want to use cloud version) __Configuration__: - `url {String}` a link to the UI Builder (default: `https://uibuilder.totaljs.com`) - `top {Number}` default: `0` - `left {Number}` default: `0` - `right {Number}` default: `0` - `bottom {Number}` default: `0` - `zindex {Number}` default: `30` - `language {String}` default: `eu` (english) - `onsave {String}` optional, a link to `function(data)` - `onpublish {String}` optional, a link to `function(data)` - `onrender {String}` optional, a link to `function(data)` - `closebutton {Boolean}` default: `true` __Model__: ```js { data: { .. UI BUILDER DESIGN .. }, upload: 'https://.../upload/', // optional groups: [{ id: 'group1', name: 'Group 1' }], // optional apps: [{ id: 'app1', name: 'App 1' }], // optional views: [{ id: 'view1', name: 'View 1' }], // optional close: function() {}, // optional, it's executed when the editor is closed save: function(data) {}, // optional, it's executed when the user saves design publish: function(data) {}, // optional, it's executed when the user compiles design render: function(data) {}, // optional, it's executed when the user wants to preview a design } ``` ## Usage ```html ``` Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-UIEditor). Copyright Peter Širka and contributors. [MIT license](/knowledge-licenses.json). ## j-ServiceWorker Source: https://forge.totaljs.es/en/components/serviceworker/ Framework: jcomponent@20 Content-SHA256: db7ce63bfad9ca3799e0164bf5dfdebe02eeade49ceedf536d1bb2e934d2ad6b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component registers /sw-jcomponent.js and sends it the asset list, cache version and offline fallback from its datasource. Serve the application over HTTPS or localhost, and place the worker at the root URL so it can handle the application pages. - This component is a little bit special. First of all, you need put the code below into file e.g. `sw-jcomponent.js` and place it to the `public` (e.g. `myproject/public/sw-jcomponent.js`) ```js var prefix='jc';function hash(s,unsigned){var hash=0,i,char;if(!s.length)return hash;var l=s.length;for(i=0;i>>0:hash}self.addEventListener('install',()=>{self.skipWaiting()});self.addEventListener('message',function(e){if(e.data.action==='jc-sw'){var data=e.data.data;data.name=prefix+'-'+data.version+'-'+hash(data.assets.toString(),true);addcache(e.data.data)}});self.addEventListener('fetch',function(e){e.respondWith(fetch(e.request).catch(function(){return caches.match(e.request).then(function(response){if(response)return response;if(e.request.mode==='navigate'||(e.request.method==='GET'&&e.request.headers.get('accept').includes('text/html')))return caches.match('jc-offline-fallback')})}))});function addcache(data){caches.open(data.name).then(function(cache){if(data.assets&&data.assets.length)cache.addAll(data.assets);if(data.fallback){fetch(data.fallback,{mode:'no-cors'}).then(function(response){return cache.put('jc-offline-fallback',response)})}}).then(function(){caches.keys().then(function(keys){return Promise.all(keys.map(function(key){if(data.name!==key)return caches.delete(key)}))})})} ``` - The component will communicate with this _service worker_ code. __Configuration__: - `expire {String}` expiration data from users storage (default: `1 day`) __we don't recommend changing this__ - `debug {Boolean}` enables `debug` mode. It'll refresh assets every reload (so you don't need to change the version) (default: `false`) - `datasource {String}` path to data-source (data-source is a object) __Datasource structure__: ```js { version: '1.00', fallback: '/', assets: [ '/js/default.js' ] } ``` __Good to know__: - __PATH__ can be used as dynamic version. It'll refresh assets instantly (without page reloading) e.g. `SET('version', '1.35')` - After add/remove something from assets, you doesn't need to increase version - __fallback__ performs offline version of html. e.g. `fallback: '/offline.html'` - Assets can be everything: fonts, partial pages, css files, javascript files - __It's work only in Single Page Applications like [this](https://github.com/totaljs/spa) or [this](https://github.com/totaljs/emptyproject-pwa)__ __Usage__: ```html ``` Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-ServiceWorker). Copyright Denis Granec. [MIT license](/knowledge-licenses.json). ## j-Paper Source: https://forge.totaljs.es/en/components/paper/ Framework: jcomponent@20 Content-SHA256: 27be8a8200fd381bf1d9ecd1c1215b31459d0476bb1e402451936dd3e34484f7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component edits a document as an array of widget objects. Bind a model path to that array, configure the widget repository, and use autosave to write edits back to the model. - output is a simple `Object Array` structure: - `[{ id: String, widget: String, newbie: Boolean, changed: Boolean, config: Object }]` - widgets repository: https://github.com/totaljs/parts/tree/main/paper __Configuration__: - `readonly {Number}` enables/disables readonly mode `0=disabled`, `1=partially enabled`, `2=fully enabled` - `parent {String}` optional, a parent element for min-height (default: `null`) - `margin {Number}` additional margin for min-height (default: `0`) - `autosave {Boolean}` changes are serialized according to the path automatically - `widgets {String}` a link to the widgets (default: Componentator CDN) - it can contain multiple addresses divided by the comma `mywidget1.html,/mywidget2.html,etc..` - or you can keep [CDN structure](https://github.com/totaljs/parts/blob/main/cdn/paper/db.json) - `icon {String}` a link to the `function(opt, callback)` - `opt.element {jQuery element}` - __IMPORTANT__: call the `callback` argument if the icon has been changed in the element - `link {String}` a link to the `function(opt)` - `opt.element {jQuery element}` - `opt.href {String}` - `opt.target {String}` - `opt.widget {Object}` a widget instance - `command {String}` a link to the `function(cmd)` - `cmd.widget {Object}` a temporary widget instance - `cmd.widgets {Array}` a list of registered widgets - `cmd.remove() {Function}` removes widget - `cmd.append(name)` replaces the current temporary widget with a new widget (`name` name of widget) - `format {String}` a link to the `function(toolbar)` - `toolbar` can be `null` - `toolbar.element {jQuery element}` a current element - `toolbar.node {HTML element}` a current element - `toolbar.widget {Object}` a widget instance - `toolbar.style {Object}` contains a current style e.g. `bold: 1, link: 1` - `upload {String}` a link to the `function(opt, callback)` - `opt.accept {String}` optional - `opt.files {FileList}` optional - `opt.multiple {Boolean}` optional, default: `false` - `opt.width {Number}` optional - `opt.height {Number}` optional - __IMPORTANT__: `callback` argument must be executed after upload with the `files {Array}` argument - `change {String}` a link to the `function(change)` - `change.id {String}` identifier - `change.block {String}` a block identifier - `change.blockprev {String}` a previous block identifier - `change.widget {String}` a widget id - `change.type {String}` operation type (insert, update, remove) - `contextmenu {String}` a link to the `function(widget)` when the user pressed the right mouse button on the widget - `check {String}` a link to the `function(widget)` that decides whether to enable editing or not - `placeholder {String}` a placeholder for the default HTML widget (default: `Press / for adding rich content`) __Methods__: - `component.save(function(data, ischange) {` for saving content - `component.import(url or url_array, [callback])` for importing additional widgets - `component.notify(event, [a], [b], [c], [d])` emits event in every widget __Good to know__: The component creates a global variable called `window.papercache {Object}` used by all `j-Paper` instances. - the component compares the content when you change data, so you can change data in real-time - the component assigns (in the form) `paper-yourwidgetname` class to every widget element - reserved HTML classes `readonly`, `widget`, `selected` - readonly usage: `.readonly .paper-yourwidgetname { ... }` - `htmlelement.$widget {Object}` contains a widget instance - `widget.remove()` method will remove the widget __Shortcuts in text edit__: - `CMD + m` highlights text - `CMD + l` creates a link - `CMD + p` adds an icon - `CMD + b` bold - `CMD + i` italic - `CMD + u` underline __Good to know__: - `[data-prevent]` attribute can prevent click event in the widget ## Usage ```html ``` Serve the widget index at /paper/db.json and its widget files from your application. The save callback receives the serialized widget array. Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-Paper). Copyright Peter Širka and contributors. [MIT license](/knowledge-licenses.json). ## j-Changer Source: https://forge.totaljs.es/en/components/changer/ Framework: jcomponent@20 Content-SHA256: a181a855e3cd544142498b950633e3f782e56ab391e5ee28cec862df5fe6e782 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component participates in jComponent change tracking for a model path. Use it for values updated by application code, such as a list of uploaded pictures, so that form validation can include their changed state. ## Usage ```html ``` Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-Changer). Copyright Peter Širka and contributors. [MIT license](/knowledge-licenses.json). ## j-WebSocket Source: https://forge.totaljs.es/en/components/websocket/ Framework: jcomponent@20 Content-SHA256: 411ad10cdc020aa516fc89fc6167c8788b819b6b49323d5caab3f4f64517115c Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: components@910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e Review: usage-reviewed The component sends and receives JSON through a reconnecting WebSocket. Configure `url`, bind a model path to receive messages, and call the `send` method to transmit objects. __Configuration__: - `url {String}` URL for websocket, it can be relative or absolute - `reconnect {Number}` can contain only a number (milliseconds, default: `3000`) - `encoder {Boolean}` performs encode/decode messages via `URI` (default: `false`) - __NEW__: `statsinterval {Number}` stats interval in milliseconds (default: `1000`) - __NEW__: `stats {String}` a link to method `function({ received: Number, sent: Number })` or path to a variable (measured in bytes) __Methods__: - `component.send(obj)` - sends JSON serialized object to the server - `component.close()` - closes connection - `component.connect()` - opens connection - `component.idletime(is)` - __NEW__ can cancel/reopen connection __Events__: - `ON('message', function(data) {})` - received data - `ON('online', function(isOnline) {})` - online/offline ## Usage ```html ``` Source: [Total.js components](https://github.com/totaljs/components/tree/910ed1a86f6e72b4f031d3ad0dc7844f9fc5cb8e/j-WebSocket). Copyright Peter Širka and contributors. [MIT license](/knowledge-licenses.json). ## What OpenPlatform is: one portal for all your web applications Source: https://forge.totaljs.es/en/openplatform/what-is-openplatform/ Framework: openplatform@5 Content-SHA256: c5101fd318eb1c8b7ff79aa421c4b307913ede4eac77dc6ba7b0518c17dd4169 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded OpenPlatform is a ready-to-run **portal for your web applications**. Your people sign in once, see the applications they are allowed to use and open them from one place; the administrators manage users, groups, permissions and notifications from one screen. It is open source under the **MIT licence**, written with Total.js 5 and PostgreSQL, and the application is the repository [totaljs/openplatform](https://github.com/totaljs/openplatform) (version 5). This section describes OpenPlatform (revision `5a54a85` of the repository). ## What it gives you - **One sign-in for many applications.** An application can be one of your own Total.js apps or any web application: OpenPlatform opens it with a signed token and the application asks OpenPlatform who the user is (see [how an app connects](/en/openplatform/how-an-app-connects/)). - **Users, groups and permissions.** A user belongs to groups; a group decides which applications the user sees and which permission values each application receives (see [groups and permissions](/en/openplatform/groups-and-permissions/)). - **Notifications.** Applications send notifications to their users through a small HTTP endpoint; the portal shows them and can email a digest of the unread ones (see [notifications and the public API](/en/openplatform/notifications-and-public-api/)). - **Sessions the user controls.** Each user can see and remove their own sessions and change their password. - **A setup screen** for the administrators (`/setup/`): users, groups, applications, settings, feedback and a dashboard with the visitors. ## How the project is organized OpenPlatform is a Total.js application with three plugins and a few controllers: | Part | What it does | Source | |---|---|---| | `login` plugin | the sign-in page, `POST /api/login/` and `POST /api/reset/` | `plugins/login/` | | `portal` plugin | the portal for signed-in users (`GET /*`) | `plugins/portal/` | | `setup` plugin | the administration screen and its API under `/setup/` | `plugins/setup/` | | account API | `/api/` actions for the session, the account, the apps, the notifications and the sessions of the user | `controllers/api.js`, `schemas/account.js` | | app protocol | `GET /verify/`, `POST /notify/`, `GET /session/` for the applications | `controllers/verify.js` | | public API | `GET /users/`, uploads of images and the `SOCKET /sync/` of several instances | `controllers/api.js`, `controllers/socket.js` | The rest of the section: [installing it](/en/openplatform/install-openplatform/), [registering an application](/en/openplatform/register-an-app/), the [settings and the database](/en/openplatform/settings-and-database/). The official documentation is at [docs.totaljs.com/openplatform](https://docs.totaljs.com/openplatform/), and the native client that Total.js 5 includes for the Open Platform protocol is in the recipe [OPENCLIENT](/en/total5/openclient-protocol/). ## Install OpenPlatform with Node.js and PostgreSQL, Docker or Docker Compose Source: https://forge.totaljs.es/en/openplatform/install-openplatform/ Framework: openplatform@5 Content-SHA256: 73796b2e998f1ca4314bd68628ca8277d707cae92f47c58d14f96500b08b1b82 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded OpenPlatform needs the latest **Node.js** and a **PostgreSQL** database. There are three ways to start it, all from the README of the repository. Do **not** run `database.sql` yourself: OpenPlatform uses that script internally on the first start. ## By hand 1. Install Node.js and PostgreSQL and create an empty database for OpenPlatform. 2. Download the [source code](https://github.com/totaljs/openplatform). 3. Install the dependencies in the root of the application: ```bash npm install ``` 4. Put the connection string in the file `config` (the file has the line `database : postgresql://user:pass@localhost:5432/database` as a model, and a line `database (env) : DATABASE` that reads it from the environment variable `DATABASE`). 5. Start it (the `start` script of `package.json` runs `node index.js 8000`): ```bash node index.js ``` 6. Open `http://127.0.0.1:8000` and, **before anything else, open the settings and configure the platform** (the README marks this step as important; the settings are in [settings and database](/en/openplatform/settings-and-database/)). ## Docker Hub ```bash docker pull totalplatform/openplatform docker run --env DATABASE='postgresql://user:pass@hostname/database' -p 8000:8000 totalplatform/openplatform ``` ## Docker Compose ```bash git clone https://github.com/totaljs/openplatform.git cd openplatform docker compose up ``` ## What the first start does When the database has no OpenPlatform tables yet (it looks for the table `cl_config` in the schema `op`), the application loads `database.sql`, replacing its placeholders with values it generates: the identifier of the installation, the cookie name, the secrets and salts, the tokens, and the first user and group. It then loads the configuration and starts the authentication (`definitions/init.js`). With the environment variable `DATABASE` (Docker) it waits three seconds before this, so that the database can be up. In both cases the server is paused (`PAUSESERVER('Database')`) until the database is ready. ## The first sign-in The README gives the default account: ```text login : info@totaljs.com password : admin ``` Sign in, **change that password** (the portal has the account action for it) and configure the settings. Remember the rule of the README: every application that you add must be assigned to a group, or nobody sees it ([groups and permissions](/en/openplatform/groups-and-permissions/)). ## Register an application in OpenPlatform Source: https://forge.totaljs.es/en/openplatform/register-an-app/ Framework: openplatform@5 Content-SHA256: 44a44499b15a22406e5d90b352edc09e62114d5b1dd40cd81560d5933f43436f Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded An application is a record that the administrator creates in the **setup** screen (`/setup/`, the apps API of the `setup` plugin). The record is the contract between OpenPlatform and your application: where it lives, how the two of them prove who they are, and what the user may do in it. The schema of the record is `@Apps` in `plugins/setup/schemas/apps.js`. | Field | Required | Meaning | |---|---|---| | `name` | yes | the name shown in the portal | | `url` | yes | the address that OpenPlatform opens | | `reqtoken` | yes | a secret that you choose and that **both sides know**: it signs the request | | `restoken` | yes | a second secret, also shared: the application uses it to sign its answer | | `color`, `icon` | no | how the application looks in the portal | | `meta` | no | an address (URL) that returns the metadata of the application: the setup screen can download it (`Apps/download`) to fill in the record | | `sortindex` | no | the order in the list (a new application goes to the end) | | `notifications` | no | whether the application may send notifications | | `isexternal` | no | the application is **not** opened inside the portal's frame: the answer to the application says `iframe: false` | | `isbookmark` | no | the application is a plain link: no token handshake, only a session identifier in the query string | | `isnewtab` | no | open it in a new browser tab instead of the frame of the portal (the setting `newtab` does it for every application) | | `isscrollbar` | no | the frame of the application in the portal keeps its scrollbar (the portal sets `scrolling` to `yes` or `no`) | | `isdisabled` | no | switch it off for everybody: the user gets "App has been temporary disabled" | | `permissions` | no | the list of permissions of the application: each one has an `id`, a `name` and a `value` (see [groups and permissions](/en/openplatform/groups-and-permissions/)) | The table `tbl_app` also has a column `allow` ("allows only specific IP addresses"): when it holds addresses, the application can call the protocol endpoints of OpenPlatform only from them. The setup schema above does not list it, so it is a database column that you fill in directly. ## The two tokens `reqtoken` and `restoken` are never sent to the browser. OpenPlatform derives from them, for each launch, the values that travel: the token in the address of the application and the header that the application sends back. The derivation is in [how an app connects](/en/openplatform/how-an-app-connects/). Use long random values and a different pair for each application. ## Removing and changing An application is never deleted from the table: removing it (`Apps/remove`) sets `isremoved` and the date of the removal, clears the cache of the users that had it, and `isdisabled` switches it off without removing it. When the address of the platform (the `url` setting) changes, OpenPlatform clears the notification links of every user and deletes the open application sessions, because both contain that address ([settings and database](/en/openplatform/settings-and-database/)). Remember the rule of the README: a registered application is visible to nobody until a group is assigned to it. ## Users, groups and permissions in OpenPlatform Source: https://forge.totaljs.es/en/openplatform/groups-and-permissions/ Framework: openplatform@5 Content-SHA256: bf071417d9206260fbcb3592fc8ca09a567f81e2d1c8ea1f513e1615cfb33afc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded OpenPlatform separates **who** (users), **where** (applications) and **what** (permissions) with groups in the middle: - A **user** has a name, an email, a language, a password and flags (`sa` for administrator, `isconfirmed`, `isdisabled`, `isinactive`, `notifications`, `sounds`...) and belongs to any number of groups (schema `@User`, `plugins/setup/schemas/users.js`). - A **group** has a name, a colour, an icon, an optional `reference` and a list of permissions (schema `@Group`, `plugins/setup/schemas/groups.js`). - An **application** declares its own permissions: each has a name and a `value`, a plain string that the application understands (`plugins/setup/schemas/apps.js`). ## How the access is computed The function `FUNC.permissions(userid, callback)` in `definitions/func.js` builds, for a user: 1. the groups of the user that are not disabled; 2. the rows of `tbl_group_permission` of those groups: a row with a permission gives that permission of an application, and a row **without** a permission just gives the application (the user sees it and receives an empty list of permissions); 3. the `value` of each granted permission, only for applications that are not removed and not disabled. The result has three parts: the applications of the user (`apps`), the permission values by application (`permissions`) and the groups (`groups`). It is stored as JSON in the column `cache` of the user, with a `cachefilter` that lists the groups (`G`) and the applications (`A`) it depends on. When a group or an application changes, `FUNC.clearcache(id)` clears the cache of every user whose filter contains that identifier, and the next request rebuilds it. ## Where the application sees it - The portal lists only the applications in `apps` and refuses to open any other one ("App not found"). - The application receives its own list in `permissions` when it verifies a launch (an array of the `value` strings), together with the ids of the groups, so it can decide what to show ([how an app connects](/en/openplatform/how-an-app-connects/)). - The setup screen decides who may use it by the flag `sa` of the user. A good habit, from the way the code works: name the `value` of a permission after the action in your application (`orders.read`, `orders.write`) and map groups to those values in OpenPlatform, so that your application only checks strings. ## How an application connects to OpenPlatform: the launch and the verification Source: https://forge.totaljs.es/en/openplatform/how-an-app-connects/ Framework: openplatform@5 Content-SHA256: 6ca3284d8734f1ae0f727ee0443412c5cba13f9a157aeba40684870245c05268 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded When a user opens an application, OpenPlatform does not send a password or a cookie to it. It sends a **one-time launch address**, and the application calls back to OpenPlatform to learn who the user is. This page follows the code (`schemas/account.js`, action `Account/run`, and `controllers/verify.js`). ## 1. The launch When the user clicks an application, the portal calls the API `run/{appid}`. OpenPlatform: 1. checks that the application is in the list of the user (`App not found` otherwise) and that it is not disabled; 2. creates a session of the application (table `tbl_app_session`) that expires after the setting `app_session_expire` (one day by default); 3. builds the **verification address**: the platform `url` + `/verify/?token=` + the identifier of the session joined to the identifier of the installation with `X`, followed by `X` and a checksum (`FUNC.checksum`, which uses the secret `saltchecksum`); 4. derives the two tokens of that session from the shared secrets of the application: - `reqtoken` = the MD5 of the verification address salted with the `reqtoken` of the application, in lower case; - `restoken` = the MD5 of that `reqtoken` salted with the `restoken` of the application; 5. opens the application at its `url` with one extra query parameter: `openplatform=~`. For an application marked as a bookmark there is no handshake: the address gets `ssid=` instead. ## 2. The verification The application takes the value of `openplatform`, which is the verification address, a `~` and the `reqtoken` of the session, and: 1. computes **its own** `restoken`: the MD5 of the `reqtoken` salted with the `restoken` that it shares with OpenPlatform; 2. calls `GET` on the whole value of `openplatform` (the `~` and the `reqtoken` stay in the query string) with the header `x-token` set to that `restoken`. OpenPlatform then (`controllers/verify.js`): 1. splits the query token at the last `~` (the part after it is the `reqtoken` that it sent) and refuses the call when the header or the token is missing; 2. checks the checksum of the session identifier, reads the session and compares both secrets (`reqtoken` and the `restoken` of the header); any difference is `Invalid token`; 3. if the application has a list of allowed addresses, checks the address of the caller (`Not allowed IP address`); 4. reads the user and refuses a disabled user (`User has been disabled`) or an inactive one (`User is inactive`); 5. makes sure the user has the notification links of this application (table `tbl_user_app`); 6. builds the answer and passes it through the transformation `verify` of the platform, so a deployment can add fields. The answer is a JSON object. Empty values are dropped from it. Its main fields are: | Field | What it is | |---|---| | `id`, `name`, `email`, `photo`, `gender`, `reference` | who the user is (`photo` is an absolute address) | | `language`, `color`, `interface`, `darkmode`, `sounds` | the preferences (the platform language and colour when the user has none) | | `sa` | the user is an administrator of the platform | | `permissions` | the `value` strings of the permissions of the user in this application | | `groups` | the ids of the groups of the user | | `appid`, `ssid` | the application and the checksum of its session | | `openplatformid`, `openplatform` | the identifier and the address of the installation | | `iframe` | `true` unless the application is external | | `notify` | the address to send notifications to, when the user accepts them ([notifications](/en/openplatform/notifications-and-public-api/)) | | `platform` | the `name` and `logo` of the platform, its `groups` and the applications of the user | The answer is kept in an in-memory cache keyed by the session token (the part before the `~`) and the cache is cleared every two minutes. A call with a token that is in that cache is answered from it, before the secrets are compared again, so a repeated verification inside that time is cheap. ## 3. Asking again later `GET /session/` takes the `ssid` that the application received (it also accepts `openplatformid`, `token` and `session` as the name of the parameter), checks its checksum and returns the user (`id`, `language`, `name`, `color`, `sa`, `isonline`) while the session of the user has not expired. ## What to remember when you build the application - Never ship the shared secrets to the browser: only the server of the application needs them. - Verify on the **server** and create your own session from the answer; the `openplatform` parameter is for one launch. - Use the `permissions` of the answer, not a role that the browser sends. - Total.js 5 has a native client for this family of protocols: see [OPENCLIENT](/en/total5/openclient-protocol/). ## Notifications and the public endpoints of OpenPlatform Source: https://forge.totaljs.es/en/openplatform/notifications-and-public-api/ Framework: openplatform@5 Content-SHA256: 172196f9c0e9c57455997c1066130953d232b02c2d6225f6a4538bce1f431188 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded Besides the launch and the verification, OpenPlatform has a few endpoints for the applications and for other systems. They are in `controllers/verify.js`, `controllers/api.js` and `controllers/socket.js`. ## Send a notification The answer of the verification contains `notify`, an address of the form `/notify/?token=`, when the user accepts notifications. The application sends a `POST` to it with the header `x-token` and a JSON body: | Field | Meaning | |---|---| | `body` | the text of the notification | | `path` | the path inside the application that the notification opens | | `icon`, `color` | optional: they replace the icon and the colour of the application | The value of `x-token` is the **notify token** that OpenPlatform derives for that user and application: the MD5 of the notify address salted with the `reqtoken` of the application, and the MD5 of that result salted with its `restoken` (`FUNC.makenotify` in `definitions/func.js`). Both secrets are the same ones that the application shares for the launch ([register an app](/en/openplatform/register-an-app/)). OpenPlatform answers `Invalid token` when the checksum or the header do not match, and `Not allowed notifications` when the user or the application does not accept them. It also checks the allowed addresses of the application and that the user is confirmed, enabled and active. When everything is right it: 1. stores the notification (table `tbl_notification`) and increases the unread counter of the user; 2. updates the sessions of that user that are open in the portal, so the counter appears at once; 3. publishes `Notifications.create` by TMS when the setting `$tms` is on; 4. returns the identifier of the notification. For users that are offline and have unread notifications, a service job sends **an email digest** ("Unread notifications") when the mail settings are configured, at most once every three days per user (`definitions/init.js`). ## The users API (a token) `GET /users/` returns the groups and the users of the platform as JSON. It is **disabled** until the settings `allow_token` and `token` are set. The caller sends the token as the query parameter `token` or as the header `x-token`; repeated wrong tries are blocked. The users come without secrets: identifier, reference, language, gender, photo (an absolute address), name, email, colour, preferences, flags (`sa`, `isdisabled`, `isinactive`, `isonline`), dates and the ids of their groups. ## Upload an image `POST /upload/base64/` (up to 2 MB) accepts a JSON body with the file name and `file` as a data URI, and only **JPEG**. It needs a signed-in user or the query token of the setting `servicetoken` (see [settings and database](/en/openplatform/settings-and-database/) for where that key comes from). The image is stored in the file storage `files` and the answer is its address, `/files/.jpg`; the address only works with the checksum. ## Several instances: the sync socket `SOCKET /sync/` connects instances of OpenPlatform. A client is accepted when the setting `sync` is on and the query `token` equals `sync_token`; any other client is closed with the code `4001` half a second after opening. The messages of a confirmed client are relayed to the others, and while a confirmed client is reconnecting the messages are queued for up to ten seconds. ## OpenPlatform settings, services and database tables Source: https://forge.totaljs.es/en/openplatform/settings-and-database/ Framework: openplatform@5 Content-SHA256: 9fcf1fdbe76125ea08f59e9f7d7e04cfb6e6d1c3b744068fafa6f10c09b65e28 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded ## The settings OpenPlatform keeps its configuration in the table `cl_config` and loads it into Total.js `CONF` at start and every eight hours (`definitions/init.js`). The setup screen reads and saves these keys (`plugins/setup/schemas/settings.js`): | Key | Meaning | |---|---| | `name`, `icon`, `color` | the name, logo and colour of the platform | | `url` | the public address of the platform (without the final `/`). Changing it clears the notification links and the open application sessions | | `language` | the default language | | `mail_smtp`, `mail_smtp_options`, `mail_from` | the SMTP server, its options (JSON) and the sender; the setup screen can test them | | `$tms`, `secret_tms` | publish the events by TMS, and the secret of that connection | | `allow_token`, `token` | enable the public `GET /users/` API and its token | | `newtab` | open every application in a new tab | | `sync`, `sync_token` | accept the `/sync/` socket of other instances, with its token | The first start (`database.sql`) also generates, inside `cl_config`, values that the setup screen does not edit: the installation `id`, the authentication `secret`, the `cookie` name, the `salt` of the passwords, the `saltchecksum` of the checksums and the secret of the TMS connection. It creates the keys with these defaults: | Key | Default | Meaning | |---|---|---| | `auth_cookie_expire` | `1 month` | how long the session cookie lives | | `auth_expire` | `5 minutes` | how long the signed-in user is kept in memory before it is read again | | `auth_cookie_options` | `{"httponly":true,"security":"lax"}` | the options of the session cookie | | `auth_strict` | `false` | strict sessions | | `app_session_expire` | `1 day` | how long an application session lasts | | `cdn` | `https://cdn.componentator.com/` | the CDN of the interface | | `language` | `eu` | the default language | | `token`, `sync_token` | generated | the token of the users API and of the sync socket (both features are off by default) | The key `servicetoken`, which the image upload endpoint compares with its query token, is **not** created by the script and the setup screen does not edit it: it exists only if you add it to `cl_config` yourself. The script also creates the group **Admin** and the first user (`info@totaljs.com`, administrator, confirmed) that belongs to it; see [installing it](/en/openplatform/install-openplatform/). ## The background services Total.js runs a service every minute. OpenPlatform uses it (`definitions/init.js`) to: - clear the in-memory cache of the verifications (every 2 minutes); - save the daily statistics: users online, the maximum and the number by device (every 3 minutes); - reload the configuration from the database (every 8 hours); - delete the expired application sessions and platform sessions (every 12 hours); - send the email digests of unread notifications (every 11 minutes, when the mail is configured). ## The database Everything lives in the PostgreSQL schema `op`: | Table | What it holds | |---|---| | `cl_config` | the configuration (key, value, type) | | `tbl_user` | the users: profile, password hash, flags, counters and the cached permissions | | `tbl_group` | the groups | | `tbl_user_group` | which user belongs to which group | | `tbl_session` | the sessions of the users in the portal (device, address, expiry) | | `tbl_app` | the applications: address, secrets, flags and allowed addresses | | `tbl_app_permission` | the permissions that each application declares | | `tbl_group_permission` | which permissions (or just which applications) each group grants | | `tbl_app_session` | the launch sessions of the applications and their derived tokens | | `tbl_user_app` | per user and application: the notification links and whether they accept notifications | | `tbl_notification` | the notifications | | `tbl_visitor` | the daily visitor statistics | | `tbl_feedback` | the feedback that users send from the portal | The dated files `database-2023-09-15.sql`, `database-2024-03-21.sql`, `database-2024-10-22.sql` and `database-2024-10-30.sql` in the repository are the changes of the schema over time, and `database.sql` is the full script that the first start runs. Back up this schema like any other PostgreSQL database. ## What is Flow: visual automation and IoT with FlowStreams Source: https://forge.totaljs.es/en/flow/what-is-flow/ Framework: flow@11.1 Content-SHA256: 1ddb2721c518c5b27cf8e863b76ab7569f9d38fc87393080eab8ca5f52cb57c4 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded **Flow** (`totaljs/flow`, version 11.1 at the time of writing) is the main application of the Total.js family for visual programming. You draw a diagram in the browser: every box is a **component**, the lines between them carry **messages**, and the diagram is a **FlowStream**. Flow keeps many FlowStreams, runs each one, and gives you the editor, the monitoring and an API to manage them. It is a Total.js 5 application, MIT licensed, and it needs **no database**: everything lives in two folders of the application (see [install and first start](/en/flow/install-and-first-start/)). ## What you get - **A visual editor** in the browser (the route `/designer/`) with a library of components, the readme of each component, a console, the variables of the stream and dark mode. - **Many independent FlowStreams** in one installation, each with a name, icon, color, group, author, version and notes. By default each stream runs in its **own Node.js process** (`flowstream_worker: fork` in the `config` file), so a stream that fails does not take the others with it, and Flow restarts it. - **Components as plain files.** A component is one HTML file with a Node.js part, its settings form and its design (see [write a component](/en/flow/write-a-component/)). The official catalogue is the repository [`flowstreamcomponents`](/en/flow/the-components-repository/). - **Ways in for the outside world**: a stream can publish HTTP routes under its own `proxypath`, receive calls on `/notify/{id}/`, and talk over WebSocket. - **Import and export** of a stream as one JSON file, pause, restart, statistics and a backup of the database of streams. - **Sign-in** with a generated login and password, or through [OpenPlatform](/en/openplatform/what-is-openplatform/) when you install Flow as one of its apps, with the permissions *Create Flows* and *Remove Flows*. - **Extensions**: HTML files that you copy to a folder to extend the editor. ## Where it fits Flow is the tool to connect things without writing a server: read a sensor, call an API every minute, transform a message, store it, send an alert, answer an HTTP request. Because the runtime is the FlowStream of Total.js 5, the same engine can also be embedded in your own application; Flow is the complete application around it. ## The family Flow has relatives in other repositories of `github.com/totaljs`: [`lesscode`](https://github.com/totaljs/lesscode), [`flowstreamdesigner`](https://github.com/totaljs/flowstreamdesigner), [`flowdesigneroffline`](https://github.com/totaljs/flowdesigneroffline), [`flowdesigner`](https://github.com/totaljs/flowdesigner) and others. They exist as separate projects; this section documents the application `flow` and its components only. ## Next 1. [Install and first start](/en/flow/install-and-first-start/) 2. [Manage FlowStreams with the API](/en/flow/manage-flowstreams-with-the-api/) 3. [Settings and files](/en/flow/settings-and-files/) 4. [Write a component](/en/flow/write-a-component/) 5. [The components repository](/en/flow/the-components-repository/) ## Install Flow and sign in the first time Source: https://forge.totaljs.es/en/flow/install-and-first-start/ Framework: flow@11.1 Content-SHA256: 5a25bf52b53d52c97ea7dadedbcef824b1f3079740fe72fe4ebfdade8152bb6b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded ## Run it with Node.js Flow needs Node.js and nothing else: no database, no external service. ```bash git clone https://github.com/totaljs/flow.git cd flow npm install npm run start ``` `npm run start` runs `node index.js 8000`. The port is optional on the command line and the default is `8000`, so you open `http://localhost:8000`. Add `--release` to run in release mode. ## Run it with Docker ```bash docker pull totalplatform/flow docker run -p 8000:8000 totalplatform/flow ``` The `docker-compose.yaml` of the repository maps port 8000 and keeps two volumes: the folder `databases` (settings and the user) and the folder `flowstream` (your streams). Keep those two volumes and you can replace the container whenever you update. ## The first sign-in At the first start Flow creates the only user of the application with a **random login and a random password**. Until the first successful sign-in, the sign-in page shows them in a box (*Default account*) with a button **Fill in the form**: click it and sign in. From that moment Flow deletes the plain copy of the password from its preferences and the box no longer appears, so open the password form of the application right away and set a login and a password of your own. Do the first sign-in as soon as you start a new installation, before anyone else can reach the address. Some details of the sign-in, read from the source: - The password is stored as a SHA-256 hash with the `cookie_secret` of the installation as the salt, and the session is a cookie of one month encrypted with the same secret. Flow generates the cookie name and the secret the first time and keeps them in `databases/config.json`. - After repeated failed attempts an address is blocked (the block is cleared every 15 minutes). - When the settings hold the tokens of an OpenPlatform (`op_reqtoken`, `op_restoken`), the sign-in page is replaced by the sign-in of that [OpenPlatform](/en/openplatform/how-an-app-connects/) and the permissions *Create Flows* and *Remove Flows* control who may create and remove streams. ## Where the data lives | Folder | What it holds | |---|---| | `databases/` | `config.json` (cookie name and secret) and `memorize_preferences.json` (name, tokens, the user, the `env`, the URLs of the components) | | `flowstream/` | `database.json` with every FlowStream: its design, components, variables and notes | | `private/` | files that the streams write and that you can list with the token of Flow | | `public/cdn/` | cache of the user-interface components that Flow downloads the first time they are needed | To move Flow to another machine, copy `databases/` and `flowstream/`. ## Update Download the new version of the repository (the file `version` tells you which one you run: `11.1` in the revision documented here) or pull the new Docker image and start it with the same volumes. ## Manage FlowStreams with the Flow API Source: https://forge.totaljs.es/en/flow/manage-flowstreams-with-the-api/ Framework: flow@11.1 Content-SHA256: 1ca332525e645680edb0d12f3c3453b31624fe152137539464bca8173d80729b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded Everything the editor does goes through one JSON endpoint: `POST /fapi/` with the body `{ "schema": "", "data": { ... } }` (the Total.js API routes, see [API routes](/en/total5/api-routes/)). The address `/fapi/` comes from the line `$api : /fapi/` of the `config` file. Every call except the sign-in needs the session cookie; without it the answer is `401: Unauthorized`. These calls were also tried against a local Flow 11.1 (Node.js 24 and `total5@0.0.19`) while this page was written. ## Sign in `Auth|login` takes `login` and `password` and answers `{"success":true}` with the session cookie. A wrong pair answers `Invalid credentials`. ```bash curl -c cookie.txt -X POST http://localhost:8000/fapi/ \ -H 'content-type: application/json' \ -d '{"schema":"Auth|login","data":{"login":"","password":""}}' ``` The next calls use `-b cookie.txt`. ## The calls | `schema` | `data` | What it does | |---|---|---| | `Streams` | none | the list of FlowStreams with `id`, `name`, `group`, `author`, `version`, `proxypath`, `size` and the live `stats` of the running ones | | `Streams\|save` | `name`, and optionally `author`, `version`, `icon`, `color`, `group`, `url`, `reference`, `readme`, `memory`, `cloning`, `proxypath`, `proxytimeout` | **creates** a stream when `id` is missing (the permission *create* is checked), otherwise updates the stream with that `id` and restarts it | | `Streams\|read` | `id` | the properties of one stream | | `Streams\|raw` | `id` | the whole stream object, with its design | | `Streams\|export` | `id` | the stream as JSON text in `value`, without the internal fields (`unixsocket`, `env`, `import`, `worker`, `asfiles`) | | `Streams\|import` | `data` (the JSON text) | creates a **new** stream from an export (up to 10 MB), with a new `id`; a repeated `proxypath` is replaced with a random one; answers `{"success":true,"value":""}` | | `Streams\|pause` | `id`, `is` (`true` or `false`) | pauses or resumes a running stream | | `Streams\|restart` | `id` | restarts the stream | | `Streams\|remove` | `id` | removes the stream and its folder (the permission *remove* is checked) | | `Streams\|stats` | none | the totals of the installation: versions of Node.js, Total.js and Flow, messages, pending, memory and connections | | `Variables\|read` / `Variables\|save` | `id` (optional), `data` | the variables of one stream, or the **global** variables when `id` is empty; saving pushes them to the running streams | | `Console\|read` / `Console\|clear` | none | the console of the application | | `CDN\|clear` | none | clears the cache of the downloaded user-interface components | | `Settings\|read` / `Settings\|save` | the settings (see [settings and files](/en/flow/settings-and-files/)) | only for the super administrator | ## Create a stream and run it Create it, then import a design built in the editor (an exported JSON file) to start it: ```bash curl -b cookie.txt -X POST http://localhost:8000/fapi/ \ -H 'content-type: application/json' \ -d '{"schema":"Streams|save","data":{"name":"Demo","author":"Me"}}' ``` A stream exported from the editor carries its `design` (the boxes and their connections), its `components` (the source of each one) and its `variables`. ## Rules of `proxypath` A stream can publish HTTP routes under a path of its own. Flow adds the slashes (`demo` becomes `/demo/`), rejects the paths that belong to Flow itself (`/`, `/cdn/`, `/fapi/`, `/private/`, `/flows/`, `/designer/`, `/parts/`, `/forms/`, `/css/`, `/js/`, `/fonts/`, `/panels/`) with `Proxy endpoint contains reserved path`, and rejects a path that another stream already uses. `proxytimeout` is the time in seconds to wait for the answer of the stream (the default is `120`). ## Calls from outside | Route | Use | |---|---| | `GET` or `POST /notify/{id}/` | sends a notification to the stream with that id (the POST body is limited to 1 MB); the components of the stream decide what to do with it. Answers `{"success":true}` | | `+SOCKET /{id}/` | the WebSocket of the editor for that stream (it needs the session) | | `GET /private/?token=` | lists the files of the folder `private/` when the token equals the `token` of the settings; ten wrong tokens block an address for 15 minutes | | `+POST /update/` | updates the application from a `.bundle` file; only for the bundled version | Keep the `token` secret, send these calls over HTTPS and put Flow behind a reverse proxy when it is reachable from the Internet. ## Flow settings, config file and folders Source: https://forge.totaljs.es/en/flow/settings-and-files/ Framework: flow@11.1 Content-SHA256: 52a070f7013e82504d2350a59a14b4bae3a3cbc0d460f3d3b237dde3e5b44741 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded ## The `config` file The file `config` in the root of Flow holds the options of the application. The ones that matter: | Line | Meaning | |---|---| | `name` | the name shown by the application (it can be changed in the settings) | | `$api : /fapi/` | the address of the JSON API | | `flowstream_worker : fork` | each FlowStream runs in its own process | | `$proxytimeout : 120` | seconds that a stream may take to answer an HTTP request | | `cookie`, `cookie_secret` | generated at the first start and kept in `databases/config.json` | Other options are read when they exist: `directory` (the folder of the streams; the default is `flowstream/` next to the application), `flowstream_memory` (a default memory limit for new streams), `flowstream_sandbox` and `flowstream_asfiles` (they are passed to every stream), `components` and `templates` (the first values of the catalogues) and `backup`. ## Settings in the application The super administrator opens the settings and finds: - **name** of the installation; - **components** and **components2**: the address of the catalogue of components (a `db.json` file, by default `https://cdn.totaljs.com/flowstream/webcomponents/db.json`) and an optional second catalogue, so you can offer your own components next to the official ones; - **templates**: the catalogue of templates of streams (by default `https://cdn.totaljs.com/flowstream/templates/db.json`); - **env**: `dev`, `test` or `prod`. The streams read it, and changing it restarts all of them one by one; - **backup**: each save of the streams renames the previous `database.json` to a file with the date and the minute, `database_yyyyMMddHHmm.bk`; - **token**: the random token for `/private/` (see [the API](/en/flow/manage-flowstreams-with-the-api/)); - **darkmode** and **notify**; - **op_reqtoken** and **op_restoken**: the tokens of an [OpenPlatform](/en/openplatform/how-an-app-connects/); when both are set, people sign in with that OpenPlatform. Plugins can add their own settings to the same form. The repository includes one, *Bookmarks*, a list of saved components that people with the permission `bookmarks` can use. ## Variables Every stream has its own **variables** and there is a set of **global variables**, both edited in the editor or with `Variables|read` and `Variables|save`. A component reads them to avoid putting addresses and keys in the design, and a change reaches the running streams at once. ## Local components: `--components--` The folder `--components--` of the repository holds a few components that travel with the application: `checkfreespace`, `checklog`, `checkpg`, `checkurl`, `console` and `print`. The official catalogue is much bigger, see [the components repository](/en/flow/the-components-repository/). ## Extensions An extension adds something to the editor of every stream. Copy an `.html` file to the folder `extensions/` (the repository documents it in `--extensions--/` with a `test.html` sample) and Flow loads it for each stream: the part between `` runs with the stream, and the rest of the file is added to the editor. ## The environment of a stream At the start of each stream Flow gives it the folder where it keeps its files (`directory`), the global variables, the `env` of the installation, its memory limit, and the extensions loader (`extensions.js`). A stream that crashes is restarted by Flow, and its statistics (messages, pending, errors, memory and process id) are returned by `Streams`. ## Write a Flow component: one HTML file Source: https://forge.totaljs.es/en/flow/write-a-component/ Framework: flow@11.1 Content-SHA256: 98e0101ffef81a1e2ff75365737b0c12e754571250c18d5e601aba641db20dff Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded A component is **one `.html` file**. Flow reads the file, runs its Node.js part inside the stream and shows its design in the editor. The official components of [the repository](/en/flow/the-components-repository/) all use this format, so you can read any of them as an example. ## An example: `shout.html` It receives a message, converts the text to upper case, adds a suffix and sends it on. ```html
    Suffix
    The component converts the text of a message to upper case and adds a suffix.
    NAME
    Shouted:
    ``` ## The parts of the file | Part | What it is for | |---|---| | ` ``` When the layout is saved, a navigation called `main` is created if it does not exist; then edit its links in the plugin *Navigation*. In the template, `value.children` is the list of visible links, `value.url` is the address being served. Give the script a `name`; with only an `id` the compiler accepts it but saving the layout does not answer. There is also `

    Hello world

    ``` `opt.config` is the configuration of the instance, `opt.html` the HTML that was inside the block, and `opt.id`, `opt.uid` and `opt.body` describe it. `next(html, replace)` gives the HTML to serve; with `true` as the second argument it replaces the whole block. We saved this file in a local CMS and a page with `data-cms="hello__..."` and `{"text":"mundo"}` came out as `

    Hello MUNDO

    `, with `.w-hello{color:#07c}` in the head. The official widget `picture` uses the same function to add `loading="lazy"` to its image, and `code` to print the code of its settings. `exports.install` and `exports.uninstall` run with the database of the CMS when the widget is added, changed or removed. ## Install and remove widgets The plugin *Widgets* of the admin imports a file; through the API it is `widgets_save` with `{ "html": "", "singleton": true }` (`singleton` skips the widget when it already exists), `widgets_list`, `widgets_read`, `widgets_detail` and `widgets_remove`. They need the permission `widgets` (see [the admin API](/en/cms/the-admin-api/)). The 43 official widgets are in [the widgets repository](/en/cms/the-widgets-repository/). ## The CMS widgets repository: 43 widgets and how to add them Source: https://forge.totaljs.es/en/cms/the-widgets-repository/ Framework: cms@8071e48 Content-SHA256: 4ad631d644c4203883e4d4e49114a1dac43eb6eb1e92f4c319e9d4c360676593 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded [`totaljs/cms-widgets`](https://github.com/totaljs/cms-widgets) holds the official widgets of the Total.js CMS. In the revision documented here (`dc92cb7`) it has **43 widgets** in `widgets/`, one HTML file each, all with the group *Content*, plus the script that generates the catalogue (`db.js`). The format of every file is described in [widgets](/en/cms/widgets/). ## What they cover The repository puts every widget in one group; the table below only orders them by what their names suggest, to help you find them. | Kind | Widgets | |---|---| | Text | `headline`, `paragraph`, `paragraph2`, `article`, `alert`, `list`, `keyvalue`, `properties`, `summary`, `tags`, `code`, `codehighlighter` | | Layout | `container`, `vcontainer`, `columns100`, `columnshalfs`, `columnsthirds`, `panelsthirds`, `box`, `emptyspace`, `line`, `gradient` | | Text with image | `textimageleft`, `textimageright`, `textimagecenter`, `textimageflex`, `features2`, `features3`, `insight`, `team`, `partners`, `expansionlist` | | Images and media | `picture`, `images`, `imagelinks`, `gallery`, `video`, `bufferwall` | | Links and buttons | `linkbutton`, `buttonsgroup`, `socialnetworks` | | Integration | `importer`, `uibuilder` (see [UI Builder](/en/uibuilder/what-is-uibuilder/)) | Nine of them use `exports.render` to build their HTML on the server (`bufferwall`, `code`, `codehighlighter`, `images`, `imagelinks`, `importer`, `picture`, `partners` and `uibuilder`); the rest are static blocks that the editor configures and the CMS serves as they are. ## Add a widget to your CMS Each file is a complete widget. In the admin, open the plugin *Widgets* and import the file, or send it with the API: ```json { "schema": "widgets_save", "data": { "html": "", "singleton": true } } ``` `POST` it to `/admin/` with the session cookie or the `x-token` header ([the admin API](/en/cms/the-admin-api/)). ## The catalogue: `db.json` The editor can list the widgets of a catalogue. `db.js` creates it: it reads every file of `widgets/`, takes `name`, `author` and `preview` from its `exports`, builds the address `https://cdn.totaljs.com/cms/` and writes `db.json` sorted by name, with one entry per widget (`id`, `name`, `url`, `author`, `preview`). `db.js` starts with `require('total4')`, so it needs Total.js 4 to run, as in the repository of the components of Flow ([the components repository](/en/flow/the-components-repository/)). ## Your own widgets Copy the closest widget, change `exports.id` and `exports.name`, and adapt the style, the design and the settings. If the widget needs a library, list it in `exports.dependencies` and the CMS adds it to the head of the pages that use it. ## The admin API of the Total.js CMS: manage a site from code, backup and restore Source: https://forge.totaljs.es/en/cms/the-admin-api/ Framework: cms@8071e48 Content-SHA256: d0108c50f8c67f006e4deadc87b0c0812812b447c52bc468e4579ab8c2d503b5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded Everything the admin interface does goes through one endpoint: `POST /admin/` with the body `{ "schema": "", "data": { ... } }` (the Total.js API routes, see [API routes](/en/total5/api-routes/)). The address comes from the line `$api : /admin/` of the file `config`. Authenticate with the session cookie (`POST /admin/` with `schema: "login"` and the `login` and `password`), with the header `x-token` or through OpenPlatform ([install and first start](/en/cms/install-and-first-start/)). ## The actions | Plugin | Calls (`schema`) | Permission | |---|---|---| | Account | `login`, `logout`, `admin_read`, `admin_save` (name, login, password), `account` | the session | | Pages | `pages_list`, `pages_read`, `pages_save`, `pages_clone`, `pages_remove`, `pages_links`, `pages_html` (reads the HTML), `pages_save_html` (`id`, `html`, up to 5 MB), `pages_copy` (`from`, `to`) | `pages` | | Layouts | `layouts_list`, `layouts_read`, `layouts_save`, `layouts_clone`, `layouts_remove`, `layouts_html`, `layouts_save_html`, `layouts_import` | `layouts` | | Widgets | `widgets_list`, `widgets_read`, `widgets_save`, `widgets_remove`, `widgets_detail` | `widgets` | | Navigation | `nav_list`, `nav_read`, `nav_save`, `nav_remove`, `nav_editor` | `navigation` | | Redirects | `redirects_list`, `redirects_read`, `redirects_save` (`url`, `target`, `permanent`), `redirects_remove` | `redirects` | | Variables | `variables_read`, `variables_save` (`vars`) | `variables` | | Posts | `posts`, `posts_read`, `posts_create`, `posts_update`, `posts_remove`, `posts_clear`, `posts_categories` | `posts` | | Files | `files_list`, `files_rename`, `files_clear`, `files_remove`, and the uploads below | `files` | | Settings | `settings_read`, `settings_save`, `settings_test` (tries the SMTP settings), `chatgpt` | `settings` | | Dashboard | `dashboard_online`, `dashboard_referers`, `dashboard_browsers`, `dashboard_pages`, `dashboard_stats` | none | The permission `admin` (and every user with the flag `sa`, including the *Bot* of the token) is allowed in all of them. A call without permission is answered with an error, and `login` is the only call that does not need a session. Create a page and its content: ```json { "schema": "pages_save", "data": { "name": "About", "layoutid": "", "url": "/about/", "title": "About us" } } { "schema": "pages_save_html", "data": { "id": "", "html": "

    About us

    " } } ``` `pages_save` answers `{ "success": true }`; read the id with `pages_list`. For a layout, `layouts_save` answers the id of the layout in `value`. When a field is missing from an update, the field is cleared (a `title` that you do not send is saved empty), so send the whole record. ## Uploading files `POST /admin/upload/` takes a multipart upload (up to 10 MB) and `POST /admin/upload/base64/` a JSON body with a data URI (png, jpeg or gif). Both answer a list of `{ id, name, type, ext, size, url }` where `url` is `/download/.`. ## Backup, restore and clear Three routes of `controllers/api.js` work on the whole site and need the permission `admin`: | Route | What it does | |---|---| | `GET /admin/backup/` | downloads the whole file storage (metadata, HTML of pages and layouts, files and posts) as one text file named after the site and the date | | `POST /admin/restore/` | uploads such a file (up to 100 MB) and loads it. | | `GET /admin/clear/` | **deletes the content of the site.** It drops the file storage and loads it again, so pages, layouts, widgets and the rest are removed | Make a backup before you try any of these, never open `/admin/clear/` in a browser out of curiosity, and keep the token private: with it, a single `GET` empties the site. ## CMS settings, posts, files, visitors and where everything is stored Source: https://forge.totaljs.es/en/cms/settings-posts-and-files/ Framework: cms@8071e48 Content-SHA256: 111717bf1e02afa7bbb01896ed4e92ee49e22fc18bc8590b127b73e3e0868ce6 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded ## Settings The plugin *Settings* (`settings_read`, `settings_save`; permission `settings`) edits the configuration that the CMS keeps inside the metadata of the site and loads into `CONF` at every start: | Key | Meaning | |---|---| | `name` | the name of the site, used in the `` of every page except `/` and in the file name of the backup | | `url` | the public address of the site; the CMS also updates it from the host of the admin requests | | `smtp` | the SMTP settings as a JSON text (`server`, `from`, `user`, `password`, `port`); `settings_test` tries them | | `icon` | an icon for the site | | `$tms`, `secret_tms` | publish the events by TMS, and the secret of that connection | | `op_reqtoken`, `op_restoken` | the tokens of an [OpenPlatform](/en/openplatform/how-an-app-connects/); when both are set the admin sign-in is replaced by the one of OpenPlatform | | `totalapi` | a key for the Total.js API services | Plugins can add more keys, which appear in the same form. Values that live in the file `config` (`$api`, `cdn`, `salt` and, if you add it, `token`) are not edited here. ## Posts The plugin *Posts* is a small manager of articles, kept in its own NoSQL file inside the storage. A post has a `name`, `category`, `picture`, `summary`, `body`, `reference`, `icon`, `color`, `hidden` and `date`; the admin lists them newest first (100 per page) and `posts_categories` returns the categories in use. The posts are data for your own code: the public renderer of the CMS (`controllers/default.js`) does not print them, so a widget or a route of yours has to read them and draw them. ## Files The plugin *Files* stores uploads in the file storage and marks them as public. `GET /download/<id>.<ext>` serves a public file (only the public ones; the rest answer 404). For images, `?s=<percent>` returns a smaller JPEG (the value must be between 10 and 80, with quality 80), and `?download=1` forces a download. The upload routes and their limits are in [the admin API](/en/cms/the-admin-api/). ## Visitors and the dashboard The module `modules/visitors.js` counts the visits of the public pages through the script `/visitors.js` that every page includes: unique visitors, hits, browsers, referrers, search, social and direct traffic, mobile and desktop, hours of the day, and the people online (a visitor is online for 20 minutes without activity). The *Dashboard* plugin draws those numbers from `dashboard_stats`, `dashboard_online`, `dashboard_browsers`, `dashboard_referers` and `dashboard_pages`. ## OpenPlatform When `op_reqtoken` and `op_restoken` are set, the CMS signs people in through [OpenPlatform](/en/openplatform/what-is-openplatform/) (module `modules/openplatform.js`) and each plugin contributes its permission to the list that OpenPlatform shows when you assign groups: `pages`, `layouts`, `widgets`, `navigation`, `posts`, `files`, `redirects`, `variables`, `settings` and `admin`. Remember the rule of OpenPlatform: an application is visible only to the groups that you assign to it. ## The data model `MAIN.db` holds the metadata of the site (`pages`, `layouts`, `widgets`, `redirects`, `vars`, `nav`, `config` and `storage`) and it is saved as one JSON document called `meta` in the file storage. The HTML of every page and layout is a file of that storage whose name is the id of the page or layout. `FUNC.load()` reads the metadata at start, compiles the widgets (running their `install` function) and rebuilds the caches; `FUNC.save()` writes it back. That is why a backup of the storage is a backup of the site. ## What Todomator is: task management for small teams Source: https://forge.totaljs.es/en/todomator/what-is-todomator/ Framework: todomator@1.7 Content-SHA256: ebc81a61f6fd57548355627d025781f2ca171530c47456ec8a0d32c472af022b Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded Todomator is a **task manager for small teams**: the people of a team create tickets, assign them, comment on them, attach files, track the time they take and follow what is pending. It is made by Total.js, it is open source under the **MIT licence** and free to use, also in commercial projects, and its repository is [totaljs/todomator](https://github.com/totaljs/todomator) (version 1.7). The project recommends it for teams of up to 30 members, and you can run one instance per team. These pages describe Todomator (revision `af448eb` of the repository). ## What it gives you - **Tickets** with a name, a status, folders, tags, a deadline, a priority flag, a billable flag, subtasks and links between tickets, written in Markdown (see [tickets, folders and tags](/en/todomator/tickets-folders-and-tags/)). - **Who sees what.** A ticket is visible to its owner, to the people assigned to it, to its watchers, or to everybody when it is public. - **Time tracking** with a start/stop timer or manual entries, for billing and payouts (see [time tracking](/en/todomator/time-tracking/)). - **Comments, attachments and notifications**, with unread marks and live updates through a WebSocket. - **An open REST API** to create tickets from other systems, for example from an email or from the contact form of a website (see [create tickets with the API](/en/todomator/create-tickets-with-the-api/)). - **Two-factor authentication** (added in version 1.7), search, a calendar of tickets and bookmarks. - **Premium plugins** (reminder, reports, user workload, extensions) that are part of the [Total.js Enterprise service](https://www.totaljs.com/enterprise/); the core of Todomator does not need them. ## How it is built Todomator is a Total.js 5 application that stores its data in PostgreSQL through `querybuilderpg`. The interface is built with jComponent and the Componentator components, and the API uses the Total.js API routes. Install it by following [install Todomator](/en/todomator/install-todomator/); the [settings and the database](/en/todomator/settings-and-database/) are described on their own page. The official documentation is at [docs.totaljs.com/todomator](https://docs.totaljs.com/todomator/). ## Install Todomator with Node.js and PostgreSQL, Docker or Docker Compose Source: https://forge.totaljs.es/en/todomator/install-todomator/ Framework: todomator@1.7 Content-SHA256: 300e289fdd80ff13b51f7fb675fbdb3de93238d77d41e733cd1392362638851d Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded Todomator needs the latest **Node.js** and a **PostgreSQL** database. Do **not** run `database.sql` yourself: Todomator uses that script internally when it starts on an empty database. ## By hand 1. Install Node.js and PostgreSQL and create a database for Todomator. 2. Download the [source code](https://github.com/totaljs/todomator). 3. Install the dependencies in the root of the application: ```bash npm install ``` 4. Set the connection in the file `config`. It reads the environment variable `DATABASE` (line `database (env) : DATABASE`) and has a line `database : postgresql://total:platform@127.0.0.1:5432/todomator` as a model. The same file has `$api : /api/` (the address of the API) and a `mail` line with the SMTP settings as a JSON object. 5. Run it (the `start` script is `node index.js 8000`): ```bash node index.js ``` 6. Open `http://127.0.0.1:8000`. ## Docker Hub ```bash docker pull totalplatform/todomator docker run --env DATABASE='postgresql://user:pass@hostname/database' -p 8000:8000 totalplatform/todomator ``` ## Docker Compose ```bash git clone https://github.com/totaljs/todomator.git cd todomator docker compose up ``` ## The first start If the table `tbl_ticket` does not exist in the schema `public`, Todomator runs `database.sql` with a generated identifier, a secret and the password hash of the first user, then loads the configuration and the tags. With the environment variable `DATABASE` (Docker) it waits three seconds first. The script creates the statuses, the first user and the configuration. The server stays paused (`PAUSESERVER('Database')`) until the database is ready. ## The first sign-in The README gives the default account: ```text login : info@totaljs.com password : admin ``` The account is created with the name John Connor and administrator rights (`sa`). **Change the password** after signing in, and configure the [settings](/en/todomator/settings-and-database/). ## Updating For an existing installation the README points to the update scripts of the repository instead of `database.sql`: `database_1-3.sql`, `database_1-4.sql`, `database_1-5.sql`, `database_1-6.sql` and `database-20240119.sql`. Apply the ones that are newer than your version; the file `version` of the repository lists what each release changed (for example, version 1.7 added two-factor authentication, improved the search and the plugins of reports, bookmarks and users). ## Tickets, folders, statuses and tags in Todomator Source: https://forge.totaljs.es/en/todomator/tickets-folders-and-tags/ Framework: todomator@1.7 Content-SHA256: 34671bd5d1988af591d37c044efd7371cc9c6952df0f651981fc840762dd480a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded The center of Todomator is the **ticket** (table `tbl_ticket`, schema `Tickets` in `schemas/tickets.js`). Everything else organizes tickets or hangs from them. ## What a ticket holds | Field | Meaning | |---|---| | `name` | the title (required) | | `statusid` | the status; a new ticket is `pending` unless you say otherwise | | `folderid` | the folder (customer or project) it belongs to | | `ownerid`, `userid`, `watcherid` | the author, the people assigned and the people who only follow it | | `ispublic` | visible to everybody; a public ticket has no assigned people | | `ispriority`, `isbillable` | a priority mark and a billable flag | | `markdown`, `html` | the content (the interface uses Markdown) | | `tags` | a list of tags | | `date`, `deadline` | the day of the ticket (today by default) and an optional deadline | | `estimate`, `worked` | the estimate and the minutes already worked ([time tracking](/en/todomator/time-tracking/)) | | `reference`, `source` | free text to connect the ticket with something outside | | `parentid` | the parent ticket, for subtasks | | `attachments` | the files of the ticket | | `attrs` | free JSON data | | `callback` | an address that receives the ticket when it changes ([API](/en/todomator/create-tickets-with-the-api/)) | ## The six statuses The table `cl_status` is created with: `pending` (Pending), `open` (In progress), `review` (Review), `postponed` (Postponed), `note` (Note) and `closed` (Closed). The names are translated into the language of the user. ## Who can see a ticket A ticket is visible to its owner, to the people in `userid`, to the people in `watcherid` and to everybody when `ispublic` is set. The list of folders that a user sees is limited the same way: a folder appears only if the user can see a ticket in it (users with `sa` see all). The list of tickets takes `type` (for example `pending`, `postponed`, `review`, `assigned`, `note`, `unread` or `all`), `q` (search), `folderid`, `date`, `skip` and `limit` (10 by default). ## Folders and tags A **folder** has a name, an icon, a colour, a customer, an email and a phone, and flags: `isbillable` (new tickets inherit it), `isprivate`, `ispinned`, `isarchived` and `isdisabled`. Only people with the `admin` permission (or administrators) manage folders. A **tag** has a name, a colour and an icon, and can belong to a folder. ## Around the ticket - **Comments** (`Comments|create`, `Comments|update`, `Comments|remove`): Markdown text attached to a ticket. - **Unread marks and bookmarks**: each user has their own unread state and bookmarks for a ticket. - **Links** between tickets, and **clone** of a ticket. - **History and logs** of the changes of a ticket. - **Attachments**: `POST /upload/` takes up to 5 MB per request. The address of a file is signed (`/download/<id>-<signature>.<ext>`): images, video and PDF open in the browser and the other types are downloaded. - **Live updates**: the WebSocket sends a `refresh` event only to the people who can see the ticket, and tells the others who is looking at a ticket right now. ## Time tracking in Todomator: timers, manual entries and the minimum log time Source: https://forge.totaljs.es/en/todomator/time-tracking/ Framework: todomator@1.7 Content-SHA256: 846740c7eea059a9159b38ff4b39d454fe32cbf6fbcc52d53c7ed2950844d9e5 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded Todomator records working time in the table `tbl_ticket_time` and keeps the sum in the field `worked` (minutes) of the ticket. The actions are in `schemas/tickets.js`. ## The timer - **Start** (`logwork_start`): opens a timer on a ticket for the current user. If the ticket was `pending`, its status changes to `open` automatically. - **Stop** (`logwork_stop`): closes the timer and adds the elapsed minutes (rounded up) to the ticket. A single timer counts at most **8 hours**, and never less than the setting `minlogtime`. - **Open timers** (`logwork_open`): lists the timers that the user has running. ## Manual entries `logwork_create` adds an entry with the ticket, the minutes, a date and an optional note; `logwork_update` and `logwork_remove` change or delete it, and after an update the total of the ticket is recalculated from all its entries. Entries are never smaller than `minlogtime`. You can also pass `worked` when you create a ticket (also through the [API](/en/todomator/create-tickets-with-the-api/)): Todomator then records an entry of that many minutes. ## The setting `minlogtime` (minutes, 1 by default) is in the [settings](/en/todomator/settings-and-database/). It is the shortest entry that Todomator records, which avoids rows of zero minutes. ## Notifications and billing Every logged time notifies the other people of the ticket and refreshes it live for those who can see it. The flag `isbillable` of the ticket (inherited from the folder) marks the time that you bill, and the premium plugins of reports and user workload build on these records. ## Create tickets from other systems with the Todomator API Source: https://forge.totaljs.es/en/todomator/create-tickets-with-the-api/ Framework: todomator@1.7 Content-SHA256: 1ef7cc7f899dabeb5c0827e652b42f39755b3320dc1891cbd1a0b0579c7ba6cc Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded Todomator exposes its actions through one API endpoint: `POST /api/` with a JSON body `{ "schema": "<name>", "data": { ... } }` (the Total.js API routes; see the recipe [API routes](/en/total5/api-routes/)). The address `/api/` comes from the line `$api` of the `config` file. ## Authenticate with the token Besides the session of a signed-in person, the API accepts a **token**: send it in the header `x-token` or in the query parameter `token`. If it equals the setting `token` (see [settings](/en/todomator/settings-and-database/)), the request runs as a built-in user called *Bot*, an administrator with the permission `bot`; any other token is refused. Use a long random token, keep it on your server and send it only over HTTPS. ## Create a ticket The name of the call is `tickets_create`. Only `name` is required; the rest is optional: | Field | Notes | |---|---| | `name` | the title | | `folder` or `folderid` | the folder, by **name** (Todomator looks it up) or by id; the ticket takes the billable flag of the folder | | `users` | the people to assign, by **name or email**; an unknown person is an error (`User "..." not found`) | | `watcherid` | the people who follow it, by **id** (unlike `users`, the schema of this version does not take them by name) | | `statusid` | `pending` (default), `open`, `review`, `postponed`, `note` or `closed` | | `markdown`, `html` | the content | | `tags`, `ispriority`, `isbillable`, `ispublic` | tags and flags | | `date`, `deadline`, `worked` | the day, a deadline and minutes already worked | | `attachments` | a list of `{ name, data }` where `data` is the file in Base64 | | `reference`, `source`, `attrs` | free fields to link the ticket with your system | | `callback` | an address that receives the ticket | ```json { "schema": "tickets_create", "data": { "name": "The invoice page fails with a 500", "folder": "Customer support", "users": ["jane@example.com"], "markdown": "Reported by the contact form.\n\nSteps: open the invoice and click *Print*.", "tags": ["bug"], "source": "website", "reference": "form-2041" } } ``` The answer is the id of the new ticket. The people assigned are notified and the open sessions of the people who may see it are refreshed. ## The callback When `callback` is set, Todomator sends a `POST` to that address with the ticket data when the ticket is created, updated or cloned, and when a comment is added (on creation and update it also sends the list of the fields that were given, `keys`). Your system can use it to mirror the status of a ticket. ## Other calls The same endpoint serves the rest of the actions, with the names of `controllers/api.js`: `tickets` (list), `tickets_detail/{id}`, `tickets_update/{id}`, `tickets_clone/{id}`, `tickets_remove/{id}`, `logwork_create`, `folders`, `tags` and more. The official API documentation is at [docs.totaljs.com/todomator](https://docs.totaljs.com/todomator/). ## Todomator settings and database tables Source: https://forge.totaljs.es/en/todomator/settings-and-database/ Framework: todomator@1.7 Content-SHA256: ebcc4e81d3b881dd5bf445b6b159386aeadd1789cc2a6d4c388975a513a54435 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded ## The settings Todomator keeps its configuration in the table `cl_config` and reloads it every 20 minutes. The settings screen (`Settings/read`, `Settings/save` in `schemas/settings.js`) edits these keys, and needs the permission `settings`: | Key | Meaning | |---|---| | `name` | the name of the instance | | `color` | the main colour | | `token` | the token of the [API](/en/todomator/create-tickets-with-the-api/) | | `minlogtime` | the shortest time entry, in minutes (1 by default) ([time tracking](/en/todomator/time-tracking/)) | | `backup` | when on, each edit of the Markdown of a ticket also stores a copy of the text, with the user, the address and the browser (table `tbl_ticket_backup`) | | `folderid` | a default folder | ## Permissions A person is an administrator when the flag `sa` is set or when the permission list contains `admin`. `admin` manages folders and the screens of administration; `settings` allows the settings; `bot` belongs to the built-in user of the API token. The sessions live in the table `tbl_session`, and expired ones are deleted once a day. ## Two-factor authentication Each user has the flag `is2fa`, which the person turns on when changing the password (`Users|password`). Sign-in then has two steps (`plugins/users/index.js`): email and password first; if the account has `is2fa`, Todomator emails a six-digit code (template `templates/mail-2fa.html`) that is valid for 10 minutes, and the person sends it back to finish. Wrong attempts are blocked after 10 tries in 10 minutes. The `mail` line of the `config` file must be set for the code to be delivered. ## The database Everything lives in the `public` schema of PostgreSQL: | Table | What it holds | |---|---| | `cl_config` | the configuration | | `cl_status` | the six statuses of a ticket | | `cl_notification` | the types of notification | | `tbl_user` | the users: profile, password hash, permissions and `is2fa` | | `tbl_folder` | the folders (customers and projects) | | `tbl_tag` | the tags | | `tbl_ticket` | the tickets | | `tbl_ticket_comment` | the comments of the tickets | | `tbl_ticket_time` | the time entries | | `tbl_ticket_bookmark` | the bookmarks of each user | | `tbl_ticket_unread` | the unread state per user and ticket | | `tbl_ticket_data` | free data of a ticket (`data_read` / `data_save`) | | `tbl_ticket_backup` | copies of the Markdown of a ticket (the `backup` setting) | | `tbl_notification` | the notifications of the users | | `tbl_file` | the files that were uploaded | | `tbl_session` | the sessions | Back this schema up like any other PostgreSQL database. For an update, apply the `database_*.sql` scripts of the repository that are newer than your version ([install Todomator](/en/todomator/install-todomator/)). ## What UI Builder is: design interfaces as a JSON file Source: https://forge.totaljs.es/en/uibuilder/what-is-uibuilder/ Framework: uibuilder@1 Content-SHA256: 329c5a47f7d4881abacafeecf422ecddaa9d5e75234b09184f4d79b0f5af9be7 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded UI Builder is a **visual editor for user interfaces**. You drag components onto a canvas, configure them and connect them, and the result is not code but a **JSON file** that describes the interface. A small web component renders that file anywhere, so a UI Builder design needs no server-side implementation. It is open source under the **MIT licence**; the editor is the repository [totaljs/uibuilder](https://github.com/totaljs/uibuilder), and you can use the cloud version at [uibuilder.totaljs.com](https://uibuilder.totaljs.com). These pages describe UI Builder (revision `620107a` of the repository). ## What it is for The templates of the editor show the kinds of interfaces it builds: | Template | Use | |---|---| | Web app | a classic web application | | Dashboard | a dashboard of data widgets | | Flowboard | a board connected to a flow of data (it works with [Total.js Flow](https://www.totaljs.com/flow/)) | | Part | a reusable piece of interface | The editor also lists templates for mobile apps and HMI panels, which are switched off in this version. Total.js presents UI Builder for web forms, dashboards, intranets, IoT screens, ERP and CRM interfaces. ## Why it fits Total.js - **The design is data.** A JSON file is easy to store in a database, to version, to generate and to give to another tool. - **It needs no special environment.** The renderer is a jComponent web component, so any page can show a design. - **Your own components.** A component is one HTML file with its style, its code and its settings form ([build a component](/en/uibuilder/build-a-component/)). - **It integrates** with [Flow](https://www.totaljs.com/flow/) and with [OpenPlatform](/en/openplatform/what-is-openplatform/), and it supports localization. Continue with [running the editor](/en/uibuilder/run-the-designer/), the [JSON format](/en/uibuilder/the-ui-json-format/) and [rendering a design in your page](/en/uibuilder/render-an-app-in-your-page/). The official documentation is at [docs.totaljs.com/uibuilder](https://docs.totaljs.com/uibuilder/). ## Use or run the UI Builder editor, and bring your own components Source: https://forge.totaljs.es/en/uibuilder/run-the-designer/ Framework: uibuilder@1 Content-SHA256: ddf1253f6ea8cd393a6083546cbd69e30aaac72f775c2905b253c4328101aa8a Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded ## The cloud editor The quickest way is the cloud version of the editor, [uibuilder.totaljs.com](https://uibuilder.totaljs.com). ## Run it yourself The editor is a small Total.js 5 application that serves static files. The README gives three steps: ```bash npm install node index.js ``` Download the source code first, from [github.com/totaljs/uibuilder](https://github.com/totaljs/uibuilder). The application has one route that serves its files (`ROUTE('GET /*')`) and the `config` file sets the name and the CDN of the interface (`cdn : //cdn.componentator.com`). The editor needs no database. What the repository contains: | Folder or file | What it holds | |---|---| | `public/` | the editor: `ui.js` and `func.js`, the forms of the editor (`forms/*.html`: settings, components, schema, import, code, paths...) and the images of the templates | | `public/templates/` | the starting designs: `app.json`, `dashboard.json`, `flowboard.json`, `part.json` and `db.json` | | `public/templates.json` | the list of templates that the editor offers (a mobile app and an HMI panel exist but are disabled) | | `public/template.txt` | the skeleton of a new component ([build a component](/en/uibuilder/build-a-component/)) | | `public/render.txt` | a page that renders a design with jComponent 20 | | `cdn/uibuilder.min@1.js` | the runtime that renders a design (the `UIBuilder` object of the page) | ## Use your own list of components The editor reads its components from a list. You can point it to your own list by adding the parameter `components` to the address, with the address of a JSON file as its value: ```text https://uibuilder.totaljs.com?components=URL_TO_YOUR_JSON_DB ``` This is how a company ships its own component library without touching the editor. ## Where the pieces come from The design saved by the editor carries, in its `components` field, the address of the library that holds each component, so a design can be rendered later by anyone who can reach that address ([the JSON format](/en/uibuilder/the-ui-json-format/)). ## The JSON format of a UI Builder design Source: https://forge.totaljs.es/en/uibuilder/the-ui-json-format/ Framework: uibuilder@1 Content-SHA256: e85f068a6d27504ab70f8fc202d298d94731a0f11e40603e0fb11bfcf4fe86e1 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded A UI Builder design is one JSON object. The starting templates of the repository (`public/templates/*.json`) show its fields. | Field | Meaning | |---|---| | `name`, `description`, `icon`, `version` | the metadata of the design (the icon is a class of the icon font, like `ti ti-totaljs`) | | `type` | the kind of design: `app`, `dashboard`, `flowboard` or `part` | | `css` | the style of the design. The placeholder `CLASS` is replaced by a unique class of the design, so its rules never leak (for example `.CLASS:root{--radius:5px}`) | | `csspublish` | the style of a `part` that is published for others to use | | `editor` | options of the editor: `download` (a flag) and the text fields `paths`, `codes` and `upload` (the templates start with them empty; see the official documentation for their use) | | `components` | where the components come from: an object with `cdn`, the address of the library (`https://cdn.componentator.com/uibuilder/app.json` in the app template), and in a `part` an object that maps the id of each component to the address of its editor form | | `children` | the tree of components of the design | | `inputs`, `outputs` | the connections of the design with the outside; the templates start with empty lists | | `args` | arguments of the design | ## The tree of components `children` is a list of nodes. Each node has: ```json { "id": "root", "component": "container", "config": { "name": "Container" }, "children": [] } ``` - `id`: the identifier of the instance inside the design. - `component`: the id of the component that renders it (the starting designs begin with a `container` called `root`). - `config`: the configuration that the settings form of the component edits. - `children`: the nodes inside it, with the same shape. A component can follow another one: when its `config.path` starts with `@`, it reads and writes the value of the component whose id comes after the `@` ([build a component](/en/uibuilder/build-a-component/)). ## Why this matters The design is plain data: you can store it in a database, compare two versions, generate it from your own tool, or let your application choose a design per customer. To show one, read [render a design in your page](/en/uibuilder/render-an-app-in-your-page/). ## Build a component for UI Builder Source: https://forge.totaljs.es/en/uibuilder/build-a-component/ Framework: uibuilder@1 Content-SHA256: bd9a9a5904c5130dd20eb775e95489977b91a56df92a270acb0fba296ed79009 Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded A UI Builder component is **one HTML file** with up to four parts. The skeleton that the editor offers for a new component (`public/template.txt`) is a clock: ```html <style> .CLASS { font-size: 14px; } </style> <script> exports.id = ''; exports.name = 'Clock'; exports.group = 'Controls'; exports.author = 'Total.js'; exports.icon = 'ti ti-clock'; exports.config = { bold: false, flash: true, seconds: true }; exports.version = '1'; exports.follow = true; exports.make = function(instance, config, element, cls, iseditor) { // build the component inside element }; </script> <readme> The component renders the current time and the model contains a `Date` object. </readme> <settings> <div class="padding"> <ui-component name="input" path="?.bold" config="type:checkbox">Apply bold font</ui-component> </div> </settings> ``` | Part | What it does | |---|---| | `<style>` | the CSS of the component; `CLASS` is replaced by a class that belongs to the component | | `<script>` | exports the metadata (`id`, `name`, `group`, `author`, `icon`, `version`, `config` with the defaults) and the function `make` | | `<readme>` | the help text shown in the editor (Markdown) | | `<settings>` | the form that edits `config`: jComponent inputs whose `path` starts with `?.` followed by the key of the config | ## The function make `make(instance, config, element, cls, iseditor)` runs when the component is created: - `instance` is the instance of the component (`set`, `on`, `emit`, `state`...). - `config` is its configuration and `element` the jQuery element to fill. - `cls` is the class that replaced `CLASS` and `iseditor` tells whether it is drawn inside the editor or in a rendered design (so, for example, a timer does not need to run while you design). Inside it you listen to events (`instance.on('configure', ...)` when the settings change and `instance.on('destroy', ...)` to clean timers), and write the value with `instance.set('value', date)`. ## Metadata, flags, methods and events From the README of the editor: - **Metadata:** `exports.follow = true` shows the component in the settings form *Path for reading/writing* (for the designer only) and `exports.hidden = true` hides it from the list of components. - **Flags of an instance:** `instance.state.bind = true` binds the component automatically inside a form, for the ones that read and write data; `instance.state.notify = true` emits only the `notify` event when the value changes, instead of setting the value of the component directly (the Counter component is the example). - **Method:** `instance.datasource(CLID_OR_@INSTANCEID__OR__#VIEWID, function(value) {})` reads a source of data and gives an array of `[id, name]`. - **Event:** `instance.on('refresh', function(meta) {})` fires when some objects changed: `meta.type` is `remove` or `configure`, with `meta.items` or `meta.item`. - **Properties of the editor** that a component can read: `DEF.cl.datasource` (code lists and components with `follow`), `DEF.cl.paths`, `DEF.cl.list` (all the instances), `DEF.cl.inputs`, `DEF.cl.outputs`, `DEF.cl.views` and `DEF.cl.apps` (sibling designs). - **Following:** a `config.path` that starts with `@` means the component follows another one. Publish the file in your own list of components ([run the editor](/en/uibuilder/run-the-designer/)) and your team can use it from the editor. ## Render a UI Builder design in your own page Source: https://forge.totaljs.es/en/uibuilder/render-an-app-in-your-page/ Framework: uibuilder@1 Content-SHA256: dd8955b5647235d035f7e4e657dfb7fb1aa72fb4a5f80311b92f060b7daec88e Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c Sources: Review: not-recorded A design is a JSON file ([the format](/en/uibuilder/the-ui-json-format/)), and rendering it is one component. The README of the editor shows it with the web component [j-uibuilder](https://componentator.com/components/j-uibuilder/): ```html <ui-component name="uibuilder" config="url:https://uibuilder.totaljs.com/render.json"></ui-component> ``` `config="url:..."` is the address of the JSON file of the design. The page needs jComponent 20 and the component `uibuilder`; the editor itself serves a ready page for this (`public/render.txt`) that loads jComponent from the CDN: ```html <link href="https://cdn.componentator.com/spa.min@20.css" rel="stylesheet" type="text/css" /> <script src="https://cdn.componentator.com/spa.min@20.js"></script> ``` Then the design appears where you put the tag: a form, a dashboard, a board of a flow. Because the design is data, your application can decide which file to show per user or per customer. ## What the page of Forge already gives you - The catalogue of components of Forge has the page [uibuilder](/en/components/uibuilder/), generated from the repository of the components, with its readme and example. - In the editor, the component list that a design uses is the one in its `components` field; a design can only be rendered where those components can be reached. ## Good to know - You do not need the editor to render: any page with jComponent 20 can do it. - The runtime that renders a design is `cdn/uibuilder.min@1.js` in the repository of the editor. - UI Studio, listed among the app templates of Total.js, builds on the same idea ([Total.js apps](https://www.totaljs.com/apps/)).