Add settings dialog

This commit is contained in:
raimund-schluessler 2014-05-27 19:59:35 +02:00
parent 62472e1662
commit 62b8b9ca03
31 changed files with 2145 additions and 187 deletions

View file

@ -33,6 +33,28 @@ $this->create('tasks_enhanced_index', '/')
$dispatcher->dispatch('PageController', 'index');
}
);
/*
* Collections
*/
$this->create('getCollections', '/collections')
->get()
->action(
function($params){
session_write_close();
$dispatcher = new Dispatcher($params);
$dispatcher->dispatch('CollectionsController', 'getCollections');
}
);
$this->create('setVisibility', '/collection/{collectionID}/visibility/{visibility}')
->post()
->action(
function($params){
session_write_close();
$dispatcher = new Dispatcher($params);
$dispatcher->dispatch('CollectionsController', 'setVisibility');
}
);
/*
* Lists
@ -209,4 +231,27 @@ $this->create('task_reminder', '/tasks/{taskID}/reminder')
$dispatcher = new Dispatcher($params);
$dispatcher->dispatch('TasksController', 'setReminderDate');
}
);
/*
* Settings
*/
$this->create('getSettings', '/settings')
->get()
->action(
function($params){
session_write_close();
$dispatcher = new Dispatcher($params);
$dispatcher->dispatch('SettingsController', 'getSettings');
}
);
$this->create('showHidden', '/settings/{type}/{setting}/{value}')
->post()
->action(
function($params){
session_write_close();
$dispatcher = new Dispatcher($params);
$dispatcher->dispatch('SettingsController', 'set');
}
);

View file

@ -93,6 +93,11 @@
transition: opacity 100ms ease 0s;
opacity: 0.6;
}
#content .icon.detail-settings {
background-position: -200px -40px;
transition: opacity 100ms ease 0s;
opacity: 0.6;
}
#content .icon.search {
background-position: -80px -20px;
transition: opacity 100ms ease 0s;
@ -359,6 +364,9 @@
height: 20px;
line-height: 20px;
}
#task-lists div.footer a.settings {
right: 0;
}
#task-lists div.scroll {
position: absolute;
top: 37px;
@ -931,6 +939,51 @@
#task-details .body .section.detail-reminder.date .section-description {
display: block;
}
#modal-wrapper {
position: absolute;
width: 100%;
height: 100%;
background: none repeat scroll 0 0 rgba(0, 0, 0, 0.25);
}
#settings_modal {
background: url("../img/bgBig.png") repeat scroll 0 0 #f3f3f3;
border-radius: 6px;
}
#settings_modal .header h2 {
font-size: 17px;
padding: 10px;
text-align: center;
}
#settings_modal .header .button {
position: absolute;
top: 3px;
right: 5px;
}
#settings_modal .navbar {
border-color: #ccc;
border-style: solid;
border-width: 1px 0;
height: 50px;
}
#settings_modal .content {
min-height: 100px;
}
.button {
background-image: -moz-linear-gradient(center top, #5cb6e7 0px, #317cd7 100%);
border-color: #0c67a5;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.3) inset;
color: #fff;
font-weight: bold;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5);
line-height: 14px;
margin-right: 8px;
padding: 6px 10px 5px;
position: relative;
float: right;
}
.button:hover {
color: #CCCCCC;
}
input,
textarea {
-moz-user-select: text;
@ -938,6 +991,9 @@ textarea {
#content a:hover .icon.detail-trash {
opacity: 1;
}
#content a:hover .icon.detail-settings {
opacity: 1;
}
#content a:hover .icon.search {
opacity: 1;
}

View file

@ -115,6 +115,11 @@
transition: opacity 100ms ease 0s;
opacity:0.6;
}
&.detail-settings{
background-position: -200px -40px;
transition: opacity 100ms ease 0s;
opacity:0.6;
}
&.search {
background-position: -80px -20px;
transition: opacity 100ms ease 0s;
@ -382,6 +387,9 @@
padding:10px;
height:20px;
line-height:20px;
&.settings{
right:0;
}
}
}
div.scroll{
@ -981,6 +989,55 @@
}
}
#modal-wrapper{
position: absolute;
width:100%;
height: 100%;
background: none repeat scroll 0 0 rgba(0, 0, 0, 0.25);
}
#settings_modal{
background: url("../img/bgBig.png") repeat scroll 0 0 #f3f3f3;
border-radius: 6px;
.header{
h2{
font-size: 17px;
padding: 10px;
text-align: center;
}
.button{
position: absolute;
top:3px;
right:5px;
}
}
.navbar{
border-color: #ccc;
border-style: solid;
border-width: 1px 0;
height: 50px;
}
.content{
min-height:100px;
}
}
.button{
background-image: -moz-linear-gradient(center top , #5cb6e7 0px, #317cd7 100%);
border-color: #0c67a5;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.3) inset;
color: #fff;
font-weight: bold;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5);
line-height: 14px;
margin-right: 8px;
padding: 6px 10px 5px;
position: relative;
float:right;
&:hover{
color:#CCCCCC;
}
}
input, textarea {
-moz-user-select: text;
}
@ -988,6 +1045,9 @@ input, textarea {
&.detail-trash{
opacity:1;
}
&.detail-settings{
opacity:1;
}
&.search{
opacity:1;
}

173
css/vendor/bootstrap/bootstrap.css vendored Normal file
View file

@ -0,0 +1,173 @@
.modal-open {
overflow: hidden;
}
.modal {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1050;
display: none;
overflow: auto;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
outline: 0;
}
.modal.fade .modal-dialog {
-webkit-transition: -webkit-transform .3s ease-out;
-moz-transition: -moz-transform .3s ease-out;
-o-transition: -o-transform .3s ease-out;
transition: transform .3s ease-out;
-webkit-transform: translate(0, -25%);
-ms-transform: translate(0, -25%);
transform: translate(0, -25%);
}
.modal.in .modal-dialog {
-webkit-transform: translate(0, 0);
-ms-transform: translate(0, 0);
transform: translate(0, 0);
}
.modal-dialog {
position: relative;
width: auto;
margin: 10px;
}
.modal-content {
position: relative;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #999;
border: 1px solid rgba(0, 0, 0, .2);
border-radius: 6px;
outline: none;
-webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
}
.modal-backdrop {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1040;
background-color: #000;
}
.modal-backdrop.fade {
filter: alpha(opacity=0);
opacity: 0;
}
.modal-backdrop.in {
filter: alpha(opacity=50);
opacity: .5;
}
.modal-header {
min-height: 16.42857143px;
padding: 15px;
border-bottom: 1px solid #e5e5e5;
}
.modal-header .close {
margin-top: -2px;
}
.modal-title {
margin: 0;
line-height: 1.42857143;
}
.modal-body {
position: relative;
padding: 20px;
}
.modal-footer {
padding: 19px 20px 20px;
margin-top: 15px;
text-align: right;
border-top: 1px solid #e5e5e5;
}
.modal-footer .btn + .btn {
margin-bottom: 0;
margin-left: 5px;
}
.modal-footer .btn-group .btn + .btn {
margin-left: -1px;
}
.modal-footer .btn-block + .btn-block {
margin-left: 0;
}
@media (min-width: 768px) {
.modal-dialog {
width: 500px;
margin: 30px auto;
}
.modal-content {
-webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
}
.modal-sm {
width: 300px;
}
}
@media (min-width: 992px) {
.modal-lg {
width: 900px;
}
}
.tab-content > .tab-pane {
display: none;
}
.tab-content > .active {
display: block;
}
ul.nav-tabs{
border-color: #ccc;
border-style: solid;
border-width: 1px 0;
clear: both;
content: " ";
display: table;
width: 100%;
}
.nav-tabs > li{
display: block;
float: left;
height: 50px;
padding: 0 10px;
position: relative;
}
.nav-tabs > li.active{
background: url("../../../img/bgSettingsActive.png") repeat scroll 0 0 #4a99db;
}
.nav-tabs >li.active a{
color:white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}
.nav-tabs > li a{
font-weight: bold;
display: block;
height: 50px;
line-height: 50px;
}
.nav-tabs > li:first-child{
margin-left: 20px;
}
.tabbable .tab-pane{
padding:20px;
}
.tab-pane select{
background-color: rgba(0, 0, 0, 0);
border: 1px solid #ccc;
border-radius: 0;
font-weight: normal;
margin: 0;
padding: 0;
width: 98px;
float:right;
}
.tab-pane li{
padding: 10px 0;
}
.tab-pane li span.title{
padding-left: 10px;
position: relative;
top: 2px;
}
}

BIN
img/bgSettingsActive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -697,22 +697,22 @@
<g>
<g>
<defs>
<rect id="SVGID_99_" x="80" y="19" width="20" height="20"/>
<rect id="SVGID_99_" x="80" y="20" width="20" height="20"/>
</defs>
<clipPath id="SVGID_100_">
<use xlink:href="#SVGID_99_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_100_)">
<defs>
<rect id="SVGID_101_" x="80" y="19" width="20" height="20"/>
<rect id="SVGID_101_" x="80" y="20" width="20" height="20"/>
</defs>
<clipPath id="SVGID_102_">
<use xlink:href="#SVGID_101_" overflow="visible"/>
</clipPath>
<circle clip-path="url(#SVGID_102_)" fill="none" stroke="#8F9090" stroke-width="2" stroke-miterlimit="10" cx="87.724" cy="26.724" r="3.898"/>
<circle clip-path="url(#SVGID_102_)" fill="none" stroke="#8F9090" stroke-width="2" stroke-miterlimit="10" cx="87.724" cy="27.724" r="3.898"/>
<line clip-path="url(#SVGID_102_)" fill="none" stroke="#8F9090" stroke-width="2" stroke-miterlimit="10" x1="90.481" y1="29.481" x2="96.956" y2="35.956"/>
<line clip-path="url(#SVGID_102_)" fill="none" stroke="#8F9090" stroke-width="2" stroke-miterlimit="10" x1="90.481" y1="30.481" x2="96.956" y2="36.956"/>
</g>
</g>
</g>
@ -1554,4 +1554,34 @@
</g>
</g>
</g>
<g>
<g>
<defs>
<rect id="SVGID_215_" x="200" y="40" width="20" height="20"/>
</defs>
<clipPath id="SVGID_216_">
<use xlink:href="#SVGID_215_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_216_)">
<defs>
<rect id="SVGID_217_" x="200" y="40" width="20" height="20"/>
</defs>
<clipPath id="SVGID_218_">
<use xlink:href="#SVGID_217_" overflow="visible"/>
</clipPath>
<path clip-path="url(#SVGID_218_)" fill="#FFFFFF" d="M217.171,50.996c0-0.538-0.071-1.06-0.194-1.562l1.754-1.401l-1.685-2.794
l-2.146,0.755c-0.795-0.715-1.756-1.26-2.827-1.57l-0.388-2.147h-3.371l-0.388,2.147c-1.093,0.316-2.071,0.876-2.876,1.612
l-2.095-0.738l-1.685,2.794l1.74,1.39c-0.115,0.488-0.181,0.994-0.181,1.514c0,0.555,0.076,1.092,0.207,1.611l-1.767,1.409
l1.685,2.797l2.192-0.773c0.783,0.691,1.723,1.221,2.769,1.524l0.399,2.21h3.371l0.398-2.21c1.045-0.303,1.982-0.832,2.766-1.523
l2.194,0.772l1.685-2.794l-1.767-1.41C217.096,52.091,217.171,51.552,217.171,50.996 M210,54.256c-1.88,0-3.404-1.459-3.404-3.26
c0-1.801,1.524-3.261,3.404-3.261c1.882,0,3.406,1.46,3.406,3.261C213.406,52.797,211.882,54.256,210,54.256"/>
<path clip-path="url(#SVGID_218_)" fill="#8F9090" d="M217.171,49.971c0-0.538-0.071-1.06-0.194-1.562l1.754-1.401l-1.685-2.794
l-2.146,0.755c-0.795-0.715-1.756-1.26-2.827-1.57l-0.388-2.147h-3.371l-0.388,2.147c-1.093,0.316-2.071,0.875-2.876,1.611
l-2.095-0.737l-1.685,2.794l1.74,1.39c-0.115,0.488-0.181,0.993-0.181,1.514c0,0.555,0.076,1.092,0.207,1.61l-1.767,1.41
l1.685,2.797l2.192-0.773c0.783,0.691,1.723,1.22,2.769,1.524l0.399,2.21h3.371l0.398-2.21c1.045-0.304,1.982-0.832,2.766-1.523
l2.194,0.772l1.685-2.795l-1.767-1.409C217.096,51.064,217.171,50.526,217.171,49.971 M210,53.23c-1.88,0-3.404-1.459-3.404-3.26
c0-1.802,1.524-3.261,3.404-3.261c1.882,0,3.406,1.459,3.406,3.261C213.406,51.771,211.882,53.23,210,53.23"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View file

