diff --git a/apps/calendar/lib/app.php b/apps/calendar/lib/app.php index eb440b5794..8cbef4646f 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 0000000000..891fbdb96d --- /dev/null +++ b/apps/tasks/ajax/addtask.php @@ -0,0 +1,26 @@ +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 0000000000..20797f31ab --- /dev/null +++ b/apps/tasks/ajax/addtaskform.php @@ -0,0 +1,20 @@ +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 0000000000..6d2868748d --- /dev/null +++ b/apps/tasks/ajax/delete.php @@ -0,0 +1,31 @@ +. + * + */ + +// 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 0000000000..78d1f19393 --- /dev/null +++ b/apps/tasks/ajax/edittask.php @@ -0,0 +1,31 @@ + 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 0000000000..a439a0c031 --- /dev/null +++ b/apps/tasks/ajax/edittaskform.php @@ -0,0 +1,24 @@ +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 0000000000..34ddaa7791 --- /dev/null +++ b/apps/tasks/ajax/getdetails.php @@ -0,0 +1,24 @@ +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 0000000000..011730d0a1 --- /dev/null +++ b/apps/tasks/ajax/gettasks.php @@ -0,0 +1,36 @@ + + * 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 0000000000..46521cf6c5 --- /dev/null +++ b/apps/tasks/ajax/update_property.php @@ -0,0 +1,68 @@ + + * 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 0000000000..f346e2aa4c --- /dev/null +++ b/apps/tasks/appinfo/app.php @@ -0,0 +1,16 @@ + 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 0000000000..21ab9a2476 --- /dev/null +++ b/apps/tasks/appinfo/info.xml @@ -0,0 +1,10 @@ + + + tasks + Tasks + 0.1 + AGPL + Bart Visscher + 2 + Tasks view from calendar + diff --git a/apps/tasks/css/style.css b/apps/tasks/css/style.css new file mode 100644 index 0000000000..d78521bc09 --- /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 0000000000..df281f3ba8 Binary files /dev/null and b/apps/tasks/img/icon.png differ diff --git a/apps/tasks/img/icon.svg b/apps/tasks/img/icon.svg new file mode 100644 index 0000000000..d46ebab865 --- /dev/null +++ b/apps/tasks/img/icon.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/apps/tasks/index.php b/apps/tasks/index.php new file mode 100644 index 0000000000..8ed5f41043 --- /dev/null +++ b/apps/tasks/index.php @@ -0,0 +1,34 @@ +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 0000000000..60d2a523be --- /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 = $('

') + .attr('title', task.description) + ; + OC.Tasks.setSummary(summary_container, task); + var task_container = $('

') + .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 = $('') + .click(OC.Tasks.complete_task); + if (task.completed) { + checkbox.attr('checked', 'checked'); + task_container.addClass('done'); + } + $('
') + .addClass('completed') + .append(checkbox) + .prependTo(task_container); + var priority = task.priority; + $('
') + .addClass('tag') + .addClass('priority') + .addClass('priority-'+(priority?priority:'n')) + .text(priority) + .prependTo(task_container); + if (task.location) { + $('
') + .addClass('tag') + .addClass('location') + .text(task.location) + .appendTo(task_container); + } + var $categories = $('
') + .addClass('categories') + .appendTo(task_container); + $(task.categories).each(function(i, category){ + $categories.append($('') + .addClass('tag') + .text(category) + ); + }); + task_container.find('.task_more').click(OC.Tasks.moreClickHandler); + task_container.find('.task_less').click(OC.Tasks.lessClickHandler); + var description = $(' +
diff --git a/apps/tasks/templates/part.tasks.php b/apps/tasks/templates/part.tasks.php new file mode 100644 index 0000000000..50be1cd6be --- /dev/null +++ b/apps/tasks/templates/part.tasks.php @@ -0,0 +1,3 @@ + +
  • + diff --git a/apps/tasks/templates/tasks.php b/apps/tasks/templates/tasks.php new file mode 100644 index 0000000000..9869840079 --- /dev/null +++ b/apps/tasks/templates/tasks.php @@ -0,0 +1,31 @@ +
    + + + + + + + + +
    +
    +
    All
    +
    Done
    +
    +
    +

    t('Loading tasks...') ?>

    +
    +

    + + + t('More') ?> + + + t('Less') ?> + +

    + diff --git a/core/img/actions/triangle-n.png b/core/img/actions/triangle-n.png new file mode 100644 index 0000000000..b0d7183caa Binary files /dev/null and b/core/img/actions/triangle-n.png differ diff --git a/core/img/actions/triangle-n.svg b/core/img/actions/triangle-n.svg new file mode 100644 index 0000000000..3565863111 --- /dev/null +++ b/core/img/actions/triangle-n.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + +