diff options
27 files changed, 1483 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 Binary files differnew file mode 100644 index 00000000000..df281f3ba86 --- /dev/null +++ b/apps/tasks/img/icon.png 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> diff --git a/core/img/actions/triangle-n.png b/core/img/actions/triangle-n.png Binary files differnew file mode 100644 index 00000000000..b0d7183caab --- /dev/null +++ b/core/img/actions/triangle-n.png diff --git a/core/img/actions/triangle-n.svg b/core/img/actions/triangle-n.svg new file mode 100644 index 00000000000..35658631111 --- /dev/null +++ b/core/img/actions/triangle-n.svg @@ -0,0 +1,92 @@ +<?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:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16px" + height="16px" + id="svg6077" + version="1.1" + inkscape:version="0.48.3.1 r9886" + sodipodi:docname="triangle-n.svg" + inkscape:export-filename="triangle-n.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs6079"> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3587-6-5-3-4-5-4-0-1" + id="linearGradient7308" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0,-0.54681372,-0.39376081,0,14.87048,24.63452)" + x1="34.992828" + y1="0.94087797" + x2="34.992828" + y2="33.955856" /> + <linearGradient + id="linearGradient3587-6-5-3-4-5-4-0-1"> + <stop + offset="0" + style="stop-color:#000000;stop-opacity:1" + id="stop3589-9-2-2-3-2-53-4-3" /> + <stop + offset="1" + style="stop-color:#363636;stop-opacity:1" + id="stop3591-7-4-73-7-9-86-9-3" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="22.197802" + inkscape:cx="-6.9113863" + inkscape:cy="8" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:grid-bbox="true" + inkscape:document-units="px" + inkscape:window-width="1920" + inkscape:window-height="1025" + inkscape:window-x="-2" + inkscape:window-y="-3" + inkscape:window-maximized="1" /> + <metadata + id="metadata6082"> + <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 + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + <path + inkscape:connector-curvature="0" + d="M 14.5,15 1.5,15 8,3 14.5,15 z" + id="path2843-0-1-6-6" + style="opacity:0.6;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + inkscape:connector-curvature="0" + d="m 14.5,13.49996 -13,0 6.49999,-12 6.50001,12 z" + id="path2843-39-5-5" + style="opacity:0.7;color:#000000;fill:url(#linearGradient7308);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + </g> +</svg> |