@ -19,7 +19,7 @@ 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/>.
###
angular.module('Tasks',['OC','ngRoute','ngAnimate'])
angular.module('Tasks',['OC','ngRoute','ngAnimate','ui.bootstrap'])
.config ['$provide','$routeProvider', '$interpolateProvider',
($provide, $routeProvider, $interpolateProvider) ->
$provide.value 'Config', config =
@ -30,6 +30,7 @@ angular.module('Tasks',['OC','ngRoute','ngAnimate'])
.when('/lists/:listID',{})
.when('/lists/:listID/edit/:listparameter',{})
.when('/lists/:listID/tasks/:taskID',{})
.when('/lists/:listID/tasks/:taskID/settings',{})
.when('/lists/:listID/tasks/:taskID/edit/:parameter',{})
.when('/search/:searchString',{})
.when('/search/:searchString/tasks/:taskID',{})
@ -71,6 +72,7 @@ angular.module('Tasks').run ['Config', '$timeout',
timeOutUpdate = ->
$timeout update, Config.taskUpdateInterval
if init
# CollectionsBusinessLayer.updateModel()
ListsBusinessLayer.updateModel()
TasksBusinessLayer.updateModel()
init = true

View file

@ -23,14 +23,15 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
angular.module('Tasks').controller 'AppController',
['$scope', 'Persistence', '$route', 'Status', '$timeout',
'$location', '$routeParams', 'Loading',
'$location', '$routeParams', 'Loading','$modal','SettingsModel',
($scope, Persistence, $route, status, $timeout, $location,
$routeParams, Loading) ->
$routeParams, Loading, $modal, SettingsModel) ->
class AppController
constructor: (@_$scope, @_persistence, @_$route, @_$status,
@_$timeout, @_$location, @_$routeparams, @_Loading) ->
@_$timeout, @_$location, @_$routeparams, @_Loading,
@_$modal,@_$settingsmodel) ->
@_$scope.initialized = false
@ -40,6 +41,8 @@ $routeParams, Loading) ->
@_$scope.status.newListName = ""
@_$scope.settingsmodel = @_$settingsmodel
successCallback = =>
@_$scope.initialized = true
@ -58,7 +61,15 @@ $routeParams, Loading) ->
@_$scope.isLoading = () ->
return _Loading.isLoading()
@_$scope.showSettings = () ->
_$scope.modalInstance = _$modal.open({
templateUrl: 'part.settings.html',
controller: 'SettingsController',
backdrop: true,
windowClass: 'test'
})
return new AppController($scope, Persistence, $route, status, $timeout,
$location, $routeParams, Loading)
$location, $routeParams, Loading, $modal, SettingsModel)
]

View file

@ -132,6 +132,16 @@ CollectionsModel, ListsBusinessLayer, $location) ->
@_$scope.getCollectionCount = (collectionID) ->
return _$collectionsmodel.getCount(collectionID)
@_$scope.hideCollection = (collectionID) ->
collection = _$collectionsmodel.getById(collectionID)
switch collection.show
when 0
return true
when 1
return false
when 2
return (@getCollectionCount(collectionID) < 1)
@_$scope.getCollectionString = (collectionID) ->
return _$collectionsmodel.getCountString(collectionID)
@ -144,6 +154,7 @@ CollectionsModel, ListsBusinessLayer, $location) ->
@_$scope.update = () ->
if not _$scope.isLoading()
# _$collectionsbusinesslayer.updateModel()
_$tasksbusinesslayer.updateModel()
_$listsbusinesslayer.updateModel()

View file

@ -0,0 +1,60 @@
###
ownCloud - Tasks
@author Raimund Schlüßler
@copyright 2013
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/>.
###
angular.module('Tasks').controller 'SettingsController',
['$scope', '$window', 'Status', '$location','$modalInstance',
'CollectionsModel', 'SettingsBusinessLayer',
($scope, $window, Status, $location, $modalInstance,CollectionsModel,
SettingsBusinessLayer) ->
class SettingsController
constructor: (@_$scope, @_$window, @_$status,
@_$location, @_$modalInstance, @_$collectionsmodel,
@_$settingsbusinesslayer) ->
@_$scope.status = @_$status.getStatus()
@_$scope.collections = @_$collectionsmodel.getAll()
@_$scope.collectionOptions = [
{
id: 0,
name: t('tasks_enhanced','Hidden')},
{
id: 1,
name: t('tasks_enhanced','Visible')},
{
id: 2,
name: t('tasks_enhanced','Automatic')}
]
@_$scope.ok = () =>
$modalInstance.close()
@_$scope.setVisibility = (collectionID) =>
collection = _$collectionsmodel.getById(collectionID)
_$settingsbusinesslayer.setVisibility(collectionID,collection.show)
return new SettingsController($scope, $window, Status, $location,
$modalInstance, CollectionsModel, SettingsBusinessLayer)
]

View file

@ -22,14 +22,16 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
angular.module('Tasks').controller 'TasksController',
['$scope', '$window', '$routeParams', 'TasksModel', 'ListsModel',
'CollectionsModel', 'TasksBusinessLayer', '$location',
'SettingsBusinessLayer',
($scope, $window, $routeParams, TasksModel, ListsModel,
CollectionsModel, TasksBusinessLayer, $location) ->
CollectionsModel, TasksBusinessLayer, $location,
SettingsBusinessLayer) ->
class TasksController
constructor: (@_$scope,@_$window,@_$routeParams,
@_$tasksmodel,@_$listsmodel,@_$collectionsmodel,
@_tasksbusinesslayer, @$location) ->
@_tasksbusinesslayer, @$location, @_settingsbusinesslayer) ->
@_$scope.tasks = @_$tasksmodel.getAll()
@_$scope.lists = @_$listsmodel.getAll()
@ -100,7 +102,7 @@ CollectionsModel, TasksBusinessLayer, $location) ->
_tasksbusinesslayer.starTask(taskID)
@_$scope.toggleHidden = () ->
_$scope.status.showhidden = !_$scope.status.showhidden
_settingsbusinesslayer.toggle('various','showHidden')
@_$scope.filterTasks = () ->
return (task) ->
@ -180,5 +182,6 @@ CollectionsModel, TasksBusinessLayer, $location) ->
return task.due
return new TasksController($scope, $window, $routeParams,
TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location)
TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location,
SettingsBusinessLayer)
]

View file

@ -0,0 +1,34 @@
###
ownCloud - Music
@author Raimund Schlüßler
@copyright 2013
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/>.
###
angular.module('Tasks').directive 'pane', ->
directive =
scope:
title: '@'
require: '^tabs'
restrict: 'E'
transclude: true
replace: true
link: (scope, element, attrs, tabsCtrl) ->
tabsCtrl.addPane(scope)
template: '<div class="tab-pane" ng-class="{active: selected}"'+
'ng-transclude>[[ ]]</div>'

View file

@ -0,0 +1,36 @@
###
ownCloud - Music
@author Raimund Schlüßler
@copyright 2013
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/>.
###
angular.module('Tasks').directive 'tabs', ->
directive =
restrict: 'E',
scope: {},
controller: ($scope, $element) ->
panes = $scope.panes = []
$scope.select = (pane) ->
angular.forEach(panes, (pane) ->
pane.selected = false
)
pane.selected = true
this.addPane = (pane) ->
$scope.select(pane) if (panes.length == 0)
panes.push(pane)

View file

@ -0,0 +1,47 @@
###
ownCloud - News
@author Bernhard Posselt
@copyright 2012 Bernhard Posselt dev@bernhard-posselt.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/>.
###
angular.module('Tasks').factory 'SettingsBusinessLayer',
['Persistence', 'SettingsModel',
(Persistence, SettingsModel) ->
class SettingsBusinessLayer
constructor: (@_persistence, @_$settingsmodel) ->
updateModel: () ->
success = () =>
@_persistence.getCollections(success, true)
setVisibility: (collectionID, visibility) ->
@_persistence.setVisibility(collectionID, visibility)
toggle: (type, setting) ->
@_$settingsmodel.toggle(type, setting)
value = @_$settingsmodel.getById(type)[setting]
@_persistence.setting(type, setting, value)
return new SettingsBusinessLayer(Persistence, SettingsModel)
]

View file

@ -79,6 +79,8 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
due.hour(date.hour()).minute(date.minute())
else
due = date
else if type == 'all'
due = date
else
return
@_$tasksmodel.setDueDate(taskID,due.format('YYYYMMDDTHHmmss'))
@ -308,7 +310,7 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
when 'uncompleted'
@uncompleteTask(taskID)
when 'today'
@setDueDate(taskID,moment().format("YYYYMMDDTHHmmss"))
@setDue(taskID,moment().startOf('day').add('h',12),'all')
when 'week', 'all'
else
@changeCalendarId(taskID,listID)
@ -319,6 +321,9 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
@_$tasksmodel.removeVoid()
@_persistence.getTasks(success, true)
setShowHidden: (showHidden) ->
@_persistence.setShowHidden(showHidden)
return new TasksBusinessLayer(TasksModel, Persistence)

