Browse Source

Remove angular, add vue

tags/v0.10.0
Raimund Schlüßler 1 year ago
parent
commit
a4c3d96ee4
No account linked to committer's email address
54 changed files with 346 additions and 5265 deletions
  1. 14
    0
      .babelrc
  2. 1
    1
      .editorconfig
  3. 3
    1
      .jshintrc
  4. 49
    172
      Makefile
  5. 31
    62
      gulpfile.js
  6. 44
    158
      js/app/app.js
  7. 21
    15
      js/app/components/TheRouter.js
  8. 0
    83
      js/app/controllers/appcontroller.js
  9. 0
    397
      js/app/controllers/detailscontroller.js
  10. 0
    90
      js/app/controllers/settingscontroller.js
  11. 0
    456
      js/app/controllers/taskscontroller.js
  12. 0
    40
      js/app/directives/appnavigationentryutils.js
  13. 0
    27
      js/app/directives/autofocusoninsert.js
  14. 0
    35
      js/app/directives/avatar.js
  15. 0
    167
      js/app/directives/colorpickerDirective.js
  16. 0
    56
      js/app/directives/datepicker.js
  17. 0
    41
      js/app/directives/occlickfocus.js
  18. 0
    39
      js/app/directives/timepicker.js
  19. 0
    34
      js/app/filters/counterFormatter.js
  20. 0
    31
      js/app/filters/dateDetails.js
  21. 0
    31
      js/app/filters/dateDetailsShort.js
  22. 0
    31
      js/app/filters/dateFromNow.js
  23. 0
    31
      js/app/filters/dateTaskList.js
  24. 0
    31
      js/app/filters/dayTaskList.js
  25. 0
    27
      js/app/filters/percentDetails.js
  26. 0
    82
      js/app/filters/reminderDetails.js
  27. 0
    31
      js/app/filters/startDetails.js
  28. 0
    31
      js/app/filters/timeTaskList.js
  29. 26
    15
      js/app/init.js
  30. 0
    71
      js/app/services/businesslayer/listsbusinesslayer.js
  31. 0
    56
      js/app/services/businesslayer/settingsbusinesslayer.js
  32. 0
    599
      js/app/services/businesslayer/tasksbusinesslayer.js
  33. 0
    461
      js/app/services/calendarservice.js
  34. 0
    57
      js/app/services/davclient.js
  35. 0
    51
      js/app/services/loading.js
  36. 0
    138
      js/app/services/model.js
  37. 0
    289
      js/app/services/models/calendar.js
  38. 0
    91
      js/app/services/models/collectionsmodel.js
  39. 0
    194
      js/app/services/models/listsmodel.js
  40. 0
    81
      js/app/services/models/settingsmodel.js
  41. 0
    307
      js/app/services/models/vtodo.js
  42. 0
    131
      js/app/services/persistence.js
  43. 0
    56
      js/app/services/publisher.js
  44. 0
    32
      js/app/services/randomstringservice.js
  45. 0
    147
      js/app/services/request.js
  46. 0
    43
      js/app/services/status.js
  47. 0
    212
      js/app/services/vtodoservice.js
  48. 15
    5
      js/app/store.js
  49. 1
    10
      js/merged.json
  50. 56
    19
      package.json
  51. 9
    0
      test/OC.js
  52. 3
    0
      test/setup.js
  53. 57
    0
      webpack.common.js
  54. 16
    0
      webpack.prod.js

+ 14
- 0
.babelrc View File

@@ -0,0 +1,14 @@
{
"env": {
"development": {
"presets": [
["env", { "modules": false }]
]
},
"test": {
"presets": [
["env", { "targets": { "node": "current" }}]
]
}
}
}

+ 1
- 1
.editorconfig View File

@@ -7,7 +7,7 @@ end_of_line = lf
insert_final_newline = true

# Set default charset and indentation
[*.{php,js}]
[*.{php,js,scss,vue}]
charset = utf-8
indent_style = tab
tab_width = 4

+ 3
- 1
.jshintrc View File

@@ -40,6 +40,8 @@
"escapeHTML": true,
"possible": true,
"dav": true,
"OCA": true
"OCA": true,
"Vue": true,
"VueRouter": true
}
}

+ 49
- 172
Makefile View File

@@ -17,10 +17,6 @@
# * tar: for building the archive
# * npm: for building and testing everything JS
#
# If no composer.json is in the app root directory, the Composer step
# will be skipped. The same goes for the package.json which can be located in
# the app root or the js/ directory.
#
# The npm command by launches the npm build script:
#
# npm run build
@@ -29,26 +25,10 @@
#
# npm run test
#
# The idea behind this is to be completely testing and build tool agnostic. All
# build tools and additional package managers should be installed locally in
# your project, since this won't pollute people's global namespace.
#
# The following npm scripts in your package.json install and update the
# npm dependencies and use gulp as build system (notice how everything is
# run from the node_modules folder):
#
# "scripts": {
# "test": "node node_modules/gulp-cli/bin/gulp.js karma",
# "prebuild": "npm install && npm upgrade",
# "build": "node node_modules/gulp-cli/bin/gulp.js"
# },

app_name=$(notdir $(CURDIR))
build_tools_directory=$(CURDIR)/build/tools
source_build_directory=$(CURDIR)/build/source/tasks
source_artifact_directory=$(CURDIR)/build/artifacts/source
source_package_name=$(source_artifact_directory)/$(app_name)
appstore_build_directory=$(CURDIR)/build/appstore/tasks
build_directory=$(CURDIR)/build
appstore_build_directory=$(CURDIR)/build/appstore/$(app_name)
appstore_artifact_directory=$(CURDIR)/build/artifacts/appstore
appstore_package_name=$(appstore_artifact_directory)/$(app_name)
npm=$(shell which npm 2> /dev/null)
@@ -71,12 +51,12 @@ private_key=$(HOME)/.nextcloud/$(app_name).key
certificate=$(HOME)/.nextcloud/$(app_name).crt
sign=php -f $(occ) integrity:sign-app --privateKey="$(private_key)" --certificate="$(certificate)"
sign_skip_msg="Skipping signing, either no key and certificate found in $(private_key) and $(certificate) or occ can not be found at $(occ)"
ifneq (,$(wildcard $(private_key)))
ifneq (,$(wildcard $(certificate)))
ifneq (,$(wildcard $(occ)))
CAN_SIGN=true
endif
endif
ifneq ("$(wildcard $(private_key))","") #(,$(wildcard $(private_key)))
ifneq ("$(wildcard $(certificate))","")#(,$(wildcard $(certificate)))
ifneq ("$(wildcard $(occ))","")#(,$(wildcard $(occ)))
CAN_SIGN=true
endif
endif
endif

all: build
@@ -86,160 +66,67 @@ all: build
# is present, the npm step is skipped
.PHONY: build
build:
make npm

# Installs npm dependencies
.PHONY: npm
npm:
$(npm) run build

# Removes the appstore build
# Sets up the development environment
.PHONY: development
development:
$(npm) install
$(npm) update
$(npm) run development

# Removes the build directory and the compiled files
.PHONY: clean
clean:
rm -rf ./build
rm -f ./css/style.scss
rm -f ./css/src/sprites.scss
rm -f ./img/sprites.svg
rm -f ./js/public/build.js
rm -f ./js/public/build.js.map
rm -rf $(build_directory)

# Same as clean but also removes dependencies installed by npm
.PHONY: distclean
distclean: clean
rm -rf vendor
rm -rf node_modules
rm -rf js/vendor
rm -rf js/node_modules

# Builds the source and appstore package
.PHONY: dist
dist:
make source
make appstore

# Run make and make dist in a Docker container
.PHONY: docker-dist
docker-dist:
docker run --rm -it -v $(CURDIR):/tasks -w /tasks node make docker-target
# Watches the js and scss files
.PHONY: watch
watch:
$(npm) run watch

# Command used inside Docker container; do not invoke directly
.PHONY: docker-target
docker-target:
which rsync zip openssl || (apt-get update && apt-get install -y rsync zip openssl)
make
make dist

