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.
               
![[Warning]](../includes/warning.gif)
![[SWF]](../includes/swf.gif)
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
![[Warning]](../includes/warning.gif)
![[SWF]](../includes/swf.gif)
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.
                  
![[Warning]](../includes/warning.gif)
![[DHTML]](../includes/dhtml.gif)
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.
               
![[Warning]](../includes/warning.gif)
![[DHTML]](../includes/dhtml.gif)
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.jsThe 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>
![[Warning]](../includes/warning.gif)
![[SWF]](../includes/swf.gif)
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.
![[Warning]](../includes/warning.gif)
![[DHTML]](../includes/dhtml.gif)
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.