Schedule Widget Sample Overview

Wearable web

The Schedule Widget sample application demonstrates how you can create a simple Web application and widgets that communicate with each other.

The sample consists of a Web application and 2 Web widgets. The application package includes the widgets, allowing the application and widgets to share data, and ensuring that when you build or run the application, the widgets are built and ran at the same time. The application contains the whole schedule feature, while the widgets are used to display the events for the current day and the monthly view.

The following figure illustrates the main screens of the Schedule Widget web application (on top) and the widgets (at the bottom).

Figure: Schedule Widget Web application and widget screens

Schedule Widget Web application screens Schedule Widget Web application screens Schedule Widget Web application screens

Schedule Event widget screen Schedule Monthly widget screen

The Web application displays lists of scheduled events in the monthly, daily, and detail views.

The widgets display more limited information:

  • The Event widget (shown at the bottom left above) shows today's events only.

    If you tap the widget, the Schedule Widget Web application is launched.

  • The Monthly widget (shown at the bottom right above) shows the current month. The current day is highlighted, and all days with events scheduled for them are marked with a dot.

    If you tap the widget, the Schedule Widget Web application is launched.

Source Files

You can create and view the sample application project, including the source files, in the IDE.

Table: Source files
File name Description
config.xml This file contains the application information for the platform to install and launch the application, including the view mode and the icon to be used in the device menu.
css/style.css This file contains the CSS styling for the application UI.
index.html This is a starting file from which the application starts loading. It contains the layout of the application screens.
js/app.js This file contains the code for handling the main functionalities of the application.
js/data.js This file contains the event information data.
js/page-daily.js This file contains the methods for the daily page.
js/page-detail.js This file contains the methods for the detail page.
js/page-history.js This file contains the methods for managing page history.
js/page-monthly.js This file contains the methods for the monthly page.
js/swipe.js This file contains the methods for the swipe event.
js/util.js This file contains the methods for utilities used in the application.
widget/ScheduleEventWidget/css/style.css This file contains the CSS styling for the Event widget UI.
widget/ScheduleEventWidget/index.html This is a starting file from which the Event widget starts loading. It contains the layout of the Event widget screens.
widget/ScheduleEventWidget/js/app.js This file contains the code for handling the main functionalities of the Event widget.
widget/ScheduleMonthlyWidget/config.xml This file contains the information for the platform to install and launch the Monthly widget, including the view mode and the icon to be used in the device menu.
widget/ScheduleMonthlyWidget/css/style.css This file contains the CSS styling for the Monthly widget UI.
widget/ScheduleMonthlyWidget/index.html This is a starting file from which the Monthly widget starts loading. It contains the layout of the Monthly widget screen.
widget/ScheduleMonthlyWidget/js/app.js This file contains the code for handling the main functionalities of the Monthly widget.
widget/ScheduleMonthlyWidget/js/data.js This file contains the event information data in the Monthly widget.
widget/ScheduleMonthlyWidget/js/page-daily.js This file contains the methods for the daily page in the Monthly widget.
widget/ScheduleMonthlyWidget/js/page-detail.js This file contains the methods for the detail page in the Monthly widget.
widget/ScheduleMonthlyWidget/js/page-history.js This file contains the methods for managing page history in the Monthly widget.
widget/ScheduleMonthlyWidget/js/page-monthly.js This file contains the methods for the monthly page in the Monthly widget.
widget/ScheduleMonthlyWidget/js/swipe.js This file contains the methods for the swipe event in the Monthly widget.
widget/ScheduleMonthlyWidget/js/util.js This file contains the methods for utilities used in the Monthly widget.

Implementation

