MotherApp Tutorial
Part 4: Offline Application
You can use MotherApp Engine to create content that can be navigated in offline (no network). This tutorial will guide you to understand:
1. Storing pages into local storage
In MotherApp Engine, there are two "wf_style", "fetch" and "force_fetch", specifying to store pages into the local storage. So, the stored pages can be retrieved in the future without access the network.
Examples:
<a href="article_1.html" wf_style="fetch button">Article 1</a> <a href="article_1.html" wf_style="force_fetch button">Article 1</a>
When the user click the first button, the "article_1.html" (specified with "fetch") will be retrieved from the network at the first time. Then "article_1.html" will be stored in the local storage. So, the same link ("article_1.html") will be retrieved from the local storage immediately next time. So the user can view the content of "article_1.html" no matter the device connects to the internet.
Sometimes, you may want to skip the cache and load the page directly from the network. Then, you can use "force_fetch" to do it. The link specified with "force_fetch" will be retrieved from the network and store it in the local storage.
2. Local database
MotherApp Engine provides developers some methods to add, delete and query records to/from the local database.
2.1. Add/Delete/Query database
2.1.1. Add
MotherApp Engine defines a special url scheme to add (key, value) pair to the local database. The syntax is wf://device/db/add?key=xxx&value=yyy
Add Shop
For better illustration, the query string part of url is urldecoded as following:
| parameter | value | explain |
|---|---|---|
| key | shop001 | key of the record |
| value | {name%20}{address%20} | value of the record. With "{" "}", MotherApp Engine would try to find the parameters in the query string to substitute the string into the "value". "%" is used to left-space-padded the variable. So the result is " ABCShop SanJose". |
| name | ABCShop | used for substitution |
| address | SanJose | used for substitution |
| redirect | shop_added.html | After adding the record, "shop_added.html" will be retrieved. |
2.1.2. Delete
Deleting a record is similar to add a new record. The syntax is wf://device/db/delete?key=xxx
2.1.3. Query
There are two ways you can get the record(s) from the local database.
- MotherApp Variable: [wf:db:(key)]
Search
"[wf:db:searchkey]" (decoded value of "%5Bwf%3Adb%3Asearchkey%5D") will be replaced by querying the value of the record with the key equal to "searchkey". - wf://device/db/query?...
Query the local database and return the records. Normally, it is used with the MotherApp Template to render the user interface with queried records.
Examples:- Return records with the key started with "15":
wf://device/db/query?subkey0:2=eq15
- Return records with the key started with "15":
wf://device/db/query?subkey0:2=eq15
- Return records with the key started with "15" or "19" or "20":
wf://device/db/query?subkey0:2=eq15,eq19,eq20
- Return records for substring(key, 0, 2) >= '15' and substring(key, 2, 4) = 'sun':
wf://device/db/query?subkey0:2=ge15&subkey2:5=eqsun
- Return records with the first two characters between "15" and "20":
wf://device/db/query?subkey0:2=ge15-le20
- Return 1 record if no result found for wf://device/db/query?subkey0:2=ge15-le20. Otherwise, return 0 record.
wf://device/db/query?subkey0:2=ge15-le20&result_filter=is_empty
- Return records with the key started with "15":
For more details, please read our reference.
2.2. MotherApp Engine Template using database
MotherApp Engine defines a way to render the user interface based on query result from the local database. "wf_source" attribute is used for this purpose. The value of the "wf_source" attribute is the database query url introduced in previous section. The returned records are used to render the user interface. It's better using examples to illustrate the power of MotherApp Engine Template.
Assume there are several records in the local database:
| key | value |
|---|---|
| Shop001 | ABCShopHK |
| Shop002 | AppShopUS |
| Shop003 | WebShopJP |
| Shop004 | HTMLShopUK |
| Shop005 | MAShopHK |
| Link001 | http://www.google.com/ |
| Link002 | http://www.apple.com/ |
Following is the html source:
<html>
<body>
<title align="center">Shops</title>
<table>
<tr wf_source="wf://device/db/query?subkey0:4=eqShop">
<td width="5%">{{counter}}</td>
<td width="35%">{{value0:8}}</td>
<td width="60%">{{value8:10}}</td>
</tr>
</table>
</body>
</html>
The "wf_source" attribute is defined in "tr" tag. MotherApp Engine would query the database according to the query defined in the attribute. ("wf://device/db/query?subkey0:4=eqShop" searchs for records which key is started with "Shop"). In this examples, there are 5 records returned (i.e. Shop001, Shop002, ..., Shop005).
Then MotherApp Engine would replicate the "tr" tag according to the searched results. In the example, 5 "tr"s are replicated. There are some special variables can be used such as {{counter}}, {{value}} (no space) and {{key}} to fill the content. For {{value}}, indexes can be used to retrieve a portion of the string.
So the result is:
<html>
<body>
<title align="center">Shops</title>
<table>
<tr wf_source="wf://device/db/query?subkey0:4=eqShop">
<td width="5%">1</td>
<td width="35%">ABCShop</td>
<td width="60%">HK</td>
</tr>
<tr wf_source="wf://device/db/query?subkey0:4=eqShop">
<td width="5%">2</td>
<td width="35%">AppShop</td>
<td width="60%">US</td>
</tr>
<tr wf_source="wf://device/db/query?subkey0:4=eqShop">
<td width="5%">3</td>
<td width="35%">WebShop</td>
<td width="60%">JP</td>
</tr>
<tr wf_source="wf://device/db/query?subkey0:4=eqShop">
<td width="5%">1</td>
<td width="35%">HTMLShop</td>
<td width="60%">UK</td>
</tr>
<tr wf_source="wf://device/db/query?subkey0:4=eqShop">
<td width="5%">1</td>
<td width="35%">MAShop</td>
<td width="60%">HK</td>
</tr>
</table>
</body>
</html>
3. Trigger actions after the page is loaded
3.1. navigation_background
Let's introduce a new concept called "navigation_background". The "wf_style" attribute of a link contains "navigation_background". The page will be loaded in the background (i.e. no user interface rendering). All the images will be loaded in the page will be loaded too.
<a href ="article_1.html" wf_style="button navigation_background">load in background</a>
3.2. onload, onload_foreground, onload_background
When a link is defined with "onload" in the "wf_style" attribute, the link will be triggered automatically after the page is loaded. For examples,
<a href ="article_1.html" wf_style="navigation_background onload"></a>The page "article_1.html" will be loaded automatically after the current page (the page contains this link) is loaded. And the page is loaded in background in this example.
<a href ="wf://device/db/add?key=load_time&value=20100629170800" wf_style="onload"></a>The database action (insert (load_time, 20100629170800)) will be triggered automatically after the page is loaded.
Sometimes, you may want to triggered the link only when the page is in the foreground (see 4.1.). You can use "onload_foreground" to trigger the link. Vice versa, "onload_background" is used to trigger the link when the page is loaded in background.
Caution: be careful that the page is looped back and created a infinite cycle of loading
4. Examples
In this section, three examples will be given to illustrate the combination usage of above features to make offline application
4.1. Sync content for offline access (Download)
Problem: There is a list of articles. We want to cache all the articles automatically in background when users first launch the application
Solution: We can make use of onload, fetch and navigation_background to complete the task
First, in the article list page, we can add an "onload" link (line 4) to trigger a sync (sync.html) action automatically in background. Following is the article list page:
<html>
<body>
<wf_titlebar><title align="center">Articles</title></wf_titlebar>
<a href="sync.html" wf_style="navigation_background onload"></a>
<table wf_style="fullscreen">
<tr wf_href="article_1.html"><td wf_style="padding">Getting Started</td></tr>
<tr wf_href="article_2.html"><td wf_style="padding">MA Debugger</td></tr>
<tr wf_href="article_3.html"><td wf_style="padding">GeoCamera</td></tr>
<tr wf_href="article_4.html"><td wf_style="padding">Offline application</td></tr>
</table>
</body>
</html>
Then, in the sync page (sync.html), fetch and onload can be used to load the articles and save them into local storage in the background after the sync page is loaded. Following is the sync page:
<html> <body> <a href="article_1.html" wf_style="onload fetch"></a> <a href="article_2.html" wf_style="onload fetch"></a> <a href="article_3.html" wf_style="onload fetch"></a> <a href="article_4.html" wf_style="onload fetch"></a> </body> </html>
So, all the articles (article_1.html, article_2.html, ...) can be automatically loaded into the local storage. If the user click the article "MA Debugger", it is loaded from the local storage directly rather than from the internet. Thus, the articles can be read in offline mode.
You can download the examples code here: Download
4.2. Bookmark article (Download)
Problem: How to bookmark article locally
Solutions: Make use of local database and MotherApp template to implement a bookmark functionality
In the article, a database inserting link (line 5) can be used to add the bookmark to the database as shown:
<html>
<body>
<wf_titlebar>
<title align="center">Getting Started</title>
<a href="wf://device/db/add?key=fav001&value=++++Getting Started++++++article_1.html" align="right">+</a>
</wf_titlebar>
<div>
Consectetuer adipiscing elit. Nam pede erat, porta eu, lobortis eget, tempus et, tellus. Etiam neque. Vivamus consequat lorem at nisl. Nullam non wisi a sem semper eleifend. Donec mattis libero eget urna. Duis pretium velit ac mauris. Proin eu wisi suscipit nulla suscipit interdum. Aenean lectus lorem, imperdiet at, ultrices eget, ornare et, wisi.
</div>
...
</body>
</html>
When user click the bookmark link, ("fav001", " Getting Started article_1.html") is added to the local database.
Then, we can make use of MotherApp template to inflate the bookmarks into the table:
<html>
<body>
<wf_titlebar>
<title align="center">Bookmarks</title>
</wf_titlebar>
<table wf_style="fullscreen">
<tr wf_source="wf://device/db/query?subkey0:3=eqfav" wf_href="{{value20:40}}">
<td wf_style="padding">{{value0:20}}</td>
</tr>
</table>
</body>
</html>
| line no. | code | description |
|---|---|---|
| 7 | wf://device/db/query?subkey0:3=eqfav | query the database with key which started with "fav" |
| 7 | {{value20:40}} | The substring [20,40) of value of the record is filled in the "wf_href" attribute (note that the output will be space-trimmed) |
| 8 | {{value0:20}} | The substring [0,20) of value of the record is filled in the content |
So, the result will be (if only first article is bookmarked):
<html>
<body>
<wf_titlebar>
<title align="center">Bookmarks</title>
</wf_titlebar>
<table wf_style="fullscreen">
<tr wf_href="article_1.html">
<td wf_style="padding">Getting Started</td>
</tr>
</table>
</body>
</html>
You can download the examples code here: Download
4.3. Offline search (Download)
Problem: How to search a website in the database
Solutions: Make use of local database: add and query and MotherApp template to implement the offline search functionality
First, you can use following code to import the data:
...
<div wf_source="wf://device/db/query?subkey0:3=eqwww&result_filter=is_empty">
<a href="db_data.html" wf_style="onload navigation_background"></a>
</div>
...
wf_source="wf://device/db/query?subkey0:3=eqwww&result_filter=is_empty" is used for checking the data is already in the database, if not, it would load "db_data.html" in background.
Second, create a <form> to let user input the search key. However, offline search should not use the server script to construct a proper wf://device/db/query. So, [wf:db:key] is introduced to help for constructing the query.
...
<form action="wf://device/db/add">
<table wf_style="fullscreen">
<tr><td>
<input type="text" wf_style="search" name="value"/>
<input type="hidden" name="key" value="searchkey"/>
<input type="hidden" name="redirect" value=""/>
</td></tr>
</table>
</form>
...
| line no. | code | description |
|---|---|---|
| 2 | <form action="wf://device/db/add"> | Tricks for using the form get to help to build the db add query |
| 5 | The search query input by the user | |
| 6 | searchkey | The key for search |
| 7 | redirect | redirect parameter |
...
<table wf_style="fullscreen">
<tr wf_source="wf://device/db/query?subkey0:3=eqwww&value=li%5Bwf%3Adb%3Asearchkey%5D" wf_href="{{value30:80}}" wf_style="browser_launched">
<td wf_style="padding">{{value0:30}}</td>
</tr>
</table>
...
Line 3 shows the merit of using "[wf:db:searchkey]" (decoded value of "%5Bwf%3Adb%3Asearchkey%5D"). So the query becomes "wf://device/db/query?subkey0:3=eqwww&value=liMother". It searchs for records with the key started with "www" and the value contains "MotherApp".
You can download the examples code here: Download
What Resources Are Available to Me as a Developer?
- MotherApp HTML Reference
Click here to see the complete reference for MotherApp HTML. You can select having the code elements displayed by category, alphabetically, or with associated screen shots. -
Development Tools
- Click here
to use the MotherApp Debugger.
Use the debugger test your application using a web browser (the Safari 4, Firefox 3.5 and Google Chrome browsers are recommended). The generated user interface may differ somewhat from the display on any particular device (since the app will display natively, and therefore differently, on each platform), but the debugger accepts the same MotherApp HTML as the devEngine. It will allow you to to check the syntax for your MotherApp HTML pages. - Click
here to use the MotherApp Sandbox
The MotherApp sandbox helps generates the testing version of app that could be actually deployed to the devices. - Click here to view our set of sample apps.
- Click here
to use the MotherApp Debugger.
-
More Information
- Click here to view our list of MotherApp "How to"s. For example, "how to deliver your completed app," or "how to launch the video player."
- Click here to view the answers to our Frequently Asked Questions (FAQ)
- Click here to go to our Support Forum.

