<?xml version="1.0" encoding="UTF-8"?>
<!--
   - ***** BEGIN LICENSE BLOCK *****
   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
   -
   - The contents of this file are subject to the Mozilla Public License Version
   - 1.1 (the "License"); you may not use this file except in compliance with
   - the License. You may obtain a copy of the License at
   - http://www.mozilla.org/MPL/
   -
   - Software distributed under the License is distributed on an "AS IS" basis,
   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   - for the specific language governing rights and limitations under the
   - License.
   -
   - The Original Code is Calendar view code.
   -
   - The Initial Developer of the Original Code is
   -   Joey Minta <jminta@gmail.com>
   - Portions created by the Initial Developer are Copyright (C) 2005
   - the Initial Developer. All Rights Reserved.
   -
   - Contributor(s):
   -   Michael Büttner <michael.buettner@sun.com>
   -   Philipp Kewisch <mozilla@kewis.ch>
   -   Martin Schroeder <mschroeder@mozilla.x-home.org>
   -
   - Alternatively, the contents of this file may be used under the terms of
   - either the GNU General Public License Version 2 or later (the "GPL"), or
   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   - in which case the provisions of the GPL or the LGPL are applicable instead
   - of those above. If you wish to allow use of your version of this file only
   - under the terms of either the GPL or the LGPL, and not to allow others to
   - use your version of this file under the terms of the MPL, indicate your
   - decision by deleting the provisions above and replace them with the notice
   - and other provisions required by the GPL or the LGPL. If you do not delete
   - the provisions above, a recipient may use your version of this file under
   - the terms of any one of the MPL, the GPL or the LGPL.
   -
   - ***** END LICENSE BLOCK *****
-->

<!-- 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 anonid="alarm-icons-box"
                              class="alarm-icons-box"
                              align="center"
                              xbl:inherits="flashing"/>
                  </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");

         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, ' ') :
                                    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 && getPrefSafe("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");
          }

          // 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));
              this.setAttribute("itemType", "todo");
          }

          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 (item.calendar instanceof Components.interfaces.calISchedulingSupport &&
              item.calendar.isInvitation(item)) {
              this.setAttribute("invitation-status", item.calendar.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;
            }
            var items;
            if (event.ctrlKey || event.metaKey) {
                items = this.calendarView.mSelectedItems;
                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 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 && 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>
