Extended Integration
This example will demonstrate how to integrate @bluepjs more deep: example will control 2 divs and 2 buttons background and text colors and buttons click event:
 
To make example more “demonstratable” new Module will be created with special types defenitions (enums, structs, classes) and Actors will demonstrate OOP Inheritance.
HTML structure for demo is simple:
    <div class="demo-page" ref="demo">
      <div id="div-1">Div 1</div>
      <div id="div-2">Div 2</div>
      <button id="btn-1">Button 1</button>
      <button id="btn-2">Button 2</button>
    </div>
css:
.demo-page {
  margin: 15px;
  padding: 10px;
  background-color: #eee;
}
.demo-page div {
  min-width: 50px;
  min-height: 50px;
  border: 1px solid #ddd;
}
Module
Let’s see all file first, and describe it by parts after:
  1const { AbstractModule } = require('@bluepjs/vm')
  2
  3const DivActor = require('./div.actor')
  4const ButtonActor = require('./button.actor')
  5
  6class PageModule extends AbstractModule {
  7  /**
  8    static method provides information about module for Vm and IDE
  9  */
 10  static metadata () {
 11    return {
 12      // module code to access module object with vm.M(code) or vm.module(code)
 13      code: 'page',
 14      name: 'Page',
 15      // let's define some module types
 16      enums: {
 17        // html colors
 18        'html/color': { // full type will be `bluep/enum/${enumCode}`
 19          code: 'html/color',
 20          name: 'Html color',
 21          values: {
 22            '#f00': 'Red',
 23            '#0f0': 'Green',
 24            '#00f': 'Blue',
 25            '#fff': 'White',
 26            '#000': 'Black',
 27            '#999': 'Grey'
 28          }
 29        }
 30      },
 31      structs: {
 32        // colors struct for background color and text color
 33        'element/colors': { // full type will be `bluep/struct/${structCode}`
 34          code: 'element/colors',
 35          name: 'Html elements colors',
 36          schema: {
 37            background: {
 38              code: 'background',
 39              name: 'Background color',
 40              type: 'bluep/enum/html/color'
 41            },
 42            text: {
 43              code: 'text',
 44              name: 'Text color',
 45              type: 'bluep/enum/html/color'
 46            }
 47          }
 48        }
 49      },
 50      // let's define IDE color for our structure
 51      types: {
 52        'bluep/struct/element/colors': {
 53          code: 'bluep/struct/element/colors',
 54          name: 'Html color',
 55          color: '#df883d'
 56        }
 57      },
 58      // ElementActor description:
 59      classes: {
 60        'html/element': { // full type will be `bluep/class/${classCode}`
 61          code: 'html/element',
 62          name: 'HTML Element',
 63          module: 'page',
 64          schema: {
 65            colors: {
 66              code: 'colors',
 67              name: 'Colors',
 68              access: 'public',
 69              readonly: true,
 70              type: 'bluep/struct/element/colors'
 71            }
 72          },
 73          methods: {
 74            colorize: {
 75              code: 'colorize',
 76              name: 'Colorize',
 77              access: 'public',
 78              type: 'method',
 79              class: 'html/element',
 80              module: 'page',
 81              context: {
 82                inputs: {
 83                  colors: {
 84                    code: 'colors',
 85                    name: 'Colors',
 86                    type: 'bluep/struct/element/colors'
 87                  }
 88                }
 89              }
 90            }
 91          }
 92        }
 93      }
 94    }
 95  }
 96
 97  // init method will be called before Vm.start and allows module generate Actors for elements
 98  async init (htmlElements) {
 99    if (htmlElements && htmlElements.length) {
100      for (let i = 0; i < htmlElements.length; i++) {
101        const el = htmlElements[i]
102        const tag = el.tagName
103        const id = el.id
104        if (tag === 'DIV') {
105          const actor = new DivActor(id, el)
106          this.vm().M('actor').addActor(actor)
107        }
108        if (tag === 'BUTTON') {
109          const actor = new ButtonActor(id, el)
110          this.vm().M('actor').addActor(actor)
111        }
112      }
113    } else {
114      /**
115        Current example architecture is not really nice.
116        Page module used only on frontend, but we take Vm.ideData() for IDE
117        from "background Vm" instead of "frontend Vm" where page module
118        will be really used.
119
120        So we just know what actors will be used on frontend, and we create
121        them here, to get them on IDE
122      */
123      if (typeof window === 'undefined') {
124        const div1 = new DivActor('div-1', null)
125        const div2 = new DivActor('div-2', null)
126        const btn1 = new ButtonActor('btn-1', null)
127        const btn2 = new ButtonActor('btn-2', null)
128        this.vm().M('actor').addActor(div1)
129        this.vm().M('actor').addActor(div2)
130        this.vm().M('actor').addActor(btn1)
131        this.vm().M('actor').addActor(btn2)
132      }
133    }
134  }
135
136  // executes on Vm.start
137  async start () {
138    // this module will be executed only in browser
139    if (typeof window === 'undefined') {
140      // use vm console for "outputs"
141      this.vm().console().error('Page module can be started only in browser')
142      return
143    }
144    this.vm().console().log('Page module starting')
145  }
146}
147
148module.exports = PageModule
Module defines:
enum
html/colorwith pairs ofcssColor-Color name. Full type code isbluep/enum/html/color
struct
element/colorswith filedsbackgroundandtext. Full type code isbluep/struct/element/colors
special color for struct
class
html/elementdescribes parent class of module actors. Because parent class is never directly used by Vm - it’s metadata can’t be directly accessible (from class metadata) and provided in module metadata.Because of not really nice demo architecture (IDE using “backend Vm”, and demo module runs only on frontent) - module initialization is “tricky” and we initialize “empty” actors just to get module/actors information for IDE
const PageModule = require('./src/vm/page.module')
vm.addModule(PageModule)
vm.M('page').init()
But on frontend module initialized with real DOM elements:
import PageModule from '@/vm/page.module'
    this.vm.addModule(PageModule)
    await this.vm.M('page').init(this.$refs.demo.children)
Note
$refs is part of Vue 3 framework.
Actors
html/element
Base class for actors in this demo named “HTML Element” (with code “html/element”).
 1const { AbstractActor } = require('@bluepjs/vm')
 2
 3/**
 4  ElementActor will be base for other actors - DivActor and ButtonActor
 5  and implement parent methods
 6
 7  ElementActor by itself will not be used - it's "abstract" class,
 8  so class will be defined in module classes metadata and here metadata will be skiped
 9*/
10class ElementActor extends AbstractActor {
11  /*
12    override actor constructor to provide html element and set inital states
13  */
14  constructor (actorId, htmlElement) {
15    super(actorId)
16
17    this._element = htmlElement || null
18
19    this._state = {
20      // according to 'html/element' class schema, struct and enums description
21      colors: {
22        background: '#fff',
23        text: '#000'
24      }
25    }
26  }
27
28  /*
29    override non-static metadata method to set nicer names
30  */
31  metadata () {
32    const base = this.constructor.metadata()
33    const id = this.id()
34    // required. exists in parent metadata() method
35    base.id = id
36    // new update
37    base.name += ` (${id})`
38    return base
39  }
40
41  // override async AbstractActor::method(code, inputs)
42  method (code, inputs) {
43    // all methods will be defined as functions named 'code'
44    // so all child classes will not override this method
45    if (!this._element || typeof this[code] !== 'function') return
46    return this[code](inputs)
47  }
48
49  // method described for ElementActor
50  async colorize ({ colors }) {
51    // don't forget to update state
52    this._state.colors = colors
53    this._element.style.color = colors.text
54    this._element.style['background-color'] = colors.background
55  }
56}
57
58module.exports = ElementActor
Take attention to _state defenition (line 19). State described at Module metadata as variable with code colors typeof bluep/struct/element/colors.
          schema: {
            colors: {
              code: 'colors',
              name: 'Colors',
              access: 'public',
              readonly: true,
              type: 'bluep/struct/element/colors'
            }
          },
Struct element/colors described having 2 fileds type of bluep/enum/html/color:
        'element/colors': { // full type will be `bluep/struct/${structCode}`
          code: 'element/colors',
          name: 'Html elements colors',
          schema: {
            background: {
              code: 'background',
              name: 'Background color',
              type: 'bluep/enum/html/color'
            },
            text: {
              code: 'text',
              name: 'Text color',
              type: 'bluep/enum/html/color'
            }
          }
        }
      },
And enum type html/color described with next values:
        'html/color': { // full type will be `bluep/enum/${enumCode}`
          code: 'html/color',
          name: 'Html color',
          values: {
            '#f00': 'Red',
            '#0f0': 'Green',
            '#00f': 'Blue',
            '#fff': 'White',
            '#000': 'Black',
            '#999': 'Grey'
          }
        }
As result state definition is:
    this._state = {
      // according to 'html/element' class schema, struct and enums description
      colors: {
        background: '#fff',
        text: '#000'
      }
    }
colorize method, described at Module metadata is simple - it updated state colors variable and css styles of html element accordingly.
  async colorize ({ colors }) {
    // don't forget to update state
    this._state.colors = colors
    this._element.style.color = colors.text
    this._element.style['background-color'] = colors.background
  }
html/div
Div Actor is very simple:
 1const ElementActor = require('./element.actor')
 2
 3/**
 4  Div actor is simple ElementActor child class
 5*/
 6class DivActor extends ElementActor {
 7  /*
 8    Div actor how nothing specal, so we can describe it only by metadata
 9  */
10  static metadata () {
11    return {
12      code: 'html/div',
13      name: 'Div Element',
14      // all schema and methods are extended fom parent class
15      extends: {
16        'module/page/html/element': {
17          module: 'page',
18          code: 'html/element'
19        }
20      }
21    }
22  }
23}
24
25module.exports = DivActor
Actor just extends html/element class. But actors of this class will be used by Vm, so there is static metadata() method, describing it.
Bleuprints
Our Module is complete and comnnected to Vm. Now all Actors behavior will be defined with Blueprints.
Vm start
Let’s colorize our actors on Vm start:
 
 
Colorize functions
Let’s create blueprint function to colorize text of our divs. Function will have one input typeof bluep/enum/html/color
 
Function do same thing as “button 1 click” blueprint with difference that text color is provided as input variable.
Now let’s do button 2 click blueprint.
Project sources
Example project with all sources can be found here: https://github.com/bluep-js/example
 
 
 
