app.lzx

<!--
* X_LZ_COPYRIGHT_BEGIN ****************************************************
* Copyright 2001-2009, 2011 Laszlo Systems, Inc.  All Rights Reserved.    *
* Use is subject to license terms.                                        *
* X_LZ_COPYRIGHT_END ******************************************************-->
<canvas width="800" height="600" bgcolor="0xcfcfcf" proxied="true" title="LZPIX"> <!-- bgcolor="0xc0c0c0" -->
  <!--
  <inittimer/>
  <versioninfo/>
  -->
    <attribute name="anm_multipler" value="1"/>
    <!-- demo for photo app -->
 
    <!-- loading sequence -->
    
    <!-- openning sequence -->

    <script>
        LzView.addProxyPolicy( function (){ return false } );
    </script>
       
    <!-- include href="classes/classes.lzx" /-->
    <include href="views/details.lzx"/>
    <include href="classes/albumlayout.lzx"/>
    <include href="classes/pivotlayout.lzx"/>
    <include href="classes/photo.lzx"/>    
    <include href="classes/clipboard.lzx"/>
    <include href="classes/favorites.lzx"/>
    <include href="classes/search.lzx"/>    
    <include href="classes/draggedphotos.lzx"/>    
    <include href="classes/dataman.lzx"/>    
    <include href="classes/spinner.lzx"/>    
    <include href="views/mybutton.lzx"/>
    <include href="classes/linkbutton.lzx"/>
    <include href="resources.lzx"/>
    
    <attribute name="isopen" value="false"/>
    
    <view name="interior" bgcolor="0xf0f0f0" width="${parent.width}" height="${parent.height}">
    
        <!-- this view is tied to the divider ( on the canvas ) and is animated in height in the transition to details -->
        <view name="details_bkgnd" bgcolor="white" height="${canvas.divider.y}" width="${canvas.width}"/>
   
        <!-- the light blue area below the header that currently only contains ( visually )  the search field -->
        <view name="tools" width="800" height="91" bgcolor="0xbac0f8">
            <text fgcolor="0x1f13b1" x="96" y="68" text="Flickr Search:" fontsize="10"/>
            <text id="gResultsCountLabel" fgcolor="0x1f13b1" x="175" y="68" width="200" fontstyle="bold" fontsize="10"/>
            <!--  TODO: bret will replace with art
            view width="800" height="1" y="88" bgcolor="0x9993ee" />
            <view width="800" height="1" y="89" bgcolor="0xFFFFFF" /-->
        </view>

        <view name="beveled_divider" y="${parent.tools.height}" resource="assets/beveled-divider.gif" stretches="width" width="${parent.width}"/>
        
        <view id="photoscontainer" name="photos" visible="false" width="${parent.width}" height="460" y="93">
           <attribute name="detailphoto" value="null"/> <!-- the ref to the photo displayed in details -->

           <pivotlayout name="lyt" yinset="50" xinset="0" spacing="50" photodimension="70" photoscale="${canvas.tools.zoomscale}" skew="0" pivotindex="0" pivot_y="0" pivot_x="50">
 
                <method name="myreset">
                    if ( isgrid ) {
                        this.photoscale = canvas.tools.zoomscale;
                        this.photodimension = 70;
                        this.spacing = 50;
                        this.skew = 0;
                        this.pivot_x = 50;
                        yinset = 50;
                        xinset = 0;
                        this.pivot_y = 0;
                        this.yspacing = 50;
                        this.xspacing = 50;
                        this.pivotindex=0;
                    } else {
                        this.photodimension = 50;
                        this.photoscale = 1;
                        this.skew = 1;
                        //this.pivot_x = 50;
                        this.pivot_y = 405;
                        this.yspacing = -50;
                        this.xspacing = 10;
                        pivotindex=0;
                    }
                    this.update();
                   
                </method>

                 <!-- this animator used to chnage the layout paramters to work in details mode -->


                <animatorgroup name="transitiontolinear_anm" start="false">
                    
                    <animatorgroup name="grp" process="simultaneous">
                       <animator attribute="skew" from="0" to="1" duration="${canvas.anm_multipler*350}" motion="easeout"/>
                       <animator name="yspacing" attribute="yspacing" to="-70" duration="${canvas.anm_multipler*450}"/>
                       <animator attribute="xspacing" to="11" duration="${canvas.anm_multipler*550}"/>
                    </animatorgroup> 
                    
                   <animatorgroup process="simultaneous" onstop="canvas.details.ph.posme.doStart();">
                        <!-- pivot_x this needs to be fixed. The value needs to calcualted 
                             and assigned before this animation actiavtes -->
                        <animator attribute="pivot_x" to="-40" relative="true" duration="${canvas.anm_multipler*350}"/>                         
                        <animator attribute="pivot_y" to="357" duration="${canvas.anm_multipler*350}"/>
                        <animator attribute="photodimension" to="50" duration="${canvas.anm_multipler*350}"/>
                        <animator attribute="photoscale" to="1" duration="${canvas.anm_multipler*350}"/>
                        <animator attribute="yspacing" to="-50" duration="${canvas.anm_multipler*350}"/>
                    </animatorgroup>   
                    
                    <animatorgroup process="simultaneous" duration="${canvas.anm_multipler*350}">
                         <!-- animate the photo within the details view into position -->
                        <animator attribute="x" to="40" target="${canvas.details.title}" duration="${canvas.anm_multipler*350}"/>
                        <animator attribute="x" to="550" target="${canvas.details.info}" duration="${canvas.anm_multipler*350}"/>
                        <animator attribute="y" to="485" target="${canvas.divider}" duration="${canvas.anm_multipler*350}"/> 
                    </animatorgroup>
              
               </animatorgroup>

               

                <!-- When the transition is done, load in the medium image to the
                    details view. -->
               <handler name="onstop" reference="transitiontolinear_anm">
                    this.animate('dimmer',1,500);
                    //canvas.details.ph.posme.doStart(); 
                    //canvas.details.loadMediumImage();
                    this.updateOnIdle( false );
               </handler>



                 <!-- this animator used to chnage the layout paramters to work in details mode -->
                <animatorgroup name="transitiontogrid_anm" start="false" duration="${canvas.anm_multipler*300}" process="simultaneous">                
                    <animator attribute="x" to="-300" target="${canvas.details.title}"/>
                    <animator attribute="x" to="1500" target="${canvas.details.info}"/>
                    <animator attribute="y" to="0" target="${canvas.divider}"/>
                </animatorgroup>
                
                <animator name="pageNext" attribute="pivot_x" to="-800" relative="true" duration="1000" start="false"/>
                <animator name="pagePrev" attribute="pivot_x" to="800" relative="true" duration="1000" start="false"/>
            </pivotlayout>

 
            <attribute name="initialDone" value="false"/>

            <method name="displaytext" args="show">
                var i;
                for (i in photoscontainer.lyt.subviews) {
                   if (photoscontainer.lyt.subviews[i].txt && photoscontainer.lyt.subviews[i].txt.setVisible) photoscontainer.lyt.subviews[i].txt.setAttribute('visible',  show );
                }
            </method>
            
            <method name="transitionToDetails" args="ph_arg">      
                // locate the details photo to that of the selected photo
                //Debug.write("ph_arg: ", ph_arg);
                //Debug.write("ph_arg.intparent: ", ph_arg.intparent);
                //Debug.write("ph_arg.intparent.interior", ph_arg.intparent.interior); 
                var v =  ph_arg.intparent.interior;
                //Debug.write("transitionToDetails");

                canvas.details.ph.setAttribute('x', v.getAttributeRelative('x', canvas) -1 );
                canvas.details.ph.setAttribute('y', v.getAttributeRelative('y', canvas) -1 );
                var maxdim = (v.width > v.height) ? v.width + 2 : v.height + 2;
                canvas.details.ph.setAttribute('width', maxdim );
                canvas.details.ph.setAttribute('height', maxdim );

                canvas.details.setAttribute('visible',  true );

                this.lyt.setAttribute('textvisible',false);
                this.lyt.setAttribute('isgrid',false);
                
                //photoscontainer.lyt.registeronly( ['onskew','onphotodimension', 'ondimmer'] );
                
                //adjust an animation parameter before starting transition
                this.lyt.updateOnIdle( true );
                canvas.interior.details_bkgnd.setAttribute('height', 2);
                canvas.interior.details_bkgnd.setAttribute('visible',  true );
                this.lyt.transitiontolinear_anm.grp.yspacing.setAttribute('to', -photoscontainer.lyt.photodimension*photoscontainer.lyt.photoscale);
                this.lyt.transitiontolinear_anm.doStart();
                // canvas.details.ph.posme.doStart(); //max's edit?
                //anm_openphotodetails.doStart();
           </method>

            <method name="transitionToGrid"> 
                this.lyt.transitiontogrid_anm.doStart();
            </method>
            
            <handler name="onstop" reference="this.lyt.transitiontogrid_anm">
                //Debug.write("TOOLS back onclick", photoscontainer.detailphoto);
                canvas.interior.details_bkgnd.setAttribute('height', 0);
                canvas.interior.details_bkgnd.setAttribute('visible',  false );
                this.lyt.isgrid = true;
                this.lyt.myreset();
                this.lyt.setAttribute('textvisible',true); this.lyt.update();
                this.showPhotoDetails( false );   
                tls.enableZoom();
            </handler>

            <method name="showPhotoDetails" args="show,ph_arg=null">
                if ( show ) {
                    var photoid = ph_arg.datapath.p.getAttr("id"); 
                    canvas.details.setAttribute('visible',  true ); 
                    canvas.details.loadDetails( photoid ); 
                    canvas.details.loadUserInfo( ph_arg.datapath.p.getAttr("owner"));
                    
                    // Disable zoom when in details mode 
                    tls.disableZoom(); 
                } else  {
                
                    canvas.details.setAttribute('visible',  false );
                    canvas.details.info.setAttribute('x', 1500);
                }
                
            </method>

            <!-- end of animation back to photo grid -->
            <!--
            <handler name="onstop" reference="anm_closephotodetails" >
                photoscontainer.lyt.setAttribute('textvisible',true);
                photoscontainer.lyt.setAttribute('isgrid',true);
            </handler>
            -->


            <datapointer name="pagecounter_dp" xpath="photods:/rsp/photos/"/>
            <attribute name="doneDel" value="$once{ new LzDelegate( this, 'initialReplicationDone' ) }"/>
            
            <!-- once that data has loaded set the datapath on the photo -->
            <handler name="ondata" reference="photods">
                //Debug.write('ondata');
                //Debug.write(this.pagecounter_dp);
                this.initialReplicationDone();
                // create a method to be called when the last photo view is created
                // find out how many images there are
                if (! this.pagecounter_dp.p) return;
                var c = this.pagecounter_dp.p.childNodes.length;
                var currentpage = this.pagecounter_dp.xpathQuery('@page');
                var perpage = this.pagecounter_dp.xpathQuery('@perpage');
                var totalpages = this.pagecounter_dp.xpathQuery('@pages');
                photoscontainer.lyt.setAttribute('currentpage', currentpage);
                photoscontainer.lyt.setAttribute('perpage', perpage);
                photoscontainer.lyt.setAttribute('totalpages', totalpages);
                tls.setpPagingParams( c );
                gResultsCountLabel.setAttribute('text', this.buildResultsString(c) );                 
                this.watchforlast();
                photoscontainer.lyt.calcpageparams = true;
            </handler>
            
            <method name="watchforlast">
                //info('watchforlast');
                if (! this.ph['clones']) return;
                var lc = this.ph.clones[ this.ph.clones.length-1 ];
                //Debug.write("ondata ( dataset ): lc .......................................",lc);                
                this.doneDel.unregisterAll();
                if (lc != null) {
                    this.doneDel.register( lc, "oninit" );
                }
            </method>
                        
            <method name="initialReplicationDone" args="ignore=null">
                
                //this.setAttribute( "initialDone", true );
                //Debug.write("initialReplicationDone");
                photoscontainer.lyt.unlock();
                photoscontainer.lyt.update();
                photoscontainer.setAttribute('visible', true);
                spnr.setAttribute('visible', false);
                
            </method>

            <!-- Build string showing how many results were found
            @args num number of results found-->
            <method name="buildResultsString" args="num">
                var str = "No photos found"; 
                if (num ==  1) {
                    str = "Found one photo"; 
                } else if (num >= 100) {
                    str = "Found hundreds of photos";
                } else if (num >= 0) {
                    str = num + " photos found";                    
                } 
                return str; 
            </method>


            <selectionmanager name="selman" toggle="false">
                <method name="isMultiSelect" args="s">
                    return lz.Keys.isKeyDown( "control" ) || lz.Keys.isKeyDown( "shift" ) ||
                           parent.isRectangleSelecting;
                </method>
            </selectionmanager>

            <attribute name="isRectangleSelecting" value="false"/>
            <method name="selectInRectangle" args="x1, y1, x2, y2">
                
                if ( !selman.isMultiSelect(null) ){
                    selman.clearSelection();
                }
                this.setAttribute( "isRectangleSelecting", true );
                if ( x1 > x2 ){
                    var tmp = x1;
                    x1 = x2;
                    x2 = tmp;
                }
                if ( y1 > y2 ){
                    var tmp = y1;
                    y1 = y2;
                    y2 = tmp;
                }
                for ( var i = subviews.length-1; i >=0; i-- ){
                    var sv = subviews[ i ];
                    if ( ! ( sv instanceof lz.photo ) ) continue;
                    if ( sv.intersectsRectangle( x1, y1, x2 , y2 ) ){
                        selman.select( sv );
                    }
                }
                this.setAttribute( "isRectangleSelecting", false );
                
            </method>
            
            <!-- PHOTO INSTANCE -->
            <photo name="ph" doesdrag="true" width="70" height="70"> <!-- visible="${ loaded }" -->
                <datapath xpath="photods:/rsp/photos/photo[1-18]"/>
                <!-- this is what should trigger photo editing -->
                
                <handler name="onplainclick">
                    if ( parent.selman.isMultiSelect(null) ){
                        // Debug.write( this , " other click." );
                        parent.selman.select( this );
                        
                    } else {
                        // there are two states to the photo collection..
                        // grid-mode and list-mode. if in grid mode
                        // clicking on details will invoke a transition, while
                        // clikcing on details in list-mode is a simpler ( fade ) transition
                        
                        if ( parent.lyt.isgrid ) { 
                            canvas.details.setImage( this.getImageURL('t'), this.getImageURL('') );
                            photoscontainer.lyt.pivotAround(this);
                            photoscontainer.lyt.setAttribute('dimmer',0.2); //a visual affect that can be eliminated if need be.
                            parent.transitionToDetails( this );
                            
                            parent.showPhotoDetails( true, this );
                            
                        } else {
                            // Ignore this click if this photo is already the detailsphoto
                            if (photoscontainer.detailphoto == this) {
                                return;
                            } else {
                                canvas.details.setImage( this.getImageURL('t'), this.getImageURL('') );
                                parent.showPhotoDetails( true, this );
                            }
                        }
                        photoscontainer.detailphoto = this;
                    }
                </handler>
 

                <attribute name="selected" value="false"/>

                <method name="startDrag" args="offx, offy">
                    super.startDrag(offx, offy);
                    if ( !isselected ) parent.selman.select( this );
                    gDragged.startDrag( this, parent.selman.getSelection() , offx, offy );
                </method>

                <method name="stopDrag">
                    super.stopDrag();
                    gDragged.stopDrag( );
                    parent.selman.clearSelection();
                </method>

                <attribute name="isselected" value="false"/>

                <method name="setSelected" args="s">
                    this.borderbg.setAttribute('bgcolor', s ? "0xFFD800" : "0xFFFFFF"); 
                    this.setAttribute( "isselected" , s );
                    this.intparent.setAttribute('opacity', s ? .5 : 1 );
                </method>

                <method name="intersectsRectangle" args="x1, y1, x2, y2">
                    
                    return  x + width >  x1 && x < x2 &&
                         y + height > y1 && y < y2;
                    
                </method>

            </photo>

            <view name="rubberband" opacity=".3" options="ignorelayout" visible="false" bgcolor="0x0000BB">
                <attribute name="_sx" value="0"/>
                <attribute name="_sy" value="0"/>

                <attribute name="updel" value="$once{ new LzDelegate( this , 'update' ) }"/>
                <method name="starter">
                    this.setAttribute('visible',  true );
                    this._sx = parent.getMouse( "x" );
                    this._sy = parent.getMouse( "y" );
                    this.updel.register( lz.Idle, "onidle" );
                    this.bringToFront();
                    this.update();
                </method>

                <method name="update" args="ignore=null">
                    
                    var mx = this.parent.getMouse( 'x' );
                    var my = this.parent.getMouse( 'y' );
                    if ( mx < _sx ){
                        this.setAttribute('x', mx );
                        this.setAttribute('width', this._sx - mx - 1);
                    } else {
                        this.setAttribute('x', this._sx );
                        this.setAttribute('width', mx - this._sx + 1);
                    }
                    if ( my < this._sy ){
                        this.setAttribute('y', my );
                        this.setAttribute('height', this._sy - my - 1);
                    } else {
                        this.setAttribute('y', this._sy );
                        this.setAttribute('height', my - this._sy + 1);
                    }
                    
                </method>

                <method name="stopper" args="f = null, rel = null">
                    this.setAttribute('visible',  false );
                    this.updel.unregisterAll();
                    this.parent.selectInRectangle( this._sx , this._sy , 
                                                this.parent.getMouse( 'x' ),
                                                this.parent.getMouse( 'y' ) );
                </method>
            </view>

            <attribute name="showhandcursor" value="false"/>
            <handler name="onmousedown">
                if ( lyt.isgrid ) rubberband.starter();
            </handler>
            <handler name="onmouseup">
                rubberband.stopper();
            </handler>

        </view> <!-- end photos -->
        
        <view name="btm" width="800" height="88" y="${canvas.bottom.y - 2}">
            <view width="800" height="1" bgcolor="0x9993ee"/>
            <view width="800" height="1" y="1" bgcolor="0xFFFFFF"/>
        </view>

    </view> <!-- end interior -->

    <!-- details view starts off invisibile. we set it to visible in 
    showDetailsView -->
    <detailsview name="details" visible="false"/>

    <view name="divider" y="0">
        <view bgcolor="0x9993ee" width="800" height="1"/>
        <view bgcolor="0xffffff" width="800" height="1" y="1"/>
        <view resource="assets/details/hide.gif" x="700" y="-4"/>
         <!--animator -->
        <!-- Button for return to grid view, aka "hide details" -->
        <mybutton name="hideDetailsButton" width="70" id="hdb" x="718" onclick="this.returnToGridView()" resource="hidedetails_rsc" y="-5">
             <text fgcolor="0x463e9D" x="15" y="-2" fontsize="9" width="100">hide details</text>
            <method name="returnToGridView">
                photoscontainer.transitionToGrid();
            </method> 
            <view width="70" height="20" onmouseover="parent.onmouseover.sendEvent()" onmouseout="parent.onmouseout.sendEvent()" onmousedown="parent.onmousedown.sendEvent()" onmouseup="parent.onmouseup.sendEvent()" onclick="photoscontainer.transitionToGrid()"/>
        </mybutton>
   
    </view>

    <!-- top of app -->
    <view name="topview" bgcolor="0x1f13b1" opacity="1" height="300" width="${parent.width}">
          
        <animatorgroup name="anm" start="false" process="simultaneous" duration="1000">
            <animator attribute="height" to="60"/>
            <animator target="${canvas.logo}" attribute="x" to="100"/>
            <animator target="${canvas.logo}" attribute="y" to="14"/>
            <animator target="${canvas.large_cam}" attribute="width" to="104"/>
            <animator target="${canvas.large_cam}" attribute="height" to="89"/>
        </animatorgroup>

        <view bgcolor="0xffffff" width="${parent.width}" height="1" y="${parent.height - 1}"/>
        
        <handler name="onstop" reference="this.anm">
            this.parent.large_cam.setAttribute('visible',  false );
            this.parent.little_cam.setAttribute('visible',  true );
        </handler>
    </view>

        
    <view resource="assets/shadow.png" width="${parent.topview.width}" y="${parent.topview.height}" stretches="width"/>
    <view name="large_cam" resource="assets/branding/big_cam.png" stretches="both"/>
    <view name="little_cam" resource="assets/branding/lil_cam.png" visible="false"/>        
    <view name="logo" resource="assets/branding/logo.png" x="474" y="160"/>

    <!-- bottom of app -->
    <view name="bottom" bgcolor="0xf0f0f0" y="${canvas.height - height}" height="300" width="${parent.width}">
          <!--
          <view name="cover" height="300" width="${parent.width}" bgcolor="0x7979e9"/>
          -->
          
         <animatorgroup name="anm" id="agroup" start="false" process="simultaneous" duration="1000">
            <animator attribute="height" to="43" start="false"/>
            <!-- animator target="${parent.cover}"       attribute="opacity"   to="0" start="false"/-->
            <animator target="${canvas.fav}" attribute="height" to="59" start="false"/>
            <animator target="${canvas.fav}" attribute="width" to="141" start="false"/>
            <animator target="${canvas.fav}" attribute="x" to="654" start="false"/>
            <animator target="${canvas.fav}" attribute="y" to="0" start="false"/>
            <animator target="${canvas.fav}" attribute="titlearea" to="15" start="false"/>
            <animator target="${canvas.fav.photos.interior.lyt}" attribute="spacing" to="8" start="false"/>
            <animator target="${gClipboard}" attribute="x" to="0" start="false"/>
            <animator target="${canvas.tools}" attribute="x" to="594" start="false"/>
            <animator target="${canvas.srch}" attribute="y" to="65"/>
            <animator target="${canvas.srch}" attribute="x" to="568"/>
            <animator target="${canvas.srch}" attribute="width" to="117"/>
         </animatorgroup>
         
        
    </view>

    <view name="links" x="475" y="350">
        <!-- TODO: simplelayout is not working width text -->
        <simplelayout spacing="5"/>

        <!-- [TODO: chnage link and fix this comment ] pop up source code in new window. -->    
        <linkbutton label="View LZX source code" width="500" url="http:../../lps/utils/viewer/viewer.jsp?file=demos/lzpix/app.lzx&lzt=source" targetframe="_blank" windowopts=""/>

        <!-- [TODO: change link and fix this comment ] load flash app in place -->        
        <linkbutton label="Flash application" width="500" url="http:app.lzx?lzr=swf10&lzt=html" targetframe="_top" windowopts=""/>

        <!-- [TODO: change link and fix this comment ] load dhtml app in place -->
        <linkbutton label="DHTML application" width="500" url="http:app.lzx?lzr=dhtml&lzt=html" targetframe="_top" windowopts=""/>

        <linkbutton label="Learn about OpenLaszlo and LZPIX" width="500" url="http://www.openlaszlo.org" targetframe="_blank" windowopts=""/>

    </view> <!-- end links -->
    
    <favorites name="fav" x="475" width="240" height="80" y="210"/>
    
    <search name="srch" id="gSearch" width="156" x="475" y="315">
        <attribute name="firsttime" value="true"/>
        <method name="sendsearch" args="ignore=null">
            photoscontainer.setAttribute('visible', false); 
            //Debug.write("sendsearch: photoscontainer.lyt.lock called");
            photoscontainer.lyt.isgrid = true;
            photoscontainer.lyt.myreset();
            photoscontainer.lyt.lock();
            canvas.spnr.setAttribute('visible',  true );
            photoscontainer.lyt.transitiontogrid_anm.doStart();
            canvas.details.setAttribute('visible',  false );
            if (this.firsttime) {
                this.firsttime = false;
                photoscontainer.lyt.calcpageparams = true;
            } else {
                photoscontainer.lyt.calcpageparams = false;
            }
            tls.reset();
            tls.enableZoom();
            gResultsCountLabel.setAttribute('text', "...searching..."); 
            super.sendsearch();           
        </method>

    </search>

    <include href="views/tools.lzx"/>
 
    <spinner name="spnr" align="center" valign="middle"/>
    
    <view id="scrn" bgcolor="0x000000" visible="false" clickable="true" width="${parent.width}" height="${parent.height - this.y}" y="91" opacity=".3"/>
    
    <clipboard id="gClipboard" width="590" x="-800"/>

    <!-- bottom border -->
    <view bgcolor="0x312897" y="598" width="800" height="1" opacity=".6"/>
    <view bgcolor="0xffffff" y="599" width="800" height="1"/>


    <!-- right border -->
    <view bgcolor="0x312897" x="798" width="1" height="599" opacity=".6"/>
    <view bgcolor="0xffffff" x="799" width="1" height="599"/>

    <draggedphotos id="gDragged"/>
    
   <!-- text id="dbgr" x="5" y="5" text="something" /-->
     
    <method name="setOpen" args="o">
        if ( o ) {
            this.topview.anm.doStart();
            this.bottom.anm.doStart();
            this.isopen = true; 
            this.links.setAttribute('visible',  false );
            return this.bottom.anm;
        }
    </method>

    <include href="views/error.lzx"/>
</canvas>

Cross References

Includes

Named Instances