lowdefy/packages/docs/concepts/custom-code.yaml
2021-09-27 12:04:20 +02:00

197 lines
9.1 KiB
YAML

# Copyright 2020-2021 Lowdefy, Inc
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
_ref:
path: templates/general.yaml.njk
vars:
pageId: custom-code
pageTitle: Custom Code
section: Concepts
filePath: concepts/custom-code.yaml
content:
- id: warning
type: Alert
properties:
message: |
SECURITY WARNING: Custom code executes JavaScript inside your Lowdefy app. Insecure code can expose your app or data. Since Lowdefy doesn't validate your custom code, make sure that you only load trusted code.
type: warning
- id: md1
type: MarkdownWithCode
properties:
content: |
Lowdefy runs as a single page web app (SPA). It is possible to extend the functionality of a Lowdefy app by loading custom code (HTML, CSS and JavaScript) into the HTML `head` and `body` to of the default `index.html` page.
The content loaded into the `head` and `body` tag can be any valid HTML, most often `script` tags are loaded to register a new [`JsAction`](/JsAction) or [`_js`](/_js) operator. However, third party code can also be imported, for example Google Analytics, Intercom, etc. Be sure to only load trusted code into your app, as this code will be able to execute JavaScript on all pages of your Lowdefy app, which could expose you app or data to security vulnerabilities. Your own code can easily be hosted from the [Lowdefy public folder](/hosting-files).
> __Warning__: Lowdefy implements the [Ant design](https://ant.design/) UI component framework for app layout and most blocks, thus the default Ant Design CSS is loaded for all Lowdefy apps. Take caution not to unintentionally overwrite existing style settings and classes which can result in a degraded user experience.
## Schema to load custom code
- `app.html.appendHead: string`: Any valid HTML content can be loaded just before the `</head>` tag of the Lowdefy app `index.html` file.
- `app.html.appendBody: string`: Any valid HTML content can be loaded just before the `</body>` tag of the Lowdefy app `index.html` file.
Most often it is convenient to abstract this HTML out to a separate file using the [`_ref`](/_ref) operator.
> __Warning__: Code imported using `appendHead` or `appendBody` will be loaded, and can execute JavaScript on every page of your Lowdefy app.
#### Examples
###### Loading third party code snippet like Google Analytics:
To add [Google Analytics](/https://developers.google.com/analytics/devguides/collection/analyticsjs) to a Lowdefy app, the `lowdefy.yaml` can be setup with:
```yaml
name: google-analytics-example
lowdefy: 3.22.0
# ...
app:
html:
appendHead: |
<!-- Google Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<!-- End Google Analytics -->
# ...
```
###### Load, register and trigger a custom `JsAction` from code in the app `public` folder:
This example fetches a list of Todos from [{JSON}placeholder](https://jsonplaceholder.typicode.com/), and updates [state](/context-and-state).
1) First, add the JavaScript code to the `public` folder and resister the `JsAction`:
```js
// /public/fetchTodos.js
function async fetchTodos(context, numItems, skip) {
const data = await fetch('https://jsonplaceholder.typicode.com/todos');
const todos = await data.json();
return todos.slice(skip, skip + numItems);
}
// Register the JsAction for the Lowdefy app to use.
window.lowdefy.registerJsAction('fetchTodos', fetchTodos);
```
2) Import the JavaScript as a module into the page:
```html
<!-- /header_modules.html -->
<script type="module" src="/public/fetchTodos.js"></script>
```
3) Set load the custom code into the app header and trigger the action on page load:
```yaml
# /lowdefy.yaml
name: json-todos
lowdefy: 3.22.0
app:
html:
appendHead:
_ref: header_modules.html # Load the custom HTML into the header.
pages:
- id: todos
type: PageHeaderMenu
events:
onEnter:
- id: get_todos
type: JsAction
params:
name: fetchTodos # Trigger the custom JavaScript action.
args:
- 10 # numItems
- 0 # skip
- id: set_todos
type: SetState
params:
todos:
# Set the response of the get_todos action to state.
_actions: get_todos.response
# ...
```
## Loading and registering a [`_js`](/_js) operator
Similar to the loading custom JavaScript actions, custom JavaScript operators can also be loaded. In order for the Lowdefy app engine to execute a custom JavaScript [operator](/operators), the JavaScript code for the operator must be loaded onto the page and registered using the `registerJsOperator` method available on the browser [`window`](https://developer.mozilla.org/en-US/docs/Web/API/window) object by calling `window.lowdefy.registerJsOperator(name: string, action: function)`.
All `_js` functions must be synchronous.
#### Examples
###### Load, register and use a custom `_js` operator from code in the app `public` folder:
This example uses a `_js` operator to remove all duplicates from a list of names.
1) First, add the JavaScript code to the `public` folder and resister the `_js` operator:
```js
// /public/foo_operators.js
function removeDuplicates(items) {
return [ ...new Set(items) ];
}
// Register the removeDuplicates function as a _js.deduplicate operator.
window.lowdefy.registerJsOperator('deduplicate', removeDuplicates);
```
2) Import the JavaScript as a module into the page:
```html
<!-- /header.html -->
<script type="module" src="/public/foo_operators.js"></script>
```
3) Set load the custom code into the app header and use the new operator on the page:
```yaml
# /lowdefy.yaml
name: operator-example
lowdefy: 3.22.0
app:
html:
appendHead:
_ref: header.html # Load the custom HTML into the header.
pages:
- id: some_names
type: PageHeaderMenu
blocks:
- id: names
type: ButtonSelector
properties:
title: Select your new friend
options:
# use the removeDuplicates function and pass a list of names as a function argument
_js.deduplicate:
- - Anne
- Sam
- Joe
- Micheal
- Sam
- Steven
- Anne
- Pepper
# ...
```
------
Custom code provides an easy way to extent the logic functionality of Lowdefy apps. However, to extend the UI capabilities beyond the existing features provided by the default Lowdefy blocks, custom blocks can be loaded onto apps.
- _ref:
path: templates/navigation_buttons.yaml
vars:
previous_page_title: Lists
previous_page_id: lists
next_page_title: Custom Blocks
next_page_id: custom-blocks