Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorBart Visscher <bartv@thisnet.nl>2012-05-05 20:26:07 +0400
committerBart Visscher <bartv@thisnet.nl>2012-05-05 20:26:13 +0400
commit2facf509cc172ab822f573f3b582caef59995dc1 (patch)
treef1fd342291a90ac9b625729844f6448743e74696 /apps
parentd46bea8867593399c04ea18bb6ad090aa2a258f2 (diff)
parent2092caf6d3be26dbb009c2f6585212841f5c823a (diff)
Merge branch 'tasks' for Tasks app
Diffstat (limited to 'apps')
-rwxr-xr-xapps/calendar/lib/app.php13
-rw-r--r--apps/tasks/ajax/addtask.php26
-rw-r--r--apps/tasks/ajax/addtaskform.php20
-rw-r--r--apps/tasks/ajax/delete.php31
-rw-r--r--apps/tasks/ajax/edittask.php31
-rw-r--r--apps/tasks/ajax/edittaskform.php24
-rw-r--r--apps/tasks/ajax/getdetails.php24
-rw-r--r--apps/tasks/ajax/gettasks.php36
-rw-r--r--apps/tasks/ajax/update_property.php68
-rw-r--r--apps/tasks/appinfo/app.php16
-rw-r--r--apps/tasks/appinfo/info.xml10
-rw-r--r--apps/tasks/css/style.css59
-rw-r--r--apps/tasks/img/icon.pngbin0 -> 457 bytes
-rw-r--r--apps/tasks/img/icon.svg101
-rw-r--r--apps/tasks/index.php34
-rw-r--r--apps/tasks/js/tasks.js532
-rw-r--r--apps/tasks/lib/app.php187
-rw-r--r--apps/tasks/lib/vtodo.php27
-rw-r--r--apps/tasks/templates/part.addtaskform.php15
-rw-r--r--apps/tasks/templates/part.details.php42
-rw-r--r--apps/tasks/templates/part.edittaskform.php5
-rw-r--r--apps/tasks/templates/part.property.php22
-rw-r--r--apps/tasks/templates/part.taskform.php36
-rw-r--r--apps/tasks/templates/part.tasks.php3
-rw-r--r--apps/tasks/templates/tasks.php31
25 files changed, 1391 insertions, 2 deletions
diff --git a/apps/calendar/lib/app.php b/apps/calendar/lib/app.php
index eb440b5794b..8cbef4646fc 100755
--- a/apps/calendar/lib/app.php
+++ b/apps/calendar/lib/app.php
@@ -179,7 +179,7 @@ class OC_Calendar_App{
foreach($events as $event) {
$vobject = OC_VObject::parse($event['calendardata']);
if(!is_null($vobject)) {
- $vcategories->loadFromVObject($vobject->VEVENT, true);
+ self::loadCategoriesFromVCalendar($vobject);
}
}
}
@@ -190,7 +190,16 @@ class OC_Calendar_App{
* @see OC_VCategories::loadFromVObject
*/
public static function loadCategoriesFromVCalendar(OC_VObject $calendar) {
- self::getVCategories()->loadFromVObject($calendar->VEVENT, true);
+ $object = null;
+ if (isset($calendar->VEVENT)) {
+ $object = $calendar->VEVENT;
+ } else
+ if (isset($calendar->VTODO)) {
+ $object = $calendar->VTODO;
+ }
+ if ($object) {
+ self::getVCategories()->loadFromVObject($object, true);
+ }
}
public static function getRepeatOptions(){
diff --git a/apps/tasks/ajax/addtask.php b/apps/tasks/ajax/addtask.php
new file mode 100644
index 00000000000..891fbdb96df
--- /dev/null
+++ b/apps/tasks/ajax/addtask.php
@@ -0,0 +1,26 @@
+<?php
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$calendars = OC_Calendar_Calendar::allCalendars(OCP\User::getUser(), true);
+$cid = reset($calendars)['id'];
+
+$input = $_GET['text'];
+$request = array();
+$request['summary'] = $input;
+$request["categories"] = null;
+$request['priority'] = null;
+$request['percent_complete'] = null;
+$request['completed'] = null;
+$request['location'] = null;
+$request['due'] = null;
+$request['description'] = null;
+$vcalendar = OC_Task_App::createVCalendarFromRequest($request);
+$id = OC_Calendar_Object::add($cid, $vcalendar->serialize());
+
+$user_timezone = OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone', date_default_timezone_get());
+$task = OC_Task_App::arrayForJSON($id, $vcalendar->VTODO, $user_timezone);
+
+OCP\JSON::success(array('task' => $task));
diff --git a/apps/tasks/ajax/addtaskform.php b/apps/tasks/ajax/addtaskform.php
new file mode 100644
index 00000000000..20797f31aba
--- /dev/null
+++ b/apps/tasks/ajax/addtaskform.php
@@ -0,0 +1,20 @@
+<?php
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$calendars = OC_Calendar_Calendar::allCalendars(OCP\User::getUser(), true);
+$category_options = OC_Calendar_App::getCategoryOptions();
+$percent_options = range(0, 100, 10);
+$priority_options = OC_Task_App::getPriorityOptions();
+$tmpl = new OC_Template('tasks','part.addtaskform');
+$tmpl->assign('calendars',$calendars);
+$tmpl->assign('category_options', $category_options);
+$tmpl->assign('percent_options', $percent_options);
+$tmpl->assign('priority_options', $priority_options);
+$tmpl->assign('details', new OC_VObject('VTODO'));
+$tmpl->assign('categories', '');
+$page = $tmpl->fetchPage();
+
+OCP\JSON::success(array('data' => array( 'page' => $page )));
diff --git a/apps/tasks/ajax/delete.php b/apps/tasks/ajax/delete.php
new file mode 100644
index 00000000000..6d2868748d1
--- /dev/null
+++ b/apps/tasks/ajax/delete.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * ownCloud - Addressbook
+ *
+ * @author Jakob Sack
+ * @copyright 2011 Jakob Sack mail@jakobsack.de
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$id = $_GET['id'];
+$task = OC_Calendar_App::getEventObject( $id );
+
+OC_Calendar_Object::delete($id);
+OCP\JSON::success(array('data' => array( 'id' => $id )));
diff --git a/apps/tasks/ajax/edittask.php b/apps/tasks/ajax/edittask.php
new file mode 100644
index 00000000000..78d1f193938
--- /dev/null
+++ b/apps/tasks/ajax/edittask.php
@@ -0,0 +1,31 @@
+<?php
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$l10n = new OC_L10N('tasks');
+
+$id = $_POST['id'];
+$vcalendar = OC_Calendar_App::getVCalendar($id);
+
+$errors = OC_Task_App::validateRequest($_POST);
+if (!empty($errors)) {
+ OCP\JSON::error(array('data' => array( 'errors' => $errors )));
+ exit();
+}
+
+OC_Task_App::updateVCalendarFromRequest($_POST, $vcalendar);
+OC_Calendar_Object::edit($id, $vcalendar->serialize());
+
+$priority_options = OC_Task_App::getPriorityOptions();
+$tmpl = new OC_Template('tasks','part.details');
+$tmpl->assign('priority_options', $priority_options);
+$tmpl->assign('details', $vcalendar->VTODO);
+$tmpl->assign('id', $id);
+$page = $tmpl->fetchPage();
+
+$user_timezone = OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone', date_default_timezone_get());
+$task = OC_Task_App::arrayForJSON($id, $vcalendar->VTODO, $user_timezone);
+
+OCP\JSON::success(array('data' => array( 'id' => $id, 'page' => $page, 'task' => $task )));
diff --git a/apps/tasks/ajax/edittaskform.php b/apps/tasks/ajax/edittaskform.php
new file mode 100644
index 00000000000..a439a0c0317
--- /dev/null
+++ b/apps/tasks/ajax/edittaskform.php
@@ -0,0 +1,24 @@
+<?php
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$id = $_GET['id'];
+$details = OC_Calendar_App::getVCalendar($id)->VTODO;
+$categories = $details->getAsString('CATEGORIES');
+
+$category_options = OC_Calendar_App::getCategoryOptions();
+$percent_options = range(0, 100, 10);
+$priority_options = OC_Task_App::getPriorityOptions();
+
+$tmpl = new OC_Template('tasks','part.edittaskform');
+$tmpl->assign('category_options', $category_options);
+$tmpl->assign('percent_options', $percent_options);
+$tmpl->assign('priority_options', $priority_options);
+$tmpl->assign('id',$id);
+$tmpl->assign('details',$details);
+$tmpl->assign('categories', $categories);
+$page = $tmpl->fetchPage();
+
+OCP\JSON::success(array('data' => array( 'page' => $page )));
diff --git a/apps/tasks/ajax/getdetails.php b/apps/tasks/ajax/getdetails.php
new file mode 100644
index 00000000000..34ddaa7791a
--- /dev/null
+++ b/apps/tasks/ajax/getdetails.php
@@ -0,0 +1,24 @@
+<?php
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$l10n = new OC_L10N('tasks');
+
+$id = $_GET['id'];
+$task = OC_Calendar_Object::find($id);
+$details = OC_VObject::parse($task['calendardata']);
+if (!$details){
+ OCP\JSON::error();
+ exit;
+}
+
+$priority_options = OC_Task_App::getPriorityOptions();
+$tmpl = new OC_Template('tasks','part.details');
+$tmpl->assign('priority_options', $priority_options);
+$tmpl->assign('details',$details->VTODO);
+$tmpl->assign('id',$id);
+$page = $tmpl->fetchPage();
+
+OCP\JSON::success(array('data' => array( 'id' => $id, 'page' => $page )));
diff --git a/apps/tasks/ajax/gettasks.php b/apps/tasks/ajax/gettasks.php
new file mode 100644
index 00000000000..011730d0a13
--- /dev/null
+++ b/apps/tasks/ajax/gettasks.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright (c) 2011 Georg Ehrke <ownclouddev at georgswebsite dot de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$calendars = OC_Calendar_Calendar::allCalendars(OCP\User::getUser(), true);
+$user_timezone = OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone', date_default_timezone_get());
+
+$tasks = array();
+foreach( $calendars as $calendar ){
+ $calendar_tasks = OC_Calendar_Object::all($calendar['id']);
+ foreach( $calendar_tasks as $task ){
+ if($task['objecttype']!='VTODO'){
+ continue;
+ }
+ if(is_null($task['summary'])){
+ continue;
+ }
+ $object = OC_VObject::parse($task['calendardata']);
+ $vtodo = $object->VTODO;
+ try {
+ $tasks[] = OC_Task_App::arrayForJSON($task['id'], $vtodo, $user_timezone);
+ } catch(Exception $e) {
+ OCP\Util::writeLog('tasks', $e->getMessage(), OCP\Util::ERROR);
+ }
+ }
+}
+
+OCP\JSON::encodedPrint($tasks);
diff --git a/apps/tasks/ajax/update_property.php b/apps/tasks/ajax/update_property.php
new file mode 100644
index 00000000000..46521cf6c58
--- /dev/null
+++ b/apps/tasks/ajax/update_property.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+// Init owncloud
+OCP\JSON::checkLoggedIn();
+OCP\JSON::checkAppEnabled('tasks');
+
+$id = $_POST['id'];
+$property = $_POST['type'];
+$vcalendar = OC_Calendar_App::getVCalendar( $id );
+
+$vtodo = $vcalendar->VTODO;
+switch($property) {
+ case 'summary':
+ $summary = $_POST['summary'];
+ $vtodo->setString('SUMMARY', $summary);
+ break;
+ case 'description':
+ $description = $_POST['description'];
+ $vtodo->setString('DESCRIPTION', $description);
+ break;
+ case 'location':
+ $location = $_POST['location'];
+ $vtodo->setString('LOCATION', $location);
+ break;
+ case 'categories':
+ $categories = $_POST['categories'];
+ $vtodo->setString('CATEGORIES', $categories);
+ break;
+ case 'due':
+ $due = $_POST['due'];
+ $due_date_only = $_POST['date'];
+ $type = null;
+ if ($due != 'false') {
+ try {
+ $timezone = OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone', date_default_timezone_get());
+ $timezone = new DateTimeZone($timezone);
+ $due = new DateTime('@'.$due);
+ $due->setTimezone($timezone);
+ $type = Sabre_VObject_Element_DateTime::LOCALTZ;
+ if ($due_date_only) {
+ $type = Sabre_VObject_Element_DateTime::DATE;
+ }
+ } catch (Exception $e) {
+ OCP\JSON::error(array('data'=>array('message'=>OC_Task_App::$l10n->t('Invalid date/time'))));
+ exit();
+ }
+ }
+ $vtodo->setDateTime('DUE', $due, $type);
+ break;
+ case 'complete':
+ $checked = $_POST['checked'];
+ OC_Task_App::setComplete($vtodo, $checked ? '100' : '0', null);
+ break;
+ default:
+ OCP\JSON::error(array('data'=>array('message'=>'Unknown type')));
+ exit();
+}
+OC_Calendar_Object::edit($id, $vcalendar->serialize());
+
+$user_timezone = OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone', date_default_timezone_get());
+$task_info = OC_Task_App::arrayForJSON($id, $vtodo, $user_timezone);
+OCP\JSON::success(array('data' => $task_info));
diff --git a/apps/tasks/appinfo/app.php b/apps/tasks/appinfo/app.php
new file mode 100644
index 00000000000..f346e2aa4c0
--- /dev/null
+++ b/apps/tasks/appinfo/app.php
@@ -0,0 +1,16 @@
+<?php
+$l=new OC_L10N('tasks');
+OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php';
+OC::$CLASSPATH['OC_Task_App'] = 'apps/tasks/lib/app.php';
+
+OCP\App::register( array(
+ 'order' => 11,
+ 'id' => 'tasks',
+ 'name' => 'Tasks' ));
+
+OCP\App::addNavigationEntry( array(
+ 'id' => 'tasks_index',
+ 'order' => 11,
+ 'href' => OCP\Util::linkTo( 'tasks', 'index.php' ),
+ 'icon' => OCP\Util::imagePath( 'tasks', 'icon.png' ),
+ 'name' => $l->t('Tasks')));
diff --git a/apps/tasks/appinfo/info.xml b/apps/tasks/appinfo/info.xml
new file mode 100644
index 00000000000..21ab9a24762
--- /dev/null
+++ b/apps/tasks/appinfo/info.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<info>
+ <id>tasks</id>
+ <name>Tasks</name>
+ <version>0.1</version>
+ <licence>AGPL</licence>
+ <author>Bart Visscher</author>
+ <require>2</require>
+ <description>Tasks view from calendar</description>
+</info>
diff --git a/apps/tasks/css/style.css b/apps/tasks/css/style.css
new file mode 100644
index 00000000000..d78521bc09c
--- /dev/null
+++ b/apps/tasks/css/style.css
@@ -0,0 +1,59 @@
+#tasks_list p.loading{margin:15px;}
+#tasks_lists .done{color:#C7C7C7;}
+#task_details{position:absolute;left:63em;top:6.4em;}
+#task_details th{padding:2px;text-align:right;vertical-align:top; }
+#task_details td{padding:2px;text-align:left;vertical-align:top; }
+.error_msg{color:red;}
+.error{border-color:red;border-width:2px;}
+#tasks_lists div{position:relative;padding:0.5em 1em;}
+#tasks_lists .active{font-weight:bold;}
+#tasks_list h1{background-color:#1D2D44;color:white;font-size:120%;padding:0 0.5em;}
+
+.task{border-radius:0.4em;position:relative;padding:0.5em 1em;}
+.task:nth-child(odd){background-color:#F4F4F4;}
+.task:hover {background-color:#DDDDDD;}
+
+.task_actions{display:none;position:absolute;left:30em;top:0.2em;}
+.task:hover .task_actions {display:block}
+.task_actions img{vertical-align:middle;}
+.task_actions span{cursor:pointer;}
+
+.task .priority{background-color:black;color:white;position:absolute;top:0.5em}
+.task .priority-n{height:2.66ex;width:0.6em;}
+.task .priority-1{background:rgb(255,0,0);}
+.task .priority-2{background:rgb(200,0,0);}
+.task .priority-3{background:rgb(150,0,0);}
+.task .priority-4{background:rgb(100,0,0);}
+.task .priority-5{background:rgb(255,255,0);color:black;}
+.task .priority-6{background:rgb(192,255,0);color:black;}
+.task .priority-7{background:rgb(128,255,0);color:black;}
+.task .priority-8{background:rgb(64,255,0);color:black;}
+.task .priority-9{background:rgb(0,255,0);color:black;}
+
+.task .completed {position:absolute;left:3em;top:0.3em;}
+
+.task .summary{padding-left:4em;}
+.task .summary input{position:relative;left:5px;}
+.task.done .summary{text-decoration:line-through;}
+
+.task .tag{border-radius:0.4em;display:inline-block;opacity:0.2;margin:0 0.2em;border:1px solid transparent;padding:0 0.4em;cursor:pointer;}
+.task .tag.active{border-color:black;opacity:0.6;}
+.task .tag.active:hover{opacity:1;}
+.task:hover .tag{opacity:0.5}
+.task:hover .tag:hover{opacity:0.8;}
+
+.task .categories{position:absolute;right:12em;text-align:right;top:0.4em}
+.task .categories a{background-color:#1d2d44;color:white;}
+.task .categories .tag.active{display:none;}
+.task input.categories{display:none;top:0;text-align:left;}
+
+.task .location{background-color:#442d44;color:white;position:absolute;right:0.6em;width:9.2em;text-align:left;top:0.4em}
+.task input.location{display:none;top:0;text-align:left;right:0.3em;background-color:white;color:#333333;}
+
+.task .more{display:none;margin-top:0.5em;}
+.task_less{display:none;}
+
+.task .description{position:relative;left:4em;}
+.task .due{position:absolute;right:0.3em;}
+.task .due .date{width:6em;}
+.task .due .time{width:6em;}
diff --git a/apps/tasks/img/icon.png b/apps/tasks/img/icon.png
new file mode 100644
index 00000000000..df281f3ba86
--- /dev/null
+++ b/apps/tasks/img/icon.png
Binary files differ
diff --git a/apps/tasks/img/icon.svg b/apps/tasks/img/icon.svg
new file mode 100644
index 00000000000..d46ebab865a
--- /dev/null
+++ b/apps/tasks/img/icon.svg
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="New document 1">
+ <defs
+ id="defs4">
+ <marker
+ style="overflow:visible"
+ inkscape:stockid="InfiniteLineStart"
+ id="InfiniteLineStart"
+ refX="0"
+ refY="0"
+ orient="auto">
+ <g
+ id="g4011"
+ transform="translate(-13,0)">
+ <circle
+ d="M 3.8,0 C 3.8,0.44182781 3.4418278,0.80000001 3,0.80000001 2.5581722,0.80000001 2.2,0.44182781 2.2,0 c 0,-0.44182781 0.3581722,-0.80000001 0.8,-0.80000001 0.4418278,0 0.8,0.3581722 0.8,0.80000001 z"
+ id="circle4013"
+ r="0.8"
+ cy="0"
+ cx="3" />
+ <circle
+ d="M 7.3,0 C 7.3,0.44182781 6.9418278,0.80000001 6.5,0.80000001 6.0581722,0.80000001 5.7,0.44182781 5.7,0 c 0,-0.44182781 0.3581722,-0.80000001 0.8,-0.80000001 0.4418278,0 0.8,0.3581722 0.8,0.80000001 z"
+ id="circle4015"
+ r="0.8"
+ cy="0"
+ cx="6.5" />
+ <circle
+ d="M 10.8,0 C 10.8,0.44182781 10.441828,0.80000001 10,0.80000001 9.5581722,0.80000001 9.2,0.44182781 9.2,0 c 0,-0.44182781 0.3581722,-0.80000001 0.8,-0.80000001 0.441828,0 0.8,0.3581722 0.8,0.80000001 z"
+ id="circle4017"
+ r="0.8"
+ cy="0"
+ cx="10" />
+ </g>
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1"
+ inkscape:cx="21.051806"
+ inkscape:cy="18.371489"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ showborder="false"
+ inkscape:showpageshadow="true"
+ inkscape:window-width="1280"
+ inkscape:window-height="1004"
+ inkscape:window-x="1278"
+ inkscape:window-y="-3"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1036.3622)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect4398"
+ width="9"
+ height="9"
+ x="3.4999998"
+ y="1040.8619" />
+ <path
+ style="fill:none;stroke:#808080;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none"
+ d="m 3.971,1040.0481 c 3.3062306,2.8933 3.3751101,6.5431 3.3751101,6.5431 0,0 3.8228259,-5.3027 6.2336249,-6.3371"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ </g>
+</svg>
diff --git a/apps/tasks/index.php b/apps/tasks/index.php
new file mode 100644
index 00000000000..8ed5f410434
--- /dev/null
+++ b/apps/tasks/index.php
@@ -0,0 +1,34 @@
+<?php
+/*************************************************
+ * ownCloud - Tasks Plugin *
+ * *
+ * (c) Copyright 2011 Bart Visscher *
+ * This file is licensed under the Affero General *
+ * Public License version 3 or later. *
+ * See the COPYING-README file. *
+ *************************************************/
+
+OCP\User::checkLoggedIn();
+OCP\App::checkAppEnabled('tasks');
+
+$calendars = OC_Calendar_Calendar::allCalendars(OCP\User::getUser(), true);
+if( count($calendars) == 0 ) {
+ header('Location: ' . OCP\Util::linkTo('calendar', 'index.php'));
+ exit;
+}
+
+OCP\Util::addScript('3rdparty/timepicker', 'jquery.ui.timepicker');
+OCP\Util::addStyle('3rdparty/timepicker', 'jquery.ui.timepicker');
+OCP\Util::addScript('tasks', 'tasks');
+OCP\Util::addStyle('tasks', 'style');
+OCP\Util::addScript('contacts','jquery.multi-autocomplete');
+OCP\Util::addScript('','oc-vcategories');
+OCP\App::setActiveNavigationEntry('tasks_index');
+
+$categories = OC_Calendar_App::getCategoryOptions();
+$l10n = new OC_L10N('tasks');
+$priority_options = OC_Task_App::getPriorityOptions();
+$output = new OC_Template('tasks', 'tasks', 'user');
+$output->assign('priority_options', $priority_options);
+$output->assign('categories', $categories);
+$output -> printPage();
diff --git a/apps/tasks/js/tasks.js b/apps/tasks/js/tasks.js
new file mode 100644
index 00000000000..60d2a523be1
--- /dev/null
+++ b/apps/tasks/js/tasks.js
@@ -0,0 +1,532 @@
+OC.Tasks = {
+ bool_string_cmp:function(a, b) {
+ if (a === b) {
+ return 0;
+ }
+ if (a === false) {
+ return -1;
+ }
+ if (b === false) {
+ return 1;
+ }
+ return a.localeCompare(b);
+ },
+ create_task_div:function(task) {
+ var actions = $('#task_actions_template');
+ var summary_container = $('<p class="summary">')
+ .attr('title', task.description)
+ ;
+ OC.Tasks.setSummary(summary_container, task);
+ var task_container = $('<div>')
+ .addClass('task')
+ .data('task', task)
+ .data('show_count', 0)
+ .attr('data-id', task.id)
+ .append(summary_container)
+ .append(actions.clone().removeAttr('id'))
+ ;
+ task_container.find('.summary a').click(OC.Tasks.summaryClickHandler);
+ var checkbox = $('<input type="checkbox">')
+ .click(OC.Tasks.complete_task);
+ if (task.completed) {
+ checkbox.attr('checked', 'checked');
+ task_container.addClass('done');
+ }
+ $('<div>')
+ .addClass('completed')
+ .append(checkbox)
+ .prependTo(task_container);
+ var priority = task.priority;
+ $('<div>')
+ .addClass('tag')
+ .addClass('priority')
+ .addClass('priority-'+(priority?priority:'n'))
+ .text(priority)
+ .prependTo(task_container);
+ if (task.location) {
+ $('<div>')
+ .addClass('tag')
+ .addClass('location')
+ .text(task.location)
+ .appendTo(task_container);
+ }
+ var $categories = $('<div>')
+ .addClass('categories')
+ .appendTo(task_container);
+ $(task.categories).each(function(i, category){
+ $categories.append($('<a>')
+ .addClass('tag')
+ .text(category)
+ );
+ });
+ task_container.find('.task_more').click(OC.Tasks.moreClickHandler);
+ task_container.find('.task_less').click(OC.Tasks.lessClickHandler);
+ var description = $('<textarea>')
+ .addClass('description')
+ .blur(function(){
+ var task = $(this).closest('.task').data('task');
+ var description = $(this).val();
+ $.post(OC.filePath('tasks', 'ajax', 'update_property.php'), {id:task.id, type:'description', description:description}, function(jsondata){
+ if(jsondata.status == 'success') {
+ task.description = description;
+ }
+ });
+ })
+ .text(task.description);
+ var due = $('<span>')
+ .addClass('due')
+ .append(t('tasks', 'Due'));
+ due
+ .append($('<input type="date">')
+ .addClass('date')
+ .datepicker({
+ dateFormat: 'dd-mm-yy',
+ onClose: OC.Tasks.dueUpdateHandler
+ }),
+ $('<input type="time">')
+ .addClass('time')
+ .timepicker({
+ showPeriodLabels:false,
+ onClose: OC.Tasks.dueUpdateHandler
+ })
+ );
+ if (task.due){
+ var date = new Date(parseInt(task.due)*1000);
+ due.find('.date').datepicker('setDate', date);
+ if (!task.due_date_only) {
+ due.find('.time').timepicker('setTime', date.getHours()+':'+date.getMinutes());
+ }
+ }
+ $('<div>')
+ .addClass('more')
+ .append(description)
+ .append(due)
+ .appendTo(task_container);
+ $('<input placeholder="'+t('tasks', 'List')+'">')
+ .addClass('categories')
+ .multiple_autocomplete({source: categories})
+ .val(task.categories)
+ .blur(function(){
+ var task = $(this).closest('.task').data('task');
+ var categories = $(this).val();
+ $.post(OC.filePath('tasks', 'ajax', 'update_property.php'), {id:task.id, type:'categories', categories:categories}, function(jsondata){
+ if(jsondata.status == 'success') {
+ task.categories = categories.split(',');
+ $categories.empty();
+ $(task.categories).each(function(i, category){
+ $categories.append($('<a>')
+ .addClass('tag')
+ .text(category)
+ );
+ });
+ }
+ });
+ })
+ .appendTo(task_container);
+ $('<input placeholder="'+t('tasks', 'Location')+'">')
+ .addClass('location')
+ .val(task.location)
+ .blur(function(){
+ var task = $(this).closest('.task').data('task');
+ var location = $(this).val();
+ $.post(OC.filePath('tasks', 'ajax', 'update_property.php'), {id:task.id, type:'location', location:location}, function(jsondata){
+ if(jsondata.status == 'success') {
+ task.location = location;
+ task_container.find('.location').text(location);
+ }
+ });
+ })
+ .appendTo(task_container);
+ return task_container;
+ },
+ filter:function(tag, find_filter) {
+ var tag_text = $(tag).text();
+ var filter = !$(tag).hasClass('active');
+ OC.Tasks.filterUpdate(filter, function(task_container){
+ var found = 0;
+ task_container.find(find_filter).each(function(){
+ if ($(this).text() == tag_text) {
+ $(this).toggleClass('active');
+ found = 1;
+ }
+ });
+ return found;
+ });
+ },
+ filterUpdate:function(filter, find_filter) {
+ var show_count = $('#tasks_list').data('show_count');
+ show_count += filter ? +1 : -1;
+ $('#tasks_list').data('show_count', show_count);
+ $('#tasks_lists .task, #tasks_list .task').each(function(i, task_container){
+ task_container = $(task_container);
+ var task = task_container.data('task');
+ var found = find_filter(task_container);
+ var hide_count = task_container.data('show_count');
+ if (!filter) {
+ hide_count-=found;
+ }
+ else {
+ hide_count+=found;
+ }
+ if (hide_count == show_count) {
+ task_container.show();
+ }
+ else {
+ task_container.hide();
+ }
+ task_container.data('show_count', hide_count);
+ });
+ },
+ order:function(sort, get_property, empty_label) {
+ var tasks = $('#tasks_list .task').not('.clone');
+ tasks.sort(sort);
+ var current = null;
+ tasks.detach();
+ var $tasks = $('#tasks_list').empty();
+ var container = $tasks;
+ tasks.each(function(){
+ if (get_property) {
+ var label = get_property($(this).data('task'));
+ if(label != current) {
+ current = label;
+ container = $('<div>').appendTo($tasks);
+ if (label == '' && empty_label) {
+ label = empty_label;
+ }
+ $('<h1>').text(label).appendTo(container);
+ }
+ }
+ container.append(this);
+ });
+ },
+ setSummary:function(summary_container, task){
+ var summary = $('<a href="index.php?id='+task.id+'">')
+ .text(task.summary)
+ .click(OC.Tasks.summaryClickHandler);
+ summary_container.html(summary);
+ },
+ summaryClickHandler:function(event){
+ event.preventDefault();
+ //event.stopPropagation();
+ var task = $(this).closest('.task').data('task');
+ var summary_container = $(this).parent();
+ var input = $('<input>').val($(this).text()).blur(function(){
+ var old_summary = task.summary;
+ task.summary = $(this).val();
+ OC.Tasks.setSummary(summary_container, task);
+ $.post(OC.filePath('tasks', 'ajax', 'update_property.php'), {id:task.id, type:'summary', summary:task.summary}, function(jsondata){
+ if(jsondata.status != 'success') {
+ task.summary = old_summary;
+ OC.Tasks.setSummary(summary_container, task);
+ }
+ });
+ });
+ summary_container.empty().append(input);
+ input.focus();
+ return false;
+ },
+ dueUpdateHandler:function(){
+ var task = $(this).closest('.task').data('task');
+ var old_due = task.due;
+ var $date = $(this).parent().children('.date');
+ var $time = $(this).parent().children('.time');
+ var date = $date.datepicker('getDate');
+ var time = $time.val().split(':');
+ var due, date_only = false;
+ if (!date){
+ due = false;
+ } else {
+ if (time.length==2){
+ date.setHours(time[0]);
+ date.setMinutes(time[1]);
+ }
+ else {
+ date_only = true;
+ }
+ due = date.getTime()/1000;
+ }
+ $.post(OC.filePath('tasks', 'ajax', 'update_property.php'), {id:task.id, type:'due', due:due, date:date_only?1:0}, function(jsondata){
+ if(jsondata.status != 'success') {
+ task.due = old_due;
+ }
+ });
+ },
+ moreClickHandler:function(event){
+ var $task = $(this).closest('.task'),
+ task = $task.data('task');
+ $task.find('.more').show();
+ $task.find('.task_more').hide();
+ $task.find('.task_less').show();
+ $task.find('div.categories').hide();
+ $task.find('input.categories').show();
+ $task.find('div.location').hide();
+ $task.find('input.location').show();
+ },
+ lessClickHandler:function(event){
+ var $task = $(this).closest('.task'),
+ task = $task.data('task');
+ $task.find('.more').hide();
+ $task.find('.task_more').show();
+ $task.find('.task_less').hide();
+ $task.find('div.categories').show();
+ $task.find('input.categories').hide();
+ $task.find('div.location').show();
+ $task.find('input.location').hide();
+ },
+ complete_task:function() {
+ var $task = $(this).closest('.task'),
+ task = $task.data('task'),
+ checked = $(this).is(':checked');
+ $.post(OC.filePath('tasks', 'ajax', 'update_property.php'), {id:task.id, type:'complete', checked:checked?1:0}, function(jsondata){
+ if(jsondata.status == 'success') {
+ task = jsondata.data;
+ $task.data('task', task)
+ if (task.completed) {
+ $task.addClass('done');
+ }
+ else {
+ $task.removeClass('done');
+ }
+ }
+ else{
+ alert(jsondata.data.message);
+ }
+ }, 'json');
+ },
+ categoriesChanged:function(newcategories){
+ categories = $.map(newcategories, function(v) {return v;});
+ console.log('Task categories changed to: ' + categories);
+ $('input.categories').multiple_autocomplete('option', 'source', categories);
+ },
+ List: {
+ create_list_div:function(category){
+ return $('<div>').text(category)
+ .click(function(){
+ OC.Tasks.filter(this, 'div.categories .tag');
+ $(this).toggleClass('active');
+ });
+ }
+ }
+};
+
+$(document).ready(function(){
+ fillHeight($('#tasks_lists'));
+ fillWindow($('#tasks_list'));
+
+ /*-------------------------------------------------------------------------
+ * Actions for startup
+ *-----------------------------------------------------------------------*/
+ $.getJSON(OC.filePath('tasks', 'ajax', 'gettasks.php'), function(jsondata) {
+ var tasks = $('#tasks_list').empty().data('show_count', 0);
+ $(jsondata).each(function(i, task) {
+ tasks.append(OC.Tasks.create_task_div(task));
+ });
+ if( $('#tasks_list div').length > 0 ){
+ $('#tasks_list div').first().addClass('active');
+ }
+ $(categories).each(function(i, category) {
+ $('#tasks_lists .all').after(OC.Tasks.List.create_list_div(category));
+ });
+ $('#tasks_lists .all').click(function(){
+ $('#tasks_lists .active').click();
+ });
+ $('#tasks_lists .done').click(function(){
+ var filter = !$(this).hasClass('active');
+ OC.Tasks.filterUpdate(filter, function(task_container){
+ return task_container.hasClass('done');
+ });
+ $(this).toggleClass('active');
+ });
+ OCCategories.changed = OC.Tasks.categoriesChanged;
+ OCCategories.app = 'calendar';
+ });
+
+ /*-------------------------------------------------------------------------
+ * Event handlers
+ *-----------------------------------------------------------------------*/
+ $('#tasks_list div.categories .tag').live('click',function(){
+ OC.Tasks.filter(this, 'div.categories .tag');
+ var tag_text = $(this).text();
+ $('#tasks_lists div:not(".all"):not(".done")').each(function(){
+ if ($(this).text() == tag_text) {
+ $(this).toggleClass('active');
+ }
+ });
+ });
+
+ $('#tasks_list .priority.tag').live('click',function(){
+ OC.Tasks.filter(this, '.priority.tag');
+ });
+
+ $('#tasks_list .location.tag').live('click',function(){
+ OC.Tasks.filter(this, '.location.tag');
+ });
+
+ $('#tasks_order_category').click(function(){
+ var tasks = $('#tasks_list .task').not('.clone');
+ var collection = {};
+ tasks.each(function(i, task) {
+ var categories = $(task).data('task').categories;
+ $(categories).each(function() {
+ if (!collection.hasOwnProperty(this)) {
+ collection[this] = [];
+ }
+ collection[this].push(task);
+ if (categories.length > 1) {
+ task = $(task).clone(true).addClass('clone').get(0);
+ }
+ });
+ if (categories.length == 0) {
+ if (!collection.hasOwnProperty('')) {
+ collection[''] = [];
+ }
+ collection[''].push(task);
+ }
+ });
+ var labels = [];
+ for (var label in collection) {
+ labels.push(label);
+ }
+ labels.sort();
+ tasks.detach();
+ var $tasks = $('#tasks_list').empty();
+ for (var index in labels) {
+ var label = labels[index];
+ var container = $('<div>').appendTo($tasks);
+ if (label == '') {
+ label = t('tasks', 'No category');
+ }
+ $('<h1>').text(label).appendTo(container);
+ container.append(collection[labels[index]]);
+ }
+ });
+
+ $('#tasks_order_due').click(function(){
+ OC.Tasks.order(function(a, b){
+ a = $(a).data('task').due;
+ b = $(b).data('task').due;
+ return OC.Tasks.bool_string_cmp(a, b);
+ });
+ });
+
+ $('#tasks_order_complete').click(function(){
+ OC.Tasks.order(function(a, b){
+ return ($(a).data('task').complete - $(b).data('task').complete) ||
+ OC.Tasks.bool_string_cmp($(a).data('task').completed, $(b).data('task').completed);
+ });
+ });
+
+ $('#tasks_order_location').click(function(){
+ OC.Tasks.order(function(a, b){
+ a = $(a).data('task').location;
+ b = $(b).data('task').location;
+ return OC.Tasks.bool_string_cmp(a, b);
+ });
+ });
+
+ $('#tasks_order_prio').click(function(){
+ OC.Tasks.order(function(a, b){
+ return $(a).data('task').priority
+ - $(b).data('task').priority;
+ });
+ });
+
+ $('#tasks_order_label').click(function(){
+ OC.Tasks.order(function(a, b){
+ return $(a).data('task').summary.localeCompare(
+ $(b).data('task').summary);
+ });
+ });
+
+ $('#tasks_delete').live('click',function(){
+ var id = $('#task_details').data('id');
+ $.getJSON('ajax/delete.php',{'id':id},function(jsondata){
+ if(jsondata.status == 'success'){
+ $('#tasks [data-id="'+jsondata.data.id+'"]').remove();
+ $('#task_details').data('id','');
+ $('#task_details').html('');
+ }
+ else{
+ alert(jsondata.data.message);
+ }
+ });
+ return false;
+ });
+
+ $('#tasks_addtask').click(function(){
+ var input = $('#tasks_newtask').val();
+ $.getJSON(OC.filePath('tasks', 'ajax', 'addtask.php'),{text:input},function(jsondata){
+ if(jsondata.status == 'success'){
+ $('#tasks_list').append(OC.Tasks.create_task_div(jsondata.task));
+ }
+ else{
+ alert(jsondata.data.message);
+ }
+ });
+ return false;
+ });
+
+ $('#tasks_addtaskform input[type="submit"]').live('click',function(){
+ $.post('ajax/addtask.php',$('#tasks_addtaskform').serialize(),function(jsondata){
+ if(jsondata.status == 'success'){
+ $('#task_details').data('id',jsondata.data.id);
+ $('#task_details').html(jsondata.data.page);
+ $('#tasks_list').append(OC.Tasks.create_task_div(jsondata.data.task));
+ }
+ else{
+ alert(jsondata.data.message);
+ }
+ }, 'json');
+ return false;
+ });
+
+ $('#tasks_edit').live('click',function(){
+ var id = $('#task_details').data('id');
+ $.getJSON('ajax/edittaskform.php',{'id':id},function(jsondata){
+ if(jsondata.status == 'success'){
+ $('#task_details').html(jsondata.data.page);
+ $('#task_details #categories').multiple_autocomplete({source: categories});
+ }
+ else{
+ alert(jsondata.data.message);
+ }
+ });
+ return false;
+ });
+
+ $('#tasks_edittaskform #percent_complete').live('change',function(event){
+ if ($(event.target).val() == 100){
+ $('#tasks_edittaskform #complete').show();
+ }else{
+ $('#tasks_edittaskform #complete').hide();
+ }
+ });
+
+ $('#tasks_edittaskform input[type="submit"]').live('click',function(){
+ $.post('ajax/edittask.php',$('#tasks_edittaskform').serialize(),function(jsondata){
+ $('.error_msg').remove();
+ $('.error').removeClass('error');
+ if(jsondata.status == 'success'){
+ var id = jsondata.data.id;
+ $('#task_details').data('id',id);
+ $('#task_details').html(jsondata.data.page);
+ var task = jsondata.data.task;
+ $('#tasks .task[data-id='+id+']')
+ .data('task', task)
+ .html(OC.Tasks.create_task_div(task).html());
+ }
+ else{
+ var errors = jsondata.data.errors;
+ for (k in errors){
+ $('#'+k).addClass('error')
+ .after('<span class="error_msg">'+errors[k]+'</span>');
+ }
+ $('.error_msg').effect('highlight', {}, 3000);
+ $('.error').effect('highlight', {}, 3000);
+ }
+ }, 'json');
+ return false;
+ });
+
+ OCCategories.app = 'calendar';
+});
diff --git a/apps/tasks/lib/app.php b/apps/tasks/lib/app.php
new file mode 100644
index 00000000000..7b908420333
--- /dev/null
+++ b/apps/tasks/lib/app.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * ownCloud - Calendar
+ *
+ * @author Bart Visscher
+ * @copyright 2011 Bart Visscher bartv@thisnet.nl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * This class manages our tasks
+ */
+OC_Task_App::$l10n = new OC_L10N('tasks');
+class OC_Task_App {
+ public static $l10n;
+
+ public static function getPriorityOptions()
+ {
+ return array(
+ '' => self::$l10n->t('Unspecified'),
+ '1' => self::$l10n->t('1=highest'),
+ '2' => '2',
+ '3' => '3',
+ '4' => '4',
+ '5' => self::$l10n->t('5=medium'),
+ '6' => '6',
+ '7' => '7',
+ '8' => '8',
+ '9' => self::$l10n->t('9=lowest'),
+ );
+ }
+
+ public static function arrayForJSON($id, $vtodo, $user_timezone)
+ {
+ $task = array( 'id' => $id );
+ $task['summary'] = $vtodo->getAsString('SUMMARY');
+ $task['description'] = $vtodo->getAsString('DESCRIPTION');
+ $task['location'] = $vtodo->getAsString('LOCATION');
+ $task['categories'] = $vtodo->getAsArray('CATEGORIES');
+ $due = $vtodo->DUE;
+ if ($due) {
+ $task['due_date_only'] = $due->getDateType() == Sabre_VObject_Element_DateTime::DATE;
+ $due = $due->getDateTime();
+ $due->setTimezone(new DateTimeZone($user_timezone));
+ $task['due'] = $due->format('U');
+ }
+ else {
+ $task['due'] = false;
+ }
+ $task['priority'] = $vtodo->getAsString('PRIORITY');
+ $completed = $vtodo->COMPLETED;
+ if ($completed) {
+ $completed = $completed->getDateTime();
+ $completed->setTimezone(new DateTimeZone($user_timezone));
+ $task['completed'] = $completed->format('Y-m-d H:i:s');
+ }
+ else {
+ $task['completed'] = false;
+ }
+ $task['complete'] = $vtodo->getAsString('PERCENT-COMPLETE');
+ return $task;
+ }
+
+ public static function validateRequest($request)
+ {
+ $errors = array();
+ if($request['summary'] == ''){
+ $errors['summary'] = self::$l10n->t('Empty Summary');
+ }
+
+ try {
+ $timezone = OCP\Config::getUserValue(OCP\User::getUser(), "calendar", "timezone", "Europe/London");
+ $timezone = new DateTimeZone($timezone);
+ new DateTime($request['due'], $timezone);
+ } catch (Exception $e) {
+ $errors['due'] = self::$l10n->t('Invalid date/time');
+ }
+
+ if ($request['percent_complete'] < 0 || $request['percent_complete'] > 100){
+ $errors['percent_complete'] = self::$l10n->t('Invalid percent complete');
+ }
+ if ($request['percent_complete'] == 100 && !empty($request['completed'])){
+ try {
+ $timezone = OCP\Config::getUserValue(OCP\User::getUser(), "calendar", "timezone", "Europe/London");
+ $timezone = new DateTimeZone($timezone);
+ new DateTime($request['completed'], $timezone);
+ } catch (Exception $e) {
+ $errors['completed'] = self::$l10n->t('Invalid date/time');
+ }
+ }
+
+ $priority_options = self::getPriorityOptions();
+ if (!in_array($request['priority'], array_keys($priority_options))) {
+ $errors['priority'] = self::$l10n->t('Invalid priority');
+ }
+ return $errors;
+ }
+
+ public static function createVCalendarFromRequest($request)
+ {
+ $vcalendar = new OC_VObject('VCALENDAR');
+ $vcalendar->add('PRODID', 'ownCloud Calendar');
+ $vcalendar->add('VERSION', '2.0');
+
+ $vtodo = new OC_VObject('VTODO');
+ $vcalendar->add($vtodo);
+
+ $vtodo->setDateTime('CREATED', 'now', Sabre_VObject_Element_DateTime::UTC);
+
+ $vtodo->setUID();
+ return self::updateVCalendarFromRequest($request, $vcalendar);
+ }
+
+ public static function updateVCalendarFromRequest($request, $vcalendar)
+ {
+ $summary = $request['summary'];
+ $categories = $request["categories"];
+ $priority = $request['priority'];
+ $percent_complete = $request['percent_complete'];
+ $completed = $request['completed'];
+ $location = $request['location'];
+ $due = $request['due'];
+ $description = $request['description'];
+
+ $vtodo = $vcalendar->VTODO;
+
+ $vtodo->setDateTime('LAST-MODIFIED', 'now', Sabre_VObject_Element_DateTime::UTC);
+ $vtodo->setDateTime('DTSTAMP', 'now', Sabre_VObject_Element_DateTime::UTC);
+ $vtodo->setString('SUMMARY', $summary);
+
+ $vtodo->setString('LOCATION', $location);
+ $vtodo->setString('DESCRIPTION', $description);
+ $vtodo->setString('CATEGORIES', $categories);
+ $vtodo->setString('PRIORITY', $priority);
+
+ if ($due) {
+ $timezone = OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone', date_default_timezone_get());
+ $timezone = new DateTimeZone($timezone);
+ $due = new DateTime($due, $timezone);
+ $vtodo->setDateTime('DUE', $due);
+ } else {
+ unset($vtodo->DUE);
+ }
+
+ self::setComplete($vtodo, $percent_complete, $completed);
+
+ return $vcalendar;
+ }
+
+ public static function setComplete($vtodo, $percent_complete, $completed)
+ {
+ if (!empty($percent_complete)) {
+ $vtodo->setString('PERCENT-COMPLETE', $percent_complete);
+ }else{
+ $vtodo->__unset('PERCENT-COMPLETE');
+ }
+
+ if ($percent_complete == 100){
+ if (!$completed){
+ $completed = 'now';
+ }
+ } else {
+ $completed = null;
+ }
+ if ($completed) {
+ $timezone = OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone', date_default_timezone_get());
+ $timezone = new DateTimeZone($timezone);
+ $completed = new DateTime($completed, $timezone);
+ $vtodo->setDateTime('COMPLETED', $completed);
+ } else {
+ unset($vtodo->COMPLETED);
+ }
+ }
+}
diff --git a/apps/tasks/lib/vtodo.php b/apps/tasks/lib/vtodo.php
new file mode 100644
index 00000000000..dc2bfaf964c
--- /dev/null
+++ b/apps/tasks/lib/vtodo.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * ownCloud - Calendar
+ *
+ * @author Bart Visscher
+ * @copyright 2011 Bart Visscher bartv@thisnet.nl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * This class manages our tasks
+ */
+class OC_Task_VTodo extends OC_Calendar_Object{
+}
diff --git a/apps/tasks/templates/part.addtaskform.php b/apps/tasks/templates/part.addtaskform.php
new file mode 100644
index 00000000000..0fad5592aa7
--- /dev/null
+++ b/apps/tasks/templates/part.addtaskform.php
@@ -0,0 +1,15 @@
+<form id="tasks_addtaskform">
+ <?php if(count($_['calendars'])==1): ?>
+ <input type="hidden" name="id" value="<?php echo $_['calendars'][0]['id']; ?>">
+ <?php else: ?>
+ <label for="id"><?php echo $l->t('Calendar'); ?></label>
+ <select name="id" size="1">
+ <?php foreach($_['calendars'] as $calendar): ?>
+ <option value="<?php echo $calendar['id']; ?>"><?php echo $calendar['displayname']; ?></option>
+ <?php endforeach; ?>
+ </select>
+ <br>
+ <?php endif; ?>
+ <?php echo $this->inc('part.taskform'); ?>
+ <input type="submit" name="submit" value="<?php echo $l->t('Create Task'); ?>">
+</form>
diff --git a/apps/tasks/templates/part.details.php b/apps/tasks/templates/part.details.php
new file mode 100644
index 00000000000..89636b6e762
--- /dev/null
+++ b/apps/tasks/templates/part.details.php
@@ -0,0 +1,42 @@
+<?php if(isset($_['details']->SUMMARY)): ?>
+<table>
+<?php
+echo $this->inc('part.property', array('label' => $l->t('Summary'), 'property' => $_['details']->SUMMARY));
+if(isset($_['details']->LOCATION)):
+ echo $this->inc('part.property', array('label' => $l->t('Location'), 'property' => $_['details']->LOCATION));
+endif;
+if(isset($_['details']->CATEGORIES)):
+ echo $this->inc('part.property', array('label' => $l->t('Categories'), 'property' => $_['details']->CATEGORIES));
+endif;
+if(isset($_['details']->DUE)):
+ echo $this->inc('part.property', array('label' => $l->t('Due'), 'property' => $_['details']->DUE[0]));
+endif;
+if(isset($_['details']->PRIORITY)):
+ echo $this->inc('part.property', array('label' => $l->t('Priority'), 'property' => $_['details']->PRIORITY[0], 'options' => $_['priority_options']));
+endif;
+if($_['details']->__isset('PERCENT-COMPLETE') || isset($_['details']->COMPLETED)):
+?>
+<tr>
+ <th>
+ <?php echo $l->t('Complete') ?>
+ </th>
+ <td>
+<?php if($_['details']->__isset('PERCENT-COMPLETE')):
+ echo $_['details']->__get('PERCENT-COMPLETE')->value.' % ';
+ endif;
+ if(isset($_['details']->COMPLETED)):
+ echo $l->t('on '). $l->l('datetime', $_['details']->COMPLETED[0]->getDateTime());
+ endif;
+ echo '</tr>';
+endif;
+if(isset($_['details']->DESCRIPTION)):
+ echo $this->inc('part.property', array('label' => $l->t('Description'), 'property' => $_['details']->DESCRIPTION));
+endif; ?>
+</table>
+<form>
+ <input type="button" id="tasks_delete" value="<?php echo $l->t('Delete');?>">
+ <input type="button" id="tasks_edit" value="<?php echo $l->t('Edit');?>">
+</form>
+<?php else: ?>
+<?php //var_dump($_['details']); ?>
+<?php endif ?>
diff --git a/apps/tasks/templates/part.edittaskform.php b/apps/tasks/templates/part.edittaskform.php
new file mode 100644
index 00000000000..fe123f07ac6
--- /dev/null
+++ b/apps/tasks/templates/part.edittaskform.php
@@ -0,0 +1,5 @@
+<form id="tasks_edittaskform">
+ <input type="hidden" name="id" value="<?php echo $_['id']; ?>">
+ <?php echo $this->inc('part.taskform'); ?>
+ <input type="submit" name="submit" value="<?php echo $l->t('Update Task'); ?>">
+</form>
diff --git a/apps/tasks/templates/part.property.php b/apps/tasks/templates/part.property.php
new file mode 100644
index 00000000000..591fd363e6f
--- /dev/null
+++ b/apps/tasks/templates/part.property.php
@@ -0,0 +1,22 @@
+<tr>
+ <th>
+ <?php echo $_['label'] ?>
+ </th>
+ <td>
+ <?php
+ switch (get_class($_['property']))
+ {
+ case 'Sabre_VObject_Element_DateTime':
+ echo $l->l('datetime', $_['property']->getDateTime());
+ break;
+ default:
+ $value = $_['property']->value;
+ if (isset($_['options']))
+ {
+ $value = $_['options'][$value];
+ }
+ echo nl2br($value);
+ }
+ ?>
+ </td>
+</tr>
diff --git a/apps/tasks/templates/part.taskform.php b/apps/tasks/templates/part.taskform.php
new file mode 100644
index 00000000000..da984d830bd
--- /dev/null
+++ b/apps/tasks/templates/part.taskform.php
@@ -0,0 +1,36 @@
+ <label for="summary"><?php echo $l->t('Summary'); ?></label>
+ <input type="text" id="summary" name="summary" placeholder="<?php echo $l->t('Summary of the task');?>" value="<?php echo isset($_['details']->SUMMARY) ? $_['details']->SUMMARY[0]->value : '' ?>">
+ <br>
+ <label for="location"><?php echo $l->t('Location'); ?></label>
+ <input type="text" id="location" name="location" placeholder="<?php echo $l->t('Location of the task');?>" value="<?php echo isset($_['details']->LOCATION) ? $_['details']->LOCATION[0]->value : '' ?>">
+ <br>
+ <label for="categories"><?php echo $l->t('Categories'); ?></label>
+ <input id="categories" name="categories" type="text" placeholder="<?php echo $l->t('Separate categories with commas'); ?>" value="<?php echo isset($_['categories']) ? htmlspecialchars($_['categories']) : '' ?>">
+ <a class="action edit" onclick="$(this).tipsy('hide');OCCategories.edit();" title="<?php echo $l->t('Edit categories'); ?>"><img alt="<?php echo $l->t('Edit categories'); ?>" src="<?php echo image_path('core','actions/rename.svg')?>" class="svg action" style="width: 16px; height: 16px;"></a>
+ <br>
+ <label for="due"><?php echo $l->t('Due'); ?></label>
+ <input type="text" id="due" name="due" placeholder="<?php echo $l->t('Due date') ?>" value="<?php echo isset($_['details']->DUE) ? $l->l('datetime', $_['details']->DUE[0]->getDateTime()) : '' ?>">
+ <br>
+ <select name="percent_complete" id="percent_complete">
+ <?php
+ foreach($_['percent_options'] as $percent){
+ echo '<option value="' . $percent . '"' . (($_['details']->__get('PERCENT-COMPLETE') && $percent == $_['details']->__get('PERCENT-COMPLETE')->value) ? ' selected="selected"' : '') . '>' . $percent . ' %</option>';
+ }
+ ?>
+ </select>
+ <label for="percent_complete"><?php echo $l->t('Complete'); ?></label>
+ <span id="complete"<?php echo ($_['details']->__get('PERCENT-COMPLETE') && $_['details']->__get('PERCENT-COMPLETE')->value == 100) ? '' : ' style="display:none;"' ?>><label for="completed"><?php echo $l->t('completed on'); ?></label>
+ <input type="text" id="completed" name="completed" value="<?php echo isset($_['details']->COMPLETED) ? $l->l('datetime', $_['details']->COMPLETED[0]->getDateTime()) : '' ?>"></span>
+ <br>
+ <label for="priority"><?php echo $l->t('Priority'); ?></label>
+ <select name="priority">
+ <?php
+ foreach($_['priority_options'] as $priority => $label){
+ echo '<option value="' . $priority . '"' . ((isset($_['details']->PRIORITY) && $priority == $_['details']->PRIORITY->value) ? ' selected="selected"' : '') . '>' . $label . '</option>';
+ }
+ ?>
+ </select>
+ <br>
+ <label for="description"><?php echo $l->t('Description'); ?></label><br>
+ <textarea placeholder="<?php echo $l->t('Description of the task');?>" name="description"><?php echo isset($_['details']->DESCRIPTION) ? $_['details']->DESCRIPTION[0]->value : '' ?></textarea>
+ <br>
diff --git a/apps/tasks/templates/part.tasks.php b/apps/tasks/templates/part.tasks.php
new file mode 100644
index 00000000000..50be1cd6bed
--- /dev/null
+++ b/apps/tasks/templates/part.tasks.php
@@ -0,0 +1,3 @@
+<?php foreach( $_['tasks'] as $task ): ?>
+ <li data-id="<?php echo $task['id']; ?>"><a href="index.php?id=<?php echo $task['id']; ?>"><?php echo $task['name']; ?></a> </li>
+<?php endforeach; ?>
diff --git a/apps/tasks/templates/tasks.php b/apps/tasks/templates/tasks.php
new file mode 100644
index 00000000000..98698400797
--- /dev/null
+++ b/apps/tasks/templates/tasks.php
@@ -0,0 +1,31 @@
+<div id="controls">
+ <input type="text" id="tasks_newtask">
+ <input type="button" id="tasks_addtask" value="<?php echo $l->t('Add Task'); ?>">
+ <input type="button" id="tasks_order_due" value="<?php echo $l->t('Order Due'); ?>">
+ <input type="button" id="tasks_order_category" value="<?php echo $l->t('Order Category'); ?>">
+ <input type="button" id="tasks_order_complete" value="<?php echo $l->t('Order Complete'); ?>">
+ <input type="button" id="tasks_order_location" value="<?php echo $l->t('Order Location'); ?>">
+ <input type="button" id="tasks_order_prio" value="<?php echo $l->t('Order Priority'); ?>">
+ <input type="button" id="tasks_order_label" value="<?php echo $l->t('Order Label'); ?>">
+</div>
+<div id="tasks_lists" class="leftcontent">
+ <div class="all">All</div>
+ <div class="done">Done</div>
+</div>
+<div id="tasks_list" class="rightcontent">
+<p class="loading"><?php echo $l->t('Loading tasks...') ?></p>
+</div>
+<p id="task_actions_template" class="task_actions">
+ <!-- span class="task_star">
+ <img title="<?php echo $l->t('Important') ?>" src="<?php echo image_path('core', 'actions/add.svg') ?>" class="svg"><?php echo $l->t('Important') ?>
+ </span -->
+ <span class="task_more">
+ <img title="<?php echo $l->t('More') ?>" src="<?php echo image_path('core', 'actions/triangle-s.svg') ?>" class="svg"><?php echo $l->t('More') ?>
+ </span>
+ <span class="task_less">
+ <img title="<?php echo $l->t('Less') ?>" src="<?php echo image_path('core', 'actions/triangle-n.svg') ?>" class="svg"><?php echo $l->t('Less') ?>
+ </span>
+</p>
+<script type='text/javascript'>
+var categories = <?php echo json_encode($_['categories']); ?>;
+</script>