<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->

<!-- Note that this file depends on helper functions in calUtils.js-->

<bindings id="calendar-core-view-bindings"
    xmlns="http://www.mozilla.org/xbl"
    xmlns:html="http://www.w3.org/1999/xhtml"
    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    xmlns:xbl="http://www.mozilla.org/xbl">

  <binding id="calendar-editable-item">
    <content mousethrough="never"
             tooltip="itemTooltip"
             tabindex="-1">
      <xul:vbox flex="1">
        <xul:hbox>
          <xul:box anonid="event-container"
                   class="calendar-color-box"
                   xbl:inherits="calendar-uri,calendar-id"
                   flex="1">
            <xul:box class="calendar-event-selection" orient="horizontal" flex="1">
              <xul:stack anonid="eventbox"
                         class="calendar-event-box-container"
                         flex="1"
                         xbl:inherits="readonly,flashing,alarm,allday,priority,progress,status,calendar,categories">
                <xul:hbox class="calendar-event-details">
                  <xul:vbox align="left"
                            flex="1"
                            xbl:inherits="context">
                    <xul:label anonid="event-name"
                               crop="end"
                               flex="1"
                               style="margin: 0;"/>
                    <xul:textbox anonid="event-name-textbox"
                                 class="plain"
                                 crop="end"
                                 hidden="true"
                                 style="background: transparent !important;"
                                 wrap="true"/>
                    <xul:spacer flex="1"/>
                  </xul:vbox>
                  <xul:stack>
                    <xul:calendar-category-box anonid="category-box"
                                               xbl:inherits="categories"
                                               pack="end"/>
                    <xul:hbox align="center">
                      <xul:hbox anonid="alarm-icons-box"
                                class="alarm-icons-box"
                                align="center"
                                xbl:inherits="flashing"/>
                      <xul:image anonid="item-classification-box"
                                  class="item-classification-box"
                                  pack="end"/>
                    </xul:hbox>
                  </xul:stack>
                </xul:hbox>
              </xul:stack>
            </xul:box>
          </xul:box>
        </xul:hbox>
      </xul:vbox>
    </content>

    <implementation>
      <constructor><![CDATA[
         Components.utils.import("resource://calendar/modules/calAlarmUtils.jsm");
         Components.utils.import("resource://calendar/modules/calUtils.jsm");
         Components.utils.import("resource://gre/modules/Preferences.jsm");

         let self = this;
         this.eventNameTextbox.onblur = function onBlur() {
             self.stopEditing(true);
         };
         this.eventNameTextbox.onkeypress = function onKeyPress(event) {
             // save on enter
             if (event.keyCode == 13)
                 self.stopEditing(true);
             // abort on escape
             else if (event.keyCode == 27)
                 self.stopEditing(false);
         };
         function stopPropagationIfEditing(event) { 
           if (self.mEditing) {
             event.stopPropagation();
           }
         }
         // while editing, single click positions cursor, so don't propagate.
         this.eventNameTextbox.onclick = stopPropagationIfEditing;
         // while editing, double click selects words, so don't propagate.
         this.eventNameTextbox.ondblclick = stopPropagationIfEditing;
         // while editing, don't propagate mousedown/up (selects calEvent).
         this.eventNameTextbox.onmousedown = stopPropagationIfEditing;
         this.eventNameTextbox.onmouseup = stopPropagationIfEditing;
      ]]></constructor>

      <field name="mOccurrence">null</field>
      <field name="mSelected">false</field>
      <field name="mCalendarView">null</field>

      <property name="parentBox"
                onget="return this.mParentBox;"
                onset="this.mParentBox = val;"/>

      <property name="selected">
        <getter><![CDATA[
          return this.mSelected;
        ]]></getter>
        <setter><![CDATA[
          if (val && !this.mSelected) {
              this.mSelected = true;
              this.setAttribute("selected", "true");
          } else if (!val && this.mSelected) {
              this.mSelected = false;
              this.removeAttribute("selected");
          }
          return val;
        ]]></setter>
      </property>
      <property name="calendarView">
        <getter><![CDATA[
          return this.mCalendarView;
        ]]></getter>
        <setter><![CDATA[
          this.mCalendarView = val;
          return val;
        ]]></setter>
      </property>

      <property name="occurrence">
        <getter><![CDATA[
          return this.mOccurrence;
        ]]></getter>
        <setter><![CDATA[
          this.mOccurrence = val;
          this.setEditableLabel();
          this.setCSSClasses();
          return val;
        ]]></setter>
      </property>

      <property name="eventNameLabel" readonly="true"
        onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'event-name');"/>
      <property name="eventNameTextbox" readonly="true"
        onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'event-name-textbox');"/>

      <method name="setEditableLabel">
        <body><![CDATA[
          var evl = this.eventNameLabel;
          var item = this.mOccurrence;
          evl.value = (item.title ? item.title.replace(/\n/g, ' ') :
                                    cal.calGetString("calendar", "eventUntitled"));
        ]]></body>
      </method>

      <method name="setCSSClasses">
        <body><![CDATA[
          var item = this.mOccurrence;          
          this.setAttribute("calendar-uri", item.calendar.uri.spec);
          this.setAttribute("calendar-id", item.calendar.id);
          var categoriesArray = item.getCategories({});
          if (categoriesArray.length > 0) {
            var cssClassesArray = categoriesArray.map(formatStringForCSSRule);
            this.setAttribute("categories", cssClassesArray.join(" "));
          }

          // Add alarm icons as needed.
          let alarms = item.getAlarms({});
          if (alarms.length && Preferences.get("calendar.alarms.indicator.show", true)) {
              let iconsBox = document.getAnonymousElementByAttribute(this, "anonid", "alarm-icons-box");
              cal.alarms.addReminderImages(iconsBox, alarms);

              // Set suppressed status on the icons box
              setElementValue(iconsBox,
                              item.calendar.getProperty("suppressAlarms") || false,
                              "suppressed");
          }

          // Item classification / privacy
          let classificationBox = document.getAnonymousElementByAttribute(this, "anonid", "item-classification-box");
          if (classificationBox) {
              classificationBox.setAttribute("classification", item.privacy || "PUBLIC");
          }

          // Set up event box attributes for use in css selectors. Note if
          // something is added here, it should also be xbl:inherited correctly
          // in the <content> section of this binding, and all that inherit it.

          // Event type specific properties
          if (cal.isEvent(item)) {
              if (item.startDate.isDate) {
                  this.setAttribute("allday", "true");
              }
              this.setAttribute("itemType", "event");
          } else if (cal.isToDo(item)) {
              // progress attribute
              this.setAttribute("progress", getProgressAtom(item));
              // Attribute for tasks and tasks image.
              this.setAttribute("itemType", "todo");
              if (item.entryDate && !item.dueDate) {
                  this.setAttribute("todoType", "start");
              } else if (!item.entryDate && item.dueDate) {
                  this.setAttribute("todoType", "end");
              }
          }

          if (this.calendarView &&
              item.hashId in this.calendarView.mFlashingEvents) {
              this.setAttribute("flashing", "true");
          }

          if (alarms.length) {
              this.setAttribute("alarm", "true")
          }

          // priority
          if (item.priority > 0 && item.priority < 5) {
              this.setAttribute("priority", "high");
          } else if (item.priority > 5 && item.priority < 10) {
              this.setAttribute("priority", "low");
          }

          // status attribute
          if (item.status) {
              this.setAttribute("status", item.status.toUpperCase());
          }

          // item class
          if (item.hasProperty("CLASS")) {
              this.setAttribute("itemclass", item.getProperty("CLASS"));
          }

          // calendar name
          this.setAttribute("calendar", item.calendar.name.toLowerCase());

          // Invitation
          if (cal.isInvitation(item)) {
              this.setAttribute("invitation-status", cal.getInvitedAttendee(item).participationStatus);
              this.setAttribute("readonly", "true");
          } else if (!isCalendarWritable(item.calendar)) {
              this.setAttribute("readonly", "true");
          }
        ]]></body>
      </method>

      <method name="startEditing">
        <body><![CDATA[
          this.editingTimer = null;
          this.mOriginalTextLabel = this.mOccurrence.title;

          this.eventNameLabel.setAttribute("hidden", "true");

          this.mEditing = true;

          this.eventNameTextbox.value = this.mOriginalTextLabel;
          this.eventNameTextbox.removeAttribute("hidden");
          this.eventNameTextbox.select();
        ]]></body>
      </method>
      <method name="select">
        <parameter name="event"/>
        <body><![CDATA[
            if (!this.calendarView) {
                return;
            }
            let items = this.calendarView.mSelectedItems.slice();
            if (event.ctrlKey || event.metaKey) {    
                if (this.selected) {
                    let pos = items.indexOf(this.mOccurrence);
                    items.splice(pos, 1);
                } else {
                    items.push(this.mOccurrence);
                }
            } else {
                items = [this.mOccurrence];
            }
            this.calendarView.setSelectedItems(items.length, items);
        ]]></body>
      </method>
      <method name="stopEditing">
        <parameter name="saveChanges"/>
        <body><![CDATA[
          if (!this.mEditing)
            return;

          this.mEditing = false;

          if (saveChanges && (this.eventNameTextbox.value != this.mOriginalTextLabel)) {
              this.calendarView.controller.modifyOccurrence(this.mOccurrence, 
                                                            null, null,
                                                            this.eventNameTextbox.value);

              // Note that as soon as we do the modifyItem, this element ceases to exist,
              // so don't bother trying to modify anything further here! ('this' exists,
              // because it's being kept alive, but our child content etc. is all gone)
              return;
          }

          this.eventNameTextbox.setAttribute("hidden", "true");
          this.eventNameLabel.removeAttribute("hidden");
          return;
        ]]></body>
      </method>
    </implementation>

    <handlers>
      <handler event="contextmenu" phase="capturing"><![CDATA[
       // If the middle/right button was used for click just select the item.
       if (!this.selected) {
         this.select(event);
       }
      ]]></handler>
      <handler event="click" button="0"><![CDATA[
        if (this.mEditing) {
            return;
        }

        // If the left button was used and the item is already selected
        // and there are no multiple items selected start
        // the 'single click edit' timeout. Otherwise select the item too.
        // Also, check if the calendar is readOnly or we are offline.

        if (this.selected && !(event.ctrlKey || event.metaKey) &&
              isCalendarWritable(this.mOccurrence.calendar)) {
            var self = this;
            if (this.editingTimer) {
                clearTimeout(this.editingTimer);
            }
            this.editingTimer = setTimeout(function editingTimeout() { self.startEditing(); }, 350);
        } else {
            this.select(event);
            event.stopPropagation();
        }
      ]]></handler>

      <handler event="dblclick" button="0"><![CDATA[
        event.stopPropagation();

        // stop 'single click edit' timeout (if started)
        if (this.editingTimer) {
            clearTimeout(this.editingTimer);
            this.editingTimer = null;
        }

        if (this.calendarView && this.calendarView.controller) {
            var item = (event.ctrlKey) ? this.mOccurrence.parentItem : this.mOccurrence;
            this.calendarView.controller.modifyOccurrence(item);
        }
      ]]></handler>
      <handler event="mouseover"><![CDATA[
        if (this.calendarView && this.calendarView.controller) {
            event.stopPropagation();
            onMouseOverItem(event);
        }
      ]]></handler>
      <handler event="draggesture"><![CDATA[
        if( event.target.localName == "calendar-event-box") {
            return;
        }
        let item = this.occurrence;
        if (!isCalendarWritable(item.calendar)
            || !userCanModifyItem(item)
            || (item.calendar instanceof Components.interfaces.calISchedulingSupport && item.calendar.isInvitation(item))) {
            return;
        }
        if (!this.selected)
            this.select(event);
        invokeEventDragSession(item, this);
      ]]></handler>
    </handlers>
  </binding>

  <binding id="calendar-category-box">
    <!-- calendar-views.css makes this binding hide if the categories attribute
         is not specified -->
    <content>
      <xul:vbox anonid="category-box"
                class="category-color-box calendar-event-selection"
                xbl:inherits="categories">
        <xul:hbox flex="1">
          <xul:image class="calendar-category-box-gradient" height="1"/>
        </xul:hbox>
        <xul:hbox height="1"/>
      </xul:vbox>
    </content>
  </binding>

</bindings>
