Table of Contents
OpenLaszlo applications run inside web browsers, and web browsers are desiged 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 "JavaScipt" 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 appliction 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 Console, 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 automaticaly 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 teminology.
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 swfEmbed()
for embedding SWF OL applcations into the HTML page; this generates an HTML <embed> tag. Similarly, there is an dhtmlEmbed()
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.
Applications compiled to SWF are executed by the Flash player and must make use of the LzBrowser
service in order to "escape" to the browser's JavaScript environment.
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 setCanvasAttribute()
and setCanvasAttribute()
methods are used.
This are discussed below.
Alhough 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 LzBrowser
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 LzBrowser
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 LzBrowser
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 envinronment. 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 setCanvasAttribute()
ore setCanvasAttribute()
, nor do you need to use the LzBrowser
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:
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
. Note that the letter "L" in this class is uppper case. This is not a typo!.
Unlike other OpenLaszlo classes which you use to build LZX applications, the Lz
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
must be include in the <lt;head> section of the page.
lps/includes/source/embednew.js
The source for embednew.js
isshipped 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
class, your application must include a line like
<script type="text/javascript" src="/legals/lps/includes/embed-compressed.js"></script>
If you generate wrappers using the developer's console, the correct <script> tag will be generated for you automatically.
Remember, if you compile your application using the Developer's Console, the wrapper pages generated include the proper calls
to the Lz
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 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="/embed-compressed.js" language="JavaScript" type="text/javascript"/>
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.swfEmbed({url: '?lzt=swf', bgcolor: '#000000', width: '', height: ''}); </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.dhtmlEmbed({url: '?lzt=swf', bgcolor: '#000000', width: '', height: ''}); </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 swfEmbed()
or dhtmlEmbed()
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 swf/dhtmlEmbed()
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 48, 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.
This page that will look something like the following:
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.5. 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 LzBrowser.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.7. 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.8. new Blank window
<canvas height="27" > <button onclick="LzBrowser.loadURL('http://www.laszlosystems.com','_blank');" text="Click Me!"/> </canvas>
This mechanism can also be used to name the window allowing subsequent loads to occur in the same window
Example 35.9. new Blank window
<canvas height="56" > <simplelayout/> <button onclick="LzBrowser.loadURL('http://www.openlaszlo.org','newOpenLaszloWindow');" text="OpenLaszlo Homepage"/> <button onclick="LzBrowser.loadURL('http://www.mylaszlo.com','newOpenLaszloWindow');" text="myLaszlo.com"/> </canvas>
Any query parameters that you add to the end of your url to load the application get passed into the application as globals.
Once the data has been passed in you can simply access it as a global variable from within the OpenLaszlo application.
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.12. Setting defaults
<canvas debug="true" width="200" height="200"> <script> var innerVar = typeof(global.globalVar) != 'undefined' ? global.globalVar : 'bar'; Debug.write(global.innerVar); </script> </canvas>
The above application is requested without a globalVar
query parameter. The debugger therefore displays the default
value bar
. If this application is requested with the
globalVar=foo
query parameter, it will display the
default value 'bar'. 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.13. Restoring state
<canvas width="300" height="250"> <script> var opened = typeof(global.tab) != 'undefined' ? global.tab : 'one'; </script> <tabslider width="150" x="10" y="10" height="200" spacing="2" slideduration="300" oninit="this[global.opened].setAttribute('selected',true)"> <tabelement name="one" text="Tabelement One"/> <tabelement name="two" text="Tabelement Two"/> <tabelement name="three" text="Tabelement Three"/> </tabslider> </canvas>
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.
Most web surfers have discovered the merits of high resolution displays. Some, though, still view the web using very low resolutions. OpenLaszlo applications can be written in a way that allows for multiple resolution versions of the same application to coexist using the same codebase.
Begin by creating your application in a library file instead of a
canvas, but use $once{}
constraints to size the
visual elements relative to the canvas.
Example 35.14. Multi-canvas application library
mainApplication.lzx: <library> <tabslider width="$once{canvas.width - 20}" x="10" y="10" height="$once{canvas.height - 20}" spacing="2" slideduration="300"> <tabelement name="one" text="Tabelement One"/> <tabelement name="two" text="Tabelement Two"/> <tabelement name="three" text="Tabelement Three"/> </tabslider> </library>
Then create multiple files, one for each canvas area you wish to support.
Example 35.15. Multi-canvas application files
mainApplication640.lzx: <canvas width="640" height="480"> <include href="mainApplication.lzx"/> </canvas> mainApplication800.lzx: <canvas width="800" height="600"> <include href="mainApplication.lzx"/> </canvas> mainApplication1024.lzx: <canvas width="1024" height="768"> <include href="mainApplication.lzx"/> </canvas> mainApplication1280.lzx: <canvas width="1280" height="1024"> <include href="mainApplication.lzx"/> </canvas>
For real world deployments, you will want to set the size of your canvas to account for screen area occupied by browser controls. Selecting the correct application size requires some JavaScript to pick the right application when the visitor comes to the page. This example keys off the screen width which will help you determine with high accuracy the height of the client as well.
Example 35.16. Selecting the Correct Canvas
<script type="text/javascript"> var screenW = screen.width; var screenH =0; switch (true) { case (screenW >= 1280): screenW = 1280; screenH = 1024; break; case (screenW >= 1024): screenW = 1024; screenH = 768; break; case (screenW >= 800): screenW = 800; screenH = 600; break; default: screenW = 640; screenH = 480; break; } lzEmbed({url: 'mainApplication'+screenW+'.lzx?lzt=swf', bgcolor: '#394660', width: screenW, height: screenH}); </script>
The LzBrowser.loadURL()()
method is used
to create a URL based on user input. This URL is then communicated to browser, where a JavaScript function is
used to unpack it and fill in a form. The wrapper page is shown immediately below.
<canvas width="200" height="400"> <attribute name="appear" type="number" value="0" /> <handler name="onappear"> win.show.doStart(); </handler> <window id="win" title="Create and Account" y="-300" width="180" height="300"> <animator name="show" attribute="y" from="-300" to="50" start="false" relative="false" duration="500" /> <animator name="hide" attribute="y" from="50" to="-300" start="false" relative="false" duration="500" /> <simplelayout axis="y" spacing="4" /> <state name="question" apply="true"> <text multiline="true" width="160" align="center"> It looks like you don't have an account. Would you like to create one now? </text> <button>Go <handler name="onclick"> parent.question.remove(); parent.signup.apply(); </handler> </button> </state> <state name="signup"> <text>Name:</text> <edittext /> <text>Email:</text> <edittext /> <text>Username:</text> <edittext name="uname"/> <text>Password:</text> <edittext name="pass" /> <button>Create Account <handler name="onclick"> var s = "javascript:fillFormValues('" + parent.uname.getText() + "', '" + parent.pass.getText() + "')"; LzBrowser.loadURL(s); parent.hide.doStart(); </handler> </button> </state> </window> </canvas>
The LzHistory
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:lzSetCanvasAttribute(attributeName, value)
to set a canvas attribute and send an event. The following example shows the way the LzHistory
service works
to move among states. To see the program in action, copy this code to your applications directory.
Example 35.17. Communicating with Back button
<canvas width="1400" height="600" debug="true"> <debug width="500" height="500" fontsize="12" x="450"/> <!-- 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="selected" type="boolean" /> <text y="20" x="4" fontsize="16" text="${parent.title}"/> <handler name="onclick"> this.setAttribute('selected', true); main.selectBlob(this); </handler> <method name="select" args="val"> if (val) { // draw a border to select this.lineStyle = 0x000000; this.lineWidth = 4; moveTo(0,0); lineTo(0,100); lineTo(100,100); lineTo(100,0); lineTo(0,0); stroke(); } else { clear(); } </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 bgcolor="#ffcccc" id="s1" title="START"/> <blob bgcolor="#ccccff" id="s2" title="STATE_2"/> <blob bgcolor="#ccffcc" id="s3" title="STATE_3"/> <blob bgcolor="#cccccc" id="s4" title="END"/> <method name="unselectAll"> s1.select(false); s2.select(false); s3.select(false); s4.select(false); </method> <method name="selectBlob" args="blob"> // save the old state LzHistory.next(); setAttribute('mystate', blob.title); unselectAll(); blob.select(true); recordState(blob.title); </method> <handler name="oninit"> unselectAll(); recordState("START"); selectBlob(s1); </handler> <handler name="onmystate"> Debug.write("got onmystate event: ", this.mystate); gotoState(this.mystate); </handler> <method name="recordState" args="newstate"> this.mystate = newstate; LzHistory.save(this,'mystate', this.mystate); Debug.write("recordState", newstate) </method> <method name="gotoState" args="ns"> unselectAll(); if (ns == "START") { s1.select(true); } else if (ns == "STATE_2") { s2.select(true); } else if (ns == "STATE_3") { s3.select(true); } else if (ns == "END") { s4.select(true); } </method> </view> </canvas>
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.
<canvas height="130" debug="true"> <command oninit="this.setKeys(['Control','n'])" onselect="Debug.write('the [Ctrl-n] key combination was pressed');" /> </canvas>
Copyright © 2002-2007 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.