View file

@ -21,41 +21,13 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
###
angular.module('Tasks').factory 'CollectionsModel',
['TasksModel', '_Model', '_EqualQuery', 'Utils',
(TasksModel, _Model, _EqualQuery, Utils) ->
['TasksModel', '_Model',
(TasksModel, _Model) ->
class CollectionsModel extends _Model
constructor: (@_$tasksmodel, @_utils) ->
constructor: (@_$tasksmodel) ->
@_nameCache = {}
@_$collections = [
{
id: "starred"
displayname: t('tasks_enhanced','Important')
},
{
id: "today"
displayname: t('tasks_enhanced', 'Today')
},
{
id: "week"
displayname: t('tasks_enhanced', 'Week')
},
{
id: "all",
displayname: t('tasks_enhanced', 'All')
},
{
id: "current",
displayname: t('tasks_enhanced', 'Current')
},
{
id: "completed"
displayname: t('tasks_enhanced', 'Done')
}
]
super()
for collection in @_$collections
@add(collection)
add: (data, clearCache=true) ->
@_nameCache[data.displayname] = data
@ -92,5 +64,5 @@ angular.module('Tasks').factory 'CollectionsModel',
else
return ''
return new CollectionsModel(TasksModel, Utils)
return new CollectionsModel(TasksModel)
]

View file

@ -0,0 +1,42 @@
###
ownCloud - Tasks
@author Raimund Schlüßler
@copyright 2013
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/>.
###
angular.module('Tasks').factory 'SettingsModel',
['_Model',
(_Model) ->
class SettingsModel extends _Model
constructor: () ->
@_nameCache = {}
super()
add: (data, clearCache=true) ->
@_nameCache[data.displayname] = data
if angular.isDefined(data.id)
super(data, clearCache)
toggle: (type, setting) ->
set = @getById(type)
@getById(type)[setting] = !set[setting]
return new SettingsModel()
]

View file

@ -34,11 +34,76 @@ angular.module('Tasks').factory 'Persistence',
successCallback = =>
@deferred.resolve()
@getCollections()
@getSettings()
@getLists()
@getTasks(successCallback)
@deferred.promise
getCollections: (onSuccess, showLoading=true) ->
onSuccess or= ->
if showLoading
@_Loading.increase()
successCallbackWrapper = (data) =>
onSuccess()
@_Loading.decrease()
failureCallbackWrapper = (data) =>
@_Loading.decrease()
else
successCallbackWrapper = (data) =>
onSuccess()
failureCallbackWrapper = (data) =>
params =
onSuccess: successCallbackWrapper
onFailure: failureCallbackWrapper
@_request.get '/apps/tasks_enhanced/collections', params
getSettings: (onSuccess, showLoading=true) ->
onSuccess or= ->
if showLoading
@_Loading.increase()
successCallbackWrapper = (data) =>
onSuccess()
@_Loading.decrease()
failureCallbackWrapper = (data) =>
@_Loading.decrease()
else
successCallbackWrapper = (data) =>
onSuccess()
failureCallbackWrapper = (data) =>
params =
onSuccess: successCallbackWrapper
onFailure: failureCallbackWrapper
@_request.get '/apps/tasks_enhanced/settings', params
setVisibility: (collectionID, visibility) ->
params =
routeParams:
collectionID: collectionID
visibility: visibility
@_request.post '/apps/tasks_enhanced/collection/
{collectionID}/visibility/{visibility}', params
setting: (type, setting, value) ->
params =
routeParams:
type: type
setting: setting
value: +value
@_request.post '/apps/tasks_enhanced/settings/
{type}/{setting}/{value}', params
getLists: (onSuccess, showLoading=true, which='all') ->
onSuccess or= ->
@ -244,6 +309,14 @@ angular.module('Tasks').factory 'Persistence',
@_request.post '/apps/tasks_enhanced/tasks/{taskID}/note', params
setShowHidden: (showHidden) ->
params =
routeParams:
showHidden: +showHidden
@_request.post '/apps/tasks_enhanced/settings/showhidden/{showHidden}',
params
return new Persistence(Request, Loading, $rootScope)
]

View file

