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>
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>
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>
<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}]
<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>
<keyframe>
<key prop = {classList:{active:(isactive)}}></key>
</keyframe>
[{isactive: true}]
or
<keyframe>
<key prop = {classList:{red|green|black:(selectedColor)}}></key>
</keyframe>
[{selectedColor: "red"}]
<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>
tagSound resource declaration
<sound name="sound-name" rel="sound-resource"></sound>
, where
name
- name of resourcerel
- file name without extension from the directory
component/res/sounds/sound-resource
if you want to use the general sounds for components, you can go up the nesting levels
rel="../../sound-resource"
<unit onclick = req("action-name",{/*args*/})></unit>
where environment variables:
"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>
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
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]>
you can use the included submodules
<unit use = url(./path-to-src-module)></unit>
or
<unit use = ./path-to-registered-module></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
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
can be specified in the "obtain" method
obtain("./path", { argv: 10 })
or right on the path
obtain("./path[argv=10]")
the simplest path has the form:
"./cat-a/cat-b/cat-c"
"./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 keyNote: 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