# Builds the source package
.PHONY: source
source:
rm -rf $(source_build_directory) $(source_artifact_directory)
mkdir -p $(source_build_directory) $(source_artifact_directory)
rsync -rv . $(source_build_directory) \
--exclude=/.git/ \
--exclude=/.idea/ \
--exclude=/build/ \
--exclude=/js/node_modules/ \
--exclude=/node_modules/ \
--exclude=*.log
ifdef CAN_SIGN
$(sign) --path "$(source_build_directory)"
else
@echo $(sign_skip_msg)
endif
tar -cvzf $(source_package_name).tar.gz -C $(source_build_directory)/../ $(app_name)

# Builds the source package for the app store, ignores php and js tests
# Builds the source package for the app store
.PHONY: appstore
appstore:
rm -rf $(appstore_build_directory) $(appstore_artifact_directory)
appstore: clean build
mkdir -p $(appstore_build_directory) $(appstore_artifact_directory)
rsync -av . $(appstore_build_directory) \
--exclude=/tests \
--exclude=/.git \
--exclude=/.idea \
--exclude=/.babelrc \
--exclude=/.editorconfig \
--exclude=/.gitattributes \
--exclude=/.gitignore \
--exclude=/.scrutinizer.yml \
--exclude=/.travis.yml \
--exclude=/.tx \
--exclude=/build.xml \
--exclude=/.gitlab-ci.yml \
--exclude=/.jshintrc \
--exclude=/.stylelintrc \
--exclude=/.v8flags*.json \
--exclude=/CONTRIBUTING.md \
--exclude=/tasks.sublime-project \
--exclude=/tasks.sublime-workspace \
--exclude=/issue_template.md \
--exclude=/gulpfile.js \
--exclude=/Makefile \
--exclude=/phpunit.xml \
--exclude=/package-lock.json \
--exclude=/package.json \
--exclude=/README.md \
--exclude=/CHANGELOG.md \
--exclude=/webpack.common.js \
--exclude=/webpack.prod.js \
--exclude=/webpack.test.js \
--exclude=/.nyc_output/ \
--exclude=/build \
--exclude=/coverage \
--exclude=/css/src \
--exclude=/img/src \
--exclude=/.jshintrc \
--exclude=/.stylelintrc \
--exclude=/gulpfile.js \
--exclude=/node_modules \
--exclude=/package.json \
--exclude=/package-lock.json \
--exclude=/js/README.md \
--exclude=/js/README.mkdir \
--exclude=/js/app \
--exclude=/js/config \
--exclude=/js/vendor/**/.bower.json \
--exclude=/js/vendor/**/.npmignore \
--exclude=/js/vendor/**/bower.json \
--exclude=/js/vendor/**/Gruntfile.js \
--exclude=/js/vendor/**/package.json \
--exclude=/js/vendor/**/*.md \
--exclude=/js/vendor/**/karma.conf.js \
--exclude=/js/vendor/**/*.map \
--exclude=/js/vendor/angular-mocks \
--exclude=/js/vendor/angular/angular.js \
--exclude=/js/vendor/angular/angular.min.js.gzip \
--exclude=/js/vendor/angular/angular-csp.css \
--exclude=/js/vendor/angular/index.js \
--exclude=/js/vendor/angular-animate/angular-animate.js \
--exclude=/js/vendor/angular-animate/index.js \
--exclude=/js/vendor/angular-drag-and-drop-lists/angular-drag-and-drop-lists.js \
--exclude=/js/vendor/angular-drag-and-drop-lists/demo \
--exclude=/js/vendor/angular-drag-and-drop-lists/test \
--exclude=/js/vendor/angular-drag-and-drop-lists/LICENSE \
--exclude=/js/vendor/angular-route/angular-route.js \
--exclude=/js/vendor/angular-route/index.js \
--exclude=/js/vendor/angular-sanitize/angular-sanitize.js \
--exclude=/js/vendor/angular-sanitize/index.js \
--exclude=/js/vendor/angular-ui-select/dist/select.js \
--exclude=/js/vendor/angular-ui-select/dist/select.css \
--exclude=/js/vendor/angular-ui-select/docs \
--exclude=/js/vendor/angular-ui-select/composer.json \
--exclude=/js/vendor/angular-ui-select/deploy-docs.sh \
--exclude=/js/vendor/ical.js/build/benchmark \
--exclude=/js/vendor/ical.js/build/ical.js \
--exclude=/js/vendor/ical.js/lib \
--exclude=/js/vendor/ical.js/samples \
--exclude=/js/vendor/ical.js/sandbox \
--exclude=/js/vendor/ical.js/tasks \
--exclude=/js/vendor/ical.js/test-agent \
--exclude=/js/vendor/ical.js/test-agent-server.js \
--exclude=/js/vendor/ical.js/test-agent-coverage.json \
--exclude=/js/vendor/jstimezonedetect/dist/jstz.js \
--exclude=/js/vendor/jstimezonedetect/LICENCE.txt \
--exclude=/js/vendor/ui-select/dist/select.js \
--exclude=/js/vendor/ui-select/dist/select.css \
--exclude=/js/vendor/ui-select/docs \
--exclude=/js/vendor/ui-select/src \
--exclude=/js/vendor/ui-select/test \
--exclude=/js/vendor/ui-select/composer.json \
--exclude=/js/vendor/ui-select/deploy-docs.sh \
--exclude=/js/vendor/ui-select/*.js \
--exclude=/js/vendor/ui-select/LICENSE \
--exclude=/js/vendor_legacy/jquery-timepicker/i18n \
--exclude=/js/vendor_legacy/jquery-timepicker/include \
--exclude=/js/vendor_legacy/jquery-timepicker/legacy_1.2.6 \
--exclude=/js/vendor_legacy/jquery-timepicker/tests \
--exclude=/js/vendor_legacy/jquery-timepicker/index.html \
--exclude=/js/vendor_legacy/jquery-timepicker/jquery.ui.timepicker.css \
--exclude=/js/vendor_legacy/jquery-timepicker/GPL-LICENSE.txt \
--exclude=/js/vendor_legacy/jquery-timepicker/MIT-LICENSE.txt \
--exclude=/js/vendor_legacy/jquery-timepicker/README.md \
--exclude=/js/vendor_legacy/jquery-timepicker/timepicker.png \
--exclude=/screenshots \
--exclude=/timezones/INFO.md
--exclude=/node_modules \
--exclude=/screenshots/ \
--exclude=/test
ifdef CAN_SIGN
mv $(configdir)/config.php $(configdir)/config-2.php
$(sign) --path="$(appstore_build_directory)"
@@ -250,24 +137,14 @@ endif
cd $(appstore_build_directory)/../; \
zip -r $(appstore_package_name).zip $(app_name)
tar -czf $(appstore_package_name).tar.gz -C $(appstore_build_directory)/../ $(app_name)
# create hash
ifdef CAN_SIGN
openssl dgst -sha512 -sign $(private_key) $(appstore_package_name).tar.gz | openssl base64 -out $(appstore_artifact_directory)/$(app_name).sha512
else
@echo "Skipping hashing, no key found in $(private_key)."
endif


# Command for running JS and PHP tests. Works for package.json files in the js/
# and root directory. If phpunit is not installed systemwide, a copy is fetched
# from the internet
# Command for running VUE tests
.PHONY: test
test:
cd js && $(npm) run test
ifeq (, $(shell which phpunit 2> /dev/null))
@echo "No phpunit command available, downloading a copy from the web"
mkdir -p $(build_tools_directory)
curl -sSL https://phar.phpunit.de/phpunit.phar -o $(build_tools_directory)/phpunit.phar
php $(build_tools_directory)/phpunit.phar -c phpunit.xml --coverage-clover build/php-unit.clover
php $(build_tools_directory)/phpunit.phar -c phpunit.integration.xml --coverage-clover build/php-integration.clover
else
phpunit -c phpunit.xml --coverage-clover build/php-unit.clover
phpunit -c phpunit.integration.xml --coverage-clover build/php-unit.clover
endif
$(npm) run test

+ 31
- 62
gulpfile.js View File

@@ -1,5 +1,5 @@
/**
* Nextcloud - Inventory
* Nextcloud - Tasks
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
@@ -19,35 +19,31 @@

// get plugins
const gulp = require('gulp'),
uglify = require('gulp-uglify'),
jshint = require('gulp-jshint'),
KarmaServer = require('karma').Server,
concat = require('gulp-concat'),
wrap = require('gulp-wrap'),
strip = require('gulp-strip-banner'),
babel = require('gulp-babel'),
stylelint = require('gulp-stylelint'),
sourcemaps = require('gulp-sourcemaps'),
svgSprite = require('gulp-svg-sprite'),
npmFiles = require('gulp-npm-files');
webpackStream = require('webpack-stream'),
webpackDevelopmentConfig = require('./webpack.common.js'),
webpackProductionConfig = require('./webpack.prod.js');

// configure
const buildTarget = 'app.min.js';
const scssBuildTarget = 'style.scss';
const karmaConfig = __dirname + '/tests/js/config/karma.js';
const destinationFolder = __dirname + '/js/public/';
const scssBuildTarget = 'style.scss';
const scssDestinationFolder = __dirname + '/css/';

const jsSources = [
'./js/app/**/*.js'
'js/app/**/*.js'
];
const scssSources = [
'./css/src/*.scss'
'css/src/*.scss'
];
const testSources = [
'test/**/*.js'
];

