HybridOS Specification 01-B
Topic: HybridOS View Markup Language
Author: Vincent Wei
Category: App Framework
Date: July 2019
Status: Proposal
Copyright Notice
Copyright (C) 2018, 2019 FMSoft Technologies
All Rights Reserved.
Table of Contents
- Introduction
- HVML Tags
- Other Extensions
- A Complete Sample
- The Implementation
Introduction
This specification describes the extended HTML 5.3 tags (HVML tags) supported by HybridOS, and the basic method to define a HybridOS app.
HVML
means HybridOS View Markup Language, which defines a few new tags
based on HTML 5.3.
In a typical Web app, a HTTP server may send a static HTML file to the web browser (the user agent), or generates a dynamic HTML content according to the request sent by the user agent.
If you want to utilize the benefits of Web app at client side (a PC or a mobile phone) without a remote HTTP server, a simple way is running a Web server on the client to feed the data to the user agent via HTTP. Essentially, this is the way used by electron, which is an open source framework to build cross-platform desktop apps.
HybridOS gives us an alternative for the same purpose, but in a different way:
-
In traditional Web app, a dynamic HTML document commonly generated by a HTTP server. But with HVML, the user agent can get data from various data producers, not only a Web server, but also a local service, a remote procedure call, a command line program, or a remote MQTT broker.
-
In essence, HVML is templated HTML. The data producer feeds data in JSON format to the user agent, the HVML parser in the user agent generates the ultimate HVML content by applying the data to a templated HVML file.
-
HVML gives the user agent the ability to generate dynamic content in-place. This reduces the load of a data producer. Indeed, HVML gives us a way to separate data and specific representation form (HTML tags).
-
The developer can extend HVML by define a customized view type easily. Generally, a view element is a complex widget, which can not be described and rendered easily by using the standard HTML elements and CSS. With HVML, a view element will be rendered in C++ language to gain the best performance, the developer can operate it in the standard Web interfaces (DOM/CSS/JavaScript).
HVML Tags
hvml
tag
First, the tag hvml
is a replacement of the tag html
, represents the
document is a HVML document.
<!DOCTYPE hvml>
<hvml>
<head>
...
</head>
<body>
...
</body>
</hvml>
archetype
and archedata
tags
HTML 5.3 introduced the template
tag. A template is a virtual element,
which can be used to generate other real elements by substituting some
attributes and inserting them to the DOM tree.
However, you still need to write a piece of script code to clone the template in HTML. But in HVML, you can use the following new tags to clone a template element without the script code:
-
archedata
: define the data in JSON format. -
archetype
: the HVML alias of HTMLtemplate
. -
iteration
: define an iteration. -
substitution
andcondition
: define a conditional substitution.
The tags iteration
and substitution
use the archedata defined in the
head element of a HVML document to clone an archetype element.
-
archedata
: like HTMLstyle
orscript
tags, this tag represents the archedata passed to the document. We use thetextContent
of an archedata element to define the real archedata, but the archedata must be in JSON format. Thename
attribute of this tag gives the name for the archedata, and the optional boolean attributeonce
tells the user agent whether to destroy the archedata after used the data. -
archetype
: this tag defines a template for HVML. The sub elements in an archetype element will be cloned and inserted to the HVML document. And the attributes, the text content, or the content of sub elements may be substituted by the data contained in the associated archedata element.
For example:
<!DOCTYPE hvml>
<hvml>
<head>
<archedata name="users" once>
[
{ "id": "1", "avatar": "/img/avatars/1.png", "name": "Tom", "region": "en_US" },
{ "id": "2", "avatar": "/img/avatars/2.png", "name": "Jerry", "region": "zh_CN" }
]
</archedata>
<archedata name="global">
{ "locale" : "zh_CN" }
</archedata>
</head>
<body>
<archetype id="footer-cn">
<p><a href="http://www.baidu.com">Baidu</a></p>
</archetype>
<archetype id="footer-tw">
<p><a href="http://www.bing.com">Bing</a></p>
</archetype>
<archetype id="footer-def">
<p><a href="http://www.google.com">Google</a></p>
</archetype>
<archetype id="user-item">
<li class="user-item" data-key="id" data-for="attribute::data-user-id">
<img data-key="avatar" data-for="attribute::src" />
<span data-key="name" data-for="textContent"></span>
</li>
</archetype>
<archetype id="no-user">
<li>
<img src="def-avatar.png" />
<p>Sign Up for the first user!</p>
</li>
</archetype>
<header>
<h1>User List</h1>
</header>
<main>
<ul>
<iteration archedata="$users">
<substitution archetype="user-item" />
</iteration>
</ul>
</main>
<footer class="footer">
<substitution>
<condition archetype="footer-cn" archedata="$global.locale" match-value="zh_CN" />
<condition archetype="footer-tw" archedata="$global.locale" match-pattern="^zh" />
<condition archetype="footer-def" />
</substitution>
</footer>
</body>
</hvml>
Data map
A simple way
For the sub elements in an archetype
element, we use one or two HVML specific
attributes to define the substitution rule. For example, in the above HVML document,
the attributes of the sub elements of the archetype
element with id="user-item"
will be substituted by values of the JSON object (an array) specified by
the archedata with name users
, one member of JSON array object for one iteration:
<li class="user-item" data-key="id" data-for="attribute::data-user-id">
<img data-key="avatar" data-for="attribute::src" />
<span data-key="name" data-for="textContent"></span>
</li>
The value of key id
will be set as the value of data-user-id
attribute of
cloned real li
element, and the value of key avatar
will be set as the value
of src
attribute of cloned real img
element, and so forth.
After the HVML document parsed, the cloned and inserted elements will be:
<ul>
<li class="user-item" data-user-id="1">
<img src="/img/avatars/1.png" />
<span>Tom</span>
</li>
<li class="user-item" data-user-id="2">
<img src="/img/avatars/2.png" />
<span>Jerry</span>
</li>
</ul>
Obviously, the archetype element defines a data-map relationship between an archedata element and the sub elements of the archetype element.
We can have many ways to define the data-map. The above method is a simple way, but not the best one. It has an obvious restrict that can not define multiple map relationship between archedata and archetype.
A better way
As an alternative, we can use the following way to define the data map:
<li class="user-item" datamap="attr.id: $@.id; attr.alt: $@.name">
<img datamap="attr.src: $@.avatar" />
<span datamap="textContent: $@.name"></span>
</li>
The alternative way uses only one attribute (datamap
) and can define multiple map
relationships.
In the above sample, we use a prefix $
to refer to a specific archedata:
-
$global.locale
: referring to the value oflocale
key of the archedata namedglobal
. -
$@
: the built-in variable, which means the current archedata item in the context of the iteration.
We may consider to use the following built-in variables like a Shell script:
-
$#
: the number of items of the current archedata when it is an array. -
$<N>
: the item with index value of<N>
of the current archedata when it is an array. -
$$
: the stringified form of the current JSON object. -
$&
: the current index value. -
$!
: a null array object.
Furthermore, it is possible to use simple string operations:
<li class="user-item" datamap="attr.id: 'user-' ^ $@.id; attr.alt: $@.name">
<img datamap="attr.src: $@.avatar" />
<span datamap="textContent: $@.name"></span>
</li>
In above code, the operator ^
concatenates two strings, like strcat
.
We could also consider to support some built-in string functions such as substr
.
iteration
tag
Use iteration
tag when you want to clone an archetype
element according to a
JSON array object specified by an archedata
element.
We may consider to add a HVML specific attribute for iteration
tag to define
the range of the index values available to visit the JSON array, for example:
<iteration archedata="$users" datarange="0, 10">
<substitution archetype="user-item" />
</iteration>
In above sample, we use datarange
attribute to define the index range of the
iteration like Python's range
function:
datarange="[start], stop[, step]"
The following datarange
defines the even index values:
datarange="0, $#, 2"
Or, you can use the following data range for iteration in reversed order:
datarange="$# - 1, -1, -1"
substitution
tag
Use substitution
tag when you want to substitute an element with a specific
archetype element.
<iteration archedata="$users" datarange="0, 10">
<substitution archedata="$@" archetype="user-item" />
</iteration>
condition
tag
Use condition
tag when you want to substitute an element under specific
condition:
<substitution archedata="$global">
<condition archetype="footer-cn" archedata=".locale"
match-value="zh_CN" />
<condition archetype="footer-tw" archedata=".locale"
match-value="zh_TW" />
<condition archetype="footer-def" />
</substitution>
In C++ language, above elements is equivalent to:
if (global.local == "zh_CN") {
// clone and insert the archetype with name 'footer-cn'
}
else if (global.local == "zh_TW") {
// clone and insert the archetype with name 'footer-tw'
}
else {
// clone and insert the archetype with name 'footer-def'
}
Because the archedata gives the value for global.local
with zh_CN
,
the above sample gives the following result:
<p><a href="http://www.baidu.com">Baidu</a></p>
We can consider to have another attribute match-pattern
for condition
tag, in
order to match the data with a regular expression, for example:
<substitution archedata="$global">
<condition archetype="footer-cn" archedata=".locale"
match-value="zh_CN" />
<condition archetype="footer-tw" archedata=".locale"
match-pattern="^zh" />
<condition archetype="footer-def" />
</substitution>
Or we can use logical expressions directly in condition
elements:
<substitution archedata="$global">
<condition archetype="footer-cn" ifmatch=".locale == 'zh_CN'" />
<condition archetype="footer-tw" ifmatch=".locale ~= '^zh'" />
<condition archetype="footer-def" />
</substitution>
In above code, the operator ==
means matching value, while the
operator ~=
means matching pattern.
nodata
tag
Like noscript
tag, when there is no archedata defined in the specific name,
or there is an error when referring to the data in the expressions,
you can use nodata
tag to define the elements to show:
<substitution archedata="$global">
<condition archetype="footer-cn" ifmatch=".locale == 'zh_CN'" />
<condition archetype="footer-tw" ifmatch=".locale ~= '^zh'" />
<condition archetype="footer-def" />
<nodata>
<p>There is no global data!</p>
</nodata>
</substitution>
or
<iteration archedata="$users">
<nodata>
<p>There is no users data!</p>
</nodata>
</iteration>
A complex usage
We can also use iteration
tag with substitution
and condition
tags.
For example:
<archetype id="user-item-cn">
<li class="user-item-cn" datamap="attr.id: $@.id">
<img datamap="attr.src: $@.avatar" />
用户名:<span datamap="textContent: $@.name"></span>
</li>
</archetype>
<iteration archetype="user-item" archedata="$users">
<substitution>
<condition archetype="user-item-cn" archedata="$@.region"
ifmatch="$global.locale == $@.region" />
</substitution>
</iteration>
The above sample will show one user only if the region of the user matches the locale.
hiview
tag
The HVML tag hiview
represents a complex widget which can not be described
and rendered easily by using the standard HTML 5.3 tags and CSS, for example,
a chart, a calendar, a meter panel, a watch face, a stop watch, and so on.
As we know, HTML 5.3 introduced some new tags especially the ones for
interaction, such as progress
, meter
, details
, summary
,
and dialog
. HVML provides well support for these tags.
However, if we want to show a complex widget, we either use a plugin or
use the canvas
to render them by using script. In order to reduce the
development efforts and improve the performance, we introduce the hiview
tag for HVML.
For example, to define a view with type TYPE
, we use the following HVML
tag hiview
:
<hiview type="TYPE" design="DEFAULT"
class="CLASS" id="IDENTIFIER"
name="NAME" value="VALUE" state=""
width="INTRINSIC WIDTH" height="INTRINSIC HEIGHT">
<param name="PARAM0" value="VALUE0">
<param name="PARAM1" value="VALUE1">
</hiview>
Note that two attributes are must for a view element:
-
type
: this attribute is used to distinguish between different view types, such as watch face, circular meter, etc. -
design
: this attribute is used to distinguish between different designs (implementations) for a specific view type. -
vendor
: this attribute is optional, and used to specify the particular vendor of the view. -
name
: this attribute is used to include ahiview
element in a form. -
value
: this attribute specifies the value of thehiview
element. -
state
: this attribute reflects the work state of thehiview
element; it is a read-only attribute.
Also note that, in above markup statements, the width
and height
attributes
define the intrinsic size of the view element. Like canvas
element, if
no width
and/or height
provided, the user agent should use 200
and 150
for the default values of these two attributes.
The main reason we introduce hiview
tag is that one app developer can
easily extend HVML with a simple mechanism, especially in performance-first
situations.
The other reason is that we can provide a customized implementation for a specific view type, but keep the API steady. The app developer can interact with a view element always in the same API, but the view instance may be rendered in a different way. Moreover, the app developer can set/get the attributes of the view instance by using the standard DOM interface.
Therefore, the user agent must provide a way to implement a new view type at the app side (in C++ language).
For example, the following HVML code defines a watch face:
<view type="watchface" design="default"
class="CLASS" id="IDENTIFIER" width="400" height="400"
name="clock" value="9:45:03" state="">
<param name="action" value="move" />
<param name="hands" value="hour,minute,second" />
</view>
The attribute value
of a view element can be used to get/set
the value which the view element represents. For example,
if we want to get the current time of the watch face, we read the
value of value
attribute.
The attribute state
of a view element can be used to get
the current state of the widget.
On the other hand, we use param
child elements for the set-only
properties of a view element, that is, the descendant param
elements
of a view element will be used only to pass the setting parameters of
the view element.
The user agent can implement this view type as a built-in view type. Or the developer can implement the view type like a plugin. Indeed, we can handle a customized view type as a light-weight plugin, but a view will have better integration with other DOM elements and script:
- A script can access/change the content of a view element by accessing
value
attribute of the element. - A script can change the content of the view element by setting the
param
child elements of the view element by using the standard DOM interfaces. For example, the script can change the parameterhands
to change the visible hands of the watch face. - A script can listen to the DOM events of a view element to interact with the user and other DOM elements.
Generally, the attributes of a view element are two-way. If the view
itself changes an attribute, the app can get it by reading the value
of the attribute. However, the parameters passed through param
elements
will not changed by the view itself, that is, they are one-way.
We need to define a specification for the customized view type:
- The user agent should provide a set of graphics interfaces for rendering the view content in C/C++ language.
- The user agent should provide an event handling model for user interaction and the customized events of DOM in C/C++ language.
- The API above should be cross-platform.
We can consider to implement the view types for different specific application
scenes in different shared libraries. Generally, the user agent will try to
load a shared library named libview-<TYPE>-<DESGIN>.so
for
the specific view type and design.
As another sample, we can implement a simple animation view element:
<hiview type="animation" design="default"
class="CLASS" id="IDENTIFIER"
name="NAME" value="0"
width="600" height="400">
<param name="interval" value="20ms" />
<param name="loop" value="yes" />
<hipl name="images">
<param src="1.png" value="0 0" />
<param src="2.png" value="100 100 2x" />
<param src="3.png" value="1x 5s" />
<param src="4.png" value="1s" />
</hipl>
</hiview>
The view of type animation
uses a set of static images to build an animation,
just like a GIF file. The value of the value
attribute indicates the
current index of the image which is being shown.
Note that we introduce a new hipl
element. A hipl
element will
be used to group a list of parameters for easily referring to them. The user
agent will give default names (with a postfix of the indices on the name of
the hipl
element) for the param
elements in a hipl
element.
The parameter named interval
defines the default interval between two
frames. The parameter named loop
defines whether repeating the
playback of the animation. The parameter list named images
defines the source of
the static images in the play order by using the src
attribute, and the offset
and the scale factor for each image by using the value
attribute.
We use src
attribute to define the extra foreign content for a parameter,
because we can utilize the user agent to fetch the content easily, and the
view renderer do not need to fetch the content by itself.
The string for value
attribute gives the following information for each image:
[offset-x offset-y] [<scale-factor>x] [<overrided-delay-time><s|ms>]
As the last sample, we can implement a view type for stopwatch:
<hiview type="stopwatch" design="analog"
class="CLASS" id="IDENTIFIER"
name="NAME" value="0" state=""
width="600" height="400">
<param name="action" value="start" />
<param name="faces" value="second, minute, hour, digits" />
<param name="secondscale" value="60" />
<param name="minutescale" value="60" />
<param name="hourscale" value="24" />
<param src="dida.mp3" name="ticktack" value="loop, always" />
</hiview>
The parameter:
-
action
gives a chance to change the work status of the stopwatch; can be one of the following values:reset
start
pause
stop
new
-
faces
gives a list indicating whether to show the second face, the minute face, the hour face, and the digits time. -
secondscale
gives the scale of the second face. -
minutescale
gives the scale of the minute face. -
hourscale
gives the scale of the hour face. -
tictac
gives how to play the tick-tack sound, andsrc
attribute specify the foreign content for the sound.
View events
Every view type will have its own events to interact with the app.
For example, the watchface
view may fire the following events if the value
of the parameter move
is auto
.
-
onHandsMoved
: indicating that one hand moved, with an event parameter indicating which hands moved, for example, "minute, second" means the minute hand and the second hand were moved.
The animation
view can fire the following events:
-
onImageChanged
: indicating a new image shown, with an event parameter indicating the index value of the new static image. And the attributevalue
will reflect the index value. -
onStopped
: indicating the playback stopped (only available when the value of the parameterloop
is notyes
).
The stopwatch
view can fire the following events:
-
onStarted
: -
onPaused
: -
onResumed
: -
onStopped
:
New widgets
Like the standard object
and embed
elements of HTML, hiview
element
gives us another way to extent ability of a user agent.
Generally, a vendor of a view type can implement the view type in a shared library or as an executable. The user agent can dynamically load the implementation of a particular view type and copy the rendering result to the webpage. In other words, the implementation of a view type works as a plugin of the user agent.
As an alternative, we can consider to implement some popular view types as built-in widget elements, in order to reduce the development effort.
himeter
tag and hihand
tag
For example, we can introduce himeter
tag and hihand
tag, which together
define a meter with multiple hands:
<himeter class="CLASS" id="IDENTIFIER">
<hihand class="speed" name="speed"
type="needle" width="600" height="400"
min="0" max="220" value="0" />
<hihand class="oil" name="oil"
type="annulus" width="400" height="400"
min="0" max="1" value="0" />
</himeter>
By default, the user agent will render a hihand
element with a default shape.
However, the developer can use an external SVG file or image to define the
shape of a hand:
<himeter class="CLASS" id="IDENTIFIER">
<hihand class="speed" name="speed"
type="needle" width="600" height="400"
src="speed.svg" min="0" max="220" value="0" />
<hihand class="oil" name="oil"
type="annulus" width="400" height="400"
src="oil-hand.png" min="0" min="0" max="1" value="0" />
</himeter>
A hihand
element will use the following attributes:
-
type
defines the type of hand, can beneedle
orannulus
. If not specified, the user agent usesneedle
as the default. -
width
andheight
define the intrinsic size of the element. If not specified, use200
and150
as the default values for these two attributes. -
src
specifies the shape of the hand by using an external content (SVG or image):- If the type is
needle
, it is the shape at the zero position (when it stands up vertically); the user agent will rotate the shape to reflect a new value. If not specified, the user agent will use a default shape (an elongate rectangle) for the hand (the DEFAULT hand). - If the type is
annulus
, it should be the whole shape of an annulus. The user agent will clip the shape to reflect the starting angle, the end angle, and the value of the hand. If not specified, the user agent will use the the values of CSS properties of-hi-annulus-XXX
to render the hand (the DEFAULT hand).
- If the type is
-
min
,max
, andvalue
define the minimal value, maximal value and the current value of the hand in floats. The default values will be 0, 1, and 0 for these attributes respectively. -
low
,high
, andoptimum
attributes: The user agent will use these attributes for other rendering properties of the hand likemeter
element of HTML5.
CSS properties for hand
In order to control the hand easily, we may consider to introduce some new CSS properties to control the rendering manner of a hand. In this way, we can utilize the CSS transition and/or CSS animation to simplify the interaction between the script and the element.
For this reason, we introduce a set of CSS properties for the hand of a circular meter:
-
-hi-min
: the minimal value of the hand in float; the initial value is equal to the value ofmin
attribute. -
-hi-max
: the maximal value of the hand in float; the initial value is equal to the value ofmax
attribute. -
-hi-value
: the current value of the hand in float; the initial value is equal to the value ofvalue
attribute. -
-hi-hand-starting-angel
: the starting angel of the hand, in degrees or radians; the initial value is0deg
. -
-hi-hand-end-angel
: the end position of the hand, in degrees or radians; the initial value is360deg
. -
-hi-hand-center-x
: the x-coordinate of the center in the hand canvas; the initial value is 50% (of intrinsic width). -
-hi-hand-center-y
: the y-coordinate of the center in the hand canvas; the initial value is 50% (of intrinsic height). -
-hi-hand-transform
: use this property to specify the transform matrix for the loaded hand shape (only apply to the loaded hand shape specified bysrc
attribute). -
-hi-hand-fill-style
: likebackground
property, the author can specify the fill style of the hand by usingsolid
,pattern
,linear-gradient
,radial-gradient
, ornormal-gradient
.
For a hand element, we also introduce the following pseudo elements
like HTML5 meter
element:
-
::-hi-hand-optimum-value
: The author can use this pseudo element to define the border and the fill style when the value is optimum for the DEFAULT hand. -
::-hi-hand-suboptimum-value
: The author use this pseudo element to define the border and the fill style when the value is suboptimum for the DEFAULT hand. -
::-hi-hand-even-less-good-value
: The author can use this pseudo element to define the border and the fill style when the value is even less good for the DEFAULT hand.
For the purpose of the pseudo elements and the usage, please refer to:
https://css-tricks.com/html5-meter-element/
Properties specific to a needle hand:
-
-hi-needle-anchor-x
: the x-coordinate of the anchor on the hand as opposed to the bottom-left corner of the hand at zero position; the initial value is 0. This property only works when the hand type is needle. -
-hi-needle-anchor-y
: the y-coordinate of the anchor on the hand as opposed to the bottom-left corner of the hand at zero position; the initial value is 0. This property only works when the hand type is needle.
Properties specific to an annulus hand:
-
-hi-annulus-inner-radius
: the radius of the inner circle of the annulus; the initial value is25%
(of intrinsic height). -
-hi-annulus-outer-radius
: the radius of the outer circle of the annulus; the initial value is50%
(of intrinsic height).
Optional properties:
-
-hi-hand-center
: the shorthand for-hi-hand-center-x
and-hi-hand-center-y
. -
-hi-needle-anchor
: the shorthand for-hi-needle-anchor-x
and-hi-needle-anchor-y
. -
-hi-annulus-radii
: the shorthand for-hi-annulus-inner-radius
and-hi-annulus-outer-radius
.
Note that -hi-min
, -hi-max
, and -hi-value
properties will
be bound to min
, max
, and value
attributes of a hand
element
respectively.
<head>
<style type="text/css">
hihand.speedo {
-hi-min: 0;
-hi-max: 1;
-hi-value: 0.5;
-hi-hand-starting-angel: 180deg;
-hi-hand-end-angel: 360deg;
-hi-hand-center: 50% 50%;
transition: -hi-value 200ms ease-out;
}
</style>
</head>
...
<himeter id="IDENTIFIER">
<hihand class="speedo" name="speed"
type="needle" width="400" height="400"
min="0" max="100" value="60"
low="60" high="90" optimum="59" />
</himeter>
If we change the value of -hi-value
property, the pointer will
move from the old position to the new position with a transition effect
in ease-out
timing function within 200ms.
Note that the attributes min
, max
, and value
define the logical
range and value of the hand, and the CSS properties with prefix
-hi-hand
define the parameters for hand rendering.
The user agent should bind the value
attribute and the -hi-value
property. That is, the effect of changing the value of the value
attribute
and changing the value of the -hi-value
is the same.
Use hand for circular progress widget
Similarly, we can implement a widget of circular progress, so we can easily define the animations or transitions for our progress widget by using CSS.
<head>
<style type="text/css">
hihand.onefile {
-hi-value: 90;
-hi-hand-starting-angel: 180deg;
-hi-hand-end-angel: 360deg;
-hi-hand-center: 50% 50%;
transition: -hi-value 200ms ease-out;
}
hihand.totle {
-hi-value: 10;
-hi-hand-starting-angel: 180deg;
-hi-hand-end-angel: 360deg;
-hi-hand-center: 50% 50%;
transition: -hi-value 200ms ease-out;
}
</style>
</head>
...
<himeter id="IDENTIFIER">
<hihand class="onefile"
type="annulus" width="600" height="600"
min="0" max="100" value="60" />
<hihand class="total"
type="annulus" width="400" height="400"
min="0" max="100" value="60" />
</himeter>
hipicker
tag and hiitem
tag
As another example, we introduce hipicker
tag and hiitem
tag,
which define a wheel picker:
<div class="CLASS" id="IDENTIFIER">
<hipicker type="text" class="year-picker"
name="year" value="2019"
width="100" height="400"
sound="dee.mp3">
<hiitem value="2010">2010 年</hiitem>
<hiitem value="2011">2011 年</hiitem>
<hiitem value="2012">2012 年</hiitem>
<hiitem value="2013">2013 年</hiitem>
<hiitem value="2014">2014 年</hiitem>
<hiitem value="2015">2015 年</hiitem>
<hiitem value="2016">2016 年</hiitem>
<hiitem value="2017">2017 年</hiitem>
<hiitem value="2018">2018 年</hiitem>
<hiitem value="2019">2019 年</hiitem>
</hipicker>
<hipicker type="text" class="month-picker"
name="month" value="1"
endtoend
width="100" height="400"
sound="dee.mp3">
<hiitem value="1">一月</hiitem>
<hiitem value="2">二月</hiitem>
<hiitem value="3">三月</hiitem>
<hiitem value="4">四月</hiitem>
<hiitem value="5">五月</hiitem>
<hiitem value="6">六月</hiitem>
<hiitem value="7">七月</hiitem>
<hiitem value="8">八月</hiitem>
<hiitem value="9">九月</hiitem>
<hiitem value="10">十月</hiitem>
<hiitem value="11">十一月</hiitem>
<hiitem value="12">十二月</hiitem>
</hipicker>
<hipicker type="integer" class="day-picker"
name="day" value="1"
min="1" max="31" step="1"
endtoend
width="100" height="400"
sound="dee.mp3">
</hipicker>
</div>
Note that the attribute endtoend
is a boolean attribute.
In order to control the wheel picker easily, we consider to introduce some new CSS properties to control the rendering manner of the element.
First, we introduce the following pseudo element for the high lighted item (the current selected item):
-
::-hi-picker-selected
: The author can use this pseudo element to define the size, border, font, and color for the selected item. -
::-hi-picker-selected-before
: The author can use this pseudo element to define the size, border, font, color, and content for the text before selected item. -
::-hi-picker-selected-after
: The author can use this pseudo element to define the size, border, font, color, and content for the text after selected item. -
::-hi-picker-items
: The author can use this pseudo element to define the size, border, font, color, and mask for the visible items.
Second, we introduce a set of CSS properties for the picker to control the rendering manner:
-
-hi-picker-rotate-y
: the rotation angle of the whole wheel; the initial value is 0deg. -
-hi-picker-damping-factor
: the damping factor of the wheel, a float, the initial value is 100.
The rendering of the wheel picker should create a physical model to hand the rotation of the wheel under the operation by touch or mouse.
The following events should be supported for interacting with the picker:
-
onchange
: fired when the selected item changed. -
onpickstart
: fired when the picker starts rotating. -
onpickend
: fired when the picker stops rotating.
Data Binding
By using HVML, we can define the binding relationship between an attribute or the content of an element and others. For example:
<hiview id="theStopWatch" type="stopwatch" design="analog"
class="CLASS" id="IDENTIFIER"
name="NAME" value="0" state=""
width="600" height="400">
<param name="action" value="start" />
<param name="faces" value="second, minute, hour, digits" />
<param name="secondscale" value="60" />
<param name="minutescale" value="60" />
<param name="hourscale" value="24" />
<param src="dida.mp3" name="ticktack" value="loop, always" />
</hiview>
<p databind="textContent: #theStopWatch.attr.value"></p>
In the above sample, we use databind
attribute to define a binding
relationship between the text content of the p
element and the
attribute value
of the hiview
element:
The initial text content of the p
element will come from the value
of the attribute value
of the hiview
element. And if the latter
changed, the text content of the p
element will automatically
change in turn.
In this way, we can reduce the development effort of the script code and improve the rendering performance of the page to some extent.
Furthermore, we may consider to use CSS selector to define the binding relationship as follows:
<hiview type="stopwatch" design="analog"
class="stopwatch" id="IDENTIFIER"
name="NAME" value="0" state=""
width="600" height="400">
<param name="action" value="start" />
<param name="faces" value="second, minute, hour, digits" />
<param name="secondscale" value="60" />
<param name="minutescale" value="60" />
<param name="hourscale" value="24" />
<param src="dida.mp3" name="ticktack" value="loop, always" />
</hiview>
<hiview type="stopwatch" design="analog"
class="stopwatch" id="IDENTIFIER"
name="NAME" value="0" state=""
width="600" height="400">
<param name="action" value="start" />
<param name="faces" value="second, minute, hour, digits" />
<param name="secondscale" value="60" />
<param name="minutescale" value="60" />
<param name="hourscale" value="24" />
<param src="dida.mp3" name="ticktack" value="loop, always" />
</hiview>
<p>
<span databind="textContent: (hiview.stopwatch)[0].attr.value"></span>
<span databind="textContent: (hiview.stopwatch)[1].attr.value"></span>
</p>
The above code define two binding relationships. The former uses the value of
the attribute value
of the first hiview
element with class stopwatch
,
and the latter uses the second.
However, this method can bring a large performance loss.
Get data from a separate data source
By using the data map, we can use HVML to separate data and specific representations. That is, the data producer generates the data always in JSON format, but the data consumer represents the data in HVML/HTML or other format. In other words, the data producer will not necessarily be an HTTP server.
For compatibility, we can define the archedata either in the HVML document, or get from another data source by sending a HTTP request, or a MQTT broker, or a hiBus command executor. After we get the archedata from a separate data source, we can tell the HVML parser to override the archedata defined in the header of the HVML document when loading the document. Thus, the HVML document will be a template for representing the data.
However, the standard Web specification does not support this manner. So we need to define a way for this purpose.
-
Solution 1:
We can introduce a newdatasrc
attribute to define the data source. For example, for an element<a>
, the user agent usesdatasrc
attribute to get the archedata, and useshref
attribute to load the HVML document. -
Solution 2:
We can define a new transfer protocol (like HTTP), which returns the archedata along with the URL of HVML document. But the solution does not separate the data and the representation. -
Solution 3:
We can use alink
element orsrc
attribute ofarchedata
element inhead
element to define the data source of the archedata for the HVML document. When the data is being fetched, the user agent renders the HVML document with thenodata
element, after the archedata been fetched and got ready, the user agent re-renders the HVML document by applying the archedata to the templated elements.
We prefer to use Solution 3, because this solution is compatible with the current Web app technologies. For example:
<!DOCTYPE hvml>
<hvml name="firstSample" root="/firstSample/index.hvml"
manifest="firstSample.appcache">
<!-- the assets of the app, such as the activities, archedata, and L10N text -->
<head>
<archedata name="users"
src="https://company.com/get-user-list?start=0&count=10" />
<!-- the links to the localization translation files -->
<link rel="localization preload" type="text/json"
href="/firstSample/assets/messages/" />
</head>
<body>
...
</body>
</hvml>
In order to support getting data from variable data producers, we will introduce some new schemas for URL. For more information, please refer to New URL schemas.
In the following samples, we use hibus as the new schema, which gets the data from a hiBus command executor:
hibus://self/get-user-list?start=0&count=10
Please note the GET parameters in the above URL. The parameters is generated from the intent data when you launch the activity.
L10N
Different from webpages, HVML handles the L10N text as an asset of an app. HAE (the HVML user agent) loads the L10N file in JSON and translate the localization text according to the identifier.
For easy localization, we introduce a new section L10N
for HVML:
<h1><!L10N[[STRID_TITLE]]></h1>
<p>
<!L10N[[Welcome to the world of <em>HybridOS</em>!]]>
</p>
The content of a L10N text file will look like:
{
"app": "第一个示例",
"locale": "zh_CN",
"STRID_TITLE": "HybridOS 的第一个示例应用",
"STRID_COPYRING": "版权所有 (C) 2018 飞漫软件",
"Welcome to the world of <em>HybridOS</em>!": "欢迎来到 <em>HybridOS</em> 的世界!",
}
We can consider app
and locale
are reserved keywords for L10N text file.
But how to specify the L10N file?
-
Solution 1:
We can specify the L10N text file in the head element of a HVML document as alink
element. Under this solution, the HVML parser should get the correct L10N file ready before it parses the body. In other words, the link types should have the keywordpreload
, so that the user agent can preemptively fetch and cache the target resource. -
Solution 2:
Direct the user agent load the correct L10N files in the root HVML document of an app, and make the L10N JSON object available for all HVML documents of the app. For this solution, we need to introduce the following new concepts:- The root document or index document of an HVML app.
It seams that Solution 1 is better than Solution 2. However, the root document of an HVML app can act more roles in HybridOS. We can define the L10N file for the app, and define the activities can be called by other modules.
Therefore, we introduce a new attribute for the top-most hvml
element: root
.
-
root
: The root document of the current HVML document. All documents have the same value forroot
attribute belongs to the same app.
The following sample uses root
attribute and defines the global L10N files to
load for the current app.
Generally, we can use the cache manifest to cache the L10N files.
<!DOCTYPE hvml>
<hvml name="firstSample" root="/firstSample/index.hvml"
manifest="firstSample.appcache">
<!-- define the assets of the app, such as the activities and L10N text -->
<head>
<!-- the links to the localization translation files -->
<link rel="localization preload" type="text/json"
href="/firstSample/assets/messages/" />
</head>
<body>
...
</body>
</hvml>
Note that for link with new type localization
or l10n
, the user agent should
append the correct locale in ISO 639-2 and ISO 3166 codes to href
to fetch the
real L10N file, e.g., /firstSample/assets/messages/zh_CN.json
.
HVML tag types
As described in above sections, we introduce nine new tags. These HVML tags can be divided into three types:
- Virtual tags. A virtual tag will not generate a real DOM elements.
It will directs the HVML parser to clone a template and insert a
real element into the DOM tree. The tags
iteration
,substitution
, andcondition
are virtual tags. - Real tags. A real tag of HVML will generate a real DOM element.
The tag
archedata
,activity
, andview
are real tags. - Special tags. A special tag will generate a real element, but in
a separate and virtual DOM tree. The tag
archetype
is a special tag.
HVML and CSS
You can apply CSS to any real HVML element, but not to virtual tags and special tags.
Other Extensions
A new MIME type for HVML
text/hvml
is a new MIME type for HVML document.
New URL schemas
For a Web app, the user agent generally requests a URL with GET or POST method via HTTP, and wait for the response data from the Web server.
When using HVML, we not only can get the response data from a Web server, but also from a local or remote service.
Therefore, we introduce the following new schemas to send a request to a local or remote service to get the data:
-
hibus
: -
mqtt
: -
sql
: -
xml
: -
etc
: -
cmd
:
Extended features
In HVML, we will provide some extended features for device and/or client apps:
- Extended DOM interfaces for activity, archetype, and archedata.
- hiBus interfaces to interact with the local system services or other modules.
- MQTT interfaces to communicate with a MQTT broker.
A Complete Sample
In this section, we provide a sample to show how the HybridOS View Markup Language works. In this sample, we show a user list with avatars and user names. When you clicked on a user item, the app will show the detailed information of the user.
The following markup statements define the app:
<!DOCTYPE hvml>
<hvml name="firstSample" index="/firstSample/index.hvml">
<!-- the assets of the app, such as the activities and L10N text -->
<head>
<meta name="activity" content="index" />
<!-- all exported activities -->
<activity name="act-user-list"
href="/firstSampe/userlist.hvml" />
<activity name="act-user-info"
href="/firstSampe/userinfo.hvml" />
<!-- the link to the localization translation file -->
<link rel="localization preload" type="text/json"
href="/firstSample/assets/messages/" />
<link rel="stylesheet" type="text/css"
href="/firstSample/assets/default.css" />
</head>
<body>
<main>
<img class="splash" src="file:///firstSample/assets/images/splash.png" />
</main>
<script>
/* launcher userList activity */
launchActivity ("act-user-list", {count: 10});
</script>
</body>
</hvml>
The following markup statements define the user list activity:
<!DOCTYPE hvml>
<!-- The user list activity -->
<hvml name="firstSample" root="/firstSample/index.hvml">
<head>
<meta name="activity" content="act-user-list" />
<!-- get archedata from hiBus -->
<archedata name="users" once
src="datasrc="hibus://self/get-user-list" />
<!-- an embedded archedata -->
<archedata name="global">
{ "locale" : "zh_CN" }
</archedata>
<!-- the activities will be used by this activity -->
<activity name="act-user-info"
href="/firstSampe/userinfo.hvml" />
<!-- the link to the localization translation file -->
<link rel="localization preload" type="text/json"
href="/firstSample/assets/messages/" />
<!-- ignored jquery javascript links here -->
</head>
<body>
<!-- define archetypes for future use -->
<archetype id="user-item">
<li class="user-item" datamap="attr.id: 'user-' ^ $@.id">
<img datamap="attr.src: $@.avatar" />
<span datamap="textContent: $@.name"></span>
</li>
</archetype>
<archetype id="footer-cn">
<p><a href="http://www.baidu.com">Baidu</a></p>
</archetype>
<archetype id="footer-tw">
<p><a href="http://www.bing.com">Bing</a></p>
</archetype>
<archetype id="footer-def">
<p><a href="http://www.google.com">Google</a></p>
</archetype>
<header>
<h1 name="theHeader" class="panel-header"><!L10N[[STRID_TITLE]]></h1>
</header>
<main>
<ul>
<iteration archetype="user-item" archedata="$users">
<substitution>
<condition archetype="user-item"
ifmatch="$@.region == $global.locale" />
</substitution>
<nodata>
<li class="no-users"></li>
</nodata>
</iteration>
</ul>
</main>
<footer class="footer">
<substitution>
<condition archetype="footer-cn"
ifmatch="$global.locale == 'zh_CN'" />
<condition archetype="footer-tw"
ifmatch="$global.locale ~= '^zh'" />
<condition archetype="footer-def" />
<nodata>
<p class="no-footer"></p>
</nodata>
</substitution>
<p class="footer-copying"><!L10N[[STRID_COPYING]]></p>
</footer>
<script>
/* bind the click event of userItem */
$(".user-item").on ('click', function ($item) {
/* launcher userInfo activity */
launchActivity ("act-user-info", {id: $item.id});
});
</script>
</body>
</hvml>
The following markup statements define the user information activity:
<!DOCTYPE hvml>
<!-- The user information activity -->
<hvml name="firstSample" root="/firstSample/index.hvml">
<head>
<meta name="activity" content="act-user-info" />
<!-- get user info from hiBus -->
<archedata name="user-info" once
src="hibus://self/get-user-info" />
<!-- the link to the localization translation file -->
<link rel="localization preload" type="text/json"
href="/firstSample/assets/messages/" />
<!-- ignored jquery javascript links here -->
</head>
<body>
...
</body>
</hvml>
The Implementation
The implementation of HVML will be based on the latest WebKit. Therefore, the latest HTML5/CSS technologies will be supported well, for example:
- canvas and canvas object.
- WebStorage
- WebSocket
- Geolocation
- SVG
- MathML
- Audio
- Video
Because it is an extension of standard HTML, so the implementation,
named hiWebKit
, is a WebKit derivative.
For more information, please refer to hiWebKit.
The following words are deprecated...
[DELETED] For a watchface
type, we may also use some of the CSS properties above
to define the parameters for the hands rendering.
By using this design, we can keep view
element for customized widgets
as simple as possible, for example:
<view type="watchface" design="default"
class="CLASS" id="IDENTIFIER" width="400" height="400"
name="clock" value="9:45:03"
va-move="static">
<param name="hands" value="hour,minute,second" />
</view>
Parameters and options (deprecated)
NOTE: The text in this section is deprecated.
[DELETED] For the parameter named images
above, it is boring to use only one param
element to define the images. We can consider to extend the param
element.
[DELETED] On the other hand, if we want to utilize the benefits of HVML, we can also
introduce a new tag paramlist
, so that we can use iteration
tag to clone the
parameters based on archedata easily.
[DELETE] In the above code, all param
elements in a paramlist
element have
no attribute name
defined. The user agent will give a default name for
such param
element: images-0
~ images-N
.
We can use multiple param
elements to define parameters for a view, for example:
<view type="animation" class="CLASS" id="IDENTIFIER" width="600" height="400"
data-interval="20s" data-loop="yes">
<param name="image0" value="1.png 0 0" />
<param name="image1" value="2.png 100 100 2x" />
<param name="image2" value="3.png 1x 5s" />
<param name="image3" value="4.png 1s">
</view>
If we have many parameters need to be grouped, we can use optgroup
and option
tags to define the parameters. For example, we can use the following HVML
statements to defines the points of a set of curves:
<optgroup name="points0" label="Volume">
<option value="0 0">Q1</option>
<option value="1 1">Q2</option>
<option value="2 2">Q3</option>
<option value="3 3">Q4</option>
</optgroup>
<optgroup name="points1" label="Profit">
<option value="0 0">Q1</option>
<option value="1 2">Q2</option>
<option value="2 4">Q3</option>
<option value="3 6">Q4</option>
</optgroup>
As another example, if we implement a wheelpicker
view, for a date picker,
we can use the following statements:
<archtype id="auto-option">
<option datamap="attr.value: $&; textContent: $&"></option>
</archtype>
<div class="CLASS" name="NAME" id="IDENTIFIER">
<view type="wheelpicker" design="default" class="year-picker"
name="year" value="2019"
width="100" height="400"
data-move-sound="dee.mp3">
<option value="2010">2010</option>
<option value="2011">2011</option>
<option value="2012">2012</option>
<option value="2013">2013</option>
<option value="2014">2014</option>
<option value="2015">2015</option>
<option value="2016">2016</option>
<option value="2017">2017</option>
<option value="2018">2018</option>
<option value="2019">2019</option>
</view>
<view type="wheelpicker" design="default" class="month-picker"
name="month" value="1"
width="100" height="400"
data-move-sound="dee.mp3">
<iteration archedata="$!" datarange="1, 12">
<substitution archetype="auto-option" />
</iteration>
</view>
<view type="wheelpicker" design="default" class="day-picker"
name="day" value="1"
width="100" height="400"
data-move-sound="dee.mp3">
<iteration archedata="$!" datarange="1, 31">
<substitution archetype="auto-option" />
</iteration>
</view>
</view>
Note that, in the statements above, we use iteration
tag to automatically
generate the parameter list for month and day values.
Note that, the view type should declare whether use param
or option
to
define the parameters. And the value of the name
attribute of a param
or optgroup
element should be defined by the view type.
Meter with multiple hands (deprecated)
NOTE: The text in this section is deprecated.
If we want to support multiple hands for a meter, we can consider
to extend the tag param
; each param
element defines one hand:
<view type="himeter" design="default" class="CLASS" name="NAME" id="IDENTIFIER"
width="400" height="400">
<param class="speed" name="hand-speed" min="0" max="220" value="0" />
<param class="oil" name="hand-oil" min="0" max="1" value="0" />
</view>
In the above statement, we use param
tags to define the hands of
an himeter
view. We extend the attributes of the param
element
to include the min
, max
attributes. We can also use the
low
, high
, and optimum
attributes for further usage.
We can even define a watch face with the following HVML statement:
<view type="himeter" design="default" class="watchface" name="NAME" id="IDENTIFIER"
width="400" height="400">
<param class="hour" name="hand-hour" min="0" max="12" value="3" />
<param class="minute" name="hand-minute" min="0" max="60" value="20" />
<param class="second" name="hand-second" min="0" max="60" value="00" />
</view>
However, if we use himeter
view to implement a watch face, it seems that
the usage will be more complicated than the watchface
view.
Container view (deprecated)
NOTE: The text in this section is deprecated.
We can consider to support a hierarchy for views, for example, we
can introduce a logical container
view, and the children views can
be contained in it. As a result, we can re-write the meter with
multiple hands in the following statements:
<head>
<style type="text/css">
view.speed {
-hi-value: 200deg;
-hi-hand-starting-angel: 200deg;
-hi-hand-end-angel: 300deg;
-hi-hand-center: 50% 50%;
}
view.oil {
-hi-value: 200deg;
-hi-hand-starting-angel: 200deg;
-hi-hand-end-angel: 300deg;
-hi-hand-center: 50% 0;
}
view.watch {
-hi-hand-center: 50% 50%;
}
</style>
</head>
...
<view type="container" class="CLASS" name="NAME" id="IDENTIFIER"
width="600" height="400">
<view type="himeter" design="default" class="speed" name="speed"
left="0" top="0" width="400" height="400"
min="0" max="220" value="0">
</view>
<view type="himeter" design="default" class="oil" name="oil"
left="0" top="300" width="400" height="100"
min="0" max="1" value="0">
</view>
<view type="watchface" design="default" class="watch" name="watch"
left="400" top="100" width="200" height="200"
data-time="9:45:03" data-move="auto">
<param name="hands" value="hour,minute" />
</view>
</view>
Note that for all views acting as children views of a container, they should share the same canvas (the rendering surface) of the container. In this way, we will save the memory use and improve the rendering performance.
Otherwise, if your app is a simple one, you can organize your code in the following manner to use only one file:
<!DOCTYPE hvml>
<hvml name="firstSample" lang="en">
<head>
<meta name="activity:act-user-list" content="userlist.html" />
<meta name="activity:act-user-info" content="userinfo.html" />
<meta name="img:defAvatar" content="/firstSample/assets/default.css" />
<link rel="localtext" type="text/json" href="/firstSample/assets/messages/zh_CN.json" />
<link rel="stylesheet" type="text/css" href="/firstSample/assets/default.css" />
</head>
<activity id="act-user-list" hbd-scope="firstSample">
...
</activity>
<activity id="act-user-info" hbd-scope="firstSample">
...
</activity>
<script>
...
</script>
</hvml>
We use a HTML document to define an activity. However, different from HTML, we can define multiple view clients for one activity, and at the same time, only one view client can be kept active. The other view clients are virtual and invisible from the users.
In a view
or archetype
, we use the standard sectioning and/or heading
content tags of HTML5 to define the structure of the view:
-
article
,aside
,nav
,section
-
header
,footer
,main
,div
-
ul
,ol
,dl
address
blockquote
figure
details
and use the following tags to define the text paragraphs:
-
h1
,h2
,h3
,h4
,h5
,h6
-
p
,prev
-
li
,dt
,dd
summary
figcaption
In a text paragraph, we use the phrasing content elements (text-level elements and embedded elements) of HTML5 to define the content. Therefore, you can use the following HTML5 tags:
-
The text-level elements:
-
a
,abbr
,b
,bdi
,bdo
,br
,cite
,code
,data
,datalist
-
del
,dfn
,em
,i
,ins
,kbd
,label
,mark
, -
output
,q
,ruby
,s
,samp
,small
,span
-
strong
,sub
,sup
,time
,u
,var
,wbr
-
-
The embedded elements:
-
img
,button
,input
,math
,meter
,picture
,progress
-
math
,svg
, -
audio
,video
-
Tag properties
-
class
: A global HTML5 property, which specifies the class of the view. -
name
: A global HTML5 property, which specifies the name of an app, an activity, a view, or a archetype, Generally, the value of this property will be a variable which you can refer to in your JavaScript or C++ code. -
id
: A global HTML5 property, which specifies the identifier of an app, an activity, a view, or a archetype, Generally, the value of this property will be a variable which you can refer to in your JavaScript or C++ code. -
content
: A global HVML property, which specifies the content of an element.
Differences between HVML and HTML
-
HVML is defined for user interfaces not documents
-
Easy to localize
In HTML5, we define a text paragraph like this:
<p>
Welcome to the world of <em>HybridOS</em>!
</p>
When we want to localize the paragraph for other locale, we generally generate a different webpage for the locale.
However, in HVML, we define a text paragraph in the following way:
<p content="$Welcome to the world of <em>HybridOS</em>!">
</p>
So a JavaScript or C++ code can easily translate the content into other locale by using a GNU message file or a JSON table.
Embed App into HTML5 Pages
It is possible to embed a HybridOS app into an existed HTML5 page:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<meta name="format-detection" content="telephone=yes"/>
<meta name="apple-touch-fullscreen" content="yes"/>
<title>The first sample of HybridOS embedded in a HTML5 page</title>
<link rel="stylesheet" type="text/css" href="//hybridos.fmsoft.cn/js/hybridos.css" />
<script type="text/javascript" src="//hybridos.fmsoft.cn/js/hybridos.js"></script>
</head>
<body>
<header>
<h1>The First Sample of HybridOS</h1>
</header>
<p>This page shows howto embedded a HybridOS app in a HTML5 page.</p>
<hvapp id="firstSample">
<assets>
...
</assets>
<activity id="act-user-list" hbd-scope="firstSample">
...
</activity>
<activity id="act-user-info" hbd-scope="firstSample">
...
</activity>
<script>
...
</script>
</hvapp>
<footer>
...
</footer>
</body>
</html>
Note that we import hybridos.css
and hybridos.js
in the head of the HTML5 page.
Define app
An HVML app should be defined by the root document, commonly a index.hvml
file.
The global assets include:
- L10N files. Please see L10N. Note that the user agent will only load the L10N file for the current locale.
- Exported activities. An exported activity means an activity which can be called by external modules.
<!DOCTYPE hvml>
<hvml name="firstSample" lang="en" root="/firstSample/index.hvml">
<!-- the assets of the app, such as the activities and L10N text -->
<head>
<!-- the links to the exported activities -->
<activity name="act-user-list" datasrc="hibus://self/get-user-list"
href="/firstSampe/userlist.hvml" default />
<activity name="act-user-info" datasrc="hibus://self/get-user-info"
href="/firstSampe/userinfo.hvml" />
<!-- the links to the localization translation files -->
<link rel="localization preload" type="text/json"
href="/firstSample/assets/messages/" />
<link rel="stylesheet" type="text/css"
href="/firstSample/assets/default.css" />
</head>
<body>
<main>
<img class="splash" src="file:///assets/images/splash.png" />
</main>
</body>
</hvml>
Obviously, if you use the method above to define the app, you need to prepare three files:
-
index.hvml
: the root document of the app; -
userlist.hvml
: the HVML document foract-user-list
activity; -
userinfo.hvml
: the HVML document foract-user-info
activity.
activity
tag
The activity
tag defines an activity will be launched by the current navigation
or other modules in the system. This tag can only appear in the head
element.
Relationship with HFCL
For the C++ edition of your HybridOS app, you use
[HybridOS Foundation C++ Class Library] (HFCL
for short) directly.
HFCL runs based on hiWebKit and provides the most extended interfaces for HybridOS apps.
Hybrid App Engine is developed based on HFCL.
...The above words are deprecated.
References
- HTML 5.3: Read the spec to understand the basic concepts about HTML, and the parsing process of HTML documents.
- DOM Specification: Read this spec to understand DOM and the standard interfaces of DOM.
- WebIDL Specification: Read this spec to know the syntax of WebIDL, which is used to describe the interfaces of DOM.
- CSS 2.2: Read this spec to understand the basic concepts of CSS. Recommend that to read some specifications of CSS Level 3 to know the key features of CSS 3, for example, CSS Box Model Module Level 3. For all specifications or drafts of CSS, you can refer to https://drafts.csswg.org/.