To implement the Schedule Widget Web application:

  1. The init() method initializes the application.

    If the application launches from a widget, it performs the requested action. The event data must be set to be shared with the widget.

    function init()
    {
       var reqAppControl, events;
    
       events = util.getEvents();
       /* Set the preference value to event data to share with the widget */
       tizen.preference.setValue('events', JSON.stringify(events));
       /* Get the requested application control passed to the current application */
       reqAppControl = tizen.application.getCurrentApplication().getRequestedAppControl();
    
       if (reqAppControl && reqAppControl.appControl.operation === 'schedule/daily')
       {
          pageDaily.activate();
       }
       else
       {
          pageMonthly.activate();
       }
    
       /* Apply a circular scrollbar */
       document.getElementById('page-daily').setAttribute("tizen-circular-scrollbar", "");
       document.getElementById('page-detail').setAttribute("tizen-circular-scrollbar", "");
       window.addEventListener('tizenhwkey', keyEventHandler);
    }
    
  2. If the daily screen is required, the activate() method in the page-daily.js file shows and generates the page content. It shows the days that have events (always shows today as an exception) from today to 4 weeks later.

    You can get the events using the getEvents() method of the util library. If the event element on the screen is clicked, the detail page of the event is activated.

    /* page-daily.js */
    function activate()
    {
       var container = document.getElementById('daily-container'),
           events = util.getEvents(),
           today, year, month, date, len, data, dateElement, noEventElement, eventElement, nameContainerElement, nameElement, nameIcon,
           timeElement, eventDateObj, eventYear, eventMonth, eventDate, eventDay, eventList, key, i, j;
    
       slideTextList = [];
       pageHistory.push(pageDaily);
       show();
    
       /* Get today's year, month, and date */
       today = new Date();
       year = today.getFullYear();
       month = today.getMonth();
       date = today.getDate();
    
       while (container.hasChildNodes())
       {
          container.removeChild(container.firstChild);
       }
    
       /* Generate days that have events from today to 4 weeks later */
       for (i = 0; i < 28; i++)
       {
          eventDateObj = new Date(year, month, date + i);
          eventYear = eventDateObj.getFullYear();
          eventMonth = eventDateObj.getMonth() + 1;
          eventDate = eventDateObj.getDate();
          eventDay = eventDateObj.getDay();
    
          /* Generate key to get event data */
          key = '' + eventYear;
          key += eventMonth > 9 ? '-' + eventMonth : '-0' + eventMonth;
          key += eventDate > 9 ? '-' + eventDate : '-0' + eventDate;
    
          /* Get the event list using the key value */
          eventList = events[key];
    
          if (i === 0 && !eventList)
          {
             dateElement = document.createElement('div');
             dateElement.classList.add('daily-date');
             dateElement.textContent = WEEKDAY[eventDay] + ', ' + MONTH[eventMonth] + ' ' + eventDate;
             noEventElement = document.createElement('div');
             noEventElement.classList.add('no-event-name');
             noEventElement.textContent = 'No events today';
             container.appendChild(dateElement);
             container.appendChild(noEventElement);
          }
          else if (eventList)
          {
             len = eventList.length;
             dateElement = document.createElement('div');
             dateElement.classList.add('daily-date');
             dateElement.textContent = WEEKDAY[eventDay] + ', ' + MONTH[eventMonth] + ' ' + eventDate;
             container.appendChild(dateElement);
             for (j = 0; j < len; j++)
             {
                data = eventList[j];
                eventElement = document.createElement('div');
                eventElement.classList.add('daily-event');
                eventElement.id = data.id;
                eventElement.key = key;
                nameContainerElement = document.createElement('div');
                nameContainerElement.classList.add('daily-event-name');
                nameIcon = document.createElement('span');
                nameIcon.classList.add('daily-event-name-icon');
                nameIcon.style.backgroundColor = data.color;
                nameElement = document.createElement('div');
                nameElement.classList.add('daily-event-name-text');
                if (data.declined)
                {
                   nameElement.classList.add('event-declined');
                }
                nameElement.textContent = data.name;
                nameElement.appendChild(nameIcon);
                nameContainerElement.appendChild(nameElement);
                timeElement = document.createElement('div');
                timeElement.classList.add('daily-event-time');
                if (data.allDay)
                {
                   timeElement.textContent = 'All day';
                }
                else
                {
                   timeElement.textContent = util.convertTimeFormat(data.startHours, data.startMinutes, data.endHours, data.endMinutes);
                }
                eventElement.appendChild(nameContainerElement);
                eventElement.appendChild(timeElement);
                container.appendChild(eventElement);
    
                if (nameElement.offsetWidth > 360)
                {
                   slideTextList.push(nameElement);
                }
                eventElement.addEventListener('click', activateDetailHandler);
             }
          }
       }
    
       scrollHandler();
       page.addEventListener('scroll', scrollHandler);
    }
    
  3. If the detail screen is required, the activate() method in the page-detail.js file shows and generates the page content. It shows the detail information of the event.

    You can get the events using the getEvents() method of the util library.

    /* page-detail.js */
    function activate (key, id)
    {
       var page = document.getElementById('page-detail'),
           events = util.getEvents(),
           date, len, data, dateElement, nameContainerElement, nameIcon, nameElement, timeElement, contentElement, i;
    
       pageHistory.push(pageDetail);
       show();
    
       while (page.hasChildNodes())
       {
          page.removeChild(page.firstChild);
       }
    
       date = new Date(key);
       events = events[key];
       len = events.length;
       for (i = 0; i < len; i++)
       {
          data = events[i];
          if (data.id === id)
          {
             dateElement = document.createElement('div');
             dateElement.classList.add('detail-date');
             dateElement.textContent = WEEKDAY[date.getDay()] + ', ' + MONTH[date.getMonth() + 1] + ' ' + date.getDate();
             page.appendChild(dateElement);
    
             nameContainerElement = document.createElement('div');
             nameContainerElement.classList.add('detail-event-name');
             nameIcon = document.createElement('span');
             nameIcon.classList.add('detail-name-icon');
             nameIcon.style.backgroundColor = data.color;
             nameElement = document.createElement('span');
             nameElement.classList.add('detail-name-text');
             nameElement.textContent = data.name;
             nameElement.appendChild(nameIcon);
             nameContainerElement.appendChild(nameElement);
             page.appendChild(nameContainerElement);
    
             timeElement = document.createElement('div');
             timeElement.classList.add('detail-time');
             if (data.allDay)
             {
                timeElement.textContent = 'All day';
             }
             else
             {
                timeElement.textContent = util.convertTimeFormat(data.startHours, data.startMinutes, data.endHours, data.endMinutes);
             }
             page.appendChild(timeElement);
    
             contentElement = document.createElement('div');
             contentElement.classList.add('detail-content');
             if (data.declined)
             {
                nameElement.classList.add('event-declined');
                contentElement.classList.add('event-declined');
             }
             contentElement.textContent = data.detail;
             page.appendChild(contentElement);
             break;
          }
       }
    }
    
  4. If the monthly screen is required, the activate() method in the page-monthly.js file shows and generates the page content. It shows 1 month at a time.

    You can get the events using the getEvents() method of the util library. If the page of the current month is clicked, the daily page is activated. If the page is clicked on another month, it moves to the current month.

    /* js/page-monthly.js */
    function activate(year, month)
    {
       var container = document.getElementById('days-container'),
           days = [],
           activeDate, firstDay, lastDate, count, el, i;
    
       if (pageHistory.getCurrentPage() !== pageMonthly)
       {
          pageHistory.push(pageMonthly);
       }
       show();
       /* Get current year and month */
       today = new Date();
       currentYear = year ? year : today.getFullYear();
       currentMonth = month ? month : today.getMonth() + 1;
    
       while (container.hasChildNodes())
       {
          container.removeChild(container.firstChild);
       }
    
       /* Set the title of the calendar */
       document.getElementById('monthly-title').textContent = MONTH[currentMonth] + ' ' + currentYear;
    
       /* Set the date to the last date of the current month */
       activeDate = new Date(currentYear, currentMonth, 0);
       lastDate = activeDate.getDate();
       activeDate.setDate(1);
       firstDay = activeDate.getDay();
    
       for (i = 0; i < firstDay; i++)
       {
          el = document.createElement('div');
    
          el.classList.add('days');
          if (i === 0)
          {
             el.classList.add('sunday');
          }
          container.appendChild(el);
       }
    
       for (i = 1; i <= lastDate; i++)
       {
          var day = i + firstDay;
    
          el = document.createElement('div');
          el.classList.add('days');
    
          if (day % 7 === 1)
          {
             el.classList.add('sunday');
          }
          else if (day % 7 === 0)
          {
             el.classList.add('saturday');
          }
          el.textContent = i;
          container.appendChild(el);
          days[i] = el;
       }
    
       count = (42 - (firstDay + lastDate)) % 7;
       for (i = 1; i <= count; i++)
       {
          el = document.createElement('div');
          el.classList.add('days');
          if (i === count)
          {
             el.classList.add('saturday');
          }
          container.appendChild(el);
       }
    
       if (count + firstDay +lastDate === 35)
       {
          document.getElementById('calendar').style.paddingTop = '19px';
       }
       else if (count + firstDay + lastDate === 42)
       {
          document.getElementById('calendar').style.paddingTop = '3px';
       }
       else if (count + firstDay + lastDate === 28)
       {
          document.getElementById('calendar').style.paddingTop = '36px';
       }
    
       if (today.getFullYear() === currentYear && today.getMonth() + 1 === currentMonth)
       {
          days[today.getDate()].classList.add('today');
       }
    }
    

