Browse Source

Initial Commit

tags/v0.2
raimund-schluessler 5 years ago
commit
a649adbbef
81 changed files with 35546 additions and 0 deletions
  1. 22
    0
      .gitattributes
  2. 222
    0
      .gitignore
  3. 59
    0
      appinfo/app.php
  4. 11
    0
      appinfo/info.xml
  5. 137
    0
      appinfo/routes.php
  6. 1
    0
      appinfo/version
  7. 72
    0
      businesslayer/businesslayer.php
  8. 100
    0
      businesslayer/listsbusinesslayer.php
  9. 199
    0
      businesslayer/tasksbusinesslayer.php
  10. 92
    0
      controller/listscontroller.php
  11. 57
    0
      controller/pagecontroller.php
  12. 214
    0
      controller/taskscontroller.php
  13. 189
    0
      core/api.php
  14. 1108
    0
      css/style.css
  15. 1138
    0
      css/style.less
  16. 69
    0
      css/vendor/timepicker/css/jquery.ui.timepicker.css
  17. 69
    0
      css/vendor/timepicker/jquery.ui.timepicker.css
  18. 28
    0
      db/imapper.php
  19. 54
    0
      db/listsmapper.php
  20. 107
    0
      db/tasksmapper.php
  21. 89
    0
      dependencyinjection/dicontainer.php
  22. BIN
      img/bgLinenBig.jpg
  23. BIN
      img/bgTask.png
  24. BIN
      img/bgTaskDetail.png
  25. BIN
      img/bgTasks.png
  26. BIN
      img/bgTasksActive.png
  27. 7
    0
      img/divider.svg
  28. 18
    0
      img/source/checkbox.svg
  29. 7
    0
      img/source/divider.svg
  30. 10
    0
      img/source/plus.svg
  31. 10
    0
      img/source/star.svg
  32. 10
    0
      img/source/star_active.svg
  33. 12
    0
      img/source/task.svg
  34. 12
    0
      img/source/task_active.svg
  35. 10
    0
      img/source/update.svg
  36. BIN
      img/sprites.png
  37. 1441
    0
      img/sprites.svg
  38. BIN
      img/tasks.png
  39. 18
    0
      img/tasks.svg
  40. 146
    0
      js/Gruntfile.coffee
  41. 38
    0
      js/README.md
  42. 121
    0
      js/app/app.coffee
  43. 63
    0
      js/app/controllers/appcontroller.coffee
  44. 155
    0
      js/app/controllers/detailscontroller.coffee
  45. 154
    0
      js/app/controllers/listcontroller.coffee
  46. 58
    0
      js/app/controllers/searchcontroller.coffee
  47. 163
    0
      js/app/controllers/taskscontroller.coffee
  48. 42
    0
      js/app/directives/datepicker.coffee
  49. 33
    0
      js/app/directives/drag.coffee
  50. 34
    0
      js/app/directives/drop.coffee
  51. 26
    0
      js/app/directives/stopevent.coffee
  52. 30
    0
      js/app/directives/watchtop.coffee
  53. 27
    0
      js/app/filters/dateDetails.coffee
  54. 27
    0
      js/app/filters/dateDetailsShort.coffee
  55. 27
    0
      js/app/filters/dateTaskList.coffee
  56. 24
    0
      js/app/filters/day.coffee
  57. 33
    0
      js/app/filters/taskAtDay.coffee
  58. 28
    0
      js/app/filters/timeDetails.coffee
  59. 63
    0
      js/app/services/businesslayer/listsbusinesslayer.coffee
  60. 107
    0
      js/app/services/businesslayer/tasksbusinesslayer.coffee
  61. 89
    0
      js/app/services/models/collectionsmodel.coffee
  62. 119
    0
      js/app/services/models/listsmodel.coffee
  63. 158
    0
      js/app/services/models/tasksmodel.coffee
  64. 213
    0
      js/app/services/persistence.coffee
  65. 50
    0
      js/app/services/services.coffee
  66. 39
    0
      js/app/services/status.coffee
  67. 34
    0
      js/package.json
  68. 1850
    0
      js/public/app.js
  69. 927
    0
      js/vendor/angularjs/angular-route.js
  70. 14
    0
      js/vendor/angularjs/angular-route.min.js
  71. 21735
    0
      js/vendor/angularjs/angular.js
  72. 211
    0
      js/vendor/angularjs/angular.min.js
  73. 1400
    0
      js/vendor/momentjs/moment.js
  74. 6
    0
      js/vendor/momentjs/moment.min.js
  75. 1406
    0
      js/vendor/timepicker/jquery.ui.timepicker.js
  76. 35
    0
      l10n/de.php
  77. 87
    0
      templates/main.php
  78. 26
    0
      templates/part.collectionall.php
  79. 26
    0
      templates/part.collectionweek.php
  80. 79
    0
      templates/part.details.php
  81. 51
    0
      templates/part.tasklist.php

+ 22
- 0
.gitattributes View File

@@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto

# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union

# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

+ 222
- 0
.gitignore View File

@@ -0,0 +1,222 @@
#################
## Eclipse
#################

*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath

# External tool builders
.externalToolBuilders/

# Locally stored "Eclipse launch configurations"
*.launch

# CDT-specific
.cproject

# PDT-specific
.buildpath


#################
## Visual Studio
#################

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.sln.docstates

# Build results