@ -37,11 +37,13 @@ angular.module('Tasks').factory 'Loading', ['_Loading', (_Loading) ->
# ]
angular.module('Tasks').factory 'Publisher',
['_Publisher', 'ListsModel', 'TasksModel',
(_Publisher, ListsModel, TasksModel) ->
['_Publisher', 'ListsModel', 'TasksModel', 'CollectionsModel', 'SettingsModel',
(_Publisher, ListsModel, TasksModel, CollectionsModel, SettingsModel) ->
# register items at publisher to automatically add incoming items
publisher = new _Publisher()
publisher.subscribeObjectTo(CollectionsModel, 'collections')
publisher.subscribeObjectTo(SettingsModel, 'settings')
publisher.subscribeObjectTo(ListsModel, 'lists')
publisher.subscribeObjectTo(TasksModel, 'tasks')

View file

@ -26,7 +26,6 @@ angular.module('Tasks').factory 'Status',
constructor: () ->
@_$status = {
showhidden: true
searchActive: false
addingList: false
focusTaskInput: false

View file

@ -12,14 +12,14 @@
(function() {
angular.module('Tasks', ['OC', 'ngRoute', 'ngAnimate']).config([
angular.module('Tasks', ['OC', 'ngRoute', 'ngAnimate', 'ui.bootstrap']).config([
'$provide', '$routeProvider', '$interpolateProvider', function($provide, $routeProvider, $interpolateProvider) {
var config;
$provide.value('Config', config = {
markReadTimeout: 500,
taskUpdateInterval: 1000 * 600
});
$routeProvider.when('/lists/:listID', {}).when('/lists/:listID/edit/:listparameter', {}).when('/lists/:listID/tasks/:taskID', {}).when('/lists/:listID/tasks/:taskID/edit/:parameter', {}).when('/search/:searchString', {}).when('/search/:searchString/tasks/:taskID', {}).when('/search/:searchString/tasks/:taskID/edit/:parameter', {}).otherwise({
$routeProvider.when('/lists/:listID', {}).when('/lists/:listID/edit/:listparameter', {}).when('/lists/:listID/tasks/:taskID', {}).when('/lists/:listID/tasks/:taskID/settings', {}).when('/lists/:listID/tasks/:taskID/edit/:parameter', {}).when('/search/:searchString', {}).when('/search/:searchString/tasks/:taskID', {}).when('/search/:searchString/tasks/:taskID/edit/:parameter', {}).otherwise({
redirectTo: '/lists/all'
});
/*
@ -227,6 +227,26 @@
}).call(this);
(function() {
angular.module('Tasks').directive('pane', function() {
var directive;
return directive = {
scope: {
title: '@'
},
require: '^tabs',
restrict: 'E',
transclude: true,
replace: true,
link: function(scope, element, attrs, tabsCtrl) {
return tabsCtrl.addPane(scope);
},
template: '<div class="tab-pane" ng-class="{active: selected}"' + 'ng-transclude>[[ ]]</div>'
};
});
}).call(this);
(function() {
angular.module('Tasks').directive('stopEvent', function() {
return {
@ -241,6 +261,33 @@
}).call(this);
(function() {
angular.module('Tasks').directive('tabs', function() {
var directive;
return directive = {
restrict: 'E',
scope: {},
controller: function($scope, $element) {
var panes;
panes = $scope.panes = [];
$scope.select = function(pane) {
angular.forEach(panes, function(pane) {
return pane.selected = false;
});
return pane.selected = true;
};
return this.addPane = function(pane) {
if (panes.length === 0) {
$scope.select(pane);
}
return panes.push(pane);
};
}
};
});
}).call(this);
(function() {
angular.module('Tasks').directive('timepicker', function() {
return {
@ -283,10 +330,10 @@
(function() {
angular.module('Tasks').controller('AppController', [
'$scope', 'Persistence', '$route', 'Status', '$timeout', '$location', '$routeParams', 'Loading', function($scope, Persistence, $route, status, $timeout, $location, $routeParams, Loading) {
'$scope', 'Persistence', '$route', 'Status', '$timeout', '$location', '$routeParams', 'Loading', '$modal', 'SettingsModel', function($scope, Persistence, $route, status, $timeout, $location, $routeParams, Loading, $modal, SettingsModel) {
var AppController;
AppController = (function() {
function AppController(_$scope, _persistence, _$route, _$status, _$timeout, _$location, _$routeparams, _Loading) {
function AppController(_$scope, _persistence, _$route, _$status, _$timeout, _$location, _$routeparams, _Loading, _$modal, _$settingsmodel) {
var successCallback,
_this = this;
this._$scope = _$scope;
@ -297,10 +344,13 @@
this._$location = _$location;
this._$routeparams = _$routeparams;
this._Loading = _Loading;
this._$modal = _$modal;
this._$settingsmodel = _$settingsmodel;
this._$scope.initialized = false;
this._$scope.status = this._$status.getStatus();
this._$scope.route = this._$routeparams;
this._$scope.status.newListName = "";
this._$scope.settingsmodel = this._$settingsmodel;
successCallback = function() {
return _this._$scope.initialized = true;
};
@ -318,12 +368,20 @@
this._$scope.isLoading = function() {
return _Loading.isLoading();
};
this._$scope.showSettings = function() {
return _$scope.modalInstance = _$modal.open({
templateUrl: 'part.settings.html',
controller: 'SettingsController',
backdrop: true,
windowClass: 'test'
});
};
}
return AppController;
})();
return new AppController($scope, Persistence, $route, status, $timeout, $location, $routeParams, Loading);
return new AppController($scope, Persistence, $route, status, $timeout, $location, $routeParams, Loading, $modal, SettingsModel);
}
]);
@ -699,6 +757,18 @@
this._$scope.getCollectionCount = function(collectionID) {
return _$collectionsmodel.getCount(collectionID);
};
this._$scope.hideCollection = function(collectionID) {
var collection;
collection = _$collectionsmodel.getById(collectionID);
switch (collection.show) {
case 0:
return true;
case 1:
return false;
case 2:
return this.getCollectionCount(collectionID) < 1;
}
};
this._$scope.getCollectionString = function(collectionID) {
return _$collectionsmodel.getCountString(collectionID);
};
@ -773,12 +843,59 @@
}).call(this);
(function() {
angular.module('Tasks').controller('SettingsController', [
'$scope', '$window', 'Status', '$location', '$modalInstance', 'CollectionsModel', 'SettingsBusinessLayer', function($scope, $window, Status, $location, $modalInstance, CollectionsModel, SettingsBusinessLayer) {
var SettingsController;
SettingsController = (function() {
function SettingsController(_$scope, _$window, _$status, _$location, _$modalInstance, _$collectionsmodel, _$settingsbusinesslayer) {
var _this = this;
this._$scope = _$scope;
this._$window = _$window;
this._$status = _$status;
this._$location = _$location;
this._$modalInstance = _$modalInstance;
this._$collectionsmodel = _$collectionsmodel;
this._$settingsbusinesslayer = _$settingsbusinesslayer;
this._$scope.status = this._$status.getStatus();
this._$scope.collections = this._$collectionsmodel.getAll();
this._$scope.collectionOptions = [
{
id: 0,
name: t('tasks_enhanced', 'Hidden')
}, {
id: 1,
name: t('tasks_enhanced', 'Visible')
}, {
id: 2,
name: t('tasks_enhanced', 'Automatic')
}
];
this._$scope.ok = function() {
return $modalInstance.close();
};
this._$scope.setVisibility = function(collectionID) {
var collection;
collection = _$collectionsmodel.getById(collectionID);
return _$settingsbusinesslayer.setVisibility(collectionID, collection.show);
};
}
return SettingsController;
})();
return new SettingsController($scope, $window, Status, $location, $modalInstance, CollectionsModel, SettingsBusinessLayer);
}
]);
}).call(this);
(function() {
angular.module('Tasks').controller('TasksController', [
'$scope', '$window', '$routeParams', 'TasksModel', 'ListsModel', 'CollectionsModel', 'TasksBusinessLayer', '$location', function($scope, $window, $routeParams, TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location) {
'$scope', '$window', '$routeParams', 'TasksModel', 'ListsModel', 'CollectionsModel', 'TasksBusinessLayer', '$location', 'SettingsBusinessLayer', function($scope, $window, $routeParams, TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location, SettingsBusinessLayer) {
var TasksController;
TasksController = (function() {
function TasksController(_$scope, _$window, _$routeParams, _$tasksmodel, _$listsmodel, _$collectionsmodel, _tasksbusinesslayer, $location) {
function TasksController(_$scope, _$window, _$routeParams, _$tasksmodel, _$listsmodel, _$collectionsmodel, _tasksbusinesslayer, $location, _settingsbusinesslayer) {
this._$scope = _$scope;
this._$window = _$window;
this._$routeParams = _$routeParams;
@ -787,6 +904,7 @@
this._$collectionsmodel = _$collectionsmodel;
this._tasksbusinesslayer = _tasksbusinesslayer;
this.$location = $location;
this._settingsbusinesslayer = _settingsbusinesslayer;
this._$scope.tasks = this._$tasksmodel.getAll();
this._$scope.lists = this._$listsmodel.getAll();
this._$scope.days = [0, 1, 2, 3, 4, 5, 6];
@ -853,7 +971,7 @@
}
};
this._$scope.toggleHidden = function() {
return _$scope.status.showhidden = !_$scope.status.showhidden;
return _settingsbusinesslayer.toggle('various', 'showHidden');
};
this._$scope.filterTasks = function() {
return function(task) {
@ -942,7 +1060,7 @@
return TasksController;
})();
return new TasksController($scope, $window, $routeParams, TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location);
return new TasksController($scope, $window, $routeParams, TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location, SettingsBusinessLayer);
}
]);
@ -1010,6 +1128,43 @@
}).call(this);
(function() {
angular.module('Tasks').factory('SettingsBusinessLayer', [
'Persistence', 'SettingsModel', function(Persistence, SettingsModel) {
var SettingsBusinessLayer;
SettingsBusinessLayer = (function() {
function SettingsBusinessLayer(_persistence, _$settingsmodel) {
this._persistence = _persistence;
this._$settingsmodel = _$settingsmodel;
}
SettingsBusinessLayer.prototype.updateModel = function() {
var success,
_this = this;
success = function() {};
return this._persistence.getCollections(success, true);
};
SettingsBusinessLayer.prototype.setVisibility = function(collectionID, visibility) {
return this._persistence.setVisibility(collectionID, visibility);
};
SettingsBusinessLayer.prototype.toggle = function(type, setting) {
var value;
this._$settingsmodel.toggle(type, setting);
value = this._$settingsmodel.getById(type)[setting];
return this._persistence.setting(type, setting, value);
};
return SettingsBusinessLayer;
})();
return new SettingsBusinessLayer(Persistence, SettingsModel);
}
]);
}).call(this);
(function() {
angular.module('Tasks').factory('TasksBusinessLayer', [
'TasksModel', 'Persistence', function(TasksModel, Persistence) {
@ -1093,6 +1248,8 @@
} else {
due = date;
}
} else if (type === 'all') {
due = date;
} else {
return;
}
@ -1376,7 +1533,7 @@
case 'uncompleted':
return this.uncompleteTask(taskID);
case 'today':
return this.setDueDate(taskID, moment().format("YYYYMMDDTHHmmss"));
return this.setDue(taskID, moment().startOf('day').add('h', 12), 'all');
case 'week':
case 'all':
break;
@ -1395,6 +1552,10 @@
return this._persistence.getTasks(success, true);
};
TasksBusinessLayer.prototype.setShowHidden = function(showHidden) {
return this._persistence.setShowHidden(showHidden);
};
return TasksBusinessLayer;
})();
@ -1409,43 +1570,15 @@
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
angular.module('Tasks').factory('CollectionsModel', [
'TasksModel', '_Model', '_EqualQuery', 'Utils', function(TasksModel, _Model, _EqualQuery, Utils) {
'TasksModel', '_Model', function(TasksModel, _Model) {
var CollectionsModel;
CollectionsModel = (function(_super) {
__extends(CollectionsModel, _super);
function CollectionsModel(_$tasksmodel, _utils) {
var collection, _i, _len, _ref;
function CollectionsModel(_$tasksmodel) {
this._$tasksmodel = _$tasksmodel;
this._utils = _utils;
this._nameCache = {};
this._$collections = [
{
id: "starred",
displayname: t('tasks_enhanced', 'Important')
}, {
id: "today",
displayname: t('tasks_enhanced', 'Today')
}, {
id: "week",
displayname: t('tasks_enhanced', 'Week')
}, {
id: "all",
displayname: t('tasks_enhanced', 'All')
}, {
id: "current",
displayname: t('tasks_enhanced', 'Current')
}, {
id: "completed",
displayname: t('tasks_enhanced', 'Done')
}
];
CollectionsModel.__super__.constructor.call(this);
_ref = this._$collections;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
collection = _ref[_i];
this.add(collection);
}
}
CollectionsModel.prototype.add = function(data, clearCache) {
@ -1513,7 +1646,7 @@
return CollectionsModel;
})(_Model);
return new CollectionsModel(TasksModel, Utils);
return new CollectionsModel(TasksModel);
}
]);
@ -1677,6 +1810,46 @@
}).call(this);
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
angular.module('Tasks').factory('SettingsModel', [
'_Model', function(_Model) {
var SettingsModel;
SettingsModel = (function(_super) {
__extends(SettingsModel, _super);
function SettingsModel() {
this._nameCache = {};
SettingsModel.__super__.constructor.call(this);
}
SettingsModel.prototype.add = function(data, clearCache) {
if (clearCache == null) {
clearCache = true;
}
this._nameCache[data.displayname] = data;
if (angular.isDefined(data.id)) {
return SettingsModel.__super__.add.call(this, data, clearCache);
}
};
SettingsModel.prototype.toggle = function(type, setting) {
var set;
set = this.getById(type);
return this.getById(type)[setting] = !set[setting];
};
return SettingsModel;
})(_Model);
return new SettingsModel();
}
]);
}).call(this);
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
@ -1925,11 +2098,96 @@
successCallback = function() {
return _this.deferred.resolve();
};
this.getCollections();
this.getSettings();
this.getLists();
this.getTasks(successCallback);
return this.deferred.promise;
};
Persistence.prototype.getCollections = function(onSuccess, showLoading) {
var failureCallbackWrapper, params, successCallbackWrapper,
_this = this;
if (showLoading == null) {
showLoading = true;
}
onSuccess || (onSuccess = function() {});
if (showLoading) {
this._Loading.increase();
successCallbackWrapper = function(data) {
onSuccess();
return _this._Loading.decrease();
};
failureCallbackWrapper = function(data) {
return _this._Loading.decrease();
};
} else {
successCallbackWrapper = function(data) {
return onSuccess();
};
failureCallbackWrapper = function(data) {};
}
params = {
onSuccess: successCallbackWrapper,
onFailure: failureCallbackWrapper
};
return this._request.get('/apps/tasks_enhanced/collections', params);
};
Persistence.prototype.getSettings = function(onSuccess, showLoading) {
var failureCallbackWrapper, params, successCallbackWrapper,
_this = this;
if (showLoading == null) {
showLoading = true;
}
onSuccess || (onSuccess = function() {});
if (showLoading) {
this._Loading.increase();
successCallbackWrapper = function(data) {
onSuccess();
return _this._Loading.decrease();
};
failureCallbackWrapper = function(data) {
return _this._Loading.decrease();
};
} else {
successCallbackWrapper = function(data) {
return onSuccess();
};
failureCallbackWrapper = function(data) {};
}
params = {
onSuccess: successCallbackWrapper,
onFailure: failureCallbackWrapper
};
return this._request.get('/apps/tasks_enhanced/settings', params);
};
Persistence.prototype.setVisibility = function(collectionID, visibility) {
var params;
params = {
routeParams: {
collectionID: collectionID,
visibility: visibility
}
};
return this._request.post('/apps/tasks_enhanced/collection/\
{collectionID}/visibility/{visibility}', params);
};
Persistence.prototype.setting = function(type, setting, value) {
var params;
params = {
routeParams: {
type: type,
setting: setting,
value: +value
}
};
return this._request.post('/apps/tasks_enhanced/settings/\
{type}/{setting}/{value}', params);
};
Persistence.prototype.getLists = function(onSuccess, showLoading, which) {
var failureCallbackWrapper, params, successCallbackWrapper,
_this = this;
@ -2223,6 +2481,16 @@
return this._request.post('/apps/tasks_enhanced/tasks/{taskID}/note', params);
};
Persistence.prototype.setShowHidden = function(showHidden) {
var params;
params = {
routeParams: {
showHidden: +showHidden
}
};
return this._request.post('/apps/tasks_enhanced/settings/showhidden/{showHidden}', params);
};
return Persistence;
})();
@ -2246,9 +2514,11 @@
]);
angular.module('Tasks').factory('Publisher', [
'_Publisher', 'ListsModel', 'TasksModel', function(_Publisher, ListsModel, TasksModel) {
'_Publisher', 'ListsModel', 'TasksModel', 'CollectionsModel', 'SettingsModel', function(_Publisher, ListsModel, TasksModel, CollectionsModel, SettingsModel) {
var publisher;
publisher = new _Publisher();
publisher.subscribeObjectTo(CollectionsModel, 'collections');
publisher.subscribeObjectTo(SettingsModel, 'settings');
publisher.subscribeObjectTo(ListsModel, 'lists');
publisher.subscribeObjectTo(TasksModel, 'tasks');
return publisher;
@ -2264,7 +2534,6 @@
Status = (function() {
function Status() {
this._$status = {
showhidden: true,
searchActive: false,
addingList: false,
focusTaskInput: false

View file

@ -0,0 +1,817 @@
/*
* angular-ui-bootstrap
* http://angular-ui.github.io/bootstrap/
* Version: 0.10.0 - 2014-01-15
* License: MIT
*/
angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.modal","ui.bootstrap.tabs"]);
angular.module("ui.bootstrap.tpls", ["template/modal/backdrop.html","template/modal/window.html","template/tabs/tab.html","template/tabs/tabset.html"]);
angular.module('ui.bootstrap.transition', [])
/**
* $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete.
* @param {DOMElement} element The DOMElement that will be animated.
* @param {string|object|function} trigger The thing that will cause the transition to start:
* - As a string, it represents the css class to be added to the element.
* - As an object, it represents a hash of style attributes to be applied to the element.
* - As a function, it represents a function to be called that will cause the transition to occur.
* @return {Promise} A promise that is resolved when the transition finishes.
*/
.factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
var $transition = function(element, trigger, options) {
options = options || {};
var deferred = $q.defer();
var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
var transitionEndHandler = function(event) {
$rootScope.$apply(function() {
element.unbind(endEventName, transitionEndHandler);
deferred.resolve(element);
});
};
if (endEventName) {
element.bind(endEventName, transitionEndHandler);
}
// Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
$timeout(function() {
if ( angular.isString(trigger) ) {
element.addClass(trigger);
} else if ( angular.isFunction(trigger) ) {
trigger(element);
} else if ( angular.isObject(trigger) ) {
element.css(trigger);
}
//If browser does not support transitions, instantly resolve
if ( !endEventName ) {
deferred.resolve(element);
}
});
// Add our custom cancel function to the promise that is returned
// We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
// i.e. it will therefore never raise a transitionEnd event for that transition
deferred.promise.cancel = function() {
if ( endEventName ) {
element.unbind(endEventName, transitionEndHandler);
}
deferred.reject('Transition cancelled');
};
return deferred.promise;
};
// Work out the name of the transitionEnd event
var transElement = document.createElement('trans');
var transitionEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'transition': 'transitionend'
};
var animationEndEventNames = {
'WebkitTransition': 'webkitAnimationEnd',
'MozTransition': 'animationend',
'OTransition': 'oAnimationEnd',
'transition': 'animationend'
};
function findEndEventName(endEventNames) {
for (var name in endEventNames){
if (transElement.style[name] !== undefined) {
return endEventNames[name];
}
}
}
$transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
$transition.animationEndEventName = findEndEventName(animationEndEventNames);
return $transition;
}]);
angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
/**
* A helper, internal data structure that acts as a map but also allows getting / removing
* elements in the LIFO order
*/
.factory('$$stackedMap', function () {
return {
createNew: function () {
var stack = [];
return {
add: function (key, value) {
stack.push({
key: key,
value: value
});
},
get: function (key) {
for (var i = 0; i < stack.length; i++) {
if (key == stack[i].key) {
return stack[i];
}
}
},
keys: function() {
var keys = [];
for (var i = 0; i < stack.length; i++) {
keys.push(stack[i].key);
}
return keys;
},
top: function () {
return stack[stack.length - 1];
},
remove: function (key) {
var idx = -1;
for (var i = 0; i < stack.length; i++) {
if (key == stack[i].key) {
idx = i;
break;
}
}
return stack.splice(idx, 1)[0];
},
removeTop: function () {
return stack.splice(stack.length - 1, 1)[0];
},
length: function () {
return stack.length;
}
};
}
};
})
/**
* A helper directive for the $modal service. It creates a backdrop element.
*/
.directive('modalBackdrop', ['$timeout', function ($timeout) {
return {
restrict: 'EA',
replace: true,
templateUrl: 'template/modal/backdrop.html',
link: function (scope) {
scope.animate = false;
//trigger CSS transitions
$timeout(function () {
scope.animate = true;
});
}
};
}])
.directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
return {
restrict: 'EA',
scope: {
index: '@',
animate: '='
},
replace: true,
transclude: true,
templateUrl: 'template/modal/window.html',
link: function (scope, element, attrs) {
scope.windowClass = attrs.windowClass || '';
$timeout(function () {
// trigger CSS transitions
scope.animate = true;
// focus a freshly-opened modal
element[0].focus();
});
scope.close = function (evt) {
var modal = $modalStack.getTop();
if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
evt.preventDefault();
evt.stopPropagation();
$modalStack.dismiss(modal.key, 'backdrop click');
}
};
}
};
}])
.factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) {
var OPENED_MODAL_CLASS = 'modal-open';
var backdropDomEl, backdropScope;
var openedWindows = $$stackedMap.createNew();
var $modalStack = {};
function backdropIndex() {
var topBackdropIndex = -1;
var opened = openedWindows.keys();
for (var i = 0; i < opened.length; i++) {
if (openedWindows.get(opened[i]).value.backdrop) {
topBackdropIndex = i;
}
}
return topBackdropIndex;
}
$rootScope.$watch(backdropIndex, function(newBackdropIndex){
if (backdropScope) {
backdropScope.index = newBackdropIndex;
}
});
function removeModalWindow(modalInstance) {
var body = $document.find('#tasks_enhanced_wrapper').eq(0);
var modalWindow = openedWindows.get(modalInstance).value;
//clean up the stack
openedWindows.remove(modalInstance);
//remove window DOM element
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, checkRemoveBackdrop);
body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
}
function checkRemoveBackdrop() {
//remove backdrop if no longer needed
if (backdropDomEl && backdropIndex() == -1) {
var backdropScopeRef = backdropScope;
removeAfterAnimate(backdropDomEl, backdropScope, 150, function () {
backdropScopeRef.$destroy();
backdropScopeRef = null;
});
backdropDomEl = undefined;
backdropScope = undefined;
}
}
function removeAfterAnimate(domEl, scope, emulateTime, done) {
// Closing animation
scope.animate = false;
var transitionEndEventName = $transition.transitionEndEventName;
if (transitionEndEventName) {
// transition out
var timeout = $timeout(afterAnimating, emulateTime);
domEl.bind(transitionEndEventName, function () {
$timeout.cancel(timeout);
afterAnimating();
scope.$apply();
});
} else {
// Ensure this call is async
$timeout(afterAnimating, 0);
}
function afterAnimating() {
if (afterAnimating.done) {
return;
}
afterAnimating.done = true;
domEl.remove();
if (done) {
done();
}
}
}
$document.bind('keydown', function (evt) {
var modal;
if (evt.which === 27) {
modal = openedWindows.top();
if (modal && modal.value.keyboard) {
$rootScope.$apply(function () {
$modalStack.dismiss(modal.key);
});
}
}
});
$modalStack.open = function (modalInstance, modal) {
openedWindows.add(modalInstance, {
deferred: modal.deferred,
modalScope: modal.scope,
backdrop: modal.backdrop,
keyboard: modal.keyboard
});
var body = $document.find('#tasks_enhanced_wrapper').eq(0),
currBackdropIndex = backdropIndex();
if (currBackdropIndex >= 0 && !backdropDomEl) {
backdropScope = $rootScope.$new(true);
backdropScope.index = currBackdropIndex;
backdropDomEl = $compile('<div modal-backdrop></div>')(backdropScope);
body.append(backdropDomEl);
}
var angularDomEl = angular.element('<div modal-window></div>');
angularDomEl.attr('window-class', modal.windowClass);
angularDomEl.attr('index', openedWindows.length() - 1);
angularDomEl.attr('animate', 'animate');
angularDomEl.html(modal.content);
var modalDomEl = $compile(angularDomEl)(modal.scope);
openedWindows.top().value.modalDomEl = modalDomEl;
body.append(modalDomEl);
body.addClass(OPENED_MODAL_CLASS);
};
$modalStack.close = function (modalInstance, result) {
var modalWindow = openedWindows.get(modalInstance).value;
if (modalWindow) {
modalWindow.deferred.resolve(result);
removeModalWindow(modalInstance);
}
};
$modalStack.dismiss = function (modalInstance, reason) {
var modalWindow = openedWindows.get(modalInstance).value;
if (modalWindow) {
modalWindow.deferred.reject(reason);
removeModalWindow(modalInstance);
}
};
$modalStack.dismissAll = function (reason) {
var topModal = this.getTop();
while (topModal) {
this.dismiss(topModal.key, reason);
topModal = this.getTop();
}
};
$modalStack.getTop = function () {
return openedWindows.top();
};
return $modalStack;
}])
.provider('$modal', function () {
var $modalProvider = {
options: {
backdrop: true, //can be also false or 'static'
keyboard: true
},
$get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
var $modal = {};
function getTemplatePromise(options) {
return options.template ? $q.when(options.template) :
$http.get(options.templateUrl, {cache: $templateCache}).then(function (result) {
return result.data;
});
}
function getResolvePromises(resolves) {
var promisesArr = [];
angular.forEach(resolves, function (value, key) {
if (angular.isFunction(value) || angular.isArray(value)) {
promisesArr.push($q.when($injector.invoke(value)));
}
});
return promisesArr;
}
$modal.open = function (modalOptions) {
var modalResultDeferred = $q.defer();
var modalOpenedDeferred = $q.defer();
//prepare an instance of a modal to be injected into controllers and returned to a caller
var modalInstance = {
result: modalResultDeferred.promise,
opened: modalOpenedDeferred.promise,
close: function (result) {
$modalStack.close(modalInstance, result);
},
dismiss: function (reason) {
$modalStack.dismiss(modalInstance, reason);
}
};
//merge and clean up options
modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
modalOptions.resolve = modalOptions.resolve || {};
//verify options
if (!modalOptions.template && !modalOptions.templateUrl) {
throw new Error('One of template or templateUrl options is required.');
}
var templateAndResolvePromise =
$q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
var modalScope = (modalOptions.scope || $rootScope).$new();
modalScope.$close = modalInstance.close;
modalScope.$dismiss = modalInstance.dismiss;
var ctrlInstance, ctrlLocals = {};
var resolveIter = 1;
//controllers
if (modalOptions.controller) {
ctrlLocals.$scope = modalScope;
ctrlLocals.$modalInstance = modalInstance;
angular.forEach(modalOptions.resolve, function (value, key) {
ctrlLocals[key] = tplAndVars[resolveIter++];
});
ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
}
$modalStack.open(modalInstance, {
scope: modalScope,
deferred: modalResultDeferred,
content: tplAndVars[0],
backdrop: modalOptions.backdrop,
keyboard: modalOptions.keyboard,
windowClass: modalOptions.windowClass
});
}, function resolveError(reason) {
modalResultDeferred.reject(reason);
});
templateAndResolvePromise.then(function () {
modalOpenedDeferred.resolve(true);
}, function () {
modalOpenedDeferred.reject(false);
});
return modalInstance;
};
return $modal;
}]
};
return $modalProvider;
});
/**
* @ngdoc overview
* @name ui.bootstrap.tabs
*
* @description
* AngularJS version of the tabs directive.
*/
angular.module('ui.bootstrap.tabs', [])
.controller('TabsetController', ['$scope', function TabsetCtrl($scope) {
var ctrl = this,
tabs = ctrl.tabs = $scope.tabs = [];
ctrl.select = function(tab) {
angular.forEach(tabs, function(tab) {
tab.active = false;
});
tab.active = true;
};
ctrl.addTab = function addTab(tab) {
tabs.push(tab);
if (tabs.length === 1 || tab.active) {
ctrl.select(tab);
}
};
ctrl.removeTab = function removeTab(tab) {
var index = tabs.indexOf(tab);
//Select a new tab if the tab to be removed is selected
if (tab.active && tabs.length > 1) {
//If this is the last tab, select the previous tab. else, the next tab.
var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
ctrl.select(tabs[newActiveIndex]);
}
tabs.splice(index, 1);
};
}])
/**
* @ngdoc directive
* @name ui.bootstrap.tabs.directive:tabset
* @restrict EA
*
* @description
* Tabset is the outer container for the tabs directive
*
* @param {boolean=} vertical Whether or not to use vertical styling for the tabs.
* @param {boolean=} justified Whether or not to use justified styling for the tabs.
*
* @example
<example module="ui.bootstrap">
<file name="index.html">
<tabset>
<tab heading="Tab 1"><b>First</b> Content!</tab>
<tab heading="Tab 2"><i>Second</i> Content!</tab>
</tabset>
<hr />
<tabset vertical="true">
<tab heading="Vertical Tab 1"><b>First</b> Vertical Content!</tab>
<tab heading="Vertical Tab 2"><i>Second</i> Vertical Content!</tab>
</tabset>
<tabset justified="true">
<tab heading="Justified Tab 1"><b>First</b> Justified Content!</tab>
<tab heading="Justified Tab 2"><i>Second</i> Justified Content!</tab>
</tabset>
</file>
</example>
*/
.directive('tabset', function() {
return {
restrict: 'EA',
transclude: true,
replace: true,
scope: {},
controller: 'TabsetController',
templateUrl: 'template/tabs/tabset.html',
link: function(scope, element, attrs) {
scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
scope.type = angular.isDefined(attrs.type) ? scope.$parent.$eval(attrs.type) : 'tabs';
}
};
})
/**
* @ngdoc directive
* @name ui.bootstrap.tabs.directive:tab
* @restrict EA
*
* @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}.
* @param {string=} select An expression to evaluate when the tab is selected.
* @param {boolean=} active A binding, telling whether or not this tab is selected.
* @param {boolean=} disabled A binding, telling whether or not this tab is disabled.
*
* @description
* Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}.
*
* @example
<example module="ui.bootstrap">
<file name="index.html">
<div ng-controller="TabsDemoCtrl">
<button class="btn btn-small" ng-click="items[0].active = true">
Select item 1, using active binding
</button>
<button class="btn btn-small" ng-click="items[1].disabled = !items[1].disabled">
Enable/disable item 2, using disabled binding
</button>
<br />
<tabset>
<tab heading="Tab 1">First Tab</tab>
<tab select="alertMe()">
<tab-heading><i class="icon-bell"></i> Alert me!</tab-heading>
Second Tab, with alert callback and html heading!
</tab>
<tab ng-repeat="item in items"
heading="{{item.title}}"
disabled="item.disabled"
active="item.active">
{{item.content}}
</tab>
</tabset>
</div>
</file>
<file name="script.js">
function TabsDemoCtrl($scope) {
$scope.items = [
{ title:"Dynamic Title 1", content:"Dynamic Item 0" },
{ title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true }
];
$scope.alertMe = function() {
setTimeout(function() {
alert("You've selected the alert tab!");
});
};
};
</file>
</example>
*/
/**
* @ngdoc directive
* @name ui.bootstrap.tabs.directive:tabHeading
* @restrict EA
*
* @description
* Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element.
*
* @example
<example module="ui.bootstrap">
<file name="index.html">
<tabset>
<tab>
<tab-heading><b>HTML</b> in my titles?!</tab-heading>
And some content, too!
</tab>
<tab>
<tab-heading><i class="icon-heart"></i> Icon heading?!?</tab-heading>
That's right.
</tab>
</tabset>
</file>
</example>
*/
.directive('tab', ['$parse', function($parse) {
return {
require: '^tabset',
restrict: 'EA',
replace: true,
templateUrl: 'template/tabs/tab.html',
transclude: true,
scope: {
heading: '@',
onSelect: '&select', //This callback is called in contentHeadingTransclude
//once it inserts the tab's content into the dom
onDeselect: '&deselect'
},
controller: function() {
//Empty controller so other directives can require being 'under' a tab
},
compile: function(elm, attrs, transclude) {
return function postLink(scope, elm, attrs, tabsetCtrl) {
var getActive, setActive;
if (attrs.active) {
getActive = $parse(attrs.active);
setActive = getActive.assign;
scope.$parent.$watch(getActive, function updateActive(value, oldVal) {
// Avoid re-initializing scope.active as it is already initialized
// below. (watcher is called async during init with value ===
// oldVal)
if (value !== oldVal) {
scope.active = !!value;
}
});
scope.active = getActive(scope.$parent);
} else {
setActive = getActive = angular.noop;
}
scope.$watch('active', function(active) {
// Note this watcher also initializes and assigns scope.active to the
// attrs.active expression.
setActive(scope.$parent, active);
if (active) {
tabsetCtrl.select(scope);
scope.onSelect();
} else {
scope.onDeselect();
}
});
scope.disabled = false;
if ( attrs.disabled ) {
scope.$parent.$watch($parse(attrs.disabled), function(value) {
scope.disabled = !! value;
});
}
scope.select = function() {
if ( ! scope.disabled ) {
scope.active = true;
}
};
tabsetCtrl.addTab(scope);
scope.$on('$destroy', function() {
tabsetCtrl.removeTab(scope);
});
//We need to transclude later, once the content container is ready.
//when this link happens, we're inside a tab heading.
scope.$transcludeFn = transclude;
};
}
};
}])
.directive('tabHeadingTransclude', [function() {
return {
restrict: 'A',
require: '^tab',
link: function(scope, elm, attrs, tabCtrl) {
scope.$watch('headingElement', function updateHeadingElement(heading) {
if (heading) {
elm.html('');
elm.append(heading);
}
});
}
};
}])
.directive('tabContentTransclude', function() {
return {
restrict: 'A',
require: '^tabset',
link: function(scope, elm, attrs) {
var tab = scope.$eval(attrs.tabContentTransclude);
//Now our tab is ready to be transcluded: both the tab heading area
//and the tab content area are loaded. Transclude 'em both.
tab.$transcludeFn(tab.$parent, function(contents) {
angular.forEach(contents, function(node) {
if (isTabHeading(node)) {
//Let tabHeadingTransclude know.
tab.headingElement = node;
} else {
elm.append(node);
}
});
});
}
};
function isTabHeading(node) {
return node.tagName && (
node.hasAttribute('tab-heading') ||
node.hasAttribute('data-tab-heading') ||
node.tagName.toLowerCase() === 'tab-heading' ||
node.tagName.toLowerCase() === 'data-tab-heading'
);
}
})
;
angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/modal/backdrop.html",
"<div class=\"modal-backdrop fade\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1040 + index*10}\"></div>");
}]);
angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/modal/window.html",
"<div tabindex=\"-1\" class=\"modal fade {{ windowClass }}\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\" ng-click=\"close($event)\">\n" +
" <div class=\"modal-dialog\"><div class=\"modal-content\" ng-transclude></div></div>\n" +
"</div>");
}]);
angular.module("template/tabs/pane.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/tabs/pane.html",
"<div class=\"tab-pane\" ng-class=\"{active: selected}\" ng-show=\"selected\" ng-transclude></div>\n" +
"");
}]);
angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/tabs/tab.html",
"<li ng-class=\"{active: active, disabled: disabled}\">\n" +
" <a ng-click=\"select()\" tab-heading-transclude>{{heading}}</a>\n" +
"</li>\n" +
"");
}]);
angular.module("template/tabs/tabs.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/tabs/tabs.html",
"<div class=\"tabbable\">\n" +
" <ul class=\"nav nav-tabs\">\n" +
" <li ng-repeat=\"pane in panes\" ng-class=\"{active:pane.selected}\">\n" +
" <a ng-click=\"select(pane)\">{{pane.heading}}</a>\n" +
" </li>\n" +
" </ul>\n" +
" <div class=\"tab-content\" ng-transclude></div>\n" +
"</div>\n" +
"");
}]);
angular.module("template/tabs/tabset-titles.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/tabs/tabset-titles.html",
"<ul class=\"nav {{type && 'nav-' + type}}\" ng-class=\"{'nav-stacked': vertical}\">\n" +
"</ul>\n" +
"");
}]);
angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/tabs/tabset.html",
"\n" +
"<div class=\"tabbable\">\n" +
" <ul class=\"nav {{type && 'nav-' + type}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
" <div class=\"tab-content\">\n" +
" <div class=\"tab-pane\" \n" +
" ng-repeat=\"tab in tabs\" \n" +
" ng-class=\"{active: tab.active}\"\n" +
" tab-content-transclude=\"tab\">\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"");
}]);

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,12 @@
<?php $TRANSLATIONS = array(
"Invalid date/time" => "Ungültige Datums-/Zeitangabe",
"Search..." => "Suche...",
"Settings" => "Einstellungen",
"General" => "Allgemein",
"Visible" => "Sichtbar",
"Hidden" => "Versteckt",
"Automatic" => "Automatisch",
"Visibility of Smart Collections" => "Sichtbarkeit der Smart-Collections",
"Tasks" => "Aufgaben",
"Today" => "Heute",
"Important" => "Wichtig",

View file

@ -0,0 +1,93 @@
<?php
/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2014 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\Tasks_enhanced\Controller,
OCP\AppFramework\Http\JSONResponse;
class CollectionsController extends Controller {
/**
* @NoAdminRequired
*/
public function getCollections(){
$l = \OCP\Util::getL10N('tasks_enhanced');
$collections = array(
array(
'id' => "starred",
'displayname' => (string)$l->t('Important'),
'show' => 2),
array(
'id' => "today",
'displayname' => (string)$l->t('Today'),
'show' => 2),
array(
'id' => "week",
'displayname' => (string)$l->t('Week'),
'show' => 2),
array(
'id' => "all",
'displayname' => (string)$l->t('All'),
'show' => 2),
array(
'id' => "current",
'displayname' => (string)$l->t('Current'),
'show' => 2),
array(
'id' => "completed",
'displayname' => (string)$l->t('Done'),
'show' => 2)
);
foreach ($collections as $key => $collection){
try{
$tmp = (int)\OCP\Config::getUserValue($this->api->getUserId(), 'tasks_enhanced','show_'.$collection['id']);
if (!in_array($tmp, array(0,1,2))) {
$tmp = 2;
\OCP\Config::setUserValue($this->api->getUserId(), 'tasks_enhanced','show_'.$collection['id'],$tmp);
}
$collections[$key]['show'] = $tmp;
}catch(\Exception $e) {
\OCP\Util::writeLog('tasks_enhanced', $e->getMessage(), \OCP\Util::ERROR);
}
}
$result = array(
'data' => array(
'collections' => $collections
)
);
$response = new JSONResponse();
$response->setData($result);
return $response;
}
public function setVisibility(){
$collectionId = (string) $this->params('collectionID');
$vis = (int) $this->params('visibility');
if (in_array($vis, array(0,1,2))){
\OCP\Config::setUserValue($this->api->getUserId(), 'tasks_enhanced','show_'.$collectionId,$vis);
}
$response = new JSONResponse();
return $response;
}
}

View file

@ -29,16 +29,19 @@ class PageController extends Controller {
\OCP\Util::addScript('tasks_enhanced', 'vendor/angularjs/angular-route');
\OCP\Util::addScript('tasks_enhanced', 'vendor/angularjs/angular-animate');
\OCP\Util::addScript('tasks_enhanced', 'vendor/momentjs/moment');
\OCP\Util::addScript('tasks_enhanced', 'vendor/bootstrap/ui-bootstrap-custom-tpls-0.10.0');
} else {
\OCP\Util::addScript('tasks_enhanced', 'vendor/angularjs/angular.min');
\OCP\Util::addScript('tasks_enhanced', 'vendor/angularjs/angular-route.min');
\OCP\Util::addScript('tasks_enhanced', 'vendor/angularjs/angular-animate.min');
\OCP\Util::addScript('tasks_enhanced', 'vendor/momentjs/moment.min');
\OCP\Util::addScript('tasks_enhanced', 'vendor/bootstrap/ui-bootstrap-custom-tpls-0.10.0.min');
}
\OCP\Util::addScript('tasks_enhanced', 'public/app');
\OCP\Util::addScript('tasks_enhanced', 'vendor/appframework/app');
\OCP\Util::addScript('tasks_enhanced', 'vendor/timepicker/jquery.ui.timepicker');
\OCP\Util::addStyle('tasks_enhanced', 'style');
\OCP\Util::addStyle('tasks_enhanced', 'vendor/bootstrap/bootstrap');
$date = new \DateTimeZone(\OC_Calendar_App::getTimezone());
$day = new \DateTime('today', $date);

View file

@ -0,0 +1,59 @@
<?php
/**
* ownCloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2014 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\Tasks_enhanced\Controller,
OCP\AppFramework\Http\JSONResponse;
class SettingsController extends Controller {
/**
* @NoAdminRequired
*/
public function getSettings(){
$settings = array(
array(
'id' => 'various',
'showHidden' => (int)\OCP\Config::getUserValue($this->api->getUserId(), 'tasks_enhanced','various_showHidden'))
);
$result = array(
'data' => array(
'settings' => $settings
)
);
$response = new JSONResponse();
$response->setData($result);
return $response;
}
/**
* @NoAdminRequired
*/
public function set(){
\OCP\Config::setUserValue($this->api->getUserId(), 'tasks_enhanced',$this->params('type').'_'.$this->params('setting'), $this->params('value'));
$response = new JSONResponse();
$response->setData();
return $response;
}
}