Schedule Event Widget

To implement the Event widget:

  1. The init() method initializes the widget. It calls the setEvents() method and adds an event listener to the page. If the page is clicked, the Schedule Widget Web application is launched with the daily screen.

    function init()
    {
       setEvents();
    
       /* Launch the Web application when the page is clicked */
       document.getElementById('page').addEventListener('click', launchApp.bind(this, 'schedule/daily'));
       /* Add an eventListener for tizenhwkey */
       window.addEventListener('tizenhwkey', keyEventHandler);
    }
    
  2. The launchApp() method launches the Schedule Widget Web application.

    function launchApp(operation)
    {
       var app = window.tizen.application.getCurrentApplication();
       var appId = app.appInfo.id.substring(0, (app.appInfo.id.lastIndexOf('.')));
       var appControl = new tizen.ApplicationControl(operation, null, null, null, null, null);
       window.tizen.application.launchAppControl(appControl, appId,
                                                 function()
                                                 {
                                                    console.log("launch application control succeed");
                                                 },
                                                 function(e)
                                                 {
                                                    console.log("launch application control failed. reason: " + e.message);
                                                 },
                                                 null);
    }
    
  3. The getEvents() method gets the event data from the Web application using the preferences (the Preference API):

    function getEvents()
    {
       return JSON.parse(tizen.preference.getValue('events'));
    }
    
  4. The setEvents() method sets and generates the event list. It shows today's events only.

    function setEvents()
    {
       var events = getEvents(),
           today = new Date(),
           count = 0,
           allDayCount = 0,
           timeAssignCount = 0,
           eventList, year, month, date, day, list, listItem, time, key, noEvent, item, i;
    
       /* Get today's year, month, date, and day */
       year = today.getFullYear();
       month = today.getMonth() + 1;
       date = today.getDate();
       day = today.getDay();
    
       /* Set today's date */
       document.getElementById('event-date').textContent = date;
       /* Set today's weekday */
       document.getElementById('event-day').textContent = WEEKDAY[day];
    
       list = document.getElementById('event-list');
    
       /* Generate key to get event data */
       key = '' + year;
       key += month > 9 ? '-' + month : '-0' + month;
       key += date > 9 ? '-' + date : '-0' + date;
    
       /* Get the event list using the key value */
       eventList = events[key];
       /* Create event list and add it to page */
       if (eventList)
       {
          count = eventList.length;
          /* Count the number of all day events and time assign events */
          for (i = 0; i < count; i++)
          {
             item = eventList[i];
             if (item.allDay)
             {
                allDayCount++;
             }
             else
             {
                timeAssignCount++;
             }
          }
          if (count <= 2)
          {
             for (i = 0; i < count; i++)
             {
                item = eventList[i];
                if (item.allDay)
                {
                   time = 'All day';
                }
                else
                {
                   time = convertTimeFormat(item.startHours, item.startMinutes, item.endHours, item.endMinutes);
                }
                listItem = generateItem(item.color, item.name, time);
                list.appendChild(listItem);
             }
          }
          else if (allDayCount >= 2 && timeAssignCount >= 1)
          {
             listItem = generateItem(eventList[0].color, allDayCount + ' all-day events');
             list.appendChild(listItem);
             item = eventList[allDayCount];
             time = convertTimeFormat(item.startHours, item.startMinutes, item.endHours, item.endMinutes);
             listItem = generateItem(item.color, item.name, time);
             list.appendChild(listItem);
    
             if (timeAssignCount > 1)
             {
                document.getElementById('event-more').textContent = '+' + (timeAssignCount - 1);
             }
          }
          else if (allDayCount >= 3)
          {
             item = eventList[0];
             listItem = generateItem(item.color, item.name, 'All day');
             list.appendChild(listItem);
             item = eventList[1];
             listItem = generateItem(item.color, (allDayCount - 1) + ' more all-day events');
             listItem.style.paddingLeft = '10px';
             listItem.style.paddingRight = '10px';
             list.appendChild(listItem);
          }
          else if (allDayCount === 1 && timeAssignCount > 2)
          {
             item = eventList[0];
             listItem = generateItem(item.color, item.name, 'All day');
             list.appendChild(listItem);
             item = eventList[allDayCount];
             time = convertTimeFormat(item.startHours, item.startMinutes, item.endHours, item.endMinutes);
             listItem = generateItem(item.color, item.name, time);
             list.appendChild(listItem);
             document.getElementById('event-more').textContent = '+' + (timeAssignCount - 1);
          }
          else if (allDayCount === 0 && timeAssignCount > 2)
          {
             item = eventList[0];
             time = convertTimeFormat(item.startHours, item.startMinutes, item.endHours, item.endMinutes);
             listItem = generateItem(item.color, item.name, time);
             list.appendChild(listItem);
             item = eventList[1];
             time = convertTimeFormat(item.startHours, item.startMinutes, item.endHours, item.endMinutes);
             listItem = generateItem(item.color, item.name, time);
             list.appendChild(listItem);
             document.getElementById('event-more').textContent = '+' + (timeAssignCount - 2);
          }
       }
    
       /* If event list does not exist, add the "no event" element to page */
       if (count === 0)
       {
          noEvent = document.createElement('div');
          noEvent.classList.add('event-no');
          noEvent.textContent = 'No upcoming event';
          list.appendChild(noEvent);
       }
    }
    

