342 lines
13 KiB
XML
342 lines
13 KiB
XML
<?xml version="1.0"?>
|
|
<!-- ***** 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 Lightning code.
|
|
-
|
|
- The Initial Developer of the Original Code is Oracle Corporation
|
|
- Portions created by the Initial Developer are Copyright (C) 2005
|
|
- the Initial Developer. All Rights Reserved.
|
|
-
|
|
- Contributor(s):
|
|
- Mike Shaver <shaver@mozilla.org>
|
|
- Dan Mosedale <dmose@mozilla.org>
|
|
- Olli.Pettay@helsinki.fi
|
|
- Daniel Boelzle <daniel.boelzle@sun.com>
|
|
- Joey Minta <jminta@gmail.com>
|
|
-
|
|
- 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 ***** -->
|
|
|
|
<bindings id="calendar-todo-bindings"
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
|
<binding id="calendar-todo-list" extends="chrome://global/content/bindings/richlistbox.xml#richlistbox"
|
|
implements="calIObserver, calICompositeObserver, calIOperationListener">
|
|
<implementation>
|
|
<destructor><![CDATA[
|
|
if (this.mCalendar)
|
|
this.mCalendar.removeObserver(this.mOperationListener);
|
|
]]></destructor>
|
|
|
|
<field name="mCalendar">null</field>
|
|
<field name="mShowCompleted">true</field>
|
|
<field name="mOperationListener"><![CDATA[
|
|
({
|
|
todoList: this,
|
|
mBatchCount: 0,
|
|
|
|
onStartBatch: function onStartBatch()
|
|
{
|
|
this.mBatchCount++;
|
|
return;
|
|
},
|
|
|
|
onEndBatch: function onEndBatch()
|
|
{
|
|
this.mBatchCount--;
|
|
if (this.mBatchCount == 0) {
|
|
this.todoList.rebuildDisplay();
|
|
}
|
|
return;
|
|
},
|
|
|
|
onLoad: function onLoad()
|
|
{
|
|
return;
|
|
},
|
|
|
|
onAddItem: function onAddItem(aItem)
|
|
{
|
|
if (!(aItem instanceof Components.interfaces.calITodo) ||
|
|
this.mBatchCount)
|
|
return;
|
|
this.todoList.addTodo(aItem);
|
|
},
|
|
|
|
onDeleteItem: function onDeleteItem(aItem)
|
|
{
|
|
if (!(aItem instanceof Components.interfaces.calITodo) ||
|
|
this.mBatchCount)
|
|
return;
|
|
this.todoList.removeTodo(aItem);
|
|
},
|
|
|
|
onModifyItem: function onModifyItem(aNewItem, aOldItem)
|
|
{
|
|
if (!(aNewItem instanceof Components.interfaces.calITodo) ||
|
|
this.mBatchCount)
|
|
return;
|
|
this.todoList.removeTodo(aOldItem);
|
|
this.todoList.addTodo(aNewItem);
|
|
},
|
|
|
|
onError: function onError(aErrNo, aMessage)
|
|
{
|
|
},
|
|
|
|
onCalendarAdded: function onCalendarAdded(aCalendar)
|
|
{
|
|
this.todoList.rebuildDisplay();
|
|
},
|
|
|
|
onCalendarRemoved: function onCalendarRemoved(aCalendar)
|
|
{
|
|
this.todoList.rebuildDisplay();
|
|
},
|
|
|
|
onDefaultCalendarChanged: function onDefaultCalendarChanged(aCalendar)
|
|
{
|
|
return;
|
|
},
|
|
|
|
onGetResult: function onGetResult(aCalendar, aStatus, aItemType, aDetail, aCount, aItems)
|
|
{
|
|
if (!Components.isSuccessCode(aStatus)) {
|
|
Components.utils.reportError(
|
|
"Failed to fetch todo items: 0x" +
|
|
aStatus.toString(16));
|
|
return;
|
|
}
|
|
aItems.forEach(this.todoList.addTodo, this.todoList);
|
|
},
|
|
|
|
onOperationComplete: function onOperationComplete(aCalendar, aStatus, aOperationType, aId,
|
|
aDetail)
|
|
{
|
|
if (!Components.isSuccessCode(aStatus))
|
|
Components.utils.reportError("Failed to fetch todo item"
|
|
+ "(" + aId + "): 0x" +
|
|
aStatus.toString(16));
|
|
},
|
|
|
|
QueryInterface: function QueryInterface(aIID) {
|
|
if (!aIID.equals(Components.interfaces.calIObserver) &&
|
|
!aIID.equals(Components.interfaces.calICompositeObserver) &&
|
|
!aIID.equals(Components.interfaces.calIOperationListener) &&
|
|
!aIID.equals(Components.interfaces.nsISupports)) {
|
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
})
|
|
]]></field>
|
|
|
|
<property name="calendar">
|
|
<getter><![CDATA[ return this.mCalendar; ]]></getter>
|
|
<setter><![CDATA[
|
|
if (this.mCalendar)
|
|
this.mCalendar.removeObserver(this.mOperationListener);
|
|
this.mCalendar = val;
|
|
if (this.mCalendar)
|
|
this.mCalendar.addObserver(this.mOperationListener);
|
|
this.rebuildDisplay();
|
|
return val;
|
|
]]></setter>
|
|
</property>
|
|
|
|
<property name="showCompleted">
|
|
<getter><![CDATA[ return this.mShowCompleted; ]]></getter>
|
|
<setter><![CDATA[
|
|
this.mShowCompleted = val;
|
|
this.rebuildDisplay();
|
|
]]></setter>
|
|
</property>
|
|
|
|
<method name="fireEvent">
|
|
<parameter name="aEventType"/>
|
|
<body><![CDATA[
|
|
var e = document.createEvent("Events");
|
|
e.initEvent("todo-" + aEventType, true, true);
|
|
this.dispatchEvent(e);
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="addTodo">
|
|
<parameter name="aTodo"/>
|
|
<body><![CDATA[
|
|
for (var i=0; i < this.childNodes.length; i++) {
|
|
var elem = this.childNodes[i];
|
|
if (elem.todo.hasSameIds(aTodo)) {
|
|
return;
|
|
}
|
|
}
|
|
void("adding new todo " + aTodo.title + "\n");
|
|
var newTodoElt = document.createElement("calendar-todo-item");
|
|
newTodoElt.setAttribute("item-calendar", aTodo.calendar.uri.spec);
|
|
|
|
this.appendChild(newTodoElt);
|
|
newTodoElt.todo = aTodo;
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="removeTodo">
|
|
<parameter name="aTodo"/>
|
|
<body><![CDATA[
|
|
// don't use for each, because the 'in' operator will return
|
|
// other properties of childNodes as well, which don't have .todo
|
|
for (var i=0; i < this.childNodes.length; i++) {
|
|
var elem = this.childNodes[i];
|
|
if (elem.todo.hasSameIds(aTodo)) {
|
|
this.removeChild(elem);
|
|
}
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="fetchTodos">
|
|
<body><![CDATA[
|
|
if (!this.mCalendar)
|
|
return;
|
|
const cIC = Components.interfaces.calICalendar;
|
|
var filter = cIC.ITEM_FILTER_TYPE_TODO;
|
|
if (this.mShowCompleted) {
|
|
filter |= cIC.ITEM_FILTER_COMPLETED_ALL;
|
|
} else {
|
|
filter |= cIC.ITEM_FILTER_COMPLETED_NO;
|
|
}
|
|
this.mCalendar.getItems(filter, 0, null, null, this.mOperationListener);
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="rebuildDisplay">
|
|
<body><![CDATA[
|
|
while (this.firstChild)
|
|
this.removeChild(this.firstChild);
|
|
this.fetchTodos();
|
|
]]></body>
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="dblclick"><![CDATA[
|
|
if (this.selectedItem)
|
|
this.fireEvent("item-open");
|
|
else
|
|
this.fireEvent("empty-dblclick");
|
|
]]></handler>
|
|
|
|
<handler event="keypress"><![CDATA[
|
|
const kKE = Components.interfaces.nsIDOMKeyEvent;
|
|
if (event.keyCode == kKE.DOM_VK_RETURN ||
|
|
event.keyCode == kKE.DOM_VK_ENTER) {
|
|
event.stopPropagation();
|
|
this.fireEvent("item-open");
|
|
} else if (event.keyCode == kKE.DOM_VK_BACK_SPACE ||
|
|
event.keyCode == kKE.DOM_VK_DELETE) {
|
|
event.stopPropagation();
|
|
this.fireEvent("item-delete");
|
|
} else if (event.keyCode == kKE.DOM_VK_SPACE) {
|
|
var selected = this.selectedItem;
|
|
selected.checkbox.checked = !this.checkbox.checked;
|
|
selected.updateTodoFromDisplay();
|
|
}
|
|
]]></handler>
|
|
</handlers>
|
|
|
|
</binding>
|
|
|
|
<binding id="calendar-todo-item" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
|
<content>
|
|
<xul:hbox align="center" flex="1">
|
|
<xul:checkbox class="calendar-todo-item-checkbox" anonid="todo-check" xbl:inherits="checked=completed" oncommand="document.getBindingParent(this).updateTodoFromDisplay();"/>
|
|
<xul:label class="calendar-todo-item-label" anonid="todo-label" crop="end" xbl:inherits="item-calendar,value=label"/>
|
|
</xul:hbox>
|
|
</content>
|
|
<implementation>
|
|
<field name="mTodo">null</field>
|
|
|
|
<property name="checkbox">
|
|
<getter><![CDATA[ return document.getAnonymousElementByAttribute(this, "anonid", "todo-check");]]></getter>
|
|
</property>
|
|
|
|
<property name="manager">
|
|
<getter><![CDATA[ return this.mManager; ]]></getter>
|
|
<setter><![CDATA[ this.mManager = val; return val; ]]></setter>
|
|
</property>
|
|
|
|
<property name="label">
|
|
<getter><![CDATA[ return document.getAnonymousElementByAttribute(this, "anonid", "todo-label");]]></getter>
|
|
</property>
|
|
|
|
<property name="todo" onget="return this.mTodo;"
|
|
onset="this.mTodo = val; this.updateDisplayFromTodo();"/>
|
|
|
|
<method name="setAttribute">
|
|
<parameter name="aAttr"/>
|
|
<parameter name="aVal"/>
|
|
<body><![CDATA[
|
|
if (aAttr == "completed")
|
|
this.checkbox.setAttribute("checked", aVal);
|
|
else if (aAttr == "label")
|
|
this.label.setAttribute("value", aVal);
|
|
return XULElement.prototype.setAttribute.call(this, aAttr, aVal);
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="updateTodoFromDisplay">
|
|
<body><![CDATA[
|
|
var dirty = false;
|
|
var clone = this.mTodo.clone();
|
|
if (this.mTodo.isCompleted != this.checkbox.checked) {
|
|
clone.isCompleted = this.checkbox.checked;
|
|
dirty = true;
|
|
}
|
|
if (this.mTodo.title != this.label.value) {
|
|
clone.title = this.label.value;
|
|
dirty = true;
|
|
}
|
|
if (dirty) {
|
|
this.mTodo.calendar.modifyItem(clone, this.mTodo, null);
|
|
// dump(clone.icalComponent.serializeToICS() + "\n");
|
|
this.mTodo = clone;
|
|
}
|
|
]]></body>
|
|
</method>
|
|
|
|
<method name="updateDisplayFromTodo">
|
|
<body><![CDATA[
|
|
this.setAttribute("completed", this.mTodo.isCompleted);
|
|
this.setAttribute("label", this.mTodo.title);
|
|
]]></body>
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
|
</bindings>
|