View file

@ -13,8 +13,10 @@ namespace OCA\Tasks_enhanced;
use OCP\AppFramework\App as MainApp,
OCP\AppFramework\IAppContainer,
OCA\Tasks_enhanced\Controller\PageController,
OCA\Tasks_enhanced\Controller\CollectionsController,
OCA\Tasks_enhanced\Controller\ListsController,
OCA\Tasks_enhanced\Controller\TasksController;
OCA\Tasks_enhanced\Controller\TasksController,
OCA\Tasks_enhanced\Controller\SettingsController;
/**
* This class manages our app actions
@ -38,12 +40,18 @@ class Dispatcher extends MainApp {
$this->container->registerService('PageController', function(IAppContainer $container) {
return new PageController($container);
});
$this->container->registerService('CollectionsController', function(IAppContainer $container) {
return new CollectionsController($container);
});
$this->container->registerService('ListsController', function(IAppContainer $container) {
return new ListsController($container);
});
$this->container->registerService('TasksController', function(IAppContainer $container) {
return new TasksController($container);
});
$this->container->registerService('SettingsController', function(IAppContainer $container) {
return new SettingsController($container);
});
}
}

View file

@ -1,4 +1,4 @@
<div ng-app="Tasks" ng-cloak ng-controller="AppController" ng-click="closeAll()">
<div ng-app="Tasks" ng-cloak ng-controller="AppController" ng-click="closeAll()" id="tasks_enhanced_wrapper">
<div id="task-lists" ng-controller="ListController">
<div id="task_lists_header" class="header" ng-class="{'search': status.searchActive}" ng-controller="SearchController">
<div id="main-toolbar">
@ -20,7 +20,7 @@
<div id="task_lists_scroll" class="scroll">
<ul id="collection_filters">
<li ng-repeat="collection in collections" id="collection_{{ collection.id }}" rel="{{ collection.id }}"
ng-class="{'animate-up': getCollectionCount(collection.id)<1, active: collection.id==route.listID}" oc-drop-task>
ng-class="{'animate-up': hideCollection(collection.id), active: collection.id==route.listID}" oc-drop-task>
<a href="#/lists/{{ collection.id }}">
<span class="icon collection-{{ collection.id }}"><text ng-show="collection.id=='today'"><?php p($_['DOM']); ?></text></span>
<span class="count">{{ getCollectionString(collection.id) }}</span>
@ -50,6 +50,9 @@
<a class="delete" ng-click="deleteList(route.listID)" ng-show="showDelete(route.listID)">
<span class="icon detail-trash"></span>
</a>
<a class="settings" ng-click="showSettings()" stop-event="click">
<span class="icon detail-settings"></span>
</a>
</div>
</div>
@ -66,12 +69,14 @@
ng-keydown="checkTaskInput($event)"/>
</form>
</div>
<div class="task-list" ng-class="{'completed-hidden':!status.showhidden}" ng-switch="route.listID">
<div class="task-list" ng-class="{'completed-hidden':!settingsmodel.getById('various').showHidden}" ng-switch="route.listID">
<?php print_unescaped($this->inc('part.tasklist')); ?>
<?php print_unescaped($this->inc('part.collectionall')); ?>
<?php print_unescaped($this->inc('part.collectionweek')); ?>
</div>
</div>
<div id="task-details" ng-include="'templates/part.details.php'" ng-class="{'details-visible':route.taskID}"></div>
<script type="text/ng-template" id="part.settings.html">
<?php print_unescaped($this->inc('part.settings')); ?>
</script>
</div>

View file

@ -1,101 +1,101 @@
<div ng-controller="DetailsController" ng-click="endEdit()" stop-event="click">
<a class="detail-checkbox" ng-click="toggleCompleted(task.id)">
<span class="icon detail-checkbox" ng-class="{'detail-checked':task.completed}"></span>
</a>
<a class="detail-star" ng-click="toggleStarred(task.id)">
<span class="icon detail-star" ng-class="{'detail-starred':task.starred}"></span>
</a>
<div class="title">
<span class="title-text" ng-class="{'strike-through':task.completed}" ng-click="editName()" stop-event="click"
ng-hide="route.parameter=='name'" oc-click-focus="{selector: '#editName', timeout: 0}">{{ task.name }}</span>
<div class="expandable-container" ng-show="route.parameter=='name'" stop-event="click">
<div class="expandingArea active">
<pre><span>{{ task.name }}</span><br /></pre>
<textarea id="editName" maxlength="200" ng-model="task.name" ng-keydown="endName($event)"></textarea>
</div>
<a class="detail-checkbox" ng-click="toggleCompleted(task.id)">
<span class="icon detail-checkbox" ng-class="{'detail-checked':task.completed}"></span>
</a>
<a class="detail-star" ng-click="toggleStarred(task.id)">
<span class="icon detail-star" ng-class="{'detail-starred':task.starred}"></span>
</a>
<div class="title">
<span class="title-text" ng-class="{'strike-through':task.completed}" ng-click="editName()" stop-event="click"
ng-hide="route.parameter=='name'" oc-click-focus="{selector: '#editName', timeout: 0}">{{ task.name }}</span>
<div class="expandable-container" ng-show="route.parameter=='name'" stop-event="click">
<div class="expandingArea active">
<pre><span>{{ task.name }}</span><br /></pre>
<textarea id="editName" maxlength="200" ng-model="task.name" ng-keydown="endName($event)"></textarea>
</div>
</div>
</div>
<div class="body" watch-top ng-style="{top:divTop}">
<div class="section detail-start" ng-class="{'date':isDue(task.start), 'editing':route.parameter=='startdate'}" ng-click="editStart()" stop-event="click">
<!-- oc-click-focus="{selector: 'div.detail-start input.datepicker-input', timeout: 0}" -->
<span class="icon detail-start" ng-class="{'overdue':isOverDue(task.start)}"></span>
<div class="section-title" ng-class="{'overdue':isOverDue(task.start)}" ng-hide="route.parameter=='startdate'">
<text>{{ task.start | startDetails }}</text>
</div>
<a class="detail-delete" ng-click="deleteStartDate()" stop-event="click">
<span class="icon detail-delete"></span>
</a>
<span class="icon detail-save" ng-click="endEdit()" stop-event="click"></span>
<div class="section-edit" ng-show="route.parameter=='startdate'">
<input class="datepicker-input medium focus" type="text" key-value="" placeholder="dd.mm.yyyy" value="{{ task.start | dateTaskList }}" datepicker="start">
<input class="timepicker-input medium focus" type="text" key-value="" placeholder="hh:mm" value="{{ task.start | timeTaskList }}" timepicker="start" stop-event="click">
</div>
</div>
<div class="body" watch-top ng-style="{top:divTop}">
<div class="section detail-start" ng-class="{'date':isDue(task.start), 'editing':route.parameter=='startdate'}" ng-click="editStart()" stop-event="click">
<!-- oc-click-focus="{selector: 'div.detail-start input.datepicker-input', timeout: 0}" -->
<span class="icon detail-start" ng-class="{'overdue':isOverDue(task.start)}"></span>
<div class="section-title" ng-class="{'overdue':isOverDue(task.start)}" ng-hide="route.parameter=='startdate'">
<text>{{ task.start | startDetails }}</text>
<div class="section detail-date" ng-class="{'date':isDue(task.due), 'editing':route.parameter=='duedate'}" ng-click="editDueDate()" stop-event="click">
<!-- oc-click-focus="{selector: 'div.detail-date input.datepicker-input', timeout: 0}" -->
<span class="icon detail-date" ng-class="{'overdue':isOverDue(task.due)}"></span>
<div class="section-title" ng-class="{'overdue':isOverDue(task.due)}" ng-hide="route.parameter=='duedate'">
<text>{{ task.due | dateDetails }}</text>
</div>
<a class="detail-delete" ng-click="deleteDueDate()" stop-event="click">
<span class="icon detail-delete"></span>
</a>
<span class="icon detail-save" ng-click="endEdit()" stop-event="click"></span>
<div class="section-edit" ng-show="route.parameter=='duedate'">
<input class="datepicker-input medium focus" type="text" key-value="" placeholder="dd.mm.yyyy" value="{{ task.due | dateTaskList }}" datepicker="due">
<input class="timepicker-input medium focus" type="text" key-value="" placeholder="hh:mm" value="{{ task.due | timeTaskList }}" timepicker="due" stop-event="click">
</div>
</div>
<div class="section detail-reminder" ng-class="{'date':isDue(task.reminder.date), 'editing':route.parameter=='reminder'}" ng-click="editReminder()" stop-event="click">
<!-- oc-click-focus="{selector: 'div.detail-reminder input.datepicker-input', timeout: 0}" -->
<span class="icon detail-reminder" ng-class="{'overdue':isOverDue(task.reminder.date)}"></span>
<span class="icon detail-remindertype" ng-click="changeReminderType(task)" ng-show="task.due || task.start"></span>
<div class="section-title" ng-class="{'overdue':isOverDue(task.reminder.date)}" ng-hide="route.parameter=='reminder'">
<text rel="">{{ task.reminder | reminderDetails:this }}</text>
</div>
<!-- <div class="section-description" ng-hide="route.parameter=='reminder'">{{ task.reminder.date | dateDetailsShort }}</div> -->
<a class="detail-delete" ng-click="deleteReminder()" stop-event="click">
<span class="icon detail-delete"></span>
</a>
<span class="icon detail-save" ng-click="endEdit()" stop-event="click"></span>
<div class="section-edit" ng-show="route.parameter=='reminder'" ng-switch='reminderType(task)'>
<div ng-switch-when="DATE-TIME">
<input class="datepicker-input medium focus" type="text" key-value="" placeholder="dd.mm.yyyy" value="{{ task.reminder.date | dateTaskList }}" datepicker="reminder">
<input class="timepicker-input medium focus" type="text" key-value="" placeholder="hh:mm" value="{{ task.reminder.date | timeTaskList }}" timepicker="reminder" stop-event="click">
</div>
<a class="detail-delete" ng-click="deleteStartDate()" stop-event="click">
<span class="icon detail-delete"></span>
<div ng-switch-when="DURATION">
<input ng-change="setReminderDuration(task.id)" class="duration-input medium focus" type="number" key-value="" placeholder="" ng-model="task.reminder.duration[task.reminder.duration.token]">
<select ng-model="task.reminder.duration.token" ng-options="duration.id as duration.names for duration in durations"></select>
<select ng-change="setReminderDuration(task.id)" ng-model="task.reminder.duration.params" ng-options="param as param.name for param in params(task) track by param.id"></select>
</div>
</div>
</div>
<!-- <ul class="subtasks buffer"></ul> -->
<div class="note">
<div class="note-body selectable" ng-click="editNote()" stop-event="click" oc-click-focus="{selector: '.expandingArea textarea', timeout: 0}">
<!--
<a class="open-fullscreen-note">
<span class="icon note-fullscreen"></span>
</a>
<span class="icon detail-save" ng-click="endEdit()" stop-event="click"></span>
<div class="section-edit" ng-show="route.parameter=='startdate'">
<input class="datepicker-input medium focus" type="text" key-value="" placeholder="dd.mm.yyyy" value="{{ task.start | dateTaskList }}" datepicker="start">
<input class="timepicker-input medium focus" type="text" key-value="" placeholder="hh:mm" value="{{ task.start | timeTaskList }}" timepicker="start" stop-event="click">
</div>
</div>
<div class="section detail-date" ng-class="{'date':isDue(task.due), 'editing':route.parameter=='duedate'}" ng-click="editDueDate()" stop-event="click">
<!-- oc-click-focus="{selector: 'div.detail-date input.datepicker-input', timeout: 0}" -->
<span class="icon detail-date" ng-class="{'overdue':isOverDue(task.due)}"></span>
<div class="section-title" ng-class="{'overdue':isOverDue(task.due)}" ng-hide="route.parameter=='duedate'">
<text>{{ task.due | dateDetails }}</text>
</div>
<a class="detail-delete" ng-click="deleteDueDate()" stop-event="click">
<span class="icon detail-delete"></span>
</a>
<span class="icon detail-save" ng-click="endEdit()" stop-event="click"></span>
<div class="section-edit" ng-show="route.parameter=='duedate'">
<input class="datepicker-input medium focus" type="text" key-value="" placeholder="dd.mm.yyyy" value="{{ task.due | dateTaskList }}" datepicker="due">
<input class="timepicker-input medium focus" type="text" key-value="" placeholder="hh:mm" value="{{ task.due | timeTaskList }}" timepicker="due" stop-event="click">
</div>
</div>
<div class="section detail-reminder" ng-class="{'date':isDue(task.reminder.date), 'editing':route.parameter=='reminder'}" ng-click="editReminder()" stop-event="click">
<!-- oc-click-focus="{selector: 'div.detail-reminder input.datepicker-input', timeout: 0}" -->
<span class="icon detail-reminder" ng-class="{'overdue':isOverDue(task.reminder.date)}"></span>
<span class="icon detail-remindertype" ng-click="changeReminderType(task)" ng-show="task.due || task.start"></span>
<div class="section-title" ng-class="{'overdue':isOverDue(task.reminder.date)}" ng-hide="route.parameter=='reminder'">
<text rel="">{{ task.reminder | reminderDetails:this }}</text>
</div>
<!-- <div class="section-description" ng-hide="route.parameter=='reminder'">{{ task.reminder.date | dateDetailsShort }}</div> -->
<a class="detail-delete" ng-click="deleteReminder()" stop-event="click">
<span class="icon detail-delete"></span>
</a>
<span class="icon detail-save" ng-click="endEdit()" stop-event="click"></span>
<div class="section-edit" ng-show="route.parameter=='reminder'" ng-switch='reminderType(task)'>
<div ng-switch-when="DATE-TIME">
<input class="datepicker-input medium focus" type="text" key-value="" placeholder="dd.mm.yyyy" value="{{ task.reminder.date | dateTaskList }}" datepicker="reminder">
<input class="timepicker-input medium focus" type="text" key-value="" placeholder="hh:mm" value="{{ task.reminder.date | timeTaskList }}" timepicker="reminder" stop-event="click">
</div>
<div ng-switch-when="DURATION">
<input ng-change="setReminderDuration(task.id)" class="duration-input medium focus" type="number" key-value="" placeholder="" ng-model="task.reminder.duration[task.reminder.duration.token]">
<select ng-model="task.reminder.duration.token" ng-options="duration.id as duration.names for duration in durations"></select>
<select ng-change="setReminderDuration(task.id)" ng-model="task.reminder.duration.params" ng-options="param as param.name for param in params(task) track by param.id"></select>
</div>
</div>
</div>
<!-- <ul class="subtasks buffer"></ul> -->
<div class="note">
<div class="note-body selectable" ng-click="editNote()" stop-event="click" oc-click-focus="{selector: '.expandingArea textarea', timeout: 0}">
<!--
<a class="open-fullscreen-note">
<span class="icon note-fullscreen"></span>
</a>
-->
<div class="content-fakeable">
<div class="display-view" ng-hide="route.parameter=='note'">{{ task.note }}</div>
<div class="edit-view" ng-show="route.parameter=='note'">
<div class="expandingArea active">
<pre><span>{{ task.note }}</span><br /><br /></pre>
<textarea ng-model="task.note"></textarea>
</div>
-->
<div class="content-fakeable">
<div class="display-view" ng-hide="route.parameter=='note'">{{ task.note }}</div>
<div class="edit-view" ng-show="route.parameter=='note'">
<div class="expandingArea active">
<pre><span>{{ task.note }}</span><br /><br /></pre>
<textarea ng-model="task.note"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<a class="detail-trash" ng-click="deleteTask(task.id)" stop-event="click">
<span class="icon detail-trash"></span>
</a>
<a class="detail-close" ng-click="closeDetails()" stop-event="click">
<span class="icon detail-close"></span>
</a>
</div>
</div>
<div class="footer">
<a class="detail-trash" ng-click="deleteTask(task.id)" stop-event="click">
<span class="icon detail-trash"></span>
</a>
<a class="detail-close" ng-click="closeDetails()" stop-event="click">
<span class="icon detail-close"></span>
</a>
</div>
</div>

View file

@ -0,0 +1,29 @@
<div id="settings_modal">
<div class="header">
<h2><?php p($l->t('Settings')); ?></h2>
<div class="button" ng-click="ok()">
<text><?php p($l->t('Done')); ?></text>
</div>
</div>
<div class="content">
<tabset justified="true">
<tab>
<tab-heading><?php p($l->t('General')); ?></tab-heading>
Allgemeine Einstellungen
</tab>
<tab>
<tab-heading><?php p($l->t('Smart Collections')); ?></tab-heading>
<text><?php p($l->t('Visibility of Smart Collections')); ?></text>
<ul>
<li ng-repeat="collection in collections">
<span class="icon collection-{{ collection.id }}"><text ng-show="collection.id=='today'"><?php p($_['DOM']); ?></text></span>
<span class="title"><text>{{ collection.displayname }}</text></span>
<span>
<select ng-change="setVisibility(collection.id)" ng-model="collection.show" ng-options="collectionOption.id as collectionOption.name for collectionOption in collectionOptions"></select>
</span>
</li>
</ul>
</tab>
</tabset>
</div>
</div>