Schedule Monthly Widget

To implement the Monthly widget:

  1. The init() method initializes the widget. It calls the setCalendar() method and adds an event listener to page.

    If the calendar is clicked, the Schedule Widget Web application is launched with the daily screen. If the CALENDAR button is clicked, the Schedule Widget Web application is launched with the monthly screen.

    function init()
    {
       setCalendar();
    
       /* Launch the Web application when the calendar is clicked */
       document.getElementById('calendar').addEventListener('click', launchApp.bind(this, 'schedule/daily'));
       /* Launch the Web application when the calendar button is clicked */
       document.getElementById('calendar-button').addEventListener('click', launchApp.bind(this, 'schedule/monthly'));
       /* Add an eventListener for tizenhwkey */
       window.addEventListener('tizenhwkey', keyEventHandler);
    }
    
  2. The launchApp() method launches the Schedule Widget Web application.

    function launchApp(operation)
    {
       var app = window.tizen.application.getCurrentApplication();
       var appId = app.appInfo.id.substring(0, (app.appInfo.id.lastIndexOf('.')));
       var appControl = new tizen.ApplicationControl(operation, null, null, null, null, null);
       window.tizen.application.launchAppControl(appControl, appId,
                                                 function()
                                                 {
                                                    console.log("launch application control succeed");
                                                 },
                                                 function(e)
                                                 {
                                                    console.log("launch application control failed. reason: " + e.message);
                                                 },
                                                 null);
    }
    
  3. The getEvents() method gets the event data from the Web application using the preferences (the Preference API):

    function getEvents()
    {
       return JSON.parse(tizen.preference.getValue('events'));
    }
    
  4. The setCalendar() method sets and generates the monthly view. It shows the current month only, so that the days with events are dotted.

    function setCalendar()
    {
       var today = new Date(),
           events = getEvents(),
           calendar = document.getElementById('calendar'),
           year, month, date, day, eventList, firstDay, lastDate, key, el, img, count, i;
    
       /* Get today's year, month and date */
       year = today.getFullYear();
       month = today.getMonth() + 1;
       date = today.getDate();
    
       document.getElementById('month').textContent = MONTH[month];
    
       today.setMonth(month);
       today.setDate(0);
       lastDate = today.getDate();
       today.setDate(1);
       firstDay = today.getDay();
    
       for (i = 0; i < firstDay; i++)
       {
          el = document.createElement('div');
          el.classList.add('days');
          if (i === 0)
          {
             el.classList.add('sunday');
          }
          calendar.appendChild(el);
       }
    
       for (i = 1; i <= lastDate; i++)
       {
          day = i + firstDay;
          el = document.createElement('div');
          el.classList.add('days');
          if (day % 7 === 1)
          {
             el.classList.add('sunday');
          }
          else if (day % 7 === 0)
          {
             el.classList.add('saturday');
          }
          el.textContent = i;
          calendar.appendChild(el);
    
          if (i === date)
          {
             el.classList.add('today');
          }
    
          /* Generate key to get event data */
          key = '' + year;
          key += month > 9 ? '-' + month : '-0' + month;
          key += i > 9 ? '-' + i : '-0' + i;
    
          /* Get the event list using the key value */
          eventList = events[key];
          if (eventList)
          {
             img = document.createElement('img');
             img.classList.add('event-icon');
             img.src = i === date ? 'image/month_view_widget_schedule_today_event.png' : 'image/month_view_widget_schedule_event.png';
             el.appendChild(img);
          }
       }
    
       count = (42 - (firstDay + lastDate)) % 7;
       for (i = 1; i <= count; i++)
       {
          el = document.createElement('div');
          el.classList.add('days');
          if (i === count)
          {
             el.classList.add('saturday');
          }
          calendar.appendChild(el);
       }
    
       if (count + firstDay +lastDate === 35)
       {
          document.getElementById('calendar').style.paddingTop = '19px';
       }
       else if (count + firstDay + lastDate === 42)
       {
          document.getElementById('calendar').style.paddingTop = '3px';
       }
       else if (count + firstDay + lastDate === 28)
       {
          document.getElementById('calendar').style.paddingTop = '36px';
       }
    }