air-m2 v0.7.5
m2
Inline plugging
view plugin
the simplest plug-in has the form:
<unit>
<view-source>
import { stream } from "m2"
export default ({ source/*, targets */}) => {
return stream( (emt, { over }) => {
over.add(source.on((evt, src) => {
emt(evt, src);
}));
} );
}
</view-source>
</unit>
you can access nested nodes and modify them
<unit>
<view-source>
import { stream } from "m2"
export default ({ source, targets: [ { node } ] }) => {
const inner = node.querySelector("[custom-plugin-inner]");
return stream( (emt, { over }) => {
over.add(source.on(emt ));
inner.textContent = 77;
} );
}
</view-source>
<div>
<span custom-plugin-inner>custom-value</span>
</div>
</unit>
stream plugin
you can also modify the data stream before use:
<unit>
<stream-source>
import { stream } from "m2"
export default ({ obtain }) =>
obtain().map( data => [data] )
</stream-source>
</unit>
View engine
Simple
Templates definition
data transmission from events
<span>`${property}`</span>
the event source must have the form
[{property: 77}]
the data source can be an object with a nested structure
<span>`${somefield.nested}`</span>
[{somefield: {nested: 77} }]
formatting
if you provide number settings, you can use formatting:
<span>`${intl.formatter-resource-name(value)}`</span>
,where {formatter-resource-name}
- data transmission template
the event source must have the form
[{property: 77}]
formatting resource file example:
[
"formatters",
["currency", { "style": "currency", "splitter": ".", "currencyDisplay": "symbol" }],
["compact-currency", { "style": "currency", "splitter": ".", "currencyDisplay": "symbol",
"minimumFractionDigits": 0
}],
["number", { "style": "decimal", "splitter": "." }],
["percent", { "style": "percent" }]
]
localization
if you supply localization resources you can use automatic literal substitution:
<span>`${lang.localization-string-resource-name}`</span>
localization resource file example:
<?xml version="1.0" encoding="utf-8"?>
<languages>
<en>
<string name="example-literal-string">Example literal text content</string>
<string name="example-literal-string-2">Example literal text content 2</string>
</en>
<ru>
<string name="example-literal-string">Пример случайной строки</string>
<string name="example-literal-string-2">Пример случайной строки 2</string>
</ru>
</languages>
Actions definition
Animation
<keyframe [name = default] [prop = {easing:"linear",duration:5}] >
<key [offset = 0] prop = {scale:0}></key>
<key [offset = 1] prop = {scale:1}></key>
</keyframe>
inline fade-in fade-out supported
<keyframe name = fade-in [duration = 5]>
<key [offset = 0] prop = {translateX:0}></key>
<key [offset = 1] prop = {translateX:100}></key>
</keyframe>
binding data from stream
<keyframe name = fade-in [duration = 5]>
<key prop = {scaleX:(x)}></key>
</keyframe>
[{x: 1.5}]
Inline (local) CSS styles & SASS
<unit>
<style [type="text/scss"]> <!-- to enable SASS processing -->
body { /* global selector */
padding: 0;
margin: 0;
}
:scope { /* local selector */
width: 100%;
background-color: #0026ff;
height: 100%;
}
</style>
<div></div>
</unit>
Class controllers
<keyframe>
<key prop = {classList:{active:(isactive)}}></key>
</keyframe>
[{isactive: true}]
or
<keyframe>
<key prop = {classList:{red|green|black:(selectedColor)}}></key>
</keyframe>
[{selectedColor: "red"}]
Sound controls
<keyframe name="animation-name">
<key prop={sound:'sound-name'}></key>
</keyframe>
Sound will be played once
or
<keyframe name="animation-name" prop="{duration: 2}">
<key offset="0.2" prop={sound:'sound-name'} ></key>
<key offset="0.7" prop={sound:'sound-name'} ></key>
</keyframe>
Sounds will be played 2 times with certain offsets and will be stopped if duration of animation less than duration of sounds
, where
sound
- name of resource declared in<sound>
tag
Sound resource declaration
<sound name="sound-name" rel="sound-resource"></sound>
, where
name
- name of resourcerel
- file name without extension from the directorycomponent/res/sounds/sound-resource
if you want to use the general sounds for components, you can go up the nesting levels
rel="../../sound-resource"
Reactions definition
<unit onclick = req("action-name",{/*args*/})></unit>
where environment variables:
- req - stream fallback method
- key - view-component name
- options - current view-component options
- event - system event data
List of supported events
"onclick"
"onclickoutside" (synthetic)
"onpointermove"
"onpointerenter"
"onpointerleave"
"onpointerup"
"onpointerdown"
"onmouseenter"
"onmouseleave"
"onmouseover"
"onmouseout"
"onchange"
"oninput"
"onglobalkeydown" (synthetic)
"onglobalkeyup" (synthetic)
"onkeydown"
"onkeyup"
"onwheel"
"onscroll"
also supported custom events
"on:custom-event"
<view-source>
import { stream } from "m2"
class MyEvent extends Event {
constructor() {
super("my-event");
this.myData = 100;
}
log() {
console.log("check", this);
}
}
export default ({ source, targets }) => {
return stream( (emt, { over }) => {
over.add(source.on((evt, src) => {
setTimeout( () => {
targets[0].node.dispatchEvent(new MyEvent());
}, 1000);
emt(evt, src);
}));
} );
}
</view-source>
Switcher
selects one view state available according to the model.
<unit tee = {a:10,b:-1}></unit>
rendered to the page if the condition when mapping data from the stream is fully met
[{a: 10, b: -1, ...other}]
or not rendered
[{a: 10, b: -2, ...other}]
allowed to use attachments and abbreviated forms
<unit tee = {obj:{prop}}></unit>
[{obj: {prop: 1}}]
functional form is also now supported
<unit tee() = "obj.prop > 0"></unit>
[{obj: {prop: 1}}]
you can even use a static form
<unit tee() = 1></unit>
however, the view component will still wait for the model stream
Common features
Coupling with model
you can link your view to the stream to get actions and process reactions
<unit stream = ./path>
any relative path will be calculated relative to the parent view, which is related to the model.
you can use the constant $name
as a parameter to pass the current name of the view to the model
<unit stream = ./path/to/model[key=$name]>
Submodules
you can use the included submodules
<unit use = url(./path-to-src-module)></unit>
or
<unit use = ./path-to-registered-module></unit>
Model unit
each model is a function that returns a stream:
it is a new stream
import { stream } from "m2"
export default ( { /*...args*/ } ) =>
stream(emt => {
emt( "something" );
})
, where
- stream - "air-stream" object "stream"
or an existing converted stream
import { stream } from "m2"
export default ( { obtain, /*...args*/ } ) =>
obtain("../some/existing-stream/path")
.map( count => count + 1 )
.controller(
obtain("../some/existing-stream-controller/path"),
({action}) => ({ action, data: "ok" })
)
, where
- obtain - method of accessing an existing model from the schema
- args - init options that were specified when accessing the stream
can be specified in the "obtain" method
obtain("./path", { argv: 10 })
or right on the path
obtain("./path[argv=10]")
Paths
the simplest path has the form:
"./cat-a/cat-b/cat-c"
Supported features
"./cat-a"
- entry to the directory"./"
- current directory"../"
- parent directory"./{name: abc, kind: 10}"
- directories with a complex name"./cat-a[kind=10]"
- passing arguments"./#component-id"
- search by id"./@component-key"
- search by key
Note: when using search by id or key it begins from parent layer and move upward until root layer. So, sometimes you MUST specify exact path to model
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago