Powered by
asq

The Web Conference 2018

Developers' Track

Andrea Gallidabino Cesare Pautasso

Software Institute

Faculty of Informatics

USI Lugano, Switzerland

Liquid.js

One User, many devices

Liquid = Flow + Adapt

Liquid User Experience

Initial Configuration

Migrate

Fork

Clone

Cross-Device Web Apps

Multiple device dynamic deployment

Decentralised

Component-based

Demo

Liquid google-youtube component

Step 1: Reuse

WebComponents Repository

Step 2: Liquid Behavior

Load liquidAPI.js script and configure the library:


    <script src="/corescripts/liquidAPI.js"></script>
    <script>
      Liquid.configure({
        host: 'localhost',
        secure: true
      })
    </script>
            

Import the Liquid Behavior into the component:


    behaviors: [LiquidBehavior],
            

Step 3: API Console

Create components:


  Liquid.createComponent('google-youtube')
            

Get component URIs:


  Liquid.getAllComponentURIs()
            

Get component instance:


  Liquid.getComponentInstance('liquid://device/componentType/componentRef')     // 'URI'
            

Get connected devices:


  Liquid.getDeviceList()
  Liquid.getDeviceList(true)
            

Migrate Component:


  Liquid.migrateComponent('componentURI', Liquid.getDeviceList(true)[0])
            

Step 4: Make State Liquid

Annotate videoID property:


    videoID: {
      value: '848QV4H0IDE',
      liquid: true
    },
            

Step 5: Liquid UI activation

Add a component header:


    <liquid-component-google-youtube liquidui="www"></liquid-component-google-youtube>
            

Instantiate the library
core-toolbar
component:


    Liquid.configure({
      host: 'localhost',
      secure: true
    })
    .then(function(){
      return Liquid.createComponent('core-toolbar')
    })
            

Step 6: State and Time Sync

Create and annotate the properties:


    state: {
      value: 0,
      liquid: true,
      observer: "_onStateChange"
    },
    currenttime: {
      value: 0,
      liquid: true,
      observer: "_onCurrentTimeChange"
    },
    duration: {
      liquid: true
    }
            

Bind properties to google-youtube component:


    <google-youtube
      id="myVideo"
      video-id="{{videoID}}"
      height="320px"  width="600px" chromeless="0"
      state="{{state}}"
      on-google-youtube-ready="_onPlayerReady"
      currenttime="{{currenttime}}"
      duration="{{duration}}"
    ></google-youtube>
            

Step 7: Send video to slides

<div id="slide-slot"></div>

Step 8: Complementary View

Add the liquid-component-slider:


    <liquid-component-slider 
      liquidui="www" 
      currenttime={{currenttime}} 
      duration="{{duration}}">
    </liquid-component-slider>
            

Add the Liquid Container behavior:


    behaviors: [LiquidBehavior, LiquidContainer],
            

Preload the component in the ready function:


    ready: function (){
      Liquid.loadComponent('slider')
    },
            

APIs

Framework configuration

Method Name Return Value
configure(options) Promise()
getLoadableComponents() Promise(componentTypes[])
getAllComponentURIs(DeviceURI) Promise(compoenntURIs[])
getAllComponentInstances() componentInstance[]
getComponentInstance(componentURI) componentInstance
getDevicename devicename
setDevicename(devicename) -
Events
devicenameChange(devicename)
Triggers when the server accepts the notification of the devicename change.
loadableComponentsListUpdate(componentTypes[])
Triggers when the available list of components on the server side changes and returns a list of componentTypes[]. The list keeps track only of the components available on the server, it does not check for components available on the clients.

Liquid User Experience API

Method Name Return Value
migrateComponent(sourceCompURI, targetDevURI) Promise(migratedComponentURI)
forkComponent(sourceCompURI, targetDevURI) Promise(forkedComponentURI)
cloneComponent(sourceCompURI, targetDevURI) Promise(clonedComponentURI)

Device Discovery API

Method Name Return Value
getDeviceInfo() deviceInfo
getDeviceURI() deviceURI
getDevicesList() availableDeviceURIs[]
getDevicesInfoList() availableDeviceInfos[]
Events
devicesListUpdate(availableDeviceInfos[])
Triggers when a new device connects to the server and is available to be paired. The callback returns the entire list of {deviceURI, clientjsFingerPrint, devicename, customData} of device connected.

Component Lifecycle API

Method Name Return Value
loadComponent(componentTypeURI) Promise(componentTypeURI)
createComponent(componentType[,DeviceURI, DOMElem,UIType]) Promise(createdComponentURI)
registerComponent(componentURI) Promise(componentURI)
instantiateComponent(compType[,DeviceURI, DOMElem,UIType]) Promise(instantiatedComponent)
deleteComponent(componentURI) Promise()

Liquid Storage API

Method Name Return Value
getState(componentURI) Promise(stateSnapshot)
setState(componentURI, stateSnapshot) Promise(componentURI)
pairComponent(sourceCompURI1, targetCompURI2) Promise()
unpairComponent(sourceCompURI1, targetCompURI2) Promise()
pairProperty(sourcePropURI, targetPropURI) Promise()
unpairProperty(sourcePropURI, targetPropURI) Promise()

Computation Offload API

Method Name Return Value
createLiquidWorker(workerName, workerURI) Promise(worker)
createLiquidWorkerArray({workerName, workerURI}[]) Promise(workers[])
pairDeviceWorkers(DeviceURI) Promise(DeviceURI)
postLiquidWorkerMessage(workerName, message) Promise(callResponse)
terminateLiquidWorker(workerName) Promise(workerName)

Liquid Worker API

Method Name Return Value
postMessage(message) Promise(callResponse)
_postMessage(message) Promise(callResponse)
terminate() Promise()

Assets (P2P) API

Method Name Return Value
requestAsset(name, deviceURI, type) Promise(script)
loadAsset(name, script) Promise(name)
getAsset(name) script
getLoadedAssets() names[]
Events
loadingChange(status)
Triggers when the Liquid.js library starts or ends fetching assets from the server or the client. The event carries the current loading status: true if Liquid.js is fetching or loading an asset, false otherwise

Device Connection API

Method Name Return Value
isSocketConnected() isSocketConnected
sendSocketCustomMessage(msg) -
socketDisconnect() -
connectDevice(deviceURI) Promise(deviceInfo)
disconnectDevice(deviceURI) Promise()
sendMessage(message) -
getConnectionList() connectedList
Events
connect(deviceID)
Triggers when the client connects to the server for the first time.
disconnect()
Triggers when the client disconnects from the server.
reconnect()
Triggers when the client reconnects to a server, this event is triggered instead of the connected event.
Custom Events
It is possible to use the socket connection opened by Liquid.js to communicate with the server side or allow the server to push custom data to the client. By sending a socketCustom message defined as {type, payload}, Liquid.js fires an event "type" with parameter "payload" on the receiving client.

Local Persistence API

Method Name Return Value
saveDeviceState(key) Promise(key)
loadDeviceState(key) Promise(key)
getAllDeviceState() Promise(deviceStateSummaries[])
getDeviceState(key) Promise(deviceStateSummary)
Method Name Return Value
saveComponentState(key, componentURI) Promise(key)
loadComponentState(key) Promise(key)
getAllComponentState() Promise(componentStateSummaries[])
getComponentState(key) Promise(componentStateSummary)
Method Name Return Value
savePropertyState(key, propertyURI) Promise(key)
getAllPropertyState() Promise(propertyStateValues[])
getPropertyState(key) Promise(propertyStateValue)

Technologies

Client-side

Server-side

Thank you

liquid.inf.usi.ch

Contact me:

Andrea Gallidabino

Software Institute

Faculty of Informatics

USI Lugano, Switzerland

andrea.gallidabino@usi.ch