Table of Contents
OpenLaszlo applications run inside web browsers, and web browsers are designed to render HTML pages. This means that each compiled OpenLaszlo application has a relationship to the HTML page that delivers it to the browser. Depending on whether the OL application was compiled to SWF or to DHTML, the mechanics of this relationship differ. However, at an abstract level the model is pretty much the same for all runtimes: an OpenLaszlo application resides within a web page that is executed by a browser; that browser has a "JavaScript" engine. The OpenLaszlo application can make requests for the JavaScript engine to execute, and the surrounding HTML page can include JavaScript code that makes requests of the OpenLaszlo application.
This chapter discusses the way that OpenLaszlo Applications relate to the HTML pages in which they're delivered, and ways in which the OpenLaszlo application and browser JavaScript engine can communicate with each other.
In this chapter we'll be talking about the structure of HTML pages that contain LZX applications. Keep in mind that if you compile your applications using the Developer Toolbar, HTML pages of the proper structure are generated automatically. Situations may arise where you may need to customized these pages or even generate pages from scratch, but in many cases, the automatically generated page is all you need. Simply press the appropriate button, "Server" or "SOLO", and follow the instructions that are then displayed.
Before going into the actual mechanics, let's take a closer look at concepts and terminology.
As we said above, web browsers display HTML pages. This means that OpenLaszlo applications are delivered to browsers by means of HTML pages. Sometimes those HTML pages contain nothing visible to the user other than the LZX application itself. In such cases the HTML page is essentially invisible, and the fact that there's an HTML page there at all doesn't really matter to the developer or to the user of the application. Such HTML pages, whose only function is to present the OpenLaszlo application to the browser, are sometimes called "wrapper pages."
Depending on which target runtime they're compiled for, OpenLaszlo applications have different relationships with the JavaScript engine of the browser in which they run. To a rough approximation, LZX applications compiled to SWF are foreign objects embedded into an HTML page, and you must use a formal protocol to get across this logical barrier between the LZX application and the JavaScript engine. Applications compiled to DHTML become just a part of the HTML page that contains them. From the point of view of the browser, there is no difference between the OpenLaszlo application and the surrounding page.
But although some of the implementation details differ
for the different runtime targets, the OpenLaszlo APIs are,
wherever possible, consistent, so that you use the same
programming model regardless of the target runtime. So, for
example, there is a method called
lz.embed.swf()
for embedding SWF OL
applications into the HTML page; this generates an HTML
<embed> tag. Similarly, there is an
lz.embed.dhtml()
for placing an OL
application compiled to DHTML within a web page. In this case
there is no <embed> generated or required, but the
methods have similar names because they perform analogous
functions.
Any attributes that are declared on the canvas are
visible to the browser JavaScript. To go "the other way",
from the browser "into" the OpenLaszlo application, the
lz.embed['lzapp'].getCanvasAttribute()
and
lz.embed['lzapp'].setCanvasAttribute()
methods are
used, where 'lzapp' denotes the application ID.
These are discussed below.
Although OpenLaszlo applications deployed on the Flash runtime are not dependent on the browser or operating system for their look or behavior, there are some important limitations that the browser container places on the application. There are also a number of Flash Player features that your application can use which are not available in applications compiled to DHTML.
OpenLaszlo applications compiled to SWF can be sent from the OpenLaszlo Server to client in any of several forms:
as "naked" swf
as swf embedded in an html "wrapper" page
as xml source
SWF only: The features described in this section only work in applications compiled to SWF. They do not work in applications compiled to other runtimes.
The
lz.Browser
service provides access to
the browser and player environment. It includes methods to
load URLs in the browser and check the version of the
player. Furthermore, by using the
lz.Browser
service together with other
OpenLaszlo functions described below, you can build
applications that pass information and control between the
OpenLaszlo application and the JavaScript of the
browser.
The
lz.Browser
service is always running.
DHTML only: The features described in this section only work in applications compiled to DHTML. They do not work in applications compiled to other runtimes.
Applications that are compiled for DHTML run within the browser's JavaScript environment. They are essentially compiled into the DOM of that page.
Each LZX application has exactly one
<canvas>
element, which, when compiled to DHTML, becomes an object.
When you embed an LZX application compiled to DHTML into an
HTML page, it just becomes part of that page's DOM, and you
can address it directly. The "foo" object of the LZX
application becomes canvas.foo of the DOM. If there is a swf
embedded in that (DHTML) Openlaszlo application, you can
still use the mechanism for talking to SWF applications to
reach it.
For DHTML, you can call canvas JavaScript directly
because it is loaded in the browser. That is to say, unlike
in the case of communicating with SWFs, you do not need to
use
getCanvasAttribute()
or
setCanvasAttribute()
, nor do you
need to use the
lz.Browser
service.
DHTML only: The features described in this section only work in applications compiled to DHTML. They do not work in applications compiled to other runtimes.
When you compile an application to SWF, the compiler includes the Laszlo Foundation Class, or LFC in the resulting file. This does not happen for applications compiled to DHTML, therefore the LFC must be downloaded explicitly. To make the LFC available to DHTML applications, include the following call in the page head:
<script type="text/javascript"> lz.embed.lfc('/lps-5.0.x/lps/includes/lfc/LFCdhtml.js', '/lps-5.0.x/'); </script>
For both applications compiled to SWF and applications
compiled to DHTML, the methods used for bidirectional
communication with the browser are in the class
lz.embed
.
Unlike other OpenLaszlo classes which you use to build
LZX applications, the
lz.embed
is designed to be incorporated into
the HTML page in which your LZX application runs. That is to
say, your LZX application is designed to be executed in the
<body> section of the page, but the
lz.embed
must be include in the <head>
section of the page.
The
lz.embed
class is defined in
lps/includes/source/embednew.js
The source for
embednew.js
is shipped compressed as
lps/includes/embed-compressed.js.
The comments/API documentation are in the source file and the class is documented in the Reference Manual.
To have access to the
lz.embed
class, your application must include a
line like
<script type="text/javascript" src="/lps-5.0.x/lps/includes/embed-compressed.js"></script>
If you generate wrappers using the Developer Toolbar, the correct <script> tag will be generated for you automatically.
Remember, if you compile your application using the
Developer Toolbar, the wrapper pages generated include the
proper calls to the
lz.embed
class. It "just works" and you don't
have to do anything special. If you craft your HTML pages "by
hand", of course, you will need to make sure that you
incorporate the lz.embed class.
When you place a OpenLaszlo application inside an HTML page, that page has to have some way to know where to place the application, and how to handle it. That is, you must inform the browser that the embedded OpenLaszlo application is actually a SWF file, and so forth.
In the
<html><head>
of an
HTML document that embeds an OpenLaszlo application compiled to
SWF, add this line:
Example 35.1. The lz Class
<script src="/lps-5.0.x/lps/includes/embed-compressed.js" language="JavaScript" type="text/javascript"></script>
At the location within the <html><body> where the application is to be embeded, add this line:
Example 35.2. Placing the LZX (SWF) application within an HTML page
<script language="JavaScript" type="text/javascript"> lz.embed.swf({url: url + '?lzt=swf&lzr=swf8', bgcolor: '#000000', width: '100%', height: '100%'}); </script>
where the url matches the URI that the application is served from, and the other properties match the attributes of the application's canvas.
At the location within the <html><body> where the application is to be embeded, add this line:
Example 35.3. Placing the LZX (DHTML) application within an HTML page
<script language="JavaScript" type="text/javascript"> lz.embed.dhtml({url: url + '?lzt=object&lzr=dhtml', bgcolor: '#000000', width: '100%', height: '100%'}); </script>
where the url matches the URI that the application is served from, and the other properties match the attributes of the application's canvas.
The optional
appenddivid
property can
be passed in to
lz.embed.swf()
or
lz.embed.dhtml()
method to specify the id
of a div whose contents should be replaced with the LZX
application. If a div with that ID doesn't exist, one will be
written into the document where
lz.embed.{swf,dhtml}()
is called. If appenddivid
is not specified, the div written will be based on the id
property + 'Container'.
Alternatively, you can generate wrappers by using the various request types on the url you use to browse to your application, as explained in Chapter 49, Understanding Compilation:
Invoke the lzx application with request type "?lzt=html". This generates the "wrapper."
Using your browser's "View source" function, copy the contents of the wrapper and place in a new file with a .html extension.
In the head of the HTML file, you will see the
script tag that includes
embed-compressed.js
Adjust the path if
necessary for deployment.
Paste to wherever you want the OpenLaszlo application to appear in HTML page
Verify by running HTML file in your browser.
The default wrapper page contains logic to detect the version of flash running on the client.
Depending on which version is running, you may wish to use some LZX features that run in some, but not all, versions of the Flash Player.
OpenLaszlo uses client-side player detection. If the user either a) doesn't have the Flash Player plug-in or b) has an older version, they'll be prompted to download a fresh version. This feature is included in the default HTML wrappers for lzt=html and the SOLO deployment wizard
Frames are a very handy way to use OpenLaszlo applications within a page. If you are using a OpenLaszlo application for your navigation or as a widget in your page you might consider using frames to format your layout.
When laying out a page that will use OpenLaszlo applications in different places, you can use a frameset like this:
Example 35.4. example frameset
<html> <frameset cols="128,*"> <frame name="navBar" src="myOpenLaszloNav.lzx?lzt=html"/> <frame name="contentArea" src="myOpenLaszloContent.lzx?lzt=html"/> </frameset> </html>
Inside your application use the target parameter of
lz.Browser.loadURL()
to load pages in
the target frame.
Like framesets, OpenLaszlo applications can be embedded within an "inline frame" or <iframe> which can be more flexible for your layout and easier to use. Like regular frames, inline frames can be named for later reference by the OpenLaszlo application.
Example 35.6. iframes and applications
<html> <body> <h1>Here is a header</h1> <div align="center"> <iframe src="myOpenLaszloApplication.lzx?lzt=html" width="200" height="200" frameborder="0" name="inlineApplication" scrolling="no"/> </div> </body> </html>
Bear in mind that the iframe will contain a canvas, and unless you want the browser to provide scrollbars, you should set the width and height equal to that of your canvas plus any margin you may have included.
The same way you would target content to a frame, you can target the loadURL to new window.
Example 35.7. new blank browser window
<canvas
width
="100%
" height
="27
">
<button
onclick
="lz.Browser.loadURL('http://www.openlaszlo.org','_blank');
" text
="Click Me!
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008, 2010 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
This mechanism can also be used to name the window allowing subsequent loads to occur in the same window
Example 35.8. reusing new browswer window
<canvas
width
="100%
" height
="56
">
<simplelayout
/>
<button
onclick
="lz.Browser.loadURL('http://www.openlaszlo.org','newOpenLaszloWindow');
" text
="OpenLaszlo Homepage
"/>
<button
onclick
="lz.Browser.loadURL('http://forum.openlaszlo.org','newOpenLaszloWindow');
" text
="OpenLaszlo Forum
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008, 2010 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Any query parameters that you add to the end of your url
to load the application are available through the
lz.Browser.getInitArg()
method.
Example 35.9. Passing query parameters to LZX application
<script type="text/javascript"> // pass 'myData' with value 'myValue' to the application lz.embed.swf({url: 'mainApplication.lzx?lzt=swf&myData=myValue', bgcolor: '#394660', width: 1024, height: 768}); </script>
Once the data has been passed in you can simply access it by calling getInitArg() from within the OpenLaszlo application.
Example 35.10. Accessing parameters
<canvas debug="true" oninit="Debug.debug("%w", lz.Browser.getInitArg('myData'))"/>
In many cases you will have full control of the HTML content that is embedding your application. In many other cases you won't be able to depend on the existence of those query parameters so it is wise to provide sane defaults for those values:
Example 35.11. setting defaults
<canvas
debug
="true
" width
="100%
" height
="200
">
<attribute
name
="onceData
" value
="$once{lz.Browser.getInitArg('myData')}
"/>
<handler
name
="oninit
">
var innerVar = lz.Browser.getInitArg('myData');
if (innerVar == null) innerVar = 'bar'; // default to 'bar'
Debug.debug("%w", canvas.onceData);
Debug.debug("%w", innerVar);
</handler
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2010 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
The above application is requested without a
myData
query parameter. The debugger
therefore displays the default value
bar
. If this application is requested with
the
myData=foo
query parameter, it will
display the value foo
. Click
here to see the application in a popup window with the
query parameter applied.
Using query parameters, you can craft your application to start up in a specific state. The default behavior of a tabslider is to have none of the tabelements opened at startup. The following application changes that default to open to the tab specified on the query parameter, and if one isn't provided, open to the first element.
Example 35.12. setting defaults
<canvas
width
="100%
" height
="250
">
<tabslider
width
="150
" x
="10
" y
="10
" height
="200
" spacing
="2
" slideduration
="300
">
<handler
name
="oninit
">
var opened = lz.Browser.getInitArg('tab') || 'one';
this[opened].setAttribute('selected', true);
</handler
>
<tabelement
name
="one
" text
="Tabelement One
"/>
<tabelement
name
="two
" text
="Tabelement Two
"/>
<tabelement
name
="three
" text
="Tabelement Three
"/>
</tabslider
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007-2008, 2010 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Click here to see this application in a popup with a different initial state applied. This is useful when creating links from outside the application, or for creating a bookmark for an application. Another thing to do is read browser cookies from JavaScript and pass in the parameters when calling the application.
The
lz.History
service allows you to preserve
the state of your application, and then use the "back" button
of the browser to move among such states.
The default wrapper page enables the back button and browser-to-LZX communication. Once you've got this, you can call the browser javascript method
javascript:lz.embed.setCanvasAttribute(attributeName, value)
to set a canvas attribute and send an event. The
following example shows the way the
lz.History
service works to move among
states. To see the program in action, follow
this link to open a popup window.
Example 35.13. history enabled application
<canvas
history
="true
">
<!-- Click on blob START, STATE_2, STATE_3, END, then click browser back button -->
<!-- a blob you can click on to select -->
<class
name
="blob
" extends
="drawview
" width
="100
" height
="100
">
<attribute
name
="title
" type
="text
"/>
<attribute
name
="lineStyle
" value
="black
" type
="color
"/>
<attribute
name
="lineWidth
" value
="4
" type
="number
"/>
<text
align
="center
" valign
="middle
" fontsize
="16
" text
="${parent.title}
"/>
<handler
name
="onclick
">
main.selectBlob(this);
</handler
>
<method
name
="select
" args
="val
">
clear();
rect(2, 2, 96, 96, 5);
if (val) {
// draw a border to select
stroke();
}
fill();
</method
>
</class
>
<!-- A view with four states -->
<view
id
="main
" x
="10
" y
="10
" layout
="axis: x; spacing: 10
">
<attribute
name
="mystate
" type
="string
" value
="START
"/>
<blob
fillStyle
="#ffcccc
" name
="s1
" title
="START
"/>
<blob
fillStyle
="#ccccff
" name
="s2
" title
="STATE_2
"/>
<blob
fillStyle
="#ccffcc
" name
="s3
" title
="STATE_3
"/>
<blob
fillStyle
="#cccccc
" name
="s4
" title
="END
"/>
<method
name
="selectBlob
" args
="blob
">
var oldstate = this.mystate;
var newstate = blob.title;
if (oldstate != newstate) {
// save the old state
lz.History.save('main', 'mystate', oldstate);
// create new history context
lz.History.next();
setAttribute('mystate', newstate);
}
</method
>
<!-- update blobs' appearance -->
<handler
name
="oninit
" method
="gotoState
"/>
<handler
name
="onmystate
" method
="gotoState
"/>
<method
name
="gotoState
" args
="ignore=null
"><![CDATA[
for (var i = subviews.length - 1; i >= 0; --i) {
var blob = subviews[i];
blob.select(blob.title == this.mystate);
}
]]>
</method
>
</view
>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2010 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
You can make the canvas of the OpenLaszlo application
either a fixed size, or you can make it expand or contract as
the browser window expands or contracts. To make the canvas an
absolute size, set its height and width with integer values,
for example,
width="40" height="40"
. To have the canvas
scale, simply express the height and width as
percentages.
Intercepting keystrokes can pose some challenges. The keys that are intercepted varies from browser to browser, but anything that the browser defines will not be passed to your OpenLaszlo application. Mozilla Firefox seems to do this correctly, but many browsers won't pass alt and ctrl key combinations down to the application. The application below should demonstrate this, [Ctrl-n] in many browsers is the command you use to open a new browser window. In Mozilla Firefox, you can get the debugger to print the right message, but only if your mouse is floating over the application.
Example 35.14. Intercepting keystrokes
<canvas
height
="130
" debug
="true
">
<command
key
="$once{['Control','n']}
" onselect
="Debug.debug('the [Ctrl-n] key combination was pressed');
"/>
</canvas
>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc. All Rights Reserved. *
* Use is subject to license terms. *
* X_LZ_COPYRIGHT_END ****************************************************** -->
Copyright © 2002-2010 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.