calendar.lzx

<!-- This is an example of a fairly sophisticated Laszlo app that makes    -->
<!-- use of advanced features such as custom events, states, and complex   -->
<!-- data bindings. Note that there is no convetion in this code with      -->
<!-- respect to variable and method names: some are all lower case, some   -->
<!-- use underscores ("_") and some use mixedCase.                         -->
<canvas title="Laszlo Calendar" bgcolor="#1E3A49" width="835" height="600">
    <include href="resources.lzx"/>
    <include href="cal-button.lzx"/>


    <!-- INCLUDES -->
    <include href="lz/scrollbar.lzx"/>

    <include href="gridsliderlayout.lzx"/>
    <include href="basepanel.lzx"/>
    <include href="cal-data.lzx"/>
    <include href="event.lzx"/>
    <include href="day.lzx"/>
    <include href="infopanel.lzx"/>
    <include href="simpletimelayout.lzx"/>
    <include href="dayname.lzx"/>
    <include href="selected-daylook.lzx"/>
    <include href="eventselector.lzx"/>
    


    <attribute name="calMonths" value="[ "January","February","March","April",                                          "May","June", "July","August",                                          "September","October", "November",                                          "December" ]"/>

    <!-- ============================ LOADING ============================= -->
    <!-- Displays splash, instantiation progress                            -->
    <!-- ================================================================== -->

    <include href="loading.lzx"/>

    <!-- ============================ MAIN ================================ -->
    <!-- This is the main section of the calendar, where all the views      -->
    <!-- ================================================================== -->

    <!-- The top panel holds the views above the calendar grid, which include
         the day names that appear as column titles.  -->
    <view font="Verdana,sans-serif" id="toppanel" x="20" y="-50" width="806" fontsize="10">

        <!-- This is the bar that appears below the toolbar (and contains the
             day names. This comes first in the file because it needs to be
             behind the toolbar. -->
        <view name="weekbkgnd" bgcolor="#354D5B" y="26" width="808" height="26">
            <!-- Day names appear as titles in month and week views.  They
                 are constrained to their respective columns within the
                 calendar grid by binding to the firs-->
            <view name="daynames" x="0" y="11" width="792">

                <!-- shows the day titles if necessary when the grid stops
                     updating -->
                <handler name="onupdatestop" method="showalldaytitles" reference="calgrid.gridlayout"/>
                <method name="showalldaytitles" args="v">
                  
                    if ( calgrid.gridlayout.displaymode != 'cell' ){
                        var svs = this.subviews;
                        for (var i = 0; i < 7; i++) {
                            svs[i].setAttribute('visible', true);
                        }
                    } 
                </method>
                <dayname name="sunday" resource="sunday_label" targetCell="cell1"/>
                <dayname name="monday" resource="monday_label" targetCell="cell2"/>
                <dayname name="tuesday" resource="tuesday_label" targetCell="cell3"/>
                <dayname name="wednesday" resource="wednesday_label" targetCell="cell4"/>
                <dayname name="thursday" resource="thursday_label" targetCell="cell5"/>
                <dayname name="friday" resource="friday_label" targetCell="cell6"/>
                <dayname name="saturday" resource="saturday_label" targetCell="cell7"/>


            </view>
            <view name="line" bgcolor="#708A94" height="1" y="25" width="${parent.width}"/>
        </view>

        <!-- TOOLBAR DISPLAY Month and a set of tools for
             manipulating that month -->
        <view name="mbar" bgcolor="#354D5B" width="${parent.width}">

            <view resource="menubar"/>
            <view resource="logo"/>

            <view name="viewbuttons" x="141" y="4">
                <calButton rightcap="shear" icon="iconDay" onclick="calgrid.showdayview()" label="day"/>
                <calButton leftcap="shear" rightcap="shear" icon="iconWeek" onclick="calgrid.showweekview()" label="week"/>
                <calButton leftcap="shear" icon="iconMonth" onclick="calgrid.showmonthview(true)" label="month"/>
                <simplelayout axis="x"/>
            </view>

            <view name="monthController" x="321" y="8" width="161">
                <calButton rightcap="shear" icon="iconLeftArrow" onclick="calgrid.prevMonth()"/>
                <calButton label=" " leftcap="shear" rightcap="shear" clickable="false" options="releasetolayout"/>
                <calButton leftcap="shear" leftinset="5" rightinset="9" icon="iconRightArrow" onclick="calgrid.nextMonth()"/>
                <resizelayout axis="x"/>
            </view>

            <!-- constrain shadow to the top -->
            <text name="monthtitleshdw" fontstyle="bold" fgcolor="#143B45" y="${parent.monthtitle.y -1}" x="${parent.monthtitle.x -0.3}" opacity=".5">
                  <attribute name="text" value="${parent.monthtitle.text}"/>
            </text>
            <text name="monthtitle" fontstyle="bold" fgcolor="#FFFFFF" y="10">
                <handler name="ontext">
                    this.setAttribute('x', Math.round( ( this.parent.width -
                               this.getTextWidth())/2.0) - 2);
                    this.setAttribute('width', this.getTextWidth()+2);
                    this.parent.monthtitleshdw.setAttribute('width', this.getTextWidth()+2);

                </handler>
            </text>

            <calButton label="Add Event" x="496" y="5" onclick="eventDataMgr.addEvent(); infopanel.open(); infopanel.setAttribute('dataapply', false);"/>
        </view>

        <!-- animates in top panel on startup -->
    <animator id="slideInTopPanel" attribute="y" to="0" duration="500" start="false" onstop="calgrid.finishStartSequence()"/>

    </view>

    <!-- The cal interior holds the views in the calendar with the exception
         of the top view.  -->
    <view id="cal_interior" x="20" y="57" visible="false" opacity="0" clip="true" font="Verdana,sans-serif" width="810" height="516" pixellock="true">
        <attribute name="viewstyle" type="string" value="month"/>

        <animator name="fadeUp" attribute="opacity" onstop="dayselectorlook.setAttribute('opacity', 1 )" duration="1000" from="0" to="1" start="false"/>

        <info_Panel name="infopanel" id="infopanel" x="830" width="203" height="516" visible="false" initstage="late" font="Verdana,sans-serif" pixellock="true">
            <datapath p="${currenteventDP.p}"/>
        </info_Panel>
      </view>

        <view id="calgrid" x="${cal_interior.x}" y="${cal_interior.y}" width="${cal_interior.width - 2}" height="${cal_interior.height}">
          <attribute name="viewmode" value="month" type="string"/>
          <attribute name="firstDay" value="null"/>
          <attribute name="keepinfoopen" type="boolean" value="false"/>

          <!-- this is the right way to do this, even though it seems
               ridiculous. The cells are calendar_day's are part of the
               app; they don't really depend on any data at this point.
               It would be nice to move them to another file, but the
               library tag won't work here, and we don't want to use an
               extra view to make the included file valid XML (with a
               single root element.) -->
          <calendar_day id="cell1"/>
          <calendar_day id="cell2"/>
          <calendar_day id="cell3"/>
          <calendar_day id="cell4"/>
          <calendar_day id="cell5"/>
          <calendar_day id="cell6"/>
          <calendar_day id="cell7"/>

          <calendar_day id="cell8"/>
          <calendar_day id="cell9"/>
          <calendar_day id="cell10"/>
          <calendar_day id="cell11"/>
          <calendar_day id="cell12"/>
          <calendar_day id="cell13"/>
          <calendar_day id="cell14"/>

          <calendar_day id="cell15"/>
          <calendar_day id="cell16"/>
          <calendar_day id="cell17"/>
          <calendar_day id="cell18"/>
          <calendar_day id="cell19"/>
          <calendar_day id="cell20"/>
          <calendar_day id="cell21"/>

          <calendar_day id="cell22"/>
          <calendar_day id="cell23"/>
          <calendar_day id="cell24"/>
          <calendar_day id="cell25"/>
          <calendar_day id="cell26"/>
          <calendar_day id="cell27"/>
          <calendar_day id="cell28"/>

          <calendar_day id="cell29"/>
          <calendar_day id="cell30"/>
          <calendar_day id="cell31"/>
          <calendar_day id="cell32"/>
          <calendar_day id="cell33"/>
          <calendar_day id="cell34"/>
          <calendar_day id="cell35"/>

          <calendar_day id="cell36"/>
          <calendar_day id="cell37"/>
          <calendar_day id="cell38"/>
          <calendar_day id="cell39"/>
          <calendar_day id="cell40"/>
          <calendar_day id="cell41"/>
          <calendar_day id="cell42"/>

          <gridsliderlayout name="gridlayout" cols="7" spacing="4"/>


          <!-- METHODS -->
          <method name="finishStartSequence">
              cal_interior.setAttribute('visible',  true );
              var now = new Date();
              this.setMonthAndYear(now.getMonth(), now.getFullYear());
              cal_interior.fadeUp.doStart();
          </method>

          <!-- Finds the day associated with a given JavaScript Date
               object -->
          <method name="get_dayview" args="t">       
              if (t < this.startdate || t > this.enddate)
                  return null;
              // to deal with daylight savings and such, we find an
              //  approximate date and then refine it by looking at
              //  the start and end of the dayviews
              var d = Math.round((t.getTime() - this.startdate.getTime())
                                 / 86400000);
              // NOTE: 86400000 represents one day in miliseconds

              if (d >= this.subviews.length) d = this.subviews.length - 1
              if (d < 0) d = 0;

              var dv = this.subviews[d];
              while (dv.startdate > t) {
                  d--;
                  dv = this.subviews[d];
              }
              while (dv.enddate <= t) {
                  d++;
                  dv = this.subviews[d];
              }
              return dv;
          </method>


         <!-- Makes the passed day the open day (with the grid in the
              background -->
         <method name="openday" args="d">       
              // d is a reference to a dayview

              //make sure it's selected
              this.daySelectionMgr.select( d );

              // don't do anything else if already opened
              // if (this['open_day'] == d) { return; }

              // Open one day, close the last

              // update gridslider
              if(gridlayout.displaymode == 'grid') gridlayout.doanimation = false;

              gridlayout.setopenview(d,true);

              this.open_day = d;  // Make the requested day the open day
          </method>


          <method name="closeday">      
              //if (this['open_day'] == undefined || this.open_day == null)
              //    return;

              //this.open_day.setAttribute( 'opened' , false);
              //this.open_day = null;
              gridlayout.doanimation = false;
              gridlayout.setopenview(null,true);

          </method>

          <method name="prevMonth">
              var prvmonth = this.month - 1;
              var prvyear = this.year;
              if (this.month == 0) {
                  prvmonth = 11;
                  prvyear -= 1;
              }
              this.setMonthAndYear(prvmonth,prvyear);
              cal_interior.viewstyle = "month";
          </method>

          <method name="nextMonth">
              var nxtmonth = this.month + 1;
              var nxtyear = this.year;
              if (this.month == 11) {
                  nxtmonth = 0;
                  nxtyear += 1;
              }
              var t = LzTimeKernel.getTimer();
              this.setMonthAndYear(nxtmonth,nxtyear);
              if (global['mytext'] != null){
                  global['mytext'].setAttribute('text', LzTimeKernel.getTimer() -t );
              }
              cal_interior.viewstyle = "month";
          </method>

          <!-- BEGIN: VIEW MODE METHODS ASSOCIATED WITH VIEW BUTTONS -->
          <method name="showonedaytitle" args="dayindex"> 
              var svs = toppanel.weekbkgnd.daynames.subviews;
              for (var i = 0; i < 7; i++){
                  if (i == dayindex)
                      svs[i].setAttribute('visible', true);
                  else
                      svs[i].setAttribute('visible', false);
              }
           </method>

          <method name="showdayview"> 
              var sday = daySelectionMgr.getSelection()[0];
              this.showonedaytitle(sday.col);
              gridlayout.showcell(sday.row,sday.col);
              cal_interior.setAttribute("viewstyle", "day");
           </method>

          <method name="showweekview"> 
              var sday = daySelectionMgr.getSelection()[0];
              gridlayout.showrow(sday.row);
              cal_interior.setAttribute("viewstyle", "week");
           </method>

          <method name="showmonthview" args="withanimation"> 
              gridlayout.showgrid(false);
              cal_interior.setAttribute("viewstyle", "month");
           </method>

          <!-- END: VIEW MODE METHODS ASSOCIATED WITH VIEW BUTTONS -->

          <method name="setMonthAndYear" args="mth,yr"> 
              if (mth == this['month'] && yr == this['year']){
                  return;
              }

              if(this.keepinfoopen == false){
                  eventselector.hide();
              }

              this.month = mth;
              this.year  = yr;

              this.gridlayout.setopenview(null,false);

              // don't animate  gridlayout on update
              gridlayout.setAttribute('doanimation',false);
              //this.gridlayout.setAttribute('displaymode','grid');
              var noanimation = true;
              gridlayout.showgrid(noanimation);

              var t = canvas.calMonths[mth] + " " + yr;
              toppanel.mbar.monthtitle.setAttribute('text', t);

              this.setDates();


              
          </method>


          <!-- These are used by the info panel when it slides in and out -->
          <method name="contract">
              gridlayout.doanimation = false;
              this.setAttribute('width', cal_interior.width - 208);
          </method>

          <method name="expand">
              gridlayout.doanimation = false;
              this.setAttribute('width', cal_interior.width);
          </method>

          <!-- This method sets the dates for all the days in the grid,
               depending on the current month. Also ensures that data is
               loaded for all visible months -->
          <method name="setDates"> 
              this.calcBoundaryDates();

              var k=0;
              var firstDay="";

              var dtstart = new Date(this.startdate);
              var lastVisibleDay = this.gridlayout.rows*7;

              for (k=0;k< this.subviews.length && k <= lastVisibleDay; k++) {
                  // to get start of next day, add 26 hours, then
                  //  zero hours/mins/secs/msecs
                  var dtend = new Date(dtstart.getTime() + 26 * 3600000);
                  dtend.setHours(0);
                  dtend.setMinutes(0);
                  dtend.setSeconds(0);
                  dtend.setMilliseconds(0);

                  var dayview = this.subviews[k];
                  dayview.setDate(dtstart, dtend);

                  //Debug.write("dtstart:  "+dtstart.getDate());

                  if (firstDay=="" && dtstart.getDate()==1)
                      firstDay=dayview;

                 //Debug.write( "k, DATE, subview =" + k + ","
                   //            + dtstart.toString() + "," + dayview);

                  dtstart = dtend;
              }

              this.enddate = dtstart;
              // Calls to getYear() returns 2 digits on FF, and 4 digits
              // on IE6. getFullYear() returns 4 digits in all.
              var i = this.startdate.getFullYear() * 100 +
                      this.startdate.getMonth();
              var en= this.enddate.getFullYear() * 100 +
                      this.enddate.getMonth();
              //now request all the months that are visible onscreen from
              //the data loader
              while (  i <= en  ){
                  var mo = i%100;
                  var yr = Math.floor( i/100 );
                  if ( mo < 11 ) i++
                  else           i += ( 100 - 11 );
                  //Debug.write( "request mo " + mo +" yr " + yr);
                  dataloader.loadData( mo+1 , yr );
              }

              // point to the new 1st day of the month
              this.daySelectionMgr.select( firstDay );
              
          </method>

          <method name="calcBoundaryDates">
              //This method is a helper for setDates
              
              // GET A NEW DATE OBJECT FOR STARTDATE
              this.startdate = new Date();

              // SET THE DATE TO THE FIRST OF THE MONTH
              this.startdate.setMonth(this.month,1);
              this.startdate.setFullYear(this.year);

              // Find the first sunday of that week which contains
              // the first of the specified month
              // NOTE: 86400000 milliseconds represents one day
              this.startdate.setTime( this.startdate.getTime() -
                                      86400000*this.startdate.getDay());

              // Zero the time for that day
              this.startdate.setHours(0,0,0,0);

              // Get a new date object for end date
              this.enddate = new Date();

              // Find the date coressponding to the sunday 5 weeks later
              // from the startdate
              this.enddate.setTime(this.startdate.getTime() + 86400000*7*5);

              // NOW set the real end date if the 5TH sunday is part of
              // the current month or not
              // first make sure next month is correct if part of next year
              var nxtmonth = this.enddate.getMonth();
              if ((this.month == 11) && (nxtmonth == 0)) nxtmonth = 12;

              if ( nxtmonth > this.month) {
                  this.enddate.setTime(this.enddate.getTime() - 86400000);
                  //step back a day
                  this.gridlayout.setAttribute('rows',5);
              } else {
                  this.enddate.setTime(this.enddate.getTime() + 86400000*6);
                  //set for next sat
                  this.gridlayout.setAttribute('rows',6);
              }
              
          </method>

          <selectionmanager name="daySelectionMgr"/>

      </view>


    <!-- This is the beveled treatment for the selected day, plus the button
         that appears in the top right corner -->
    <selectedDayLook id="dayselectorlook" width="150" height="23" font="Verdana,sans-serif" visible="false" opacity="0"/>

    <eventSelectorbar id="eventselector" font="Verdana,sans-serif"/>

    <!-- Start the ui appearing with a cool animation when the canvas is ready -->
    <handler reference="canvas" name="oninit">
        slideInTopPanel.doStart(); // make the top panel slide in
        loadingView.destroy();  
    </handler>
    
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
<!-- @LZX_VERSION@                                                         -->

Cross References

Includes

Named Instances