const testSources = ['./tests/js/unit/**/*.js'];
const lintSources = jsSources.concat(testSources).concat(['*.js']);
const watchSources = lintSources;
const watchSources = jsSources.concat(['js/app/**/*.vue']);

const svgConfig = {
shape: {
@@ -62,7 +58,7 @@ const svgConfig = {
sprite: "../img/sprites.svg",
render: {
scss: {
dest: "src/sprite.scss"
dest: "src/sprites.scss"
}
}
}
@@ -70,31 +66,27 @@ const svgConfig = {
};

// tasks
gulp.task('build', ['lint'], () => {

return gulp.src(jsSources)
.pipe(babel({
presets: ['es2015'],
compact: false,
babelrc: false,
ast: false
}))
.pipe(strip())
.pipe(sourcemaps.init({identityMap: true}))
.pipe(concat(buildTarget))
.pipe(wrap(`(function($, oc_requesttoken, undefined){
'use strict';

<%= contents %>
})(jQuery, oc_requesttoken);`))
.pipe(uglify())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(destinationFolder));

gulp.task('default', ['build']);

gulp.task('build', ['lint', 'scssConcat'], function(callback) {
return webpackStream(webpackProductionConfig, require('webpack'))
.pipe(gulp.dest(destinationFolder));
});

gulp.task('development', ['lint', 'scssConcat'], function(callback) {
return webpackStream(webpackDevelopmentConfig, require('webpack'))
.pipe(gulp.dest(destinationFolder));
});

gulp.task('default', ['build', 'vendor', 'scsslint', 'scssConcat']);
gulp.task('jsWatch', ['jslint'], function(callback) {
return webpackStream(webpackDevelopmentConfig, require('webpack'))
.pipe(gulp.dest(destinationFolder));
});

gulp.task('lint', () => {
gulp.task('lint', ['jslint', 'scsslint']);

gulp.task('jslint', () => {
return gulp.src(lintSources)
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('default'))
@@ -124,35 +116,12 @@ gulp.task('scssConcatWatch', ['scsslint'], () => {
});

gulp.task('watch', () => {
gulp.watch(watchSources, ['build']);
gulp.watch(watchSources, ['jsWatch']);
gulp.watch(scssSources, ['scssConcatWatch']);
});

gulp.task('karma', (done) => {
new KarmaServer({
configFile: karmaConfig,
singleRun: true,
browsers: ['Firefox'],
reporters: ['progress', 'coverage']
}, done).start();
});

gulp.task('watch-karma', (done) => {
new KarmaServer({
configFile: karmaConfig,
autoWatch: true,
browsers: ['Firefox'],
reporters: ['progress', 'coverage']
}, done).start();
});

gulp.task('svg_sprite', () => {
return gulp.src('**/*.svg', {cwd: 'img/src'})
.pipe(svgSprite(svgConfig))
.pipe(gulp.dest('.'));
});

gulp.task("vendor", () => {
return gulp.src(npmFiles(), { base: "./node_modules" })
.pipe(gulp.dest('./js/vendor'));
});

+ 44
- 158
js/app/app.js View File

@@ -18,168 +18,54 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
'use strict';

$('#content.app-tasks').attr('ng-app', 'Tasks');
$('#content.app-tasks').attr('ng-cloak');
$('#content.app-tasks').attr('ng-controller', 'AppController');
$('#content.app-tasks').attr('ng-click', 'closeAll($event)');
$('#content.app-tasks').addClass('handler');
import Vue from 'vue';
import Vuex from 'vuex';
import { mapState } from 'vuex';
import VueRouter from 'vue-router';

angular.module('Tasks', ['ngRoute', 'ngAnimate', 'ui.select', 'ngSanitize', 'dndLists']).config([
'$provide', '$routeProvider', '$interpolateProvider', '$httpProvider',
function($provide, $routeProvider, $interpolateProvider, $httpProvider) {
'use strict';
var config;
$provide.value('Config', config = {
markReadTimeout: 500,
taskUpdateInterval: 1000 * 600
});
$httpProvider.defaults.headers.common.requesttoken = oc_requesttoken;
$routeProvider
.when('/calendars/:calendarID', {})
.when('/calendars/:calendarID/edit/:listparameter', {})
.when('/calendars/:calendarID/tasks/:taskID', {})
.when('/calendars/:calendarID/tasks/:taskID/settings', {})
.when('/calendars/:calendarID/tasks/:taskID/edit/:parameter', {})
.when('/collections/:collectionID/tasks/:taskID', {})
.when('/collections/:collectionID/tasks/:taskID/settings', {})
.when('/collections/:collectionID/tasks/:taskID/edit/:parameter', {})
.when('/collections/:collectionID', {})
.when('/search/:searchString', {})
.when('/search/:searchString/tasks/:taskID', {})
.when('/search/:searchString/tasks/:taskID/edit/:parameter', {})
.otherwise({
redirectTo: '/collections/all'
});
}
]);
import router from './components/TheRouter.js';
import store from './store';

angular.module('Tasks').run([
'$document', '$rootScope', 'Config', '$timeout', 'ListsBusinessLayer', 'TasksBusinessLayer', 'SearchBusinessLayer',
function($document, $rootScope, Config, $timeout, TasksBusinessLayer, ListsBusinessLayer, SearchBusinessLayer) {
'use strict';
var update;
var init = false;
(update = function() {
var timeOutUpdate;
timeOutUpdate = function() {
return $timeout(update, Config.taskUpdateInterval);
};
init = true;
return timeOutUpdate();
}).call();
OCA.Search.tasks = SearchBusinessLayer;
$document.click(function(event) {
$rootScope.$broadcast('documentClicked', event);
});
moment.locale('details', {
calendar: {
lastDay: '[' + t('tasks', 'Due yesterday') + '], HH:mm',
sameDay: '[' + t('tasks', 'Due today') + '], HH:mm',
nextDay: '[' + t('tasks', 'Due tomorrow') + '], HH:mm',
lastWeek: '[' + t('tasks', 'Due on') + '] MMM DD, YYYY, HH:mm',
nextWeek: '[' + t('tasks', 'Due on') + '] MMM DD, YYYY, HH:mm',
sameElse: '[' + t('tasks', 'Due on') + '] MMM DD, YYYY, HH:mm'
}
});
moment.locale('details_allday', {
calendar: {
lastDay: '[' + t('tasks', 'Due yesterday') + ']',
sameDay: '[' + t('tasks', 'Due today') + ']',
nextDay: '[' + t('tasks', 'Due tomorrow') + ']',
lastWeek: '[' + t('tasks', 'Due on') + '] MMM DD, YYYY',
nextWeek: '[' + t('tasks', 'Due on') + '] MMM DD, YYYY',
sameElse: '[' + t('tasks', 'Due on') + '] MMM DD, YYYY'
}
});
moment.locale('start', {
calendar: {
lastDay: '[' + t('tasks', 'Started yesterday') + '], HH:mm',
sameDay: '[' + t('tasks', 'Starts today') + '], HH:mm',
nextDay: '[' + t('tasks', 'Starts tomorrow') + '], HH:mm',
lastWeek: '[' + t('tasks', 'Started on') + '] MMM DD, YYYY, HH:mm',
nextWeek: '[' + t('tasks', 'Starts on') + '] MMM DD, YYYY, HH:mm',
sameElse: function() {
if (this.diff(moment()) > 0) {
return '[' + t('tasks', 'Starts on') + '] MMM DD, YYYY, HH:mm';
} else {
return '[' + t('tasks', 'Started on') + '] MMM DD, YYYY, HH:mm';
}
}
}
});
moment.locale('start_allday', {
calendar: {
lastDay: '[' + t('tasks', 'Started yesterday') + ']',
sameDay: '[' + t('tasks', 'Starts today') + ']',
nextDay: '[' + t('tasks', 'Starts tomorrow') + ']',
lastWeek: '[' + t('tasks', 'Started on') + '] MMM DD, YYYY',
nextWeek: '[' + t('tasks', 'Starts on') + '] MMM DD, YYYY',
sameElse: function() {
if (this.diff(moment()) > 0) {
return '[' + t('tasks', 'Starts on') + '] MMM DD, YYYY';
} else {
return '[' + t('tasks', 'Started on') + '] MMM DD, YYYY';
Vue.prototype.OC = OC;
Vue.prototype.t = t;
Vue.prototype.n = n;

export class App {
start() {
OCA.Tasks.App.Vue = new Vue({
el: '.app-tasks',
router: router,
store: store,
data: {
active: 'items',
searchString: '',
snap: false,
views: [
{
name: t('tasks', 'Collections'),
id: "collections"
},
{
name: t('tasks', 'Calendars'),
id: "calendars"
}
]
},
methods: {
filter(query) {
this.searchString = query;
},
cleanSearch() {
this.searchString = '';
}
}
});
moment.locale('reminder', {
calendar: {
lastDay: t('tasks', '[Remind me yesterday at ]HH:mm'),
sameDay: t('tasks', '[Remind me today at ]HH:mm'),
nextDay: t('tasks', '[Remind me tomorrow at ]HH:mm'),
lastWeek: t('tasks', '[Remind me on ]MMM DD, YYYY,[ at ]HH:mm'),
nextWeek: t('tasks', '[Remind me on ]MMM DD, YYYY,[ at ]HH:mm'),
sameElse: t('tasks', '[Remind me on ]MMM DD, YYYY,[ at ]HH:mm')
}
});
moment.locale('tasks', {
calendar: {
lastDay: '[' + t('tasks', 'Yesterday') + ']',
sameDay: '[' + t('tasks', 'Today') + ']',
nextDay: '[' + t('tasks', 'Tomorrow') + ']',
lastWeek: 'DD.MM.YYYY',
nextWeek: 'DD.MM.YYYY',
sameElse: 'DD.MM.YYYY'
}
});
moment.locale('details_short', {
calendar: {
lastDay: '[' + t('tasks', 'Yesterday') + ']',
sameDay: '[' + t('tasks', 'Today') + ']',
nextDay: '[' + t('tasks', 'Tomorrow') + ']',
lastWeek: 'MMM DD, YYYY',
nextWeek: 'MMM DD, YYYY',
sameElse: 'MMM DD, YYYY'
}
});
moment.locale('list_week', {
calendar: {
lastDay: '[' + t('tasks', 'Yesterday') + ']',
sameDay: '[' + t('tasks', 'Today') + '], MMM. DD',
nextDay: '[' + t('tasks', 'Tomorrow') + '], MMM. DD',
lastWeek: 'ddd, MMM. DD',
nextWeek: 'ddd, MMM. DD',
sameElse: 'ddd, MMM. DD'
}
});
return moment.locale('en', {
relativeTime: {
future: t('tasks', "in %s"),
past: t('tasks', "%s ago"),
s: t('tasks', "seconds"),
m: t('tasks', "a minute"),
mm: t('tasks', "%d minutes"),
h: t('tasks', "an hour"),
hh: t('tasks', "%d hours"),
d: t('tasks', "a day"),
dd: t('tasks', "%d days"),
M: t('tasks', "a month"),
MM: t('tasks', "%d months"),
y: t('tasks', "a year"),
yy: t('tasks', "%d years")
}
},
computed: mapState({
showModal: state => state.showModal
})
});

store.dispatch('loadItems');
}
]);
}

js/app/filters/priorityDetails.js → js/app/components/TheRouter.js View File

@@ -19,20 +19,26 @@
*
*/

import Vue from "vue";
import VueRouter from "vue-router";

angular.module('Tasks').filter('priorityDetails', function() {
'use strict';
return function(priority) {
var string;
string = t('tasks', 'priority %s: ').replace('%s', priority);
if (+priority === 6 || +priority === 7 || +priority === 8 || +priority === 9) {
return string + ' ' + t('tasks', 'high');
} else if (+priority === 5) {
return string + ' ' + t('tasks', 'medium');
} else if (+priority === 1 || +priority === 2 || +priority === 3 || +priority === 4) {
return string + ' ' + t('tasks', 'low');
} else {
return t('tasks', 'no priority assigned');
}
};
import Collections from "./TheCollections.vue";
import ItemsNew from "./TheItemsCreator.vue";

const routes = [
// using
// { path: '/collections', component: Collections, alias: '/' },
// instead of
{ path: '/', redirect: '/collections' },
{ path: '/collections', component: Collections},
// would also be an option, but it currently does not work
// reliably with router-link due to
// https://github.com/vuejs/vue-router/issues/419
{ path: '/calendars/:id', component: Calendars, props: true},
];

Vue.use(VueRouter);

export default new VueRouter({
routes, // short for `routes: routes`
});

+ 0
- 83
js/app/controllers/appcontroller.js View File

@@ -1,83 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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('AppController', [
'$scope', '$rootScope', 'ListsBusinessLayer', '$route', 'Status', '$timeout', '$location', '$routeParams', 'Loading', 'SettingsModel', 'Persistence', function($scope, $rootScope, ListsBusinessLayer, $route, status, $timeout, $location, $routeParams, Loading, SettingsModel, Persistence) {
'use strict';
var AppController = (function() {
function AppController(_$scope, $rootScope, _$listsbusinesslayer, _$route, _$status, _$timeout, _$location, _$routeparams, _Loading, _$settingsmodel, _persistence) {
this._$scope = _$scope;
this._$listsbusinesslayer = _$listsbusinesslayer;
this._$route = _$route;
this._$status = _$status;
this._$timeout = _$timeout;
this._$location = _$location;
this._$routeparams = _$routeparams;
this._Loading = _Loading;
this._$settingsmodel = _$settingsmodel;
this._persistence = _persistence;
this._$scope.status = this._$status.getStatus();
this._$scope.route = this._$routeparams;
this._$scope.status.newListName = "";
this._$scope.settingsmodel = this._$settingsmodel;

this._$listsbusinesslayer.init().then(function(results) {
Promise.all(results).then(function() {
$scope.$apply();
});
});

this._persistence.init();

this._$scope.closeAll = function($event) {
if ($($event.target).closest('.close-all').length || $($event.currentTarget).is($($event.target).closest('.handler'))) {
if (!angular.isUndefined(_$scope.route.calendarID)) {
if (_$scope.route.listparameter === 'name') {
$rootScope.$broadcast('cancelEditCalendar', _$scope.route.calendarID);
}
_$location.path('/calendars/' + _$scope.route.calendarID);
} else if (!angular.isUndefined(_$scope.route.collectionID)) {
_$location.path('/collections/' + _$scope.route.collectionID);
} else {
_$location.path('/collections/all');
}
_$scope.status.addingList = false;
_$scope.status.focusTaskInput = false;
_$scope.status.newListName = "";
}
if (!$($event.target).closest('.newList').length) {
_$scope.status.addingList = false;
_$scope.status.newListName = "";
}
if (!$($event.target).closest('.add-subtask').length) {
_$scope.status.addSubtaskTo = null;
_$scope.status.focusSubtaskInput = false;
}
};
this._$scope.isLoading = function() {
return _Loading.isLoading();
};
}
return AppController;
})();
return new AppController($scope, $rootScope, ListsBusinessLayer, $route, status, $timeout, $location, $routeParams, Loading, SettingsModel, Persistence);
}
]);

+ 0
- 397
js/app/controllers/detailscontroller.js View File

@@ -1,397 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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('DetailsController', [
'$scope', '$window', 'TasksModel', 'TasksBusinessLayer', '$route', '$location', '$timeout', '$routeParams', 'SettingsModel', 'Loading', 'ListsModel',
function($scope, $window, TasksModel, TasksBusinessLayer, $route, $location, $timeout, $routeParams, SettingsModel, Loading, ListsModel) {
'use strict';
var DetailsController = (function() {
function DetailsController(_$scope, _$window, _$tasksmodel,
_tasksbusinesslayer, _$route, _$location, _$timeout, _$routeparams, _$settingsmodel, _Loading, _$listsmodel) {
this._$scope = _$scope;
this._$window = _$window;
this._$tasksmodel = _$tasksmodel;
this._$listsmodel = _$listsmodel;
this._tasksbusinesslayer = _tasksbusinesslayer;
this._$route = _$route;
this._$location = _$location;
this._$timeout = _$timeout;
this._$routeparams = _$routeparams;
this._$settingsmodel = _$settingsmodel;
this._Loading = _Loading;
this._$scope.task = _$tasksmodel.getById(_$scope.route.taskID);
this._$scope.found = true;
this._$scope.$on('$routeChangeSuccess', function() {
var task = _$tasksmodel.getByUri(_$scope.route.taskID);

if (!(angular.isUndefined(task) || task === null)) {
_$scope.task = task;
// Bind categories to task.cats as angular.ui/ui-select seems to have problems with Getter/Setter
_$scope.task.cats = task.categories;
_$scope.found = true;
} else if (_$scope.route.taskID !== void 0) {
_$scope.found = false;
}
});

this._$scope.settingsmodel = this._$settingsmodel;
this._$scope.settingsmodel.add({
'id': 'various',
'categories': []
});
this._$scope.isAddingComment = false;
this._$scope.timers = [];
this._$scope.durations = [{
name: t('tasks', 'week'),
names: t('tasks', 'weeks'),
id: 'week'
}, {
name: t('tasks', 'day'),
names: t('tasks', 'days'),
id: 'day'
}, {
name: t('tasks', 'hour'),
names: t('tasks', 'hours'),
id: 'hour'
}, {
name: t('tasks', 'minute'),
names: t('tasks', 'minutes'),
id: 'minute'
}, {
name: t('tasks', 'second'),
names: t('tasks', 'seconds'),
id: 'second'
}
];
this._$scope.loadTask = function(taskID) {
var task = _$tasksmodel.getByUri(_$scope.route.taskID);
if (!(angular.isUndefined(task) || task === null)) {
_$scope.task = task;
_$scope.found = true;
}
};
this._$scope.TaskState = function() {
if (_$scope.found) {
return 'found';
} else {
if (_Loading.isLoading()) {
return 'loading';
} else {
return null;
}
}
};
this._$scope.params = [
{
name: t('tasks', 'before beginning'),
invert: true,
related: 'START',
id: "10"
}, {
name: t('tasks', 'after beginning'),
invert: false,
related: 'START',
id: "00"
}, {
name: t('tasks', 'before end'),
invert: true,
related: 'END',
id: "11"
}, {
name: t('tasks', 'after end'),
invert: false,
related: 'END',
id: "01"
}
];
this._$scope.filterParams = function(params) {
var task;
task = _$tasksmodel.getById(_$scope.route.taskID);
if (!(angular.isUndefined(task) || task === null)) {
if (task.due && task.start) {
return params;
} else if (task.start) {
return params.slice(0, 2);
} else {
return params.slice(2);
}
}
};
this._$scope.deleteTask = function(task) {
return _$timeout(function() {
return _tasksbusinesslayer.deleteTask(task).then(function () {
return $scope.$apply();
});
}, 500);
};
this._$scope.triggerUpdate = function(task) {
_tasksbusinesslayer.triggerUpdate(task);
};
this._$scope.editName = function($event, task) {
if (task.calendar.writable) {
if (!$($event.target).is('a')) {
_$scope.setEditRoute('name');
}
}
};
this._$scope.editDueDate = function($event, task) {
if (task.calendar.writable) {
if ($($event.currentTarget).is($($event.target).closest('.handler'))) {
_$scope.setEditRoute('duedate');
_tasksbusinesslayer.initDueDate(task);
}
}
};
this._$scope.editStart = function($event, task) {
if (task.calendar.writable) {
if ($($event.currentTarget).is($($event.target).closest('.handler'))) {
_$scope.setEditRoute('startdate');
_tasksbusinesslayer.initStartDate(task);
}
}
};
this._$scope.editReminder = function($event, task) {
if (task.calendar.writable) {
if ($($event.currentTarget).is($($event.target).closest('.handler'))) {
_$scope.setEditRoute('reminer');
return _tasksbusinesslayer.initReminder(_$scope.route.taskID);
}
}
};
this._$scope.editNote = function($event, task) {
if (task.calendar.writable) {
if ($($event.currentTarget).is($($event.target).closest('.handler'))) {
if (!$($event.target).is('a')) {
_$scope.setEditRoute('note');
}
}
}
};
this._$scope.editPriority = function($event, task) {
if (task.calendar.writable) {
if ($($event.currentTarget).is($($event.target).closest('.handler'))) {
_$scope.setEditRoute('priority');
}
}
};
this._$scope.editPercent = function($event, task) {
if (task.calendar.writable) {
if ($($event.currentTarget).is($($event.target).closest('.handler'))) {
_$scope.setEditRoute('percent');
}
}
};
this._$scope.endEdit = function($event) {
if ($($event.target).closest('.end-edit').length || $($event.currentTarget).is($($event.target).closest('.handler'))) {
_$scope.resetRoute();
}
};
this._$scope.endName = function($event) {
if ($event.keyCode === 13) {
$event.preventDefault();
_$scope.resetRoute();
}
if ($event.keyCode === 27) {
return _$scope.resetRoute();
}
};

this._$scope.setEditRoute = function(type) {
var calendarID = _$scope.route.calendarID;
var collectionID = _$scope.route.collectionID;
if (calendarID) {
$location.path('/calendars/' + calendarID + '/tasks/' + _$scope.route.taskID + '/edit/' + type);
} else if (collectionID) {
$location.path('/collections/' + collectionID + '/tasks/' + _$scope.route.taskID + '/edit/' + type);
}
};

this._$scope.resetRoute = function() {
var calendarID = _$scope.route.calendarID;
var collectionID = _$scope.route.collectionID;
if (calendarID) {
$location.path('/calendars/' + calendarID + '/tasks/' + _$scope.route.taskID);
} else if (collectionID) {
$location.path('/collections/' + collectionID + '/tasks/' + _$scope.route.taskID);
}
};
this._$scope.deletePercent = function(task) {
return _tasksbusinesslayer.setPercentComplete(task, 0);
};
this._$scope.deleteReminder = function() {
return _tasksbusinesslayer.deleteReminderDate(_$scope.route.taskID);
};

this._$scope.toggleCompleted = function(task) {
if (task.completed) {
_tasksbusinesslayer.setPercentComplete(task, 0);
} else {
_tasksbusinesslayer.setPercentComplete(task, 100);
}
};

this._$scope.setPercentComplete = function(task, complete) {
_tasksbusinesslayer.setPercentComplete(task, complete);
};

this._$scope.toggleStarred = function(task) {
if (task.priority > 5) {
_tasksbusinesslayer.setPriority(task, 0);
} else {
_tasksbusinesslayer.setPriority(task, 9);
}
};

this._$scope.deletePriority = function(task) {
return _tasksbusinesslayer.setPriority(task, 0);
};
this._$scope.isDue = function(date) {
return _$tasksmodel.due(date);
};
this._$scope.isOverDue = function(date) {
return _$tasksmodel.overdue(date);
};

this._$scope.setstartday = function(date) {
return _tasksbusinesslayer.setStart(_$scope.task, moment(date, 'MM/DD/YYYY'), 'day');
};
this._$scope.setstarttime = function(date) {
return _tasksbusinesslayer.setStart(_$scope.task, moment(date, 'HH:mm'), 'time');
};
this._$scope.deleteStartDate = function(task) {
_tasksbusinesslayer.deleteStartDate(task);
};

this._$scope.setdueday = function(date) {
return _tasksbusinesslayer.setDue(_$scope.task, moment(date, 'MM/DD/YYYY'), 'day');
};
this._$scope.setduetime = function(date) {
return _tasksbusinesslayer.setDue(_$scope.task, moment(date, 'HH:mm'), 'time');
};
this._$scope.deleteDueDate = function(task) {
_tasksbusinesslayer.deleteDueDate(task);
};

this._$scope.isAllDayPossible = function(task) {
return !angular.isUndefined(task) && task.calendar.writable && (task.due || task.start);
};
this._$scope.toggleAllDay = function(task) {
_tasksbusinesslayer.setAllDay(task, !task.allDay);
};

this._$scope.setreminderday = function(date) {
return _tasksbusinesslayer.setReminderDate(_$scope.route.taskID, moment(date, 'MM/DD/YYYY'), 'day');
};
this._$scope.setremindertime = function(date) {
return _tasksbusinesslayer.setReminderDate(_$scope.route.taskID, moment(date, 'HH:mm'), 'time');
};
this._$scope.reminderType = function(task) {
if (!angular.isUndefined(task)) {
if (task.reminder === null) {
if (moment(task.start, "YYYYMMDDTHHmmss").isValid() || moment(task.due, "YYYYMMDDTHHmmss").isValid()) {
return 'DURATION';
} else {
return 'DATE-TIME';
}
} else {
return task.reminder.type;
}
}
};
this._$scope.changeReminderType = function(task) {
_tasksbusinesslayer.checkReminderDate(task.id);
if (this.reminderType(task) === 'DURATION') {
if (task.reminder) {
task.reminder.type = 'DATE-TIME';
} else {
task.reminder = {
type: 'DATE-TIME'
};
}
} else {
if (task.reminder) {
task.reminder.type = 'DURATION';
} else {
task.reminder = {
type: 'DURATION'
};
}
}
return _tasksbusinesslayer.setReminder(task.id);
};
this._$scope.setReminderDuration = function(taskID) {
return _tasksbusinesslayer.setReminder(_$scope.route.taskID);
};
this._$scope.addComment = function() {
var comment,
_this = this;
if (_$scope.CommentContent) {
_$scope.isAddingComment = true;
comment = {
tmpID: 'newComment' + Date.now(),
comment: _$scope.CommentContent,
taskID: _$scope.route.taskID,
time: moment().format('YYYYMMDDTHHmmss'),
name: $('#expandDisplayName').text()
};
_tasksbusinesslayer.addComment(comment, function(data) {
_$tasksmodel.updateComment(data);
_$scope.isAddingComment = false;
}, function() {
_$scope.isAddingComment = false;
});
_$scope.CommentContent = '';
}
};
this._$scope.sendComment = function(event) {
if (event.keyCode === 13) {
return _$scope.addComment();
}
};
this._$scope.deleteComment = function(commentID) {
return _tasksbusinesslayer.deleteComment(_$scope.route.taskID, commentID);
};
this._$scope.commentStrings = function() {
return {
button: t('tasks', 'Comment'),
input: t('tasks', 'Add a comment')
};
};
this._$scope.addCategory = function(category, model) {
_$scope.task.categories = _$scope.task.cats;
var default_categories = _$scope.settingsmodel.getById('various').categories;
if (default_categories.indexOf(category) < 0) {
default_categories.push(category);
}
_tasksbusinesslayer.doUpdate(_$scope.task);
};
this._$scope.removeCategory = function(category, model) {
_$scope.task.categories = _$scope.task.cats;
_tasksbusinesslayer.doUpdate(_$scope.task);
};
}

return DetailsController;

})();
return new DetailsController($scope, $window, TasksModel, TasksBusinessLayer, $route, $location, $timeout, $routeParams, SettingsModel, Loading, ListsModel);
}
]);

+ 0
- 90
js/app/controllers/settingscontroller.js View File

@@ -1,90 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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', 'CollectionsModel', 'SettingsBusinessLayer', 'SettingsModel', function($scope, $window, Status, $location, CollectionsModel, SettingsBusinessLayer, SettingsModel) {
'use strict';
var SettingsController;
SettingsController = (function() {
function SettingsController(_$scope, _$window, _$status, _$location, _$collectionsmodel, _$settingsbusinesslayer, _$settingsmodel) {
var _this = this;
this._$scope = _$scope;
this._$window = _$window;
this._$status = _$status;
this._$location = _$location;
this._$collectionsmodel = _$collectionsmodel;
this._$settingsbusinesslayer = _$settingsbusinesslayer;
this._$settingsmodel = _$settingsmodel;
this._$scope.status = this._$status.getStatus();
this._$scope.collections = this._$collectionsmodel.getAll();
this._$scope.settingsmodel = this._$settingsmodel;
this._$scope.collectionOptions = [
{
id: 0,
name: t('tasks', 'Hidden')
}, {
id: 1,
name: t('tasks', 'Visible')
}, {
id: 2,
name: t('tasks', 'Automatic')
}
];
this._$scope.startOfWeekOptions = [
{
id: 0,
name: t('tasks', 'Sunday')
}, {
id: 1,
name: t('tasks', 'Monday')
}, {
id: 2,
name: t('tasks', 'Tuesday')
}, {
id: 3,
name: t('tasks', 'Wednesday')
}, {
id: 4,
name: t('tasks', 'Thursday')
}, {
id: 5,
name: t('tasks', 'Friday')
}, {
id: 6,
name: t('tasks', 'Saturday')
}
];
this._$scope.setVisibility = function(collectionID) {
var collection;
collection = _$collectionsmodel.getById(collectionID);
return _$settingsbusinesslayer.setVisibility(collectionID, collection.show);
};
this._$scope.setStartOfWeek = function() {
return _$settingsbusinesslayer.set('various', 'startOfWeek', _$settingsmodel.getById('various').startOfWeek);
};
}

return SettingsController;

})();
return new SettingsController($scope, $window, Status, $location, CollectionsModel, SettingsBusinessLayer, SettingsModel);
}
]);

+ 0
- 456
js/app/controllers/taskscontroller.js View File

@@ -1,456 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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/>.
*
*/

(function() {
'use strict';
var __indexOf = [].indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
};

angular.module('Tasks').controller('TasksController', [
'$scope', '$window', '$routeParams', 'TasksModel', 'ListsModel', 'CollectionsModel', 'TasksBusinessLayer', '$location',
'SettingsBusinessLayer', 'SearchBusinessLayer', 'VTodo', 'SettingsModel',
function($scope, $window, $routeParams, TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location,
SettingsBusinessLayer, SearchBusinessLayer, VTodo, SettingsModel) {
var TasksController;
TasksController = (function() {
function TasksController(_$scope, _$window, _$routeParams, _$tasksmodel, _$listsmodel, _$collectionsmodel, _tasksbusinesslayer, $location,
_settingsbusinesslayer, _searchbusinesslayer, vtodo, _$settingsmodel) {
var _this = this;
this._$scope = _$scope;
this._$window = _$window;
this._$routeParams = _$routeParams;
this._$tasksmodel = _$tasksmodel;
this._$listsmodel = _$listsmodel;
this._$collectionsmodel = _$collectionsmodel;
this._tasksbusinesslayer = _tasksbusinesslayer;
this.$location = $location;
this._settingsbusinesslayer = _settingsbusinesslayer;
this._searchbusinesslayer = _searchbusinesslayer;
this._vtodo = vtodo;
this._$scope.tasks = this._$tasksmodel.getAll();
this._$scope.draggedTasks = [];
this._$scope.calendars = this._$listsmodel.getAll();
this._$scope.days = [0, 1, 2, 3, 4, 5, 6];
this._$scope.isAddingTask = false;
this._$scope.focusInputField = false;
this._$scope.TasksModel = this._$tasksmodel;
this._$scope.TasksBusinessLayer = this._tasksbusinesslayer;
this._$settingsmodel = _$settingsmodel;

this._$scope.addTask = function(taskName, related, calendar, parent) {
var _ref, _this = this;
if (calendar === null) {
calendar = '';
}
_$scope.isAddingTask = true;
var task = {
calendar: null,
related: related,
summary: taskName,
priority: '0',
due: false,
start: false,
reminder: null,
completed: false,
complete: '0',
note: ''
};
if (((_ref = _$scope.route.collectionID) === 'starred' || _ref === 'today' || _ref === 'week' || _ref === 'all' || _ref === 'completed' || _ref === 'current')) {
if (related) {
task.calendar = calendar;
} else {
task.calendar = _$listsmodel.getStandardList();
}
if (_$scope.route.collectionID === 'starred') {
task.priority = '1';
}
if (_$scope.route.collectionID === 'today') {
task.due = moment().startOf('day').format("YYYY-MM-DDTHH:mm:ss");
}
if (_$scope.route.collectionID === 'current') {
task.start = moment().format("YYYY-MM-DDTHH:mm:ss");
}
} else {
task.calendar = _$listsmodel.getByUri(_$scope.route.calendarID);
}
task = VTodo.create(task);
_tasksbusinesslayer.add(task).then(function(task) {
_$scope.isAddingTask = false;
_$scope.openDetails(task.uri, null);
return $scope.$apply();
});
if (parent) {
_tasksbusinesslayer.setHideSubtasks(parent, 0);
}
_$scope.status.focusTaskInput = false;
_$scope.status.focusSubtaskInput = false;
_$scope.status.addSubtaskTo = null;
_$scope.status.taskName = '';
_$scope.status.subtaskName = '';
};

this._$scope.getAddString = function() {
var calendar = _$listsmodel.getStandardList();
if (angular.isDefined(calendar)) {
if (angular.isDefined(_$scope.route.collectionID)) {
switch (_$scope.route.collectionID) {
case 'starred':
return t('tasks', 'Add an important item in "%s"...').replace('%s', calendar.displayname);
case 'today':
return t('tasks', 'Add an item due today in "%s"...').replace('%s', calendar.displayname);
case 'all':
return t('tasks', 'Add an item in "%s"...').replace('%s', calendar.displayname);
case 'current':
return t('tasks', 'Add a current item in "%s"...').replace('%s', calendar.displayname);
case 'completed':
case 'week':
return null;
}
} else {
if (angular.isDefined(_$listsmodel.getByUri(_$scope.route.calendarID))) {
return t('tasks', 'Add an item in "%s"...').replace('%s', _$listsmodel.getByUri(_$scope.route.calendarID).displayname);
}
}
}
};

this._$scope.getSubAddString = function(taskname) {
return t('tasks', 'Add a subtask to "%s"...').replace('%s', taskname);
};

this._$scope.showSubtaskInput = function(uid) {
_$scope.status.addSubtaskTo = uid;
};

this._$scope.hideSubtasks = function(task) {
var taskID = _$scope.route.taskID;
var descendantIDs = _$tasksmodel.getDescendantIDs(task);
if (task.uri === taskID) {
return false;
} else if (__indexOf.call(descendantIDs, taskID) >= 0) {
return false;
} else {
return task.hideSubtasks;
}
};

this._$scope.showInput = function() {
var collectionID = _$scope.route.collectionID;
var calendar = _$listsmodel.getByUri(_$scope.route.calendarID);
if (collectionID === 'completed' || collectionID === 'week') {
return false;
}
if (angular.isDefined(calendar)) {
return calendar.writable;
} else {
return true;
}
};

this._$scope.focusTaskInput = function() {
_$scope.status.focusTaskInput = true;
};
this._$scope.focusSubtaskInput = function() {
_$scope.status.focusSubtaskInput = true;
};

this._$scope.openDetails = function(id, $event) {
var calendarID = _$scope.route.calendarID;
var collectionID = _$scope.route.collectionID;
if ($event === null || $($event.currentTarget).is($($event.target).closest('.handler'))) {
var parent = _$tasksmodel.getByUri(id);
if (!parent.loadedCompleted) {
_tasksbusinesslayer.getAll(parent.calendar, true, parent).then(function() {
parent.loadedCompleted = true;
$scope.$apply();
});
}
if (calendarID) {
$location.path('/calendars/' + calendarID + '/tasks/' + id);
} else if (collectionID) {
$location.path('/collections/' + collectionID + '/tasks/' + id);
}
}
};

this._$scope.toggleCompleted = function(task) {
if (task.completed) {
_tasksbusinesslayer.setPercentComplete(task, 0);
} else {
_tasksbusinesslayer.setPercentComplete(task, 100);
}
};

this._$scope.toggleStarred = function(task) {
if (task.priority > 5) {
_tasksbusinesslayer.setPriority(task, 0);
} else {
_tasksbusinesslayer.setPriority(task, 9);
}
};

this._$scope.toggleHidden = function() {
return _settingsbusinesslayer.toggle('various', 'showHidden');
};

this._$scope.filterTasks = function(task, filter) {
return function(task) {
return _$tasksmodel.filterTasks(task, filter);
};
};

this._$scope.getSubTasks = function(tasks, parent) {
var ret, task, _i, _len;
ret = [];
for (_i = 0, _len = tasks.length; _i < _len; _i++) {
task = tasks[_i];
if (task.related === parent.uid && task !== parent && !(parent.hideCompletedSubtasks && task.completed)) {
ret.push(task);
}
}
return ret;
};

this._$scope.hasNoParent = function(task) {
return function(task) {
return _$tasksmodel.hasNoParent(task);
};
};

this._$scope.hasSubtasks = function(task) {
return _$tasksmodel.hasSubtasks(task.uid);
};

this._$scope.hasCompletedSubtasks = function(task) {
return _$tasksmodel.hasCompletedSubtasks(task.uid);
};

this._$scope.toggleSubtasks = function(task) {
_tasksbusinesslayer.setHideSubtasks(task, !task.hideSubtasks);
};

this._$scope.toggleCompletedSubtasks = function(task) {
_tasksbusinesslayer.setHideCompletedSubtasks(task, !task.hideCompletedSubtasks);
};

this._$scope.filterTasksByString = function(task) {
return function(task) {
var filter = _searchbusinesslayer.getFilter();
return _$tasksmodel.filterTasksByString(task, filter);
};
};

this._$scope.filteredTasks = function() {
var filter;
filter = _searchbusinesslayer.getFilter();
return _$tasksmodel.filteredTasks(filter);
};

this._$scope.dayHasEntry = function() {
return function(date) {
var filter, task, tasks, _i, _len;
filter = _searchbusinesslayer.getFilter();
tasks = _$tasksmodel.filteredTasks(filter);
for (_i = 0, _len = tasks.length; _i < _len; _i++) {
task = tasks[_i];
if (task.completed || !_$tasksmodel.hasNoParent(task)) {
continue;
}
if (_$tasksmodel.taskAtDay(task, date)) {
return true;
}
}
return false;
};
};
this._$scope.taskAtDay = function(task, day) {
return function(task) {
return _$tasksmodel.taskAtDay(task, day);
};
};
this._$scope.filterLists = function() {
return function(calendar) {
return _$scope.getCount(calendar.uri, _$scope.route.collectionID);
};
};

this._$scope.getCount = function(calendarID, type) {
var filter = _searchbusinesslayer.getFilter();
return _$listsmodel.getCount(calendarID, type, filter);
};

this._$scope.getCountString = function(calendarID, type) {
var filter = _searchbusinesslayer.getFilter();
return n('tasks', '%n Completed Task', '%n Completed Tasks', _$listsmodel.getCount(calendarID, type, filter));
};

this._$scope.checkTaskInput = function($event) {
if ($event.keyCode === 27) {
$($event.currentTarget).blur();
_$scope.status.taskName = '';
_$scope.status.subtaskName = '';
_$scope.status.addSubtaskTo = null;
_$scope.status.focusTaskInput = false;
_$scope.status.focusSubtaskInput = false;
}
};

this._$scope.getCompletedTasks = function(calendarID) {
var calendar = _$listsmodel.getById(calendarID);
_tasksbusinesslayer.getAll(calendar, true).then(function() {
_$listsmodel.setLoadedCompleted(calendarID);
$scope.$apply();
});
};

this._$scope.loadedCompleted = function(calendarID) {
return _$listsmodel.loadedCompleted(calendarID);
};

this._$scope.sortDue = function(task) {
if (task.due === null) {
return 'last';
} else {
return task.due;
}
};

this._$scope.sortStart = function(task) {
if (task.start === null) {
return 'last';
} else {
return task.start;
}
};

this._$scope.getSortOrder = function() {
switch (_$scope.settingsmodel.getById('various').sortOrder) {
case 'due':
return _$scope.sortDue;
case 'start':
return _$scope.sortStart;
case 'priority':
return '-priority';
case 'alphabetically':
return 'summary';
case 'manual':
return 'manual';
default:
return ['completed', _$scope.sortDue, '-priority', _$scope.sortStart, 'summary'];
}
};

this._$scope.getSortOrderIcon = function() {
switch (_$scope.settingsmodel.getById('various').sortOrder) {
case 'due':
case 'start':
return 'icon-calendar';
case 'priority':
return 'icon-task-star';
case 'alphabetically':
return 'icon-alphabetically';
case 'manual':
return 'icon-manual';
default:
return 'icon-list';
}
};

this._$scope.setSortOrder = function($event, order) {
_$scope.settingsmodel.getById('various').sortDirection = (_$scope.settingsmodel.getById('various').sortOrder === order) ? +!_$scope.settingsmodel.getById('various').sortDirection : 0;
_$scope.settingsmodel.getById('various').sortOrder = order;
_settingsbusinesslayer.set('various', 'sortOrder', order);
_settingsbusinesslayer.set('various', 'sortDirection', _$scope.settingsmodel.getById('various').sortDirection);
};

this._$scope.dropAsSubtask = function($event, item, index) {
if ($event.dataTransfer.dropEffect === 'move') {
var parentID = $($event.target).closest('.task-item').attr('taskID');
var task = _$tasksmodel.getByUri(item.uri);
var parent = _$tasksmodel.getByUri(parentID);
_tasksbusinesslayer.changeParent(task, parent);
}
$('.subtasks-container').removeClass('dropzone-visible');
return true;

};

this._$scope.dropAsRootTask = function($event, item, index) {
if ($event.dataTransfer.dropEffect === 'move') {
var task = _$tasksmodel.getByUri(item.uri);
var collectionID = $($event.target).closest('ol[dnd-list]').attr('collectionID');
var calendarID = $($event.target).closest('ol[dnd-list]').attr('calendarID');
var newCalendar = _$listsmodel.getByUri(calendarID);
var queries = _tasksbusinesslayer.makeRootTask(task, newCalendar, collectionID);
Promise.all(queries).then(function() {
$scope.$apply();
});
}
$('.subtasks-container').removeClass('dropzone-visible');
return true;
};

this._$scope.dragover = function($event, item, index) {
$('.subtasks-container').removeClass('dropzone-visible');
var calendarID = $($event.target).closest('ol[dnd-list]').attr('calendarID');
var calendar = _$listsmodel.getByUri(calendarID);
if (calendar.writable) {
$($event.target).closest('.task-item').children('.subtasks-container').addClass('dropzone-visible');
return true;
} else {
return false;
}
};

this._$scope.allow = function(task) {
if (task.calendar.writable) {
return "copyMove";
} else {
return "copy";
}
};

this._$scope.dragStart = function($event) {
if ($event.dataTransfer.effectAllowed === 'copy' || ($event.dataTransfer.effectAllowed === 'copyMove' && $event.ctrlKey)) {
$($event.target).addClass('copy');
}
};

this._$scope.dragEnd = function($event) {
$($event.target).removeClass('copy');
};
}

return TasksController;

})();
return new TasksController($scope, $window, $routeParams, TasksModel, ListsModel, CollectionsModel, TasksBusinessLayer, $location, SettingsBusinessLayer,
SearchBusinessLayer, VTodo, SettingsModel);
}
]);

}).call(this);

+ 0
- 40
js/app/directives/appnavigationentryutils.js View File

@@ -1,40 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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('appNavigationEntryUtils', function() {
'use strict';
return {
restrict: 'C',
link: function(scope, elm) {
var button, menu;
menu = elm.siblings('.app-navigation-entry-menu');
button = $(elm).find('.app-navigation-entry-utils-menu-button button');
button.click(function() {
menu.toggleClass('open');
});
scope.$on('documentClicked', function(scope, event) {
if (event.target !== button[0]) {
menu.removeClass('open');
}
});
}
};
});

+ 0
- 27
js/app/directives/autofocusoninsert.js View File

@@ -1,27 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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('autofocusOnInsert', function() {
'use strict';
return function(scope, elm) {
return elm.focus();
};
});

+ 0
- 35
js/app/directives/avatar.js View File

@@ -1,35 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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('avatar', function() {
'use strict';
return {
restrict: 'A',
scope: false,
link: function(scope, elm, attr) {
return attr.$observe('userid', function() {
if (attr.userid) {
return elm.avatar(attr.userid, attr.size);
}
});
}
};
});

+ 0
- 167
js/app/directives/colorpickerDirective.js View File

@@ -1,167 +0,0 @@
/**
* Nextcloud - Tasks App
*
* @author Raghu Nayyar
* @author Georg Ehrke
* @copyright 2017 Raghu Nayyar <beingminimal@gmail.com>
* @copyright 2017 Georg Ehrke <oc.list@georgehrke.com>
* @copyright 2017 John Molakvoæ <fremulon@protonmail.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/>.
*
*/

/* https://github.com/kayellpeee/hsl_rgb_converter
* expected hue range: [0, 360)
* expected saturation range: [0, 1]
* expected lightness range: [0, 1]
*/
var hslToRgb = function(hue, saturation, lightness) {
'use strict';
// based on algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
if(Array.isArray(hue)) {
saturation = hue[1];
lightness = hue[2];
hue = hue[0];
}
if (hue === undefined) {
return [0, 0, 0];
}
saturation /= 100;
lightness /= 100;

var chroma = (1 - Math.abs((2 * lightness) - 1)) * saturation;
var huePrime = hue / 60;
var secondComponent = chroma * (1 - Math.abs((huePrime % 2) - 1));

huePrime = Math.floor(huePrime);
var red;
var green;
var blue;

if (huePrime === 0) {
red = chroma;
green = secondComponent;
blue = 0;
} else if (huePrime === 1) {
red = secondComponent;
green = chroma;
blue = 0;
} else if (huePrime === 2) {
red = 0;
green = chroma;
blue = secondComponent;
} else if (huePrime === 3) {
red = 0;
green = secondComponent;
blue = chroma;
} else if (huePrime === 4) {
red = secondComponent;
green = 0;
blue = chroma;
} else if (huePrime === 5) {
red = chroma;
green = 0;
blue = secondComponent;
}

var lightnessAdjustment = lightness - (chroma / 2);
red += lightnessAdjustment;
green += lightnessAdjustment;
blue += lightnessAdjustment;

return [Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255)];

};

/*
* Convert rgb array to hex string
*/
var rgbToHex = function(r, g, b) {
'use strict';
if(Array.isArray(r)) {
g = r[1];
b = r[2];
r = r[0];
}
return '#' + parseInt(r, 10).toString(16) + parseInt(g, 10).toString(16) + parseInt(b, 10).toString(16);
};

var listofcolours = [
'#31CC7C',
'#317CCC',
'#FF7A66',
'#F1DB50',
'#7C31CC',
'#CC317C',
'#3A3B3D',
'#CACBCD'
];

/*
* Generate a random colour with the core generator
*/
var randColour = function() {
'use strict';
if (typeof String.prototype.toHsl === 'function') {
return rgbToHex(hslToRgb(Math.random().toString().toHsl()));
} else {
return listofcolours[Math.floor(Math.random() * listofcolours.length)];
}
};

/**
* Directive: Colorpicker
* Description: Colorpicker for the Tasks app.
*/


angular.module('Tasks').directive('colorpicker', function() {
'use strict';
if (typeof String.prototype.toHsl === 'function') {
var hsl = "";
var hslcolour = "";
// 0 40 80 120 160 200 240 280 320
listofcolours = ["15", "9", "4", "b", "6", "11", "74", "f", "57"];
listofcolours.forEach(function(hash, index) {
hsl = hash.toHsl();
hslcolour = hslToRgb(hsl);
listofcolours[index] = rgbToHex(hslcolour);
});
}
return {
scope: {
selected: '=',
customizedColors: '=colors'
},
restrict: 'AE',
templateUrl: OC.filePath('tasks', 'templates', 'colorpicker.html'),
link: function(scope, element, attr) {
scope.colors = scope.customizedColors || listofcolours;
scope.selected = scope.selected || scope.colors[0];
scope.random = "#000000";

scope.randomizeColour = function() {
scope.random = randColour();
scope.pick(scope.random);
};

scope.pick = function(color) {
scope.selected = color;
};

}
};

});

+ 0
- 56
js/app/directives/datepicker.js View File

@@ -1,56 +0,0 @@
/**
* Nextcloud - Tasks
*
* @author Raimund Schlüßler
* @copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org>
*
* 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('datepicker', function() {
'use strict';
return {
restrict: 'A',
scope: false,