[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile

# Visual Studio profiler
*.psess
*.vsp
*.vspx

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
*.ncrunch*
.*crunch*.local.xml

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.Publish.xml
*.pubxml

# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/

# Windows Azure Build Output
csx
*.build.csdef

# Windows Store app package directory
AppPackages/

# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
App_Data/*.mdf
App_Data/*.ldf

#############
## Windows detritus
#############

# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Mac crap
.DS_Store


#############
## Python
#############

*.py[co]

# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg

# Installer logs
pip-log.txt

# Unit test / coverage reports
.coverage
.tox

#Translations
*.mo

#Mr Developer
.mr.developer.cfg


#######
Node.js
#######
node_modules
*.ai

+ 59
- 0
appinfo/app.php View File

@@ -0,0 +1,59 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/
namespace OCA\Tasks_enhanced;

use \OCA\AppFramework\Core\API;

// dont break owncloud when the appframework is not enabled
if(\OCP\App::isEnabled('appframework') && \OCP\App::isEnabled('calendar')){

$api = new API('tasks_enhanced');

$api->addNavigationEntry(array(

// the string under which your app will be referenced in owncloud
'id' => $api->getAppName(),

// sorting weight for the navigation. The higher the number, the higher
// will it be listed in the navigation
'order' => 100,

// the route that will be shown on startup
'href' => $api->linkToRoute('tasks_enhanced_index'),

// the icon that will be shown in the navigation
// this file needs to exist in img/example.png
'icon' => $api->imagePath('tasks.svg'),
// 'icon' => $api->imagePath('core', 'places/music.svg'),

// the title of your application. This will be used in the
// navigation or on the settings page of your app
'name' => $api->getTrans()->t('Tasks 2')

));

} else {
$msg = 'Can not enable the Tasks app because the App Framework App or the Calendar App is disabled.';
\OCP\Util::writeLog('tasks_enhanced', $msg, \OCP\Util::ERROR);
}

+ 11
- 0
appinfo/info.xml View File

@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<info>
<id>tasks_enhanced</id>
<name>tasks_enhanced</name>
<version>0.1</version>
<licence>AGPL</licence>
<author>Raimund Schlüßler</author>
<require>5.0.11</require>
<shipped>true</shipped>
<description>Enhanced Task App for Calender TODOs</description>
</info>

+ 137
- 0
appinfo/routes.php View File

@@ -0,0 +1,137 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/

namespace OCA\Tasks_enhanced;

use \OCA\AppFramework\App;

use \OCA\Tasks_enhanced\DependencyInjection\DIContainer;

$this->create('tasks_enhanced_index', '/')->get()->action(
function($params){
// call the index method on the class PageController
App::main('PageController', 'index', $params, new DIContainer());
}
);

/*
* Lists
*/
$this->create('getLists', '/lists')->get()->action(
function($params){
App::main('ListsController', 'getLists', $params, new DIContainer());
}
);

$this->create('list_add', '/lists/add/{name}')->post()->action(
function($params){
App::main('ListsController', 'addList', $params, new DIContainer());
}
);

$this->create('list_delete', '/lists/{listID}/delete')->post()->action(
function($params){
App::main('ListsController', 'deleteList', $params, new DIContainer());
}
);

$this->create('list_name', '/lists/{listID}/name')->post()->action(
function($params){
App::main('ListsController', 'setListName', $params, new DIContainer());
}
);

/*
* Tasks
*/
$this->create('getTasks', '/tasks')->get()->action(
function($params){
App::main('TasksController', 'getTasks', $params, new DIContainer());
}
);

$this->create('task_star', '/tasks/{taskID}/star')->post()->action(
function($params){
App::main('TasksController', 'starTask', $params, new DIContainer());
}
);

$this->create('task_unstar', '/tasks/{taskID}/unstar')->post()->action(
function($params){
App::main('TasksController', 'unstarTask', $params, new DIContainer());
}
);

$this->create('task_complete', '/tasks/{taskID}/complete')->post()->action(
function($params){
App::main('TasksController', 'completeTask', $params, new DIContainer());
}
);

$this->create('task_uncomplete', '/tasks/{taskID}/uncomplete')->post()->action(
function($params){
App::main('TasksController', 'uncompleteTask', $params, new DIContainer());
}
);

$this->create('task_add', '/tasks/add/{calendarID}/{name}')->post()->action(
function($params){
App::main('TasksController', 'addTask', $params, new DIContainer());
}
);

$this->create('task_delete', '/tasks/{taskID}/delete')->post()->action(
function($params){
App::main('TasksController', 'deleteTask', $params, new DIContainer());
}
);

$this->create('task_name', '/tasks/{taskID}/name')->post()->action(
function($params){
App::main('TasksController', 'setTaskName', $params, new DIContainer());
}
);

$this->create('task_calendar', '/tasks/{taskID}/calendar')->post()->action(
function($params){
App::main('TasksController', 'setTaskCalendar', $params, new DIContainer());
}
);

$this->create('task_note', '/tasks/{taskID}/note')->post()->action(
function($params){
App::main('TasksController', 'setTaskNote', $params, new DIContainer());
}
);

$this->create('task_due', '/tasks/{taskID}/due')->post()->action(
function($params){
App::main('TasksController', 'setDueDate', $params, new DIContainer());
}
);

$this->create('task_reminder', '/tasks/{taskID}/reminder')->post()->action(
function($params){
App::main('TasksController', 'setReminderDate', $params, new DIContainer());
}
);

+ 1
- 0
appinfo/version View File

@@ -0,0 +1 @@
0.1

+ 72
- 0
businesslayer/businesslayer.php View File

@@ -0,0 +1,72 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/

namespace OCA\Tasks_enhanced\BusinessLayer;

use \OCA\AppFramework\Db\DoesNotExistException;
use \OCA\AppFramework\Db\MultipleObjectsReturnedException;

use \OCA\Tasks_enhanced\Db\IMapper;


abstract class BusinessLayer {

protected $mapper;

public function __construct(IMapper $mapper){
$this->mapper = $mapper;
}


/**
* Delete an entity
* @param int $id the id of the entity
* @param string $userId the name of the user for security reasons
* @throws DoesNotExistException if the entity does not exist
* @throws MultipleObjectsReturnedException if more than one entity exists
*/
public function delete($id, $userId){
$entity = $this->find($id, $userId);
$this->mapper->delete($entity);
}


/**
* Finds an entity by id
* @param int $id the id of the entity
* @param string $userId the name of the user for security reasons
* @throws DoesNotExistException if the entity does not exist
* @throws MultipleObjectsReturnedException if more than one entity exists
* @return Entity the entity
*/
public function find($id, $userId){
try {
return $this->mapper->find($id, $userId);
} catch(DoesNotExistException $ex){
throw new BusinessLayerException($ex->getMessage());
} catch(MultipleObjectsReturnedException $ex){
throw new BusinessLayerException($ex->getMessage());
}
}

}

+ 100
- 0
businesslayer/listsbusinesslayer.php View File

@@ -0,0 +1,100 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/

namespace OCA\Tasks_enhanced\BusinessLayer;

use \OCA\AppFramework\Core\API;
use \OCA\AppFramework\Utility\TimeFactory;

use \OCA\Tasks_enhanced\Db\ListsMapper;


class ListsBusinessLayer extends BusinessLayer {

private $api;

public function __construct(ListsMapper $listsMapper,
API $api
){
parent::__construct($listsMapper);
$this->api = $api;
}

public function getAllLists($userId) {
return $this->mapper->getAllLists($userId);
}

public function addList($listName,$userId){
if(trim($listName) == '') {
// OCP\JSON::error(array('message'=>'empty'));
exit;
}
$calendars = $this->api->getAllCalendars($userId);
foreach($calendars as $cal) {
if($cal['displayname'] == $listName) {
// OCP\JSON::error(array('message'=>'namenotavailable'));
exit;
}
}
$color = '#CCCCCC';
$calendarId = $this->api->addCalendar($userId,$listName,$color);
$this->api->setCalendarActive($calendarId);
$calendar = $this->api->findCalendar($calendarId);
return $calendar;
}

public function deleteList($listId){
try {
$del = $this->api->deleteCalendar($listId);
if($del == true) {
return true;
}else{
return array('error'=>'dberror');
}
} catch(Exception $e) {
return array('message'=>$e->getMessage());
}
}

public function editList($calendarId,$listName,$userId){
if(trim($listName) == '') {
// OCP\JSON::error(array('message'=>'empty'));
exit;
}
$calendars = $this->api->getAllCalendars($userId);
foreach($calendars as $cal) {
if($cal['userid'] != $userId){
continue;
}
if($cal['displayname'] == $listName && $cal['id'] != $calendarId) {
// OCP\JSON::error(array('message'=>'namenotavailable'));
exit;
}
}

$color = '#CCCCCC';
$this->api->editCalendar($calendarId,$listName,$color);
$calendar = $this->api->findCalendar($calendarId);
return $calendar;
}
}

+ 199
- 0
businesslayer/tasksbusinesslayer.php View File

@@ -0,0 +1,199 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/

namespace OCA\Tasks_enhanced\BusinessLayer;

use \OCA\AppFramework\Core\API;
use \OCA\AppFramework\Utility\TimeFactory;

use \OCA\Tasks_enhanced\Db\TasksMapper;


class TasksBusinessLayer extends BusinessLayer {

private $api;
private $timeFactory;
private $autoPurgeMinimumInterval;

public function __construct(TasksMapper $tasksMapper,
API $api
){
parent::__construct($tasksMapper);
$this->api = $api;
}

public function getInitialTasks($userId) {
return $this->mapper->getInitialTasks($userId);
}

public function getAllTasks($userId) {
return $this->mapper->getAllTasks($userId);
}

public function star($taskId, $isStarred){
try {
$vcalendar = $this->mapper->findByID($taskId);
$vtodo = $vcalendar->VTODO;
if($isStarred){
$vtodo->setString('PRIORITY',1);
}else{
$vtodo->__unset('PRIORITY');
}
$this->api->editCalendarObject($taskId, $vcalendar);
} catch(\Exception $e) {
// throw new BusinessLayerException($e->getMessage());
}
}

public function complete($taskId, $isCompleted, $percent_complete){
try {
$vcalendar = $this->mapper->findByID($taskId);
$vtodo = $vcalendar->VTODO;
if (!empty($percent_complete)) {
$vtodo->setString('PERCENT-COMPLETE', $percent_complete);
}else{
$vtodo->__unset('PERCENT-COMPLETE');
}

if ($percent_complete == 100) {
if (!$isCompleted) {
$isCompleted = 'now';
}
} else {
$isCompleted = null;
}
if ($isCompleted) {
$timezone = $this->api->getTimezone();
$timezone = new \DateTimeZone($timezone);
$isCompleted = new \DateTime($isCompleted, $timezone);
$vtodo->setDateTime('COMPLETED', $isCompleted);
} else {
unset($vtodo->COMPLETED);
}
$this->api->editCalendarObject($taskId, $vcalendar);
} catch(\Exception $e) {
// throw new BusinessLayerException($e->getMessage());
}
}

public function add($taskName, $calendarId, $starred, $due){
$calendars = $this->api->getAllCalendars($this->api->getUserId());
$user_timezone = $this->api->getTimezone($this->api->getUserId());
$request = array(
'summary' => $taskName,
'categories' => null,
'priority' => $starred,
'location' => null,
'due' => $due,
'description' => null
);
$vcalendar = $this->api->createVCalendarFromRequest($request);
$taskId = $this->api->addCalendarObject($calendarId, $vcalendar);

$task = $this->api->arrayForJSON($taskId, $vcalendar->VTODO, $user_timezone);
$task['calendarid'] = $calendarId;
return $task;
}

public function setName($taskId, $name){
try {
$vcalendar = $this->mapper->findByID($taskId);
$vtodo = $vcalendar->VTODO;
$vtodo->setString('SUMMARY', $name);
$this->api->editCalendarObject($taskId, $vcalendar);
} catch(\Exception $e) {
// throw new BusinessLayerException($e->getMessage());
}
}

public function setCalendar($taskId, $calendar){
try {
$data = $this->api->getEventObject($taskId);
if ($data['calendarid'] != $calendar) {
$this->api->moveToCalendar($taskId, $calendar);
}
} catch(\Exception $e) {
// throw new BusinessLayerException($e->getMessage());
}
}

public function setNote($taskId, $note){
try {
$vcalendar = $this->mapper->findByID($taskId);
$vtodo = $vcalendar->VTODO;
$vtodo->setString('DESCRIPTION', $note);
$this->api->editCalendarObject($taskId, $vcalendar);
} catch(\Exception $e) {
// throw new BusinessLayerException($e->getMessage());
}
}

public function setDue($taskId, $due, $due_date_only){
try{
$vcalendar = $this->mapper->findByID($taskId);
$vtodo = $vcalendar->VTODO;
$type = null;
if ($due != 'false') {
$timezone = $this->api->getTimezone();
$timezone = new \DateTimeZone($timezone);

$due = new \DateTime('@'.$due);
$due->setTimezone($timezone);
$type = \Sabre\VObject\Property\DateTime::LOCALTZ;
if ($due_date_only) {
$type = \Sabre\VObject\Property\DateTime::DATE;
}
}
} catch (\Exception $e) {

}
$vtodo->setDateTime('DUE', $due, $type);
$this->api->editCalendarObject($taskId, $vcalendar);
}

public function setReminder(){

}

public function setCategories($taskId, $categories){
try {
$vcalendar = $this->mapper->findByID($taskId);
$vtodo = $vcalendar->VTODO;
$vtodo->setString('CATEGORIES', $categories);
$this->api->editCalendarObject($taskId, $vcalendar);
} catch(\Exception $e) {
// throw new BusinessLayerException($e->getMessage());
}
}

public function setLocation($taskId, $location){
try {
$vcalendar = $this->mapper->findByID($taskId);
$vtodo = $vcalendar->VTODO;
$vtodo->setString('LOCATION', $location);
$this->api->editCalendarObject($taskId, $vcalendar);
} catch(\Exception $e) {
// throw new BusinessLayerException($e->getMessage());
}
}
}

+ 92
- 0
controller/listscontroller.php View File

@@ -0,0 +1,92 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/

namespace OCA\Tasks_enhanced\Controller;

use \OCA\AppFramework\Controller\Controller;
use \OCA\AppFramework\Core\API;
use \OCA\AppFramework\Http\Request;

use \OCA\Tasks_enhanced\BusinessLayer\ListsBusinessLayer;

class ListsController extends Controller {

private $listsBusinessLayer;

public function __construct(API $api, Request $request,
ListsBusinessLayer $listsBusinessLayer){
parent::__construct($api, $request);
$this->listsBusinessLayer = $listsBusinessLayer;
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function getLists(){
$lists = $this->listsBusinessLayer->getAllLists($this->api->getUserId());
$result = array(
'lists' => $lists
);
return $this->renderJSON($result);
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function addList(){
$listName = $this->params('name');
$list = $this->listsBusinessLayer->addList($listName,$this->api->getUserId());
$list['tmpID'] = $this->params('tmpID');
$result = array(
'list' => $list
);
return $this->renderJSON($result);
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function deleteList(){
$listId = $this->params('listID');
$result = $this->listsBusinessLayer->deleteList($listId);
return $this->renderJSON();
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function setListName(){
$listId = (int) $this->params('listID');
$listName = $this->params('name');
$result = $this->listsBusinessLayer->editList($listId, $listName,$this->api->getUserId());
return $this->renderJSON($result);
}
}

+ 57
- 0
controller/pagecontroller.php View File

@@ -0,0 +1,57 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/

namespace OCA\Tasks_enhanced\Controller;

use \OCA\AppFramework\Controller\Controller;
use \OCA\AppFramework\Core\API;
use \OCA\AppFramework\Http\Request;

class PageController extends Controller {


public function __construct(API $api, Request $request){
parent::__construct($api, $request);
}


/**
* ATTENTION!!!
* The following comments turn off security checks
* Please look up their meaning in the documentation!
*
* @CSRFExemption
* @IsAdminExemption
* @IsSubAdminExemption
*/
public function index(){
$date = new \DateTimeZone(\OC_Calendar_App::getTimezone());
$day = new \DateTime('today', $date);
$day = $day->format('d');
return $this->render('main', array(
'DOM' => $day
));
}


}

+ 214
- 0
controller/taskscontroller.php View File

@@ -0,0 +1,214 @@
<?php

/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2013 Raimund Schlüßler raimund.schluessler@googlemail.com
*
* 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/>.
*
*/

namespace OCA\Tasks_enhanced\Controller;

use \OCA\AppFramework\Controller\Controller;
use \OCA\AppFramework\Core\API;
use \OCA\AppFramework\Http\Request;

use \OCA\Tasks_enhanced\BusinessLayer\TasksBusinessLayer;

class TasksController extends Controller {

private $tasksBusinessLayer;

public function __construct(API $api, Request $request,
TasksBusinessLayer $tasksBusinessLayer){
parent::__construct($api, $request);
$this->tasksBusinessLayer = $tasksBusinessLayer;
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function getTasks(){
$tasks = $this->tasksBusinessLayer->getAllTasks($this->api->getUserId());
$result = array(
'tasks' => $tasks
);
return $this->renderJSON($result);
}

private function setStarred($isStarred){
$taskID = (int) $this->params('taskID');
$this->tasksBusinessLayer->star($taskID, $isStarred);
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function starTask(){
try {
$this->setStarred(true);
return $this->renderJSON();
} catch(\Exception $e) {
return $this->renderJSON(array(), $e->getMessage());
}
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function unstarTask(){
try {
$this->setStarred(false);
return $this->renderJSON();
} catch(\Exception $e) {
return $this->renderJSON(array(), $e->getMessage());
}
}

private function setCompleted($isCompleted){
$taskId = (int) $this->params('taskID');
$this->tasksBusinessLayer->complete($taskId, null, $isCompleted ? '100' : '0');
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function completeTask(){
try {
$this->setCompleted(true);
return $this->renderJSON();
} catch(\Exception $e) {
return $this->renderJSON(array(), $e->getMessage());
}
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function uncompleteTask(){
try {
$this->setCompleted(false);
return $this->renderJSON();
} catch(\Exception $e) {
return $this->renderJSON(array(), $e->getMessage());
}
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function addTask(){
$taskName = $this->params('name');
$calendarID = $this->params('calendarID');
$starred = $this->params('starred');
$due = $this->params('due');
$task = $this->tasksBusinessLayer->add($taskName, $calendarID, $starred, $due);
$task['tmpID'] = $this->params('tmpID');
$result = array(
'task' => $task
);
return $this->renderJSON($result);
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function deleteTask(){
$taskId = $this->params('taskID');
$task = $this->api->getEventObject($taskId);

$this->api->deleteCalendarObject($taskId);
return $this->renderJSON();
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function setTaskName(){
$taskId = (int) $this->params('taskID');
$taskName = $this->params('name');
$this->tasksBusinessLayer->setName($taskId, $taskName);
return $this->renderJSON();
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function setTaskCalendar(){
$taskId = $this->params('taskID');
$calendarId = $this->params('calendarID');
$this->tasksBusinessLayer->setCalendar($taskId, $calendarId);
return $this->renderJSON();
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function setTaskNote(){
$taskId = $this->params('taskID');
$note = $this->params('note');
$this->tasksBusinessLayer->setNote($taskId, $note);
return $this->renderJSON();
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function setDueDate(){
$taskId = $this->params('taskID');
$due = $this->params('due');
$date = 1;
$this->tasksBusinessLayer->setDue($taskId, $due, $date);
return $this->renderJSON();
}

/**
* @IsAdminExemption
* @IsSubAdminExemption
* @Ajax
*/
public function setReminderDate(){
$taskID = $this->params('taskID');
$reminder = $this->params('reminder');
$this->tasksBusinessLayer->setReminder($taskId, $due);
return $this->renderJSON();
}


}

+ 189
- 0
core/api.php View File

@@ -0,0 +1,189 @@
<?php

/**
* ownCloud - Music app
*
* @author Morris Jobke
* @copyright 2013 Morris Jobke <morris.jobke@gmail.com>
*
* 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/>.
*
*/


namespace OCA\Tasks_enhanced\Core;

use \OCA\AppFramework\Core\API as BaseAPI;

class API extends BaseAPI {

public function parseVTODO($data) {
$object = \OC_VObject::parse($data);
$vtodo = $object->VTODO;
return $vtodo;
}

public static function arrayForJSON($id, $vtodo, $user_timezone){
$task = array( 'id' => $id );
$task['name'] = $vtodo->getAsString('SUMMARY');
$task['note'] = $vtodo->getAsString('DESCRIPTION');
$task['location'] = $vtodo->getAsString('LOCATION');
$task['categories'] = $vtodo->getAsArray('CATEGORIES');
$due = $vtodo->DUE;
if ($due) {
try {
$due = $due->getDateTime();
$due->setTimezone(new \DateTimeZone($user_timezone));
$task['due'] = $due->format('Ymd\THis');
} catch(\Exception $e) {
$task['due'] = 'undefined';
\OCP\Util::writeLog('tasks_enhanced', $e->getMessage(), \OCP\Util::ERROR);
}
} else {
$task['due'] = 'undefined';
}
$reminder = $vtodo->REMINDER;
if($reminder) {
try {
$reminder = $reminder->getDateTime();
$reminder->setTimezone(new \DateTimeZone($user_timezone));
$task['reminder'] = $reminder->format('Ymd\THis');
} catch(\Exception $e) {
$task['reminder'] = 'undefined';
\OCP\Util::writeLog('tasks_enhanced', $e->getMessage(), \OCP\Util::ERROR);
}
} else {
$task['reminder'] = 'undefined';
}
$starred = $vtodo->getAsString('PRIORITY');
if($starred){
$task['starred'] = true;
} else {
$task['starred'] = false;
}
$completed = $vtodo->COMPLETED;
if ($completed) {
try {
$completed = $completed->getDateTime();
$completed->setTimezone(new \DateTimeZone($user_timezone));
$task['completed_date'] = $completed->format('Ymd\THis');
$task['completed'] = true;
} catch(\Exception $e) {
$task['completed'] = false;
\OCP\Util::writeLog('tasks_enhanced', $e->getMessage(), \OCP\Util::ERROR);
}
} else {
$task['completed'] = false;
}
$task['complete'] = $vtodo->getAsString('PERCENT-COMPLETE');
return $task;
}

public static function getAllCalendars($userId){
return \OC_Calendar_Calendar::allCalendars($userId, true);
}

public static function deleteCalendar($calendarId){
return \OC_Calendar_Calendar::deleteCalendar($calendarId);
}

public static function addCalendar($userId,$listName,$color){
return \OC_Calendar_Calendar::addCalendar($userId, strip_tags($listName), 'VEVENT,VTODO,VJOURNAL', null, 0, $color);
}

public static function setCalendarActive($calendarId){
return \OC_Calendar_Calendar::setCalendarActive($calendarId, 1);
}

public static function editCalendar($calendarId,$listName,$color) {
return \OC_Calendar_Calendar::editCalendar($calendarId, strip_tags($listName), null, null, null, $color);
}

public static function findCalendar($calendarId){
return \OC_Calendar_Calendar::find($calendarId);
}

public static function getTimezone(){
return \OC_Calendar_App::getTimezone();
}

public static function getVCalendar($taskId){
return \OC_Calendar_App::getVCalendar($taskId);
}

public static function getEventObject($taskID){
return \OC_Calendar_App::getEventObject($taskID);
}

public static function getAllTasks($calendarId){
return \OC_Calendar_Object::all($calendarId);
}

public static function editCalendarObject($taskId, $vcalendar){
return \OC_Calendar_Object::edit($taskId, $vcalendar->serialize());
}

public static function moveToCalendar($taskId, $calendarId){
return \OC_Calendar_Object::moveToCalendar($taskId, $calendarId);
}

public static function addCalendarObject($calendarId, $vcalendar){
return \OC_Calendar_Object::add($calendarId, $vcalendar->serialize());
}

public static function deleteCalendarObject($taskID){
return \OC_Calendar_Object::delete($taskID);
}

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\Property\DateTime::UTC);

$vtodo->setUID();
return self::updateVCalendarFromRequest($request, $vcalendar);
}

public static function updateVCalendarFromRequest($request, $vcalendar){
$vtodo = $vcalendar->VTODO;

$vtodo->setDateTime('LAST-MODIFIED', 'now', \Sabre\VObject\Property\DateTime::UTC);
$vtodo->setDateTime('DTSTAMP', 'now', \Sabre\VObject\Property\DateTime::UTC);
$vtodo->setString('SUMMARY', $request['summary']);

$vtodo->setString('LOCATION', $request['location']);
$vtodo->setString('DESCRIPTION', $request['description']);
$vtodo->setString('CATEGORIES', $request["categories"]);
$vtodo->setString('PRIORITY', $request['priority']);

$due = $request['due'];
if ($due) {
$timezone = self::getTimezone();
$timezone = new \DateTimeZone($timezone);
$due = new \DateTime($due, $timezone);
$vtodo->setDateTime('DUE', $due);
} else {
unset($vtodo->DUE);
}

return $vcalendar;
}


}

+ 1108
- 0
css/style.css View File

@@ -0,0 +1,1108 @@
* {
-moz-user-select: -moz-none;
margin: 0;
padding: 0;
text-decoration: none;
}
#content {
overflow: hidden;
color: #423E3E;
background: url("%appswebroot%/tasks_enhanced/img/bgLinenBig.jpg") repeat scroll 0 0 #000000;
}
#content .icon {
background-image: url("%appswebroot%/tasks_enhanced/img/sprites.svg");
height: 20px;
width: 20px;
display: inline-block;
cursor: pointer;
vertical-align: middle;
}
#content .icon.list-list {
background-position: -40px 0px;
}
#content .icon.collection-starred {
background-position: -20px 0px;
}
#content .icon.collection-today {
-moz-box-sizing: border-box;
background-position: -240px 0px;
color: #AAAAAA;
font-size: 7px;
font-weight: bold;
line-height: 9px;
padding-top: 7px;
text-align: center;
text-shadow: 0 1px 0 white;
}
#content .icon.collection-week {
background-position: -220px 0px;
}
#content .icon.collection-completed {
background-position: -100px 0px;
}
#content .icon.collection-all {
background-position: -200px 0px;
}
#content .icon.detail-add {
background-position: -80px 0px;
cursor: default;
height: 20px;
width: 20px;
opacity: 0.5;
}
#content .icon.input-date {
display: none;
background-position: -160px -100px;
opacity: 0.4;
transition: opacity 100ms ease 0s;
right: 35px;
top: 7px;
}
#content .icon.input-star {
display: none;
background-position: -100px -180px;
opacity: 0.5;
right: 9px;
}
#content .icon.input-star.starred {
background-position: -120px -180px;
opacity: 1;
}
#content .icon.detail-delete {
background-position: 0 -40px;
height: 20px;
opacity: 0.4;
width: 20px;
}
#content .icon.task-checkbox {
background-position: -60px 0px;
height: 20px;
width: 20px;
left: 8px;
position: absolute;
top: 7px;
}
#content .icon.task-attachment {
background-position: 0 -60px;
}
#content .icon.detail-trash {
background-position: -260px 0px;
transition: opacity 100ms ease 0s;
opacity: 0.6;
}
#content .icon.search {
background-position: -80px -20px;
transition: opacity 100ms ease 0s;
opacity: 0.6;
}
#content .icon.menu-search {
background-position: -80px -20px;
}
#content .icon.detail-close {
background-position: -260px -20px;
opacity: 0.6;
transition: opacity 100ms ease 0s;
}
#content .icon.detail-checkbox {
left: 18px;
position: absolute;
top: 17px;
background-position: -60px 0px;
}
#content .icon.detail-reminder {
background-position: -40px -40px;
height: 20px;
width: 20px;
}
#content .icon.task-checked,
#content .icon.detail-checked {
background-position: -60px -20px;
height: 20px;
width: 20px;
}
#content .icon.detail-star {
position: absolute;
right: 15px;
top: -2px;
background-position: -60px -40px;
height: 60px;
width: 30px;
}
#content .icon.detail-star:hover {
background-position: -90px -40px;
}
#content .icon.detail-starred {
top: -2px !important;
position: absolute;
right: 15px;
top: -2px;
background-position: -120px -40px !important;
height: 60px;
width: 30px;
}
#content .icon.detail-save {
background-position: -20px -40px;
}
#content .icon.note-fullscreen {
background-position: -140px -60px;
opacity: 0.6;
}
#content .icon.note-fullscreen:hover {
opacity: 1;
}
#content .icon.toggle-completed-tasks {
background-position: -120px 0;
height: 20px;
opacity: 0.8;
width: 20px;
}
#content .icon.toggle-completed-tasks:hover {
opacity: 1;
}
#content li.task-item {
cursor: default;
height: 37px;
list-style: none outside none;
overflow: hidden;
z-index: 100 !important;
}
#content li.task-item.done {
opacity: 0.6;
}
#content li.task-item.done .title {
text-decoration: line-through;
text-shadow: none;
}
#content li.task-item .task-body {
-moz-box-sizing: border-box;
background: url("%appswebroot%/tasks_enhanced/img/bgTask.png") repeat-x scroll 0 0 #f8f8f8;
border-radius: 2px 2px 2px 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(0, 0, 0, 0.08);
height: 34px;
list-style: none outside none;
margin: 1px 1px 0;
position: relative;
}
#content li.task-item .task-body .icon.task-separator {
cursor: default;
height: 100%;
left: 34px;
position: absolute;
top: 1px;
background-position: 0 -20px;
width: 2px;
}
#content li.task-item .task-body .icon.task-star {
float: right;
margin: 0 8px 0 5px;
background-position: -140px 0px;
height: 34px;
width: 20px;
}
#content li.task-item .task-body .icon.task-star:hover {
background-position: -160px 0;
}
#content li.task-item .task-body .icon.task-starred,
#content li.task-item .task-body .icon.task-starred:hover {
background-position: -180px 0;
margin-left: 5px;
margin-right: 8px;
margin-top: 0;
}
#content li.task-item .task-body .title-wrapper {
cursor: pointer;
color: #423E3E;
display: block;
line-height: 16px;
margin: 0 0 0 44px;
overflow: hidden;
padding: 9px 0;
position: relative;
text-overflow: ellipsis;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
white-space: nowrap;
}
#content li.task-item .task-body .title-wrapper .title {
cursor: text;
}
#content li.task-item .task-body .title-wrapper.attachment .task-attachment {
display: inline-block;
}
#content li.task-item .task-body .title-wrapper .task-attachment {
display: none;
height: 20px;
margin-top: -3px;
}
#content li.task-item .task-body .duedate {
color: #3B6594;
float: right;
font-size: 11px;
line-height: 14px;
margin: 11px 3px 0 7px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
}
#content li.task-item .task-body .duedate.overdue {
color: #B3312D;
}
#task-lists {
background: url("%appswebroot%/tasks_enhanced/img/bgTasks.png") repeat scroll 0 0 #eeeeee;
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 250px;
font-family: "Helvetica Neue", "Helvetica", "Arial", Sans-Serif;
font-size: 13px;
}
#task-lists div.header {
height: 37px;
border-bottom: 1px solid #AFAFAF;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%) repeat scroll 0 0 transparent;
background: -moz-linear-gradient(center top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%) repeat scroll 0 0 transparent;
background: -ms-linear-gradient(center top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%) repeat scroll 0 0 transparent;
background: -o-linear-gradient(center top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%) repeat scroll 0 0 transparent;
background: linear-gradient(top, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 100%) repeat scroll 0 0 transparent;
}
#task-lists div.header a {
position: absolute;
top: 0;
bottom: 0;
cursor: pointer;
padding: 10px;
height: 20px;
line-height: 20px;
}
#task-lists div.header.search #search-toolbar {
display: block;
}
#task-lists div.header.search #main-toolbar {
display: none;
}
#task-lists div.header #search-toolbar {
display: none;
}
#task-lists div.header #search-toolbar .icon.menu-search {
left: 41px;
position: absolute;
top: 9px;
z-index: 100;
}
#task-lists div.header #search-toolbar input {
border-radius: 15px 15px 15px 15px;
left: 36px;
padding: 4px 4px 4px 25px;
position: absolute;
right: 36px;
top: 6px;
width: 210px;
-moz-box-sizing: border-box;
background: none repeat scroll 0 0 white;
border: 1px solid #BDBCBB;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset;
margin: 0;
}
#task-lists div.header #search-toolbar input:focus {
background-color: #F8F8F8;
border: 1px solid rgba(43, 136, 217, 0.65);
box-shadow: 0 0 4px rgba(43, 136, 217, 0.32), 0 1px 1px rgba(255, 255, 255, 0.43), 0 2px 4px rgba(43, 136, 217, 0.12) inset, 0 0 4px rgba(43, 136, 217, 0.2) inset;
}
#task-lists div.header #search,
#task-lists div.header #cancel-search {
position: absolute;
right: 0;
top: 0;
cursor: pointer;
padding: 8px;
display: block;
}
#task-lists div.header #loading {
position: absolute;
left: 0;
top: 0;
cursor: pointer;
padding: 10px;
display: block;
}
#task-lists div.header #loading span {
height: 20px;
width: 20px;
display: inline-block;
cursor: pointer;
vertical-align: middle;
background-size: 20px 20px;
}
#task-lists div.header #loading span.done {
background: url("%appswebroot%/tasks_enhanced/img/sprites.svg") repeat-x scroll center bottom transparent;
background-position: 0 0;
}
#task-lists div.footer {
height: 40px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
#task-lists div.footer a {
position: absolute;
top: 0;
bottom: 0;
cursor: pointer;
padding: 10px;
height: 20px;
line-height: 20px;
}
#task-lists div.scroll {
position: absolute;
top: 37px;
bottom: 40px;
right: 0;
left: 0;
overflow: auto;
}
#task-lists a.addlist {
background: none repeat scroll 0 0 transparent;
}
#task-lists .count {
color: #B0B0B0;
float: right;
}
#task-lists .addlist:hover .title {
color: #625F5F;
}
#task-lists .addlist:hover .detail-add {
opacity: 1;
}
#task-lists .addlist .title {
color: #999999;
}
#task-lists .addlist,
#task-lists li a {
background: url("%appswebroot%/tasks_enhanced/img/divider.svg") repeat-x scroll center bottom transparent;
display: block;
-moz-box-sizing: border-box;
-o-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
position: relative;
height: 34px;
padding: 6px 12px 8px 8px;
color: #413D3F;
font-weight: bold;
text-shadow: 0 1px 0 white;
}
#task-lists input.edit {
border: 1px solid #3F84B3;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1) inset;
font-family: "Helvetica Neue", "Helvetica", "Arial", Sans-Serif;
font-weight: bold;
font-size: 13px;
left: 34px;
padding: 4px;
position: absolute;
right: 46px;
top: 5px;
width: auto;
margin: 0;
border-radius: 0;
}
#task-lists li {
height: 34px;
overflow: hidden;
position: relative;
transition: height 300ms ease 0s !important;
}
#task-lists li.active {
border-top: 2px solid #ECECEC;
margin-top: -2px;
}
#task-lists li.active a {
background: url("%appswebroot%/tasks_enhanced/img/bgTasksActive.png") repeat scroll 0 0 transparent;
border-bottom: 1px solid transparent;
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}
#task-lists li.active a .count {
color: white;
}
#task-lists li.active .icon.collection-all {
background-position: -200px -20px;
}
#task-lists li.active .icon.list-list {
background-position: -40px -20px;
}
#task-lists li.active .icon.collection-starred {
background-position: -20px -20px;
}
#task-lists li.active .icon.collection-today {
background-position: -240px -20px;
color: white;
text-shadow: 0 1px 0 #336692;
}
#task-lists li.active .icon.collection-week {
background-position: -220px -20px;
}
#task-lists li.active .icon.collection-completed {
background-position: -100px -20px;
}
#task-lists li.dragOver a {
border: 2px solid #2b88d9;
padding: 6px 10px 6px 6px;
}
#task-lists li.dragOver a .title {
left: 38px;
right: 28px;
top: 6px;
}
#task-lists li.animate-up {
height: 0px !important;
border-bottom: 0;
}
#task-lists li input.edit {
border: 1px solid #3F84B3;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1) inset;
font-family: "Helvetica Neue", "Helvetica", "Arial", Sans-Serif;
font-weight: bold;
font-size: 13px;
left: 34px;
padding: 4px;
position: absolute;
right: 46px;
top: 5px;
width: auto;
margin: 0;
border-radius: 0;
}
#task-lists .title {
position: absolute;
left: 40px;
right: 30px;
top: 6px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
#task-tasks {
-webkit-transition: right 0.4s ease-in-out;
-moz-transition: right 0.4s ease-in-out;
-ms-transition: right 0.4s ease-in-out;
-o-transition: right 0.4s ease-in-out;
transition: right 0.4s ease-in-out;
position: absolute;
left: 250px;
right: 0;
top: 0;
bottom: 0;
overflow-x: hidden;
padding: 6px 17px 15px 17px;
}
#task-tasks.details-visible {
right: 360px;
}
#task-tasks h2 {
font-weight: bold;
color: white;
font-size: 12px;
margin-bottom: 10px;
margin-top: 20px !important;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
word-wrap: break-word;
}
#task-tasks #add-task {
background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.1) 100%) repeat scroll 0 0 transparent;
background: -moz-linear-gradient(center top, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.1) 100%) repeat scroll 0 0 transparent;
background: -ms-linear-gradient(center top, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.1) 100%) repeat scroll 0 0 transparent;
background: -o-linear-gradient(center top, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.1) 100%) repeat scroll 0 0 transparent;
background: linear-gradient(top, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.1) 100%) repeat scroll 0 0 transparent;
border-radius: 4px 4px 4px 4px;
border-top: 1px solid rgba(0, 0, 0, 0.4);
box-shadow: 0 0 4px rgba(0, 0, 0, 0.4) inset, 0 1px 0 rgba(255, 255, 255, 0.4);
margin: 12px 0;
padding: 6px 12px;
position: relative;
}
#task-tasks #add-task.focus {
box-shadow: 0 0 4px rgba(0, 0, 0, 0.4) inset, 0 1px 0 rgba(255, 255, 255, 0.1), 0 0 5px rgba(255, 255, 255, 0.7);
}
#task-tasks #add-task.focus .icon.input-date {
display: block;
}
#task-tasks #add-task.focus .icon.input-star {
display: block;
}
#task-tasks #add-task .icon {
position: absolute;
top: 6px;
}
#task-tasks #add-task input {
-moz-box-sizing: border-box;
font-size: 13px;
font-weight: bold;
padding-right: 60px;
width: 100%;
color: #DBDBDB;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
background: none repeat scroll 0 0 transparent !important;
border: medium none !important;
border-radius: 0 0 0 0 !important;
box-shadow: none !important;
padding: 0 60px 0 0;
margin: 0;
cursor: text;
}
#task-tasks div.task-list h2.heading text,
#task-tasks div.task-list h2.heading-hiddentasks text {
cursor: pointer;
}
#task-tasks div.task-list h2.heading .icon.toggle-completed-tasks,
#task-tasks div.task-list h2.heading-hiddentasks .icon.toggle-completed-tasks {
float: right;
}
#task-tasks div.task-list .loadmore {
font-size: 11px;
margin-top: 10px;
text-align: center;
}
#task-tasks div.task-list .loadmore span:hover {
color: #A0A0A0;
cursor: pointer;
}
#task-tasks div.task-list.completed-hidden ol.completed-tasks {
display: none;
}
#task-tasks div.task-list.completed-hidden h2.heading-hiddentasks text {
opacity: 0.7;
}
#task-tasks div.task-list.completed-hidden h2.heading-hiddentasks text:hover {
opacity: 1;
}
#task-tasks div.task-list.completed-hidden h2.heading-hiddentasks .icon.toggle-completed-tasks {
opacity: 0.5;
background-position: -120px -20px;
}
#task-tasks div.task-list.completed-hidden h2.heading-hiddentasks .icon.toggle-completed-tasks:hover {
opacity: 0.7;
}
#task-tasks div.task-list.completed-hidden div.loadmore {
display: none;
}
#task-tasks div.task-list .grouped-tasks {
position: relative;
}
#task-details {
-webkit-transition: right 0.4s ease-in-out;
-moz-transition: right 0.4s ease-in-out;
-ms-transition: right 0.4s ease-in-out;
-o-transition: right 0.4s ease-in-out;
transition: right 0.4s ease-in-out;
position: absolute;
right: -400px;
bottom: 0;
top: 0;
padding: 0;
width: 360px;
}
#task-details.details-visible {
right: 0;
}
#task-details > div {
background: url("%appswebroot%/tasks_enhanced/img/bgTaskDetail.png") repeat scroll 0 0 #f8f8f8;
border-radius: 5px 0px 0px 5px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
height: 100%;
position: relative;
}
#task-details div.footer {
background: none repeat scroll 0 0 #f1f1f1;
border-radius: 0 0 5px 5px;
border-top: 1px solid #D3D3D3;
bottom: 0;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset;
height: 35px;
left: 0;
position: absolute;
right: 0;
}
#task-details div.footer .detail-close .icon {
left: auto;
right: 8px;
}
#task-details div.footer .icon {
position: absolute;
top: 8px;
left: 8px;
}
#task-details.completed .body .section .section-title {
color: #9FA2A6 !important;
}
#task-details.completed .body .section .icon.detail-date {
background-position: -100px -40px !important;
}
#task-details.completed .body .section .icon.detail-reminder {
background-position: -40px -40px !important;
}
#task-details .title {
background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) repeat scroll 0 0 transparent;
background: -moz-linear-gradient(center top, rgba(255, 255, 255, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) repeat scroll 0 0 transparent;
background: -ms-linear-gradient(center top, rgba(255, 255, 255, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) repeat scroll 0 0 transparent;
background: -o-linear-gradient(center top, rgba(255, 255, 255, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) repeat scroll 0 0 transparent;
background: linear-gradient(top, rgba(255, 255, 255, 0.1) 0%, rgba(0, 0, 0, 0.05) 100%) repeat scroll 0 0 transparent;
border-bottom: 1px solid rgba(0, 0, 0, 0.24);
border-radius: 5px 5px 0 0;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
font-size: 16px;
font-weight: bold;
line-height: 24px;
min-height: 24px;
padding: 16px 55px 13px;
text-shadow: 0 1px 0 white;
word-wrap: break-word;
}
#task-details .title .title-text {
cursor: text;
}
#task-details .title .title-text.strike-through {
text-decoration: line-through;
text-shadow: none;
}
#task-details .title textarea,
#task-details .title pre {
box-shadow: none;
font-size: 16px;
font-weight: bold;
line-height: 24px;
background: none repeat scroll 0 0 transparent;
border: medium none;
font-family: "Helvetica Neue", "Helvetica", Arial, sans-serif;
padding: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#task-details .title pre {
border: 0 none !important;
display: block;
margin: 0;
outline: 0 none;
padding: 0 !important;
visibility: hidden;
}
#task-details .title textarea {
margin: 0;
border-radius: 0;
height: 100%;
left: 0;
overflow: hidden;
position: absolute;
resize: none;
top: 0;
width: 100%;
}
#task-details .title .expandable-container {
background: none repeat scroll 0 0 #FFFFFF;
border: 1px solid #AAAAAA;
margin: -1px -4px -1px -7px;
padding: 0 5px;
}
#task-details .title .expandable-container .expandingArea {
position: relative;
}
#task-details .body {
bottom: 36px;
left: 0;
overflow: auto;
position: absolute;
right: 0;
top: 55px;
}
#task-details .body .note {
background: -webkit-linear-gradient(top, #dee2d0 1px, transparent 1px) repeat scroll 0 0 / 100% 26px #f8f5db;
background: -moz-linear-gradient(center top, #dee2d0 1px, transparent 1px) repeat scroll 0 0 / 100% 26px #f8f5db;
background: -ms-linear-gradient(center top, #dee2d0 1px, transparent 1px) repeat scroll 0 0 / 100% 26px #f8f5db;
background: -o-linear-gradient(center top, #dee2d0 1px, transparent 1px) repeat scroll 0 0 / 100% 26px #f8f5db;
background: linear-gradient(top, #dee2d0 1px, transparent 1px) repeat scroll 0 0 / 100% 26px #f8f5db;
background-color: #f8f5db;
border: 1px solid #CFCFCF;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 1px 0 #f8f5db inset;
font-size: 13px;
line-height: 26px;
margin: 20px;
padding: 8px 15px